]> git.openstreetmap.org Git - rails.git/blob - vendor/assets/iD/iD/mapillary-js/mapillary.module.js
Merge remote-tracking branch 'upstream/pull/3716'
[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 (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
21     return extendStatics(d, b);
22 };
23
24 function __extends(d, b) {
25     if (typeof b !== "function" && b !== null)
26         throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
27     extendStatics(d, b);
28     function __() { this.constructor = d; }
29     d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
30 }
31
32 function __awaiter(thisArg, _arguments, P, generator) {
33     function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
34     return new (P || (P = Promise))(function (resolve, reject) {
35         function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
36         function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
37         function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
38         step((generator = generator.apply(thisArg, _arguments || [])).next());
39     });
40 }
41
42 function __generator(thisArg, body) {
43     var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
44     return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
45     function verb(n) { return function (v) { return step([n, v]); }; }
46     function step(op) {
47         if (f) throw new TypeError("Generator is already executing.");
48         while (_) try {
49             if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
50             if (y = 0, t) op = [op[0] & 2, t.value];
51             switch (op[0]) {
52                 case 0: case 1: t = op; break;
53                 case 4: _.label++; return { value: op[1], done: false };
54                 case 5: _.label++; y = op[1]; op = [0]; continue;
55                 case 7: op = _.ops.pop(); _.trys.pop(); continue;
56                 default:
57                     if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
58                     if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
59                     if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
60                     if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
61                     if (t[2]) _.ops.pop();
62                     _.trys.pop(); continue;
63             }
64             op = body.call(thisArg, _);
65         } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
66         if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
67     }
68 }
69
70 function __values(o) {
71     var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
72     if (m) return m.call(o);
73     if (o && typeof o.length === "number") return {
74         next: function () {
75             if (o && i >= o.length) o = void 0;
76             return { value: o && o[i++], done: !o };
77         }
78     };
79     throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
80 }
81
82 function __read(o, n) {
83     var m = typeof Symbol === "function" && o[Symbol.iterator];
84     if (!m) return o;
85     var i = m.call(o), r, ar = [], e;
86     try {
87         while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
88     }
89     catch (error) { e = { error: error }; }
90     finally {
91         try {
92             if (r && !r.done && (m = i["return"])) m.call(i);
93         }
94         finally { if (e) throw e.error; }
95     }
96     return ar;
97 }
98
99 function __spreadArray(to, from) {
100     for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
101         to[j] = from[i];
102     return to;
103 }
104
105 function __await(v) {
106     return this instanceof __await ? (this.v = v, this) : new __await(v);
107 }
108
109 function __asyncGenerator(thisArg, _arguments, generator) {
110     if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
111     var g = generator.apply(thisArg, _arguments || []), i, q = [];
112     return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
113     function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
114     function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
115     function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
116     function fulfill(value) { resume("next", value); }
117     function reject(value) { resume("throw", value); }
118     function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
119 }
120
121 function __asyncValues(o) {
122     if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
123     var m = o[Symbol.asyncIterator], i;
124     return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
125     function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
126     function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
127 }
128
129 function isFunction(value) {
130     return typeof value === 'function';
131 }
132
133 function createErrorClass(createImpl) {
134     var _super = function (instance) {
135         Error.call(instance);
136         instance.stack = new Error().stack;
137     };
138     var ctorFunc = createImpl(_super);
139     ctorFunc.prototype = Object.create(Error.prototype);
140     ctorFunc.prototype.constructor = ctorFunc;
141     return ctorFunc;
142 }
143
144 var UnsubscriptionError = createErrorClass(function (_super) {
145     return function UnsubscriptionErrorImpl(errors) {
146         _super(this);
147         this.message = errors
148             ? errors.length + " errors occurred during unsubscription:\n" + errors.map(function (err, i) { return i + 1 + ") " + err.toString(); }).join('\n  ')
149             : '';
150         this.name = 'UnsubscriptionError';
151         this.errors = errors;
152     };
153 });
154
155 function arrRemove(arr, item) {
156     if (arr) {
157         var index = arr.indexOf(item);
158         0 <= index && arr.splice(index, 1);
159     }
160 }
161
162 var Subscription = (function () {
163     function Subscription(initialTeardown) {
164         this.initialTeardown = initialTeardown;
165         this.closed = false;
166         this._parentage = null;
167         this._teardowns = null;
168     }
169     Subscription.prototype.unsubscribe = function () {
170         var e_1, _a, e_2, _b;
171         var errors;
172         if (!this.closed) {
173             this.closed = true;
174             var _parentage = this._parentage;
175             if (_parentage) {
176                 this._parentage = null;
177                 if (Array.isArray(_parentage)) {
178                     try {
179                         for (var _parentage_1 = __values(_parentage), _parentage_1_1 = _parentage_1.next(); !_parentage_1_1.done; _parentage_1_1 = _parentage_1.next()) {
180                             var parent_1 = _parentage_1_1.value;
181                             parent_1.remove(this);
182                         }
183                     }
184                     catch (e_1_1) { e_1 = { error: e_1_1 }; }
185                     finally {
186                         try {
187                             if (_parentage_1_1 && !_parentage_1_1.done && (_a = _parentage_1.return)) _a.call(_parentage_1);
188                         }
189                         finally { if (e_1) throw e_1.error; }
190                     }
191                 }
192                 else {
193                     _parentage.remove(this);
194                 }
195             }
196             var initialTeardown = this.initialTeardown;
197             if (isFunction(initialTeardown)) {
198                 try {
199                     initialTeardown();
200                 }
201                 catch (e) {
202                     errors = e instanceof UnsubscriptionError ? e.errors : [e];
203                 }
204             }
205             var _teardowns = this._teardowns;
206             if (_teardowns) {
207                 this._teardowns = null;
208                 try {
209                     for (var _teardowns_1 = __values(_teardowns), _teardowns_1_1 = _teardowns_1.next(); !_teardowns_1_1.done; _teardowns_1_1 = _teardowns_1.next()) {
210                         var teardown_1 = _teardowns_1_1.value;
211                         try {
212                             execTeardown(teardown_1);
213                         }
214                         catch (err) {
215                             errors = errors !== null && errors !== void 0 ? errors : [];
216                             if (err instanceof UnsubscriptionError) {
217                                 errors = __spreadArray(__spreadArray([], __read(errors)), __read(err.errors));
218                             }
219                             else {
220                                 errors.push(err);
221                             }
222                         }
223                     }
224                 }
225                 catch (e_2_1) { e_2 = { error: e_2_1 }; }
226                 finally {
227                     try {
228                         if (_teardowns_1_1 && !_teardowns_1_1.done && (_b = _teardowns_1.return)) _b.call(_teardowns_1);
229                     }
230                     finally { if (e_2) throw e_2.error; }
231                 }
232             }
233             if (errors) {
234                 throw new UnsubscriptionError(errors);
235             }
236         }
237     };
238     Subscription.prototype.add = function (teardown) {
239         var _a;
240         if (teardown && teardown !== this) {
241             if (this.closed) {
242                 execTeardown(teardown);
243             }
244             else {
245                 if (teardown instanceof Subscription) {
246                     if (teardown.closed || teardown._hasParent(this)) {
247                         return;
248                     }
249                     teardown._addParent(this);
250                 }
251                 (this._teardowns = (_a = this._teardowns) !== null && _a !== void 0 ? _a : []).push(teardown);
252             }
253         }
254     };
255     Subscription.prototype._hasParent = function (parent) {
256         var _parentage = this._parentage;
257         return _parentage === parent || (Array.isArray(_parentage) && _parentage.includes(parent));
258     };
259     Subscription.prototype._addParent = function (parent) {
260         var _parentage = this._parentage;
261         this._parentage = Array.isArray(_parentage) ? (_parentage.push(parent), _parentage) : _parentage ? [_parentage, parent] : parent;
262     };
263     Subscription.prototype._removeParent = function (parent) {
264         var _parentage = this._parentage;
265         if (_parentage === parent) {
266             this._parentage = null;
267         }
268         else if (Array.isArray(_parentage)) {
269             arrRemove(_parentage, parent);
270         }
271     };
272     Subscription.prototype.remove = function (teardown) {
273         var _teardowns = this._teardowns;
274         _teardowns && arrRemove(_teardowns, teardown);
275         if (teardown instanceof Subscription) {
276             teardown._removeParent(this);
277         }
278     };
279     Subscription.EMPTY = (function () {
280         var empty = new Subscription();
281         empty.closed = true;
282         return empty;
283     })();
284     return Subscription;
285 }());
286 var EMPTY_SUBSCRIPTION = Subscription.EMPTY;
287 function isSubscription(value) {
288     return (value instanceof Subscription ||
289         (value && 'closed' in value && isFunction(value.remove) && isFunction(value.add) && isFunction(value.unsubscribe)));
290 }
291 function execTeardown(teardown) {
292     if (isFunction(teardown)) {
293         teardown();
294     }
295     else {
296         teardown.unsubscribe();
297     }
298 }
299
300 var config = {
301     onUnhandledError: null,
302     onStoppedNotification: null,
303     Promise: undefined,
304     useDeprecatedSynchronousErrorHandling: false,
305     useDeprecatedNextContext: false,
306 };
307
308 var timeoutProvider = {
309     setTimeout: function () {
310         var args = [];
311         for (var _i = 0; _i < arguments.length; _i++) {
312             args[_i] = arguments[_i];
313         }
314         var delegate = timeoutProvider.delegate;
315         return ((delegate === null || delegate === void 0 ? void 0 : delegate.setTimeout) || setTimeout).apply(void 0, __spreadArray([], __read(args)));
316     },
317     clearTimeout: function (handle) {
318         var delegate = timeoutProvider.delegate;
319         return ((delegate === null || delegate === void 0 ? void 0 : delegate.clearTimeout) || clearTimeout)(handle);
320     },
321     delegate: undefined,
322 };
323
324 function reportUnhandledError(err) {
325     timeoutProvider.setTimeout(function () {
326         {
327             throw err;
328         }
329     });
330 }
331
332 function noop() { }
333
334 var COMPLETE_NOTIFICATION = (function () { return createNotification('C', undefined, undefined); })();
335 function errorNotification(error) {
336     return createNotification('E', undefined, error);
337 }
338 function nextNotification(value) {
339     return createNotification('N', value, undefined);
340 }
341 function createNotification(kind, value, error) {
342     return {
343         kind: kind,
344         value: value,
345         error: error,
346     };
347 }
348
349 var context = null;
350 function errorContext(cb) {
351     if (config.useDeprecatedSynchronousErrorHandling) {
352         var isRoot = !context;
353         if (isRoot) {
354             context = { errorThrown: false, error: null };
355         }
356         cb();
357         if (isRoot) {
358             var _a = context, errorThrown = _a.errorThrown, error = _a.error;
359             context = null;
360             if (errorThrown) {
361                 throw error;
362             }
363         }
364     }
365     else {
366         cb();
367     }
368 }
369
370 var Subscriber = (function (_super) {
371     __extends(Subscriber, _super);
372     function Subscriber(destination) {
373         var _this = _super.call(this) || this;
374         _this.isStopped = false;
375         if (destination) {
376             _this.destination = destination;
377             if (isSubscription(destination)) {
378                 destination.add(_this);
379             }
380         }
381         else {
382             _this.destination = EMPTY_OBSERVER;
383         }
384         return _this;
385     }
386     Subscriber.create = function (next, error, complete) {
387         return new SafeSubscriber(next, error, complete);
388     };
389     Subscriber.prototype.next = function (value) {
390         if (this.isStopped) {
391             handleStoppedNotification(nextNotification(value), this);
392         }
393         else {
394             this._next(value);
395         }
396     };
397     Subscriber.prototype.error = function (err) {
398         if (this.isStopped) {
399             handleStoppedNotification(errorNotification(err), this);
400         }
401         else {
402             this.isStopped = true;
403             this._error(err);
404         }
405     };
406     Subscriber.prototype.complete = function () {
407         if (this.isStopped) {
408             handleStoppedNotification(COMPLETE_NOTIFICATION, this);
409         }
410         else {
411             this.isStopped = true;
412             this._complete();
413         }
414     };
415     Subscriber.prototype.unsubscribe = function () {
416         if (!this.closed) {
417             this.isStopped = true;
418             _super.prototype.unsubscribe.call(this);
419             this.destination = null;
420         }
421     };
422     Subscriber.prototype._next = function (value) {
423         this.destination.next(value);
424     };
425     Subscriber.prototype._error = function (err) {
426         try {
427             this.destination.error(err);
428         }
429         finally {
430             this.unsubscribe();
431         }
432     };
433     Subscriber.prototype._complete = function () {
434         try {
435             this.destination.complete();
436         }
437         finally {
438             this.unsubscribe();
439         }
440     };
441     return Subscriber;
442 }(Subscription));
443 var SafeSubscriber = (function (_super) {
444     __extends(SafeSubscriber, _super);
445     function SafeSubscriber(observerOrNext, error, complete) {
446         var _this = _super.call(this) || this;
447         var next;
448         if (isFunction(observerOrNext)) {
449             next = observerOrNext;
450         }
451         else if (observerOrNext) {
452             (next = observerOrNext.next, error = observerOrNext.error, complete = observerOrNext.complete);
453             var context_1;
454             if (_this && config.useDeprecatedNextContext) {
455                 context_1 = Object.create(observerOrNext);
456                 context_1.unsubscribe = function () { return _this.unsubscribe(); };
457             }
458             else {
459                 context_1 = observerOrNext;
460             }
461             next = next === null || next === void 0 ? void 0 : next.bind(context_1);
462             error = error === null || error === void 0 ? void 0 : error.bind(context_1);
463             complete = complete === null || complete === void 0 ? void 0 : complete.bind(context_1);
464         }
465         _this.destination = {
466             next: next ? wrapForErrorHandling(next) : noop,
467             error: wrapForErrorHandling(error !== null && error !== void 0 ? error : defaultErrorHandler),
468             complete: complete ? wrapForErrorHandling(complete) : noop,
469         };
470         return _this;
471     }
472     return SafeSubscriber;
473 }(Subscriber));
474 function wrapForErrorHandling(handler, instance) {
475     return function () {
476         var args = [];
477         for (var _i = 0; _i < arguments.length; _i++) {
478             args[_i] = arguments[_i];
479         }
480         try {
481             handler.apply(void 0, __spreadArray([], __read(args)));
482         }
483         catch (err) {
484             {
485                 reportUnhandledError(err);
486             }
487         }
488     };
489 }
490 function defaultErrorHandler(err) {
491     throw err;
492 }
493 function handleStoppedNotification(notification, subscriber) {
494     var onStoppedNotification = config.onStoppedNotification;
495     onStoppedNotification && timeoutProvider.setTimeout(function () { return onStoppedNotification(notification, subscriber); });
496 }
497 var EMPTY_OBSERVER = {
498     closed: true,
499     next: noop,
500     error: defaultErrorHandler,
501     complete: noop,
502 };
503
504 var observable = (function () { return (typeof Symbol === 'function' && Symbol.observable) || '@@observable'; })();
505
506 function identity(x) {
507     return x;
508 }
509
510 function pipeFromArray(fns) {
511     if (fns.length === 0) {
512         return identity;
513     }
514     if (fns.length === 1) {
515         return fns[0];
516     }
517     return function piped(input) {
518         return fns.reduce(function (prev, fn) { return fn(prev); }, input);
519     };
520 }
521
522 var Observable = (function () {
523     function Observable(subscribe) {
524         if (subscribe) {
525             this._subscribe = subscribe;
526         }
527     }
528     Observable.prototype.lift = function (operator) {
529         var observable = new Observable();
530         observable.source = this;
531         observable.operator = operator;
532         return observable;
533     };
534     Observable.prototype.subscribe = function (observerOrNext, error, complete) {
535         var _this = this;
536         var subscriber = isSubscriber(observerOrNext) ? observerOrNext : new SafeSubscriber(observerOrNext, error, complete);
537         errorContext(function () {
538             var _a = _this, operator = _a.operator, source = _a.source;
539             subscriber.add(operator
540                 ?
541                     operator.call(subscriber, source)
542                 : source
543                     ?
544                         _this._subscribe(subscriber)
545                     :
546                         _this._trySubscribe(subscriber));
547         });
548         return subscriber;
549     };
550     Observable.prototype._trySubscribe = function (sink) {
551         try {
552             return this._subscribe(sink);
553         }
554         catch (err) {
555             sink.error(err);
556         }
557     };
558     Observable.prototype.forEach = function (next, promiseCtor) {
559         var _this = this;
560         promiseCtor = getPromiseCtor(promiseCtor);
561         return new promiseCtor(function (resolve, reject) {
562             var subscription;
563             subscription = _this.subscribe(function (value) {
564                 try {
565                     next(value);
566                 }
567                 catch (err) {
568                     reject(err);
569                     subscription === null || subscription === void 0 ? void 0 : subscription.unsubscribe();
570                 }
571             }, reject, resolve);
572         });
573     };
574     Observable.prototype._subscribe = function (subscriber) {
575         var _a;
576         return (_a = this.source) === null || _a === void 0 ? void 0 : _a.subscribe(subscriber);
577     };
578     Observable.prototype[observable] = function () {
579         return this;
580     };
581     Observable.prototype.pipe = function () {
582         var operations = [];
583         for (var _i = 0; _i < arguments.length; _i++) {
584             operations[_i] = arguments[_i];
585         }
586         return pipeFromArray(operations)(this);
587     };
588     Observable.prototype.toPromise = function (promiseCtor) {
589         var _this = this;
590         promiseCtor = getPromiseCtor(promiseCtor);
591         return new promiseCtor(function (resolve, reject) {
592             var value;
593             _this.subscribe(function (x) { return (value = x); }, function (err) { return reject(err); }, function () { return resolve(value); });
594         });
595     };
596     Observable.create = function (subscribe) {
597         return new Observable(subscribe);
598     };
599     return Observable;
600 }());
601 function getPromiseCtor(promiseCtor) {
602     var _a;
603     return (_a = promiseCtor !== null && promiseCtor !== void 0 ? promiseCtor : config.Promise) !== null && _a !== void 0 ? _a : Promise;
604 }
605 function isObserver(value) {
606     return value && isFunction(value.next) && isFunction(value.error) && isFunction(value.complete);
607 }
608 function isSubscriber(value) {
609     return (value && value instanceof Subscriber) || (isObserver(value) && isSubscription(value));
610 }
611
612 function hasLift(source) {
613     return isFunction(source === null || source === void 0 ? void 0 : source.lift);
614 }
615 function operate(init) {
616     return function (source) {
617         if (hasLift(source)) {
618             return source.lift(function (liftedSource) {
619                 try {
620                     return init(liftedSource, this);
621                 }
622                 catch (err) {
623                     this.error(err);
624                 }
625             });
626         }
627         throw new TypeError('Unable to lift unknown Observable type');
628     };
629 }
630
631 var OperatorSubscriber = (function (_super) {
632     __extends(OperatorSubscriber, _super);
633     function OperatorSubscriber(destination, onNext, onComplete, onError, onFinalize) {
634         var _this = _super.call(this, destination) || this;
635         _this.onFinalize = onFinalize;
636         _this._next = onNext
637             ? function (value) {
638                 try {
639                     onNext(value);
640                 }
641                 catch (err) {
642                     destination.error(err);
643                 }
644             }
645             : _super.prototype._next;
646         _this._error = onError
647             ? function (err) {
648                 try {
649                     onError(err);
650                 }
651                 catch (err) {
652                     destination.error(err);
653                 }
654                 finally {
655                     this.unsubscribe();
656                 }
657             }
658             : _super.prototype._error;
659         _this._complete = onComplete
660             ? function () {
661                 try {
662                     onComplete();
663                 }
664                 catch (err) {
665                     destination.error(err);
666                 }
667                 finally {
668                     this.unsubscribe();
669                 }
670             }
671             : _super.prototype._complete;
672         return _this;
673     }
674     OperatorSubscriber.prototype.unsubscribe = function () {
675         var _a;
676         var closed = this.closed;
677         _super.prototype.unsubscribe.call(this);
678         !closed && ((_a = this.onFinalize) === null || _a === void 0 ? void 0 : _a.call(this));
679     };
680     return OperatorSubscriber;
681 }(Subscriber));
682
683 function refCount() {
684     return operate(function (source, subscriber) {
685         var connection = null;
686         source._refCount++;
687         var refCounter = new OperatorSubscriber(subscriber, undefined, undefined, undefined, function () {
688             if (!source || source._refCount <= 0 || 0 < --source._refCount) {
689                 connection = null;
690                 return;
691             }
692             var sharedConnection = source._connection;
693             var conn = connection;
694             connection = null;
695             if (sharedConnection && (!conn || sharedConnection === conn)) {
696                 sharedConnection.unsubscribe();
697             }
698             subscriber.unsubscribe();
699         });
700         source.subscribe(refCounter);
701         if (!refCounter.closed) {
702             connection = source.connect();
703         }
704     });
705 }
706
707 var ConnectableObservable = (function (_super) {
708     __extends(ConnectableObservable, _super);
709     function ConnectableObservable(source, subjectFactory) {
710         var _this = _super.call(this) || this;
711         _this.source = source;
712         _this.subjectFactory = subjectFactory;
713         _this._subject = null;
714         _this._refCount = 0;
715         _this._connection = null;
716         if (hasLift(source)) {
717             _this.lift = source.lift;
718         }
719         return _this;
720     }
721     ConnectableObservable.prototype._subscribe = function (subscriber) {
722         return this.getSubject().subscribe(subscriber);
723     };
724     ConnectableObservable.prototype.getSubject = function () {
725         var subject = this._subject;
726         if (!subject || subject.isStopped) {
727             this._subject = this.subjectFactory();
728         }
729         return this._subject;
730     };
731     ConnectableObservable.prototype._teardown = function () {
732         this._refCount = 0;
733         var _connection = this._connection;
734         this._subject = this._connection = null;
735         _connection === null || _connection === void 0 ? void 0 : _connection.unsubscribe();
736     };
737     ConnectableObservable.prototype.connect = function () {
738         var _this = this;
739         var connection = this._connection;
740         if (!connection) {
741             connection = this._connection = new Subscription();
742             var subject_1 = this.getSubject();
743             connection.add(this.source.subscribe(new OperatorSubscriber(subject_1, undefined, function () {
744                 _this._teardown();
745                 subject_1.complete();
746             }, function (err) {
747                 _this._teardown();
748                 subject_1.error(err);
749             }, function () { return _this._teardown(); })));
750             if (connection.closed) {
751                 this._connection = null;
752                 connection = Subscription.EMPTY;
753             }
754         }
755         return connection;
756     };
757     ConnectableObservable.prototype.refCount = function () {
758         return refCount()(this);
759     };
760     return ConnectableObservable;
761 }(Observable));
762
763 var ObjectUnsubscribedError = createErrorClass(function (_super) {
764     return function ObjectUnsubscribedErrorImpl() {
765         _super(this);
766         this.name = 'ObjectUnsubscribedError';
767         this.message = 'object unsubscribed';
768     };
769 });
770
771 var Subject = (function (_super) {
772     __extends(Subject, _super);
773     function Subject() {
774         var _this = _super.call(this) || this;
775         _this.closed = false;
776         _this.observers = [];
777         _this.isStopped = false;
778         _this.hasError = false;
779         _this.thrownError = null;
780         return _this;
781     }
782     Subject.prototype.lift = function (operator) {
783         var subject = new AnonymousSubject(this, this);
784         subject.operator = operator;
785         return subject;
786     };
787     Subject.prototype._throwIfClosed = function () {
788         if (this.closed) {
789             throw new ObjectUnsubscribedError();
790         }
791     };
792     Subject.prototype.next = function (value) {
793         var _this = this;
794         errorContext(function () {
795             var e_1, _a;
796             _this._throwIfClosed();
797             if (!_this.isStopped) {
798                 var copy = _this.observers.slice();
799                 try {
800                     for (var copy_1 = __values(copy), copy_1_1 = copy_1.next(); !copy_1_1.done; copy_1_1 = copy_1.next()) {
801                         var observer = copy_1_1.value;
802                         observer.next(value);
803                     }
804                 }
805                 catch (e_1_1) { e_1 = { error: e_1_1 }; }
806                 finally {
807                     try {
808                         if (copy_1_1 && !copy_1_1.done && (_a = copy_1.return)) _a.call(copy_1);
809                     }
810                     finally { if (e_1) throw e_1.error; }
811                 }
812             }
813         });
814     };
815     Subject.prototype.error = function (err) {
816         var _this = this;
817         errorContext(function () {
818             _this._throwIfClosed();
819             if (!_this.isStopped) {
820                 _this.hasError = _this.isStopped = true;
821                 _this.thrownError = err;
822                 var observers = _this.observers;
823                 while (observers.length) {
824                     observers.shift().error(err);
825                 }
826             }
827         });
828     };
829     Subject.prototype.complete = function () {
830         var _this = this;
831         errorContext(function () {
832             _this._throwIfClosed();
833             if (!_this.isStopped) {
834                 _this.isStopped = true;
835                 var observers = _this.observers;
836                 while (observers.length) {
837                     observers.shift().complete();
838                 }
839             }
840         });
841     };
842     Subject.prototype.unsubscribe = function () {
843         this.isStopped = this.closed = true;
844         this.observers = null;
845     };
846     Object.defineProperty(Subject.prototype, "observed", {
847         get: function () {
848             var _a;
849             return ((_a = this.observers) === null || _a === void 0 ? void 0 : _a.length) > 0;
850         },
851         enumerable: false,
852         configurable: true
853     });
854     Subject.prototype._trySubscribe = function (subscriber) {
855         this._throwIfClosed();
856         return _super.prototype._trySubscribe.call(this, subscriber);
857     };
858     Subject.prototype._subscribe = function (subscriber) {
859         this._throwIfClosed();
860         this._checkFinalizedStatuses(subscriber);
861         return this._innerSubscribe(subscriber);
862     };
863     Subject.prototype._innerSubscribe = function (subscriber) {
864         var _a = this, hasError = _a.hasError, isStopped = _a.isStopped, observers = _a.observers;
865         return hasError || isStopped
866             ? EMPTY_SUBSCRIPTION
867             : (observers.push(subscriber), new Subscription(function () { return arrRemove(observers, subscriber); }));
868     };
869     Subject.prototype._checkFinalizedStatuses = function (subscriber) {
870         var _a = this, hasError = _a.hasError, thrownError = _a.thrownError, isStopped = _a.isStopped;
871         if (hasError) {
872             subscriber.error(thrownError);
873         }
874         else if (isStopped) {
875             subscriber.complete();
876         }
877     };
878     Subject.prototype.asObservable = function () {
879         var observable = new Observable();
880         observable.source = this;
881         return observable;
882     };
883     Subject.create = function (destination, source) {
884         return new AnonymousSubject(destination, source);
885     };
886     return Subject;
887 }(Observable));
888 var AnonymousSubject = (function (_super) {
889     __extends(AnonymousSubject, _super);
890     function AnonymousSubject(destination, source) {
891         var _this = _super.call(this) || this;
892         _this.destination = destination;
893         _this.source = source;
894         return _this;
895     }
896     AnonymousSubject.prototype.next = function (value) {
897         var _a, _b;
898         (_b = (_a = this.destination) === null || _a === void 0 ? void 0 : _a.next) === null || _b === void 0 ? void 0 : _b.call(_a, value);
899     };
900     AnonymousSubject.prototype.error = function (err) {
901         var _a, _b;
902         (_b = (_a = this.destination) === null || _a === void 0 ? void 0 : _a.error) === null || _b === void 0 ? void 0 : _b.call(_a, err);
903     };
904     AnonymousSubject.prototype.complete = function () {
905         var _a, _b;
906         (_b = (_a = this.destination) === null || _a === void 0 ? void 0 : _a.complete) === null || _b === void 0 ? void 0 : _b.call(_a);
907     };
908     AnonymousSubject.prototype._subscribe = function (subscriber) {
909         var _a, _b;
910         return (_b = (_a = this.source) === null || _a === void 0 ? void 0 : _a.subscribe(subscriber)) !== null && _b !== void 0 ? _b : EMPTY_SUBSCRIPTION;
911     };
912     return AnonymousSubject;
913 }(Subject));
914
915 var BehaviorSubject = (function (_super) {
916     __extends(BehaviorSubject, _super);
917     function BehaviorSubject(_value) {
918         var _this = _super.call(this) || this;
919         _this._value = _value;
920         return _this;
921     }
922     Object.defineProperty(BehaviorSubject.prototype, "value", {
923         get: function () {
924             return this.getValue();
925         },
926         enumerable: false,
927         configurable: true
928     });
929     BehaviorSubject.prototype._subscribe = function (subscriber) {
930         var subscription = _super.prototype._subscribe.call(this, subscriber);
931         !subscription.closed && subscriber.next(this._value);
932         return subscription;
933     };
934     BehaviorSubject.prototype.getValue = function () {
935         var _a = this, hasError = _a.hasError, thrownError = _a.thrownError, _value = _a._value;
936         if (hasError) {
937             throw thrownError;
938         }
939         this._throwIfClosed();
940         return _value;
941     };
942     BehaviorSubject.prototype.next = function (value) {
943         _super.prototype.next.call(this, (this._value = value));
944     };
945     return BehaviorSubject;
946 }(Subject));
947
948 var dateTimestampProvider = {
949     now: function () {
950         return (dateTimestampProvider.delegate || Date).now();
951     },
952     delegate: undefined,
953 };
954
955 var ReplaySubject = (function (_super) {
956     __extends(ReplaySubject, _super);
957     function ReplaySubject(_bufferSize, _windowTime, _timestampProvider) {
958         if (_bufferSize === void 0) { _bufferSize = Infinity; }
959         if (_windowTime === void 0) { _windowTime = Infinity; }
960         if (_timestampProvider === void 0) { _timestampProvider = dateTimestampProvider; }
961         var _this = _super.call(this) || this;
962         _this._bufferSize = _bufferSize;
963         _this._windowTime = _windowTime;
964         _this._timestampProvider = _timestampProvider;
965         _this._buffer = [];
966         _this._infiniteTimeWindow = true;
967         _this._infiniteTimeWindow = _windowTime === Infinity;
968         _this._bufferSize = Math.max(1, _bufferSize);
969         _this._windowTime = Math.max(1, _windowTime);
970         return _this;
971     }
972     ReplaySubject.prototype.next = function (value) {
973         var _a = this, isStopped = _a.isStopped, _buffer = _a._buffer, _infiniteTimeWindow = _a._infiniteTimeWindow, _timestampProvider = _a._timestampProvider, _windowTime = _a._windowTime;
974         if (!isStopped) {
975             _buffer.push(value);
976             !_infiniteTimeWindow && _buffer.push(_timestampProvider.now() + _windowTime);
977         }
978         this._trimBuffer();
979         _super.prototype.next.call(this, value);
980     };
981     ReplaySubject.prototype._subscribe = function (subscriber) {
982         this._throwIfClosed();
983         this._trimBuffer();
984         var subscription = this._innerSubscribe(subscriber);
985         var _a = this, _infiniteTimeWindow = _a._infiniteTimeWindow, _buffer = _a._buffer;
986         var copy = _buffer.slice();
987         for (var i = 0; i < copy.length && !subscriber.closed; i += _infiniteTimeWindow ? 1 : 2) {
988             subscriber.next(copy[i]);
989         }
990         this._checkFinalizedStatuses(subscriber);
991         return subscription;
992     };
993     ReplaySubject.prototype._trimBuffer = function () {
994         var _a = this, _bufferSize = _a._bufferSize, _timestampProvider = _a._timestampProvider, _buffer = _a._buffer, _infiniteTimeWindow = _a._infiniteTimeWindow;
995         var adjustedBufferSize = (_infiniteTimeWindow ? 1 : 2) * _bufferSize;
996         _bufferSize < Infinity && adjustedBufferSize < _buffer.length && _buffer.splice(0, _buffer.length - adjustedBufferSize);
997         if (!_infiniteTimeWindow) {
998             var now = _timestampProvider.now();
999             var last = 0;
1000             for (var i = 1; i < _buffer.length && _buffer[i] <= now; i += 2) {
1001                 last = i;
1002             }
1003             last && _buffer.splice(0, last + 1);
1004         }
1005     };
1006     return ReplaySubject;
1007 }(Subject));
1008
1009 var Action = (function (_super) {
1010     __extends(Action, _super);
1011     function Action(scheduler, work) {
1012         return _super.call(this) || this;
1013     }
1014     Action.prototype.schedule = function (state, delay) {
1015         return this;
1016     };
1017     return Action;
1018 }(Subscription));
1019
1020 var intervalProvider = {
1021     setInterval: function () {
1022         var args = [];
1023         for (var _i = 0; _i < arguments.length; _i++) {
1024             args[_i] = arguments[_i];
1025         }
1026         var delegate = intervalProvider.delegate;
1027         return ((delegate === null || delegate === void 0 ? void 0 : delegate.setInterval) || setInterval).apply(void 0, __spreadArray([], __read(args)));
1028     },
1029     clearInterval: function (handle) {
1030         var delegate = intervalProvider.delegate;
1031         return ((delegate === null || delegate === void 0 ? void 0 : delegate.clearInterval) || clearInterval)(handle);
1032     },
1033     delegate: undefined,
1034 };
1035
1036 var AsyncAction = (function (_super) {
1037     __extends(AsyncAction, _super);
1038     function AsyncAction(scheduler, work) {
1039         var _this = _super.call(this, scheduler, work) || this;
1040         _this.scheduler = scheduler;
1041         _this.work = work;
1042         _this.pending = false;
1043         return _this;
1044     }
1045     AsyncAction.prototype.schedule = function (state, delay) {
1046         if (delay === void 0) { delay = 0; }
1047         if (this.closed) {
1048             return this;
1049         }
1050         this.state = state;
1051         var id = this.id;
1052         var scheduler = this.scheduler;
1053         if (id != null) {
1054             this.id = this.recycleAsyncId(scheduler, id, delay);
1055         }
1056         this.pending = true;
1057         this.delay = delay;
1058         this.id = this.id || this.requestAsyncId(scheduler, this.id, delay);
1059         return this;
1060     };
1061     AsyncAction.prototype.requestAsyncId = function (scheduler, _id, delay) {
1062         if (delay === void 0) { delay = 0; }
1063         return intervalProvider.setInterval(scheduler.flush.bind(scheduler, this), delay);
1064     };
1065     AsyncAction.prototype.recycleAsyncId = function (_scheduler, id, delay) {
1066         if (delay === void 0) { delay = 0; }
1067         if (delay != null && this.delay === delay && this.pending === false) {
1068             return id;
1069         }
1070         intervalProvider.clearInterval(id);
1071         return undefined;
1072     };
1073     AsyncAction.prototype.execute = function (state, delay) {
1074         if (this.closed) {
1075             return new Error('executing a cancelled action');
1076         }
1077         this.pending = false;
1078         var error = this._execute(state, delay);
1079         if (error) {
1080             return error;
1081         }
1082         else if (this.pending === false && this.id != null) {
1083             this.id = this.recycleAsyncId(this.scheduler, this.id, null);
1084         }
1085     };
1086     AsyncAction.prototype._execute = function (state, _delay) {
1087         var errored = false;
1088         var errorValue;
1089         try {
1090             this.work(state);
1091         }
1092         catch (e) {
1093             errored = true;
1094             errorValue = (!!e && e) || new Error(e);
1095         }
1096         if (errored) {
1097             this.unsubscribe();
1098             return errorValue;
1099         }
1100     };
1101     AsyncAction.prototype.unsubscribe = function () {
1102         if (!this.closed) {
1103             var _a = this, id = _a.id, scheduler = _a.scheduler;
1104             var actions = scheduler.actions;
1105             this.work = this.state = this.scheduler = null;
1106             this.pending = false;
1107             arrRemove(actions, this);
1108             if (id != null) {
1109                 this.id = this.recycleAsyncId(scheduler, id, null);
1110             }
1111             this.delay = null;
1112             _super.prototype.unsubscribe.call(this);
1113         }
1114     };
1115     return AsyncAction;
1116 }(Action));
1117
1118 var Scheduler = (function () {
1119     function Scheduler(schedulerActionCtor, now) {
1120         if (now === void 0) { now = Scheduler.now; }
1121         this.schedulerActionCtor = schedulerActionCtor;
1122         this.now = now;
1123     }
1124     Scheduler.prototype.schedule = function (work, delay, state) {
1125         if (delay === void 0) { delay = 0; }
1126         return new this.schedulerActionCtor(this, work).schedule(state, delay);
1127     };
1128     Scheduler.now = dateTimestampProvider.now;
1129     return Scheduler;
1130 }());
1131
1132 var AsyncScheduler = (function (_super) {
1133     __extends(AsyncScheduler, _super);
1134     function AsyncScheduler(SchedulerAction, now) {
1135         if (now === void 0) { now = Scheduler.now; }
1136         var _this = _super.call(this, SchedulerAction, now) || this;
1137         _this.actions = [];
1138         _this._active = false;
1139         _this._scheduled = undefined;
1140         return _this;
1141     }
1142     AsyncScheduler.prototype.flush = function (action) {
1143         var actions = this.actions;
1144         if (this._active) {
1145             actions.push(action);
1146             return;
1147         }
1148         var error;
1149         this._active = true;
1150         do {
1151             if ((error = action.execute(action.state, action.delay))) {
1152                 break;
1153             }
1154         } while ((action = actions.shift()));
1155         this._active = false;
1156         if (error) {
1157             while ((action = actions.shift())) {
1158                 action.unsubscribe();
1159             }
1160             throw error;
1161         }
1162     };
1163     return AsyncScheduler;
1164 }(Scheduler));
1165
1166 var asyncScheduler = new AsyncScheduler(AsyncAction);
1167 var async = asyncScheduler;
1168
1169 var EMPTY$1 = new Observable(function (subscriber) { return subscriber.complete(); });
1170 function empty(scheduler) {
1171     return scheduler ? emptyScheduled(scheduler) : EMPTY$1;
1172 }
1173 function emptyScheduled(scheduler) {
1174     return new Observable(function (subscriber) { return scheduler.schedule(function () { return subscriber.complete(); }); });
1175 }
1176
1177 function scheduleArray(input, scheduler) {
1178     return new Observable(function (subscriber) {
1179         var i = 0;
1180         return scheduler.schedule(function () {
1181             if (i === input.length) {
1182                 subscriber.complete();
1183             }
1184             else {
1185                 subscriber.next(input[i++]);
1186                 if (!subscriber.closed) {
1187                     this.schedule();
1188                 }
1189             }
1190         });
1191     });
1192 }
1193
1194 var isArrayLike = (function (x) { return x && typeof x.length === 'number' && typeof x !== 'function'; });
1195
1196 function isPromise(value) {
1197     return isFunction(value === null || value === void 0 ? void 0 : value.then);
1198 }
1199
1200 function scheduleObservable(input, scheduler) {
1201     return new Observable(function (subscriber) {
1202         var sub = new Subscription();
1203         sub.add(scheduler.schedule(function () {
1204             var observable$1 = input[observable]();
1205             sub.add(observable$1.subscribe({
1206                 next: function (value) { sub.add(scheduler.schedule(function () { return subscriber.next(value); })); },
1207                 error: function (err) { sub.add(scheduler.schedule(function () { return subscriber.error(err); })); },
1208                 complete: function () { sub.add(scheduler.schedule(function () { return subscriber.complete(); })); },
1209             }));
1210         }));
1211         return sub;
1212     });
1213 }
1214
1215 function schedulePromise(input, scheduler) {
1216     return new Observable(function (subscriber) {
1217         return scheduler.schedule(function () {
1218             return input.then(function (value) {
1219                 subscriber.add(scheduler.schedule(function () {
1220                     subscriber.next(value);
1221                     subscriber.add(scheduler.schedule(function () { return subscriber.complete(); }));
1222                 }));
1223             }, function (err) {
1224                 subscriber.add(scheduler.schedule(function () { return subscriber.error(err); }));
1225             });
1226         });
1227     });
1228 }
1229
1230 function getSymbolIterator() {
1231     if (typeof Symbol !== 'function' || !Symbol.iterator) {
1232         return '@@iterator';
1233     }
1234     return Symbol.iterator;
1235 }
1236 var iterator = getSymbolIterator();
1237
1238 function caughtSchedule(subscriber, scheduler, execute, delay) {
1239     if (delay === void 0) { delay = 0; }
1240     var subscription = scheduler.schedule(function () {
1241         try {
1242             execute.call(this);
1243         }
1244         catch (err) {
1245             subscriber.error(err);
1246         }
1247     }, delay);
1248     subscriber.add(subscription);
1249     return subscription;
1250 }
1251
1252 function scheduleIterable(input, scheduler) {
1253     return new Observable(function (subscriber) {
1254         var iterator$1;
1255         subscriber.add(scheduler.schedule(function () {
1256             iterator$1 = input[iterator]();
1257             caughtSchedule(subscriber, scheduler, function () {
1258                 var _a = iterator$1.next(), value = _a.value, done = _a.done;
1259                 if (done) {
1260                     subscriber.complete();
1261                 }
1262                 else {
1263                     subscriber.next(value);
1264                     this.schedule();
1265                 }
1266             });
1267         }));
1268         return function () { return isFunction(iterator$1 === null || iterator$1 === void 0 ? void 0 : iterator$1.return) && iterator$1.return(); };
1269     });
1270 }
1271
1272 function scheduleAsyncIterable(input, scheduler) {
1273     if (!input) {
1274         throw new Error('Iterable cannot be null');
1275     }
1276     return new Observable(function (subscriber) {
1277         var sub = new Subscription();
1278         sub.add(scheduler.schedule(function () {
1279             var iterator = input[Symbol.asyncIterator]();
1280             sub.add(scheduler.schedule(function () {
1281                 var _this = this;
1282                 iterator.next().then(function (result) {
1283                     if (result.done) {
1284                         subscriber.complete();
1285                     }
1286                     else {
1287                         subscriber.next(result.value);
1288                         _this.schedule();
1289                     }
1290                 });
1291             }));
1292         }));
1293         return sub;
1294     });
1295 }
1296
1297 function isInteropObservable(input) {
1298     return isFunction(input[observable]);
1299 }
1300
1301 function isIterable(input) {
1302     return isFunction(input === null || input === void 0 ? void 0 : input[iterator]);
1303 }
1304
1305 function isAsyncIterable(obj) {
1306     return Symbol.asyncIterator && isFunction(obj === null || obj === void 0 ? void 0 : obj[Symbol.asyncIterator]);
1307 }
1308
1309 function createInvalidObservableTypeError(input) {
1310     return new TypeError("You provided " + (input !== null && typeof input === 'object' ? 'an invalid object' : "'" + input + "'") + " where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.");
1311 }
1312
1313 function readableStreamLikeToAsyncGenerator(readableStream) {
1314     return __asyncGenerator(this, arguments, function readableStreamLikeToAsyncGenerator_1() {
1315         var reader, _a, value, done;
1316         return __generator(this, function (_b) {
1317             switch (_b.label) {
1318                 case 0:
1319                     reader = readableStream.getReader();
1320                     _b.label = 1;
1321                 case 1:
1322                     _b.trys.push([1, , 9, 10]);
1323                     _b.label = 2;
1324                 case 2:
1325                     return [4, __await(reader.read())];
1326                 case 3:
1327                     _a = _b.sent(), value = _a.value, done = _a.done;
1328                     if (!done) return [3, 5];
1329                     return [4, __await(void 0)];
1330                 case 4: return [2, _b.sent()];
1331                 case 5: return [4, __await(value)];
1332                 case 6: return [4, _b.sent()];
1333                 case 7:
1334                     _b.sent();
1335                     return [3, 2];
1336                 case 8: return [3, 10];
1337                 case 9:
1338                     reader.releaseLock();
1339                     return [7];
1340                 case 10: return [2];
1341             }
1342         });
1343     });
1344 }
1345 function isReadableStreamLike(obj) {
1346     return isFunction(obj === null || obj === void 0 ? void 0 : obj.getReader);
1347 }
1348
1349 function scheduleReadableStreamLike(input, scheduler) {
1350     return scheduleAsyncIterable(readableStreamLikeToAsyncGenerator(input), scheduler);
1351 }
1352
1353 function scheduled(input, scheduler) {
1354     if (input != null) {
1355         if (isInteropObservable(input)) {
1356             return scheduleObservable(input, scheduler);
1357         }
1358         if (isArrayLike(input)) {
1359             return scheduleArray(input, scheduler);
1360         }
1361         if (isPromise(input)) {
1362             return schedulePromise(input, scheduler);
1363         }
1364         if (isAsyncIterable(input)) {
1365             return scheduleAsyncIterable(input, scheduler);
1366         }
1367         if (isIterable(input)) {
1368             return scheduleIterable(input, scheduler);
1369         }
1370         if (isReadableStreamLike(input)) {
1371             return scheduleReadableStreamLike(input, scheduler);
1372         }
1373     }
1374     throw createInvalidObservableTypeError(input);
1375 }
1376
1377 function from(input, scheduler) {
1378     return scheduler ? scheduled(input, scheduler) : innerFrom(input);
1379 }
1380 function innerFrom(input) {
1381     if (input instanceof Observable) {
1382         return input;
1383     }
1384     if (input != null) {
1385         if (isInteropObservable(input)) {
1386             return fromInteropObservable(input);
1387         }
1388         if (isArrayLike(input)) {
1389             return fromArrayLike(input);
1390         }
1391         if (isPromise(input)) {
1392             return fromPromise(input);
1393         }
1394         if (isAsyncIterable(input)) {
1395             return fromAsyncIterable(input);
1396         }
1397         if (isIterable(input)) {
1398             return fromIterable(input);
1399         }
1400         if (isReadableStreamLike(input)) {
1401             return fromReadableStreamLike(input);
1402         }
1403     }
1404     throw createInvalidObservableTypeError(input);
1405 }
1406 function fromInteropObservable(obj) {
1407     return new Observable(function (subscriber) {
1408         var obs = obj[observable]();
1409         if (isFunction(obs.subscribe)) {
1410             return obs.subscribe(subscriber);
1411         }
1412         throw new TypeError('Provided object does not correctly implement Symbol.observable');
1413     });
1414 }
1415 function fromArrayLike(array) {
1416     return new Observable(function (subscriber) {
1417         for (var i = 0; i < array.length && !subscriber.closed; i++) {
1418             subscriber.next(array[i]);
1419         }
1420         subscriber.complete();
1421     });
1422 }
1423 function fromPromise(promise) {
1424     return new Observable(function (subscriber) {
1425         promise
1426             .then(function (value) {
1427             if (!subscriber.closed) {
1428                 subscriber.next(value);
1429                 subscriber.complete();
1430             }
1431         }, function (err) { return subscriber.error(err); })
1432             .then(null, reportUnhandledError);
1433     });
1434 }
1435 function fromIterable(iterable) {
1436     return new Observable(function (subscriber) {
1437         var e_1, _a;
1438         try {
1439             for (var iterable_1 = __values(iterable), iterable_1_1 = iterable_1.next(); !iterable_1_1.done; iterable_1_1 = iterable_1.next()) {
1440                 var value = iterable_1_1.value;
1441                 subscriber.next(value);
1442                 if (subscriber.closed) {
1443                     return;
1444                 }
1445             }
1446         }
1447         catch (e_1_1) { e_1 = { error: e_1_1 }; }
1448         finally {
1449             try {
1450                 if (iterable_1_1 && !iterable_1_1.done && (_a = iterable_1.return)) _a.call(iterable_1);
1451             }
1452             finally { if (e_1) throw e_1.error; }
1453         }
1454         subscriber.complete();
1455     });
1456 }
1457 function fromAsyncIterable(asyncIterable) {
1458     return new Observable(function (subscriber) {
1459         process(asyncIterable, subscriber).catch(function (err) { return subscriber.error(err); });
1460     });
1461 }
1462 function fromReadableStreamLike(readableStream) {
1463     return fromAsyncIterable(readableStreamLikeToAsyncGenerator(readableStream));
1464 }
1465 function process(asyncIterable, subscriber) {
1466     var asyncIterable_1, asyncIterable_1_1;
1467     var e_2, _a;
1468     return __awaiter(this, void 0, void 0, function () {
1469         var value, e_2_1;
1470         return __generator(this, function (_b) {
1471             switch (_b.label) {
1472                 case 0:
1473                     _b.trys.push([0, 5, 6, 11]);
1474                     asyncIterable_1 = __asyncValues(asyncIterable);
1475                     _b.label = 1;
1476                 case 1: return [4, asyncIterable_1.next()];
1477                 case 2:
1478                     if (!(asyncIterable_1_1 = _b.sent(), !asyncIterable_1_1.done)) return [3, 4];
1479                     value = asyncIterable_1_1.value;
1480                     subscriber.next(value);
1481                     if (subscriber.closed) {
1482                         return [2];
1483                     }
1484                     _b.label = 3;
1485                 case 3: return [3, 1];
1486                 case 4: return [3, 11];
1487                 case 5:
1488                     e_2_1 = _b.sent();
1489                     e_2 = { error: e_2_1 };
1490                     return [3, 11];
1491                 case 6:
1492                     _b.trys.push([6, , 9, 10]);
1493                     if (!(asyncIterable_1_1 && !asyncIterable_1_1.done && (_a = asyncIterable_1.return))) return [3, 8];
1494                     return [4, _a.call(asyncIterable_1)];
1495                 case 7:
1496                     _b.sent();
1497                     _b.label = 8;
1498                 case 8: return [3, 10];
1499                 case 9:
1500                     if (e_2) throw e_2.error;
1501                     return [7];
1502                 case 10: return [7];
1503                 case 11:
1504                     subscriber.complete();
1505                     return [2];
1506             }
1507         });
1508     });
1509 }
1510
1511 function internalFromArray(input, scheduler) {
1512     return scheduler ? scheduleArray(input, scheduler) : fromArrayLike(input);
1513 }
1514
1515 function isScheduler(value) {
1516     return value && isFunction(value.schedule);
1517 }
1518
1519 function last$1(arr) {
1520     return arr[arr.length - 1];
1521 }
1522 function popResultSelector(args) {
1523     return isFunction(last$1(args)) ? args.pop() : undefined;
1524 }
1525 function popScheduler(args) {
1526     return isScheduler(last$1(args)) ? args.pop() : undefined;
1527 }
1528 function popNumber(args, defaultValue) {
1529     return typeof last$1(args) === 'number' ? args.pop() : defaultValue;
1530 }
1531
1532 function of() {
1533     var args = [];
1534     for (var _i = 0; _i < arguments.length; _i++) {
1535         args[_i] = arguments[_i];
1536     }
1537     var scheduler = popScheduler(args);
1538     return scheduler ? scheduleArray(args, scheduler) : internalFromArray(args);
1539 }
1540
1541 function throwError(errorOrErrorFactory, scheduler) {
1542     var errorFactory = isFunction(errorOrErrorFactory) ? errorOrErrorFactory : function () { return errorOrErrorFactory; };
1543     var init = function (subscriber) { return subscriber.error(errorFactory()); };
1544     return new Observable(scheduler ? function (subscriber) { return scheduler.schedule(init, 0, subscriber); } : init);
1545 }
1546
1547 var EmptyError = createErrorClass(function (_super) { return function EmptyErrorImpl() {
1548     _super(this);
1549     this.name = 'EmptyError';
1550     this.message = 'no elements in sequence';
1551 }; });
1552
1553 function isValidDate(value) {
1554     return value instanceof Date && !isNaN(value);
1555 }
1556
1557 var TimeoutError = createErrorClass(function (_super) {
1558     return function TimeoutErrorImpl(info) {
1559         if (info === void 0) { info = null; }
1560         _super(this);
1561         this.message = 'Timeout has occurred';
1562         this.name = 'TimeoutError';
1563         this.info = info;
1564     };
1565 });
1566 function timeout(config, schedulerArg) {
1567     var _a = (isValidDate(config)
1568         ? { first: config }
1569         : typeof config === 'number'
1570             ? { each: config }
1571             : config), first = _a.first, each = _a.each, _b = _a.with, _with = _b === void 0 ? timeoutErrorFactory : _b, _c = _a.scheduler, scheduler = _c === void 0 ? schedulerArg !== null && schedulerArg !== void 0 ? schedulerArg : asyncScheduler : _c, _d = _a.meta, meta = _d === void 0 ? null : _d;
1572     if (first == null && each == null) {
1573         throw new TypeError('No timeout provided.');
1574     }
1575     return operate(function (source, subscriber) {
1576         var originalSourceSubscription;
1577         var timerSubscription;
1578         var lastValue = null;
1579         var seen = 0;
1580         var startTimer = function (delay) {
1581             timerSubscription = caughtSchedule(subscriber, scheduler, function () {
1582                 originalSourceSubscription.unsubscribe();
1583                 innerFrom(_with({
1584                     meta: meta,
1585                     lastValue: lastValue,
1586                     seen: seen,
1587                 })).subscribe(subscriber);
1588             }, delay);
1589         };
1590         originalSourceSubscription = source.subscribe(new OperatorSubscriber(subscriber, function (value) {
1591             timerSubscription === null || timerSubscription === void 0 ? void 0 : timerSubscription.unsubscribe();
1592             seen++;
1593             subscriber.next((lastValue = value));
1594             each > 0 && startTimer(each);
1595         }, undefined, undefined, function () {
1596             if (!(timerSubscription === null || timerSubscription === void 0 ? void 0 : timerSubscription.closed)) {
1597                 timerSubscription === null || timerSubscription === void 0 ? void 0 : timerSubscription.unsubscribe();
1598             }
1599             lastValue = null;
1600         }));
1601         startTimer(first != null ? (typeof first === 'number' ? first : +first - scheduler.now()) : each);
1602     });
1603 }
1604 function timeoutErrorFactory(info) {
1605     throw new TimeoutError(info);
1606 }
1607
1608 function map(project, thisArg) {
1609     return operate(function (source, subscriber) {
1610         var index = 0;
1611         source.subscribe(new OperatorSubscriber(subscriber, function (value) {
1612             subscriber.next(project.call(thisArg, value, index++));
1613         }));
1614     });
1615 }
1616
1617 var isArray$6 = Array.isArray;
1618 function callOrApply(fn, args) {
1619     return isArray$6(args) ? fn.apply(void 0, __spreadArray([], __read(args))) : fn(args);
1620 }
1621 function mapOneOrManyArgs(fn) {
1622     return map(function (args) { return callOrApply(fn, args); });
1623 }
1624
1625 var isArray$5 = Array.isArray;
1626 var getPrototypeOf = Object.getPrototypeOf, objectProto = Object.prototype, getKeys = Object.keys;
1627 function argsArgArrayOrObject(args) {
1628     if (args.length === 1) {
1629         var first_1 = args[0];
1630         if (isArray$5(first_1)) {
1631             return { args: first_1, keys: null };
1632         }
1633         if (isPOJO(first_1)) {
1634             var keys = getKeys(first_1);
1635             return {
1636                 args: keys.map(function (key) { return first_1[key]; }),
1637                 keys: keys,
1638             };
1639         }
1640     }
1641     return { args: args, keys: null };
1642 }
1643 function isPOJO(obj) {
1644     return obj && typeof obj === 'object' && getPrototypeOf(obj) === objectProto;
1645 }
1646
1647 function createObject(keys, values) {
1648     return keys.reduce(function (result, key, i) { return ((result[key] = values[i]), result); }, {});
1649 }
1650
1651 function combineLatest() {
1652     var args = [];
1653     for (var _i = 0; _i < arguments.length; _i++) {
1654         args[_i] = arguments[_i];
1655     }
1656     var scheduler = popScheduler(args);
1657     var resultSelector = popResultSelector(args);
1658     var _a = argsArgArrayOrObject(args), observables = _a.args, keys = _a.keys;
1659     if (observables.length === 0) {
1660         return from([], scheduler);
1661     }
1662     var result = new Observable(combineLatestInit(observables, scheduler, keys
1663         ?
1664             function (values) { return createObject(keys, values); }
1665         :
1666             identity));
1667     return resultSelector ? result.pipe(mapOneOrManyArgs(resultSelector)) : result;
1668 }
1669 function combineLatestInit(observables, scheduler, valueTransform) {
1670     if (valueTransform === void 0) { valueTransform = identity; }
1671     return function (subscriber) {
1672         maybeSchedule(scheduler, function () {
1673             var length = observables.length;
1674             var values = new Array(length);
1675             var active = length;
1676             var remainingFirstValues = length;
1677             var _loop_1 = function (i) {
1678                 maybeSchedule(scheduler, function () {
1679                     var source = from(observables[i], scheduler);
1680                     var hasFirstValue = false;
1681                     source.subscribe(new OperatorSubscriber(subscriber, function (value) {
1682                         values[i] = value;
1683                         if (!hasFirstValue) {
1684                             hasFirstValue = true;
1685                             remainingFirstValues--;
1686                         }
1687                         if (!remainingFirstValues) {
1688                             subscriber.next(valueTransform(values.slice()));
1689                         }
1690                     }, function () {
1691                         if (!--active) {
1692                             subscriber.complete();
1693                         }
1694                     }));
1695                 }, subscriber);
1696             };
1697             for (var i = 0; i < length; i++) {
1698                 _loop_1(i);
1699             }
1700         }, subscriber);
1701     };
1702 }
1703 function maybeSchedule(scheduler, execute, subscription) {
1704     if (scheduler) {
1705         subscription.add(scheduler.schedule(execute));
1706     }
1707     else {
1708         execute();
1709     }
1710 }
1711
1712 function mergeInternals(source, subscriber, project, concurrent, onBeforeNext, expand, innerSubScheduler, additionalTeardown) {
1713     var buffer = [];
1714     var active = 0;
1715     var index = 0;
1716     var isComplete = false;
1717     var checkComplete = function () {
1718         if (isComplete && !buffer.length && !active) {
1719             subscriber.complete();
1720         }
1721     };
1722     var outerNext = function (value) { return (active < concurrent ? doInnerSub(value) : buffer.push(value)); };
1723     var doInnerSub = function (value) {
1724         expand && subscriber.next(value);
1725         active++;
1726         var innerComplete = false;
1727         innerFrom(project(value, index++)).subscribe(new OperatorSubscriber(subscriber, function (innerValue) {
1728             onBeforeNext === null || onBeforeNext === void 0 ? void 0 : onBeforeNext(innerValue);
1729             if (expand) {
1730                 outerNext(innerValue);
1731             }
1732             else {
1733                 subscriber.next(innerValue);
1734             }
1735         }, function () {
1736             innerComplete = true;
1737         }, undefined, function () {
1738             if (innerComplete) {
1739                 try {
1740                     active--;
1741                     var _loop_1 = function () {
1742                         var bufferedValue = buffer.shift();
1743                         innerSubScheduler ? subscriber.add(innerSubScheduler.schedule(function () { return doInnerSub(bufferedValue); })) : doInnerSub(bufferedValue);
1744                     };
1745                     while (buffer.length && active < concurrent) {
1746                         _loop_1();
1747                     }
1748                     checkComplete();
1749                 }
1750                 catch (err) {
1751                     subscriber.error(err);
1752                 }
1753             }
1754         }));
1755     };
1756     source.subscribe(new OperatorSubscriber(subscriber, outerNext, function () {
1757         isComplete = true;
1758         checkComplete();
1759     }));
1760     return function () {
1761         additionalTeardown === null || additionalTeardown === void 0 ? void 0 : additionalTeardown();
1762     };
1763 }
1764
1765 function mergeMap(project, resultSelector, concurrent) {
1766     if (concurrent === void 0) { concurrent = Infinity; }
1767     if (isFunction(resultSelector)) {
1768         return mergeMap(function (a, i) { return map(function (b, ii) { return resultSelector(a, b, i, ii); })(innerFrom(project(a, i))); }, concurrent);
1769     }
1770     else if (typeof resultSelector === 'number') {
1771         concurrent = resultSelector;
1772     }
1773     return operate(function (source, subscriber) { return mergeInternals(source, subscriber, project, concurrent); });
1774 }
1775
1776 function mergeAll(concurrent) {
1777     if (concurrent === void 0) { concurrent = Infinity; }
1778     return mergeMap(identity, concurrent);
1779 }
1780
1781 function concatAll() {
1782     return mergeAll(1);
1783 }
1784
1785 function concat() {
1786     var args = [];
1787     for (var _i = 0; _i < arguments.length; _i++) {
1788         args[_i] = arguments[_i];
1789     }
1790     return concatAll()(internalFromArray(args, popScheduler(args)));
1791 }
1792
1793 var nodeEventEmitterMethods = ['addListener', 'removeListener'];
1794 var eventTargetMethods = ['addEventListener', 'removeEventListener'];
1795 var jqueryMethods = ['on', 'off'];
1796 function fromEvent(target, eventName, options, resultSelector) {
1797     if (isFunction(options)) {
1798         resultSelector = options;
1799         options = undefined;
1800     }
1801     if (resultSelector) {
1802         return fromEvent(target, eventName, options).pipe(mapOneOrManyArgs(resultSelector));
1803     }
1804     var _a = __read(isEventTarget(target)
1805         ? eventTargetMethods.map(function (methodName) { return function (handler) { return target[methodName](eventName, handler, options); }; })
1806         :
1807             isNodeStyleEventEmitter(target)
1808                 ? nodeEventEmitterMethods.map(toCommonHandlerRegistry(target, eventName))
1809                 : isJQueryStyleEventEmitter(target)
1810                     ? jqueryMethods.map(toCommonHandlerRegistry(target, eventName))
1811                     : [], 2), add = _a[0], remove = _a[1];
1812     if (!add) {
1813         if (isArrayLike(target)) {
1814             return mergeMap(function (subTarget) { return fromEvent(subTarget, eventName, options); })(internalFromArray(target));
1815         }
1816     }
1817     if (!add) {
1818         throw new TypeError('Invalid event target');
1819     }
1820     return new Observable(function (subscriber) {
1821         var handler = function () {
1822             var args = [];
1823             for (var _i = 0; _i < arguments.length; _i++) {
1824                 args[_i] = arguments[_i];
1825             }
1826             return subscriber.next(1 < args.length ? args : args[0]);
1827         };
1828         add(handler);
1829         return function () { return remove(handler); };
1830     });
1831 }
1832 function toCommonHandlerRegistry(target, eventName) {
1833     return function (methodName) { return function (handler) { return target[methodName](eventName, handler); }; };
1834 }
1835 function isNodeStyleEventEmitter(target) {
1836     return isFunction(target.addListener) && isFunction(target.removeListener);
1837 }
1838 function isJQueryStyleEventEmitter(target) {
1839     return isFunction(target.on) && isFunction(target.off);
1840 }
1841 function isEventTarget(target) {
1842     return isFunction(target.addEventListener) && isFunction(target.removeEventListener);
1843 }
1844
1845 function timer(dueTime, intervalOrScheduler, scheduler) {
1846     if (dueTime === void 0) { dueTime = 0; }
1847     if (scheduler === void 0) { scheduler = async; }
1848     var intervalDuration = -1;
1849     if (intervalOrScheduler != null) {
1850         if (isScheduler(intervalOrScheduler)) {
1851             scheduler = intervalOrScheduler;
1852         }
1853         else {
1854             intervalDuration = intervalOrScheduler;
1855         }
1856     }
1857     return new Observable(function (subscriber) {
1858         var due = isValidDate(dueTime) ? +dueTime - scheduler.now() : dueTime;
1859         if (due < 0) {
1860             due = 0;
1861         }
1862         var n = 0;
1863         return scheduler.schedule(function () {
1864             if (!subscriber.closed) {
1865                 subscriber.next(n++);
1866                 if (0 <= intervalDuration) {
1867                     this.schedule(undefined, intervalDuration);
1868                 }
1869                 else {
1870                     subscriber.complete();
1871                 }
1872             }
1873         }, due);
1874     });
1875 }
1876
1877 function merge() {
1878     var args = [];
1879     for (var _i = 0; _i < arguments.length; _i++) {
1880         args[_i] = arguments[_i];
1881     }
1882     var scheduler = popScheduler(args);
1883     var concurrent = popNumber(args, Infinity);
1884     var sources = args;
1885     return !sources.length
1886         ?
1887             EMPTY$1
1888         : sources.length === 1
1889             ?
1890                 innerFrom(sources[0])
1891             :
1892                 mergeAll(concurrent)(internalFromArray(sources, scheduler));
1893 }
1894
1895 var isArray$4 = Array.isArray;
1896 function argsOrArgArray(args) {
1897     return args.length === 1 && isArray$4(args[0]) ? args[0] : args;
1898 }
1899
1900 function filter(predicate, thisArg) {
1901     return operate(function (source, subscriber) {
1902         var index = 0;
1903         source.subscribe(new OperatorSubscriber(subscriber, function (value) { return predicate.call(thisArg, value, index++) && subscriber.next(value); }));
1904     });
1905 }
1906
1907 function zip() {
1908     var args = [];
1909     for (var _i = 0; _i < arguments.length; _i++) {
1910         args[_i] = arguments[_i];
1911     }
1912     var resultSelector = popResultSelector(args);
1913     var sources = argsOrArgArray(args);
1914     return sources.length
1915         ? new Observable(function (subscriber) {
1916             var buffers = sources.map(function () { return []; });
1917             var completed = sources.map(function () { return false; });
1918             subscriber.add(function () {
1919                 buffers = completed = null;
1920             });
1921             var _loop_1 = function (sourceIndex) {
1922                 innerFrom(sources[sourceIndex]).subscribe(new OperatorSubscriber(subscriber, function (value) {
1923                     buffers[sourceIndex].push(value);
1924                     if (buffers.every(function (buffer) { return buffer.length; })) {
1925                         var result = buffers.map(function (buffer) { return buffer.shift(); });
1926                         subscriber.next(resultSelector ? resultSelector.apply(void 0, __spreadArray([], __read(result))) : result);
1927                         if (buffers.some(function (buffer, i) { return !buffer.length && completed[i]; })) {
1928                             subscriber.complete();
1929                         }
1930                     }
1931                 }, function () {
1932                     completed[sourceIndex] = true;
1933                     !buffers[sourceIndex].length && subscriber.complete();
1934                 }));
1935             };
1936             for (var sourceIndex = 0; !subscriber.closed && sourceIndex < sources.length; sourceIndex++) {
1937                 _loop_1(sourceIndex);
1938             }
1939             return function () {
1940                 buffers = completed = null;
1941             };
1942         })
1943         : EMPTY$1;
1944 }
1945
1946 function audit(durationSelector) {
1947     return operate(function (source, subscriber) {
1948         var hasValue = false;
1949         var lastValue = null;
1950         var durationSubscriber = null;
1951         var isComplete = false;
1952         var endDuration = function () {
1953             durationSubscriber === null || durationSubscriber === void 0 ? void 0 : durationSubscriber.unsubscribe();
1954             durationSubscriber = null;
1955             if (hasValue) {
1956                 hasValue = false;
1957                 var value = lastValue;
1958                 lastValue = null;
1959                 subscriber.next(value);
1960             }
1961             isComplete && subscriber.complete();
1962         };
1963         var cleanupDuration = function () {
1964             durationSubscriber = null;
1965             isComplete && subscriber.complete();
1966         };
1967         source.subscribe(new OperatorSubscriber(subscriber, function (value) {
1968             hasValue = true;
1969             lastValue = value;
1970             if (!durationSubscriber) {
1971                 innerFrom(durationSelector(value)).subscribe((durationSubscriber = new OperatorSubscriber(subscriber, endDuration, cleanupDuration)));
1972             }
1973         }, function () {
1974             isComplete = true;
1975             (!hasValue || !durationSubscriber || durationSubscriber.closed) && subscriber.complete();
1976         }));
1977     });
1978 }
1979
1980 function auditTime(duration, scheduler) {
1981     if (scheduler === void 0) { scheduler = async; }
1982     return audit(function () { return timer(duration, scheduler); });
1983 }
1984
1985 function bufferCount(bufferSize, startBufferEvery) {
1986     if (startBufferEvery === void 0) { startBufferEvery = null; }
1987     startBufferEvery = startBufferEvery !== null && startBufferEvery !== void 0 ? startBufferEvery : bufferSize;
1988     return operate(function (source, subscriber) {
1989         var buffers = [];
1990         var count = 0;
1991         source.subscribe(new OperatorSubscriber(subscriber, function (value) {
1992             var e_1, _a, e_2, _b;
1993             var toEmit = null;
1994             if (count++ % startBufferEvery === 0) {
1995                 buffers.push([]);
1996             }
1997             try {
1998                 for (var buffers_1 = __values(buffers), buffers_1_1 = buffers_1.next(); !buffers_1_1.done; buffers_1_1 = buffers_1.next()) {
1999                     var buffer = buffers_1_1.value;
2000                     buffer.push(value);
2001                     if (bufferSize <= buffer.length) {
2002                         toEmit = toEmit !== null && toEmit !== void 0 ? toEmit : [];
2003                         toEmit.push(buffer);
2004                     }
2005                 }
2006             }
2007             catch (e_1_1) { e_1 = { error: e_1_1 }; }
2008             finally {
2009                 try {
2010                     if (buffers_1_1 && !buffers_1_1.done && (_a = buffers_1.return)) _a.call(buffers_1);
2011                 }
2012                 finally { if (e_1) throw e_1.error; }
2013             }
2014             if (toEmit) {
2015                 try {
2016                     for (var toEmit_1 = __values(toEmit), toEmit_1_1 = toEmit_1.next(); !toEmit_1_1.done; toEmit_1_1 = toEmit_1.next()) {
2017                         var buffer = toEmit_1_1.value;
2018                         arrRemove(buffers, buffer);
2019                         subscriber.next(buffer);
2020                     }
2021                 }
2022                 catch (e_2_1) { e_2 = { error: e_2_1 }; }
2023                 finally {
2024                     try {
2025                         if (toEmit_1_1 && !toEmit_1_1.done && (_b = toEmit_1.return)) _b.call(toEmit_1);
2026                     }
2027                     finally { if (e_2) throw e_2.error; }
2028                 }
2029             }
2030         }, function () {
2031             var e_3, _a;
2032             try {
2033                 for (var buffers_2 = __values(buffers), buffers_2_1 = buffers_2.next(); !buffers_2_1.done; buffers_2_1 = buffers_2.next()) {
2034                     var buffer = buffers_2_1.value;
2035                     subscriber.next(buffer);
2036                 }
2037             }
2038             catch (e_3_1) { e_3 = { error: e_3_1 }; }
2039             finally {
2040                 try {
2041                     if (buffers_2_1 && !buffers_2_1.done && (_a = buffers_2.return)) _a.call(buffers_2);
2042                 }
2043                 finally { if (e_3) throw e_3.error; }
2044             }
2045             subscriber.complete();
2046         }, undefined, function () {
2047             buffers = null;
2048         }));
2049     });
2050 }
2051
2052 function bufferWhen(closingSelector) {
2053     return operate(function (source, subscriber) {
2054         var buffer = null;
2055         var closingSubscriber = null;
2056         var openBuffer = function () {
2057             closingSubscriber === null || closingSubscriber === void 0 ? void 0 : closingSubscriber.unsubscribe();
2058             var b = buffer;
2059             buffer = [];
2060             b && subscriber.next(b);
2061             innerFrom(closingSelector()).subscribe((closingSubscriber = new OperatorSubscriber(subscriber, openBuffer, noop)));
2062         };
2063         openBuffer();
2064         source.subscribe(new OperatorSubscriber(subscriber, function (value) { return buffer === null || buffer === void 0 ? void 0 : buffer.push(value); }, function () {
2065             buffer && subscriber.next(buffer);
2066             subscriber.complete();
2067         }, undefined, function () { return (buffer = closingSubscriber = null); }));
2068     });
2069 }
2070
2071 function catchError(selector) {
2072     return operate(function (source, subscriber) {
2073         var innerSub = null;
2074         var syncUnsub = false;
2075         var handledResult;
2076         innerSub = source.subscribe(new OperatorSubscriber(subscriber, undefined, undefined, function (err) {
2077             handledResult = innerFrom(selector(err, catchError(selector)(source)));
2078             if (innerSub) {
2079                 innerSub.unsubscribe();
2080                 innerSub = null;
2081                 handledResult.subscribe(subscriber);
2082             }
2083             else {
2084                 syncUnsub = true;
2085             }
2086         }));
2087         if (syncUnsub) {
2088             innerSub.unsubscribe();
2089             innerSub = null;
2090             handledResult.subscribe(subscriber);
2091         }
2092     });
2093 }
2094
2095 function scanInternals(accumulator, seed, hasSeed, emitOnNext, emitBeforeComplete) {
2096     return function (source, subscriber) {
2097         var hasState = hasSeed;
2098         var state = seed;
2099         var index = 0;
2100         source.subscribe(new OperatorSubscriber(subscriber, function (value) {
2101             var i = index++;
2102             state = hasState
2103                 ?
2104                     accumulator(state, value, i)
2105                 :
2106                     ((hasState = true), value);
2107             emitOnNext && subscriber.next(state);
2108         }, emitBeforeComplete &&
2109             (function () {
2110                 hasState && subscriber.next(state);
2111                 subscriber.complete();
2112             })));
2113     };
2114 }
2115
2116 function reduce(accumulator, seed) {
2117     return operate(scanInternals(accumulator, seed, arguments.length >= 2, false, true));
2118 }
2119
2120 function concatMap(project, resultSelector) {
2121     return isFunction(resultSelector) ? mergeMap(project, resultSelector, 1) : mergeMap(project, 1);
2122 }
2123
2124 function fromSubscribable(subscribable) {
2125     return new Observable(function (subscriber) { return subscribable.subscribe(subscriber); });
2126 }
2127
2128 var DEFAULT_CONFIG = {
2129     connector: function () { return new Subject(); },
2130 };
2131 function connect(selector, config) {
2132     if (config === void 0) { config = DEFAULT_CONFIG; }
2133     var connector = config.connector;
2134     return operate(function (source, subscriber) {
2135         var subject = connector();
2136         from(selector(fromSubscribable(subject))).subscribe(subscriber);
2137         subscriber.add(source.subscribe(subject));
2138     });
2139 }
2140
2141 function debounceTime(dueTime, scheduler) {
2142     if (scheduler === void 0) { scheduler = asyncScheduler; }
2143     return operate(function (source, subscriber) {
2144         var activeTask = null;
2145         var lastValue = null;
2146         var lastTime = null;
2147         var emit = function () {
2148             if (activeTask) {
2149                 activeTask.unsubscribe();
2150                 activeTask = null;
2151                 var value = lastValue;
2152                 lastValue = null;
2153                 subscriber.next(value);
2154             }
2155         };
2156         function emitWhenIdle() {
2157             var targetTime = lastTime + dueTime;
2158             var now = scheduler.now();
2159             if (now < targetTime) {
2160                 activeTask = this.schedule(undefined, targetTime - now);
2161                 subscriber.add(activeTask);
2162                 return;
2163             }
2164             emit();
2165         }
2166         source.subscribe(new OperatorSubscriber(subscriber, function (value) {
2167             lastValue = value;
2168             lastTime = scheduler.now();
2169             if (!activeTask) {
2170                 activeTask = scheduler.schedule(emitWhenIdle, dueTime);
2171                 subscriber.add(activeTask);
2172             }
2173         }, function () {
2174             emit();
2175             subscriber.complete();
2176         }, undefined, function () {
2177             lastValue = activeTask = null;
2178         }));
2179     });
2180 }
2181
2182 function defaultIfEmpty(defaultValue) {
2183     return operate(function (source, subscriber) {
2184         var hasValue = false;
2185         source.subscribe(new OperatorSubscriber(subscriber, function (value) {
2186             hasValue = true;
2187             subscriber.next(value);
2188         }, function () {
2189             if (!hasValue) {
2190                 subscriber.next(defaultValue);
2191             }
2192             subscriber.complete();
2193         }));
2194     });
2195 }
2196
2197 function take(count) {
2198     return count <= 0
2199         ?
2200             function () { return EMPTY$1; }
2201         : operate(function (source, subscriber) {
2202             var seen = 0;
2203             source.subscribe(new OperatorSubscriber(subscriber, function (value) {
2204                 if (++seen <= count) {
2205                     subscriber.next(value);
2206                     if (count <= seen) {
2207                         subscriber.complete();
2208                     }
2209                 }
2210             }));
2211         });
2212 }
2213
2214 function distinctUntilChanged(comparator, keySelector) {
2215     if (keySelector === void 0) { keySelector = identity; }
2216     comparator = comparator !== null && comparator !== void 0 ? comparator : defaultCompare$3;
2217     return operate(function (source, subscriber) {
2218         var previousKey;
2219         var first = true;
2220         source.subscribe(new OperatorSubscriber(subscriber, function (value) {
2221             var currentKey = keySelector(value);
2222             if (first || !comparator(previousKey, currentKey)) {
2223                 first = false;
2224                 previousKey = currentKey;
2225                 subscriber.next(value);
2226             }
2227         }));
2228     });
2229 }
2230 function defaultCompare$3(a, b) {
2231     return a === b;
2232 }
2233
2234 function throwIfEmpty(errorFactory) {
2235     if (errorFactory === void 0) { errorFactory = defaultErrorFactory; }
2236     return operate(function (source, subscriber) {
2237         var hasValue = false;
2238         source.subscribe(new OperatorSubscriber(subscriber, function (value) {
2239             hasValue = true;
2240             subscriber.next(value);
2241         }, function () { return (hasValue ? subscriber.complete() : subscriber.error(errorFactory())); }));
2242     });
2243 }
2244 function defaultErrorFactory() {
2245     return new EmptyError();
2246 }
2247
2248 function expand(project, concurrent, scheduler) {
2249     if (concurrent === void 0) { concurrent = Infinity; }
2250     concurrent = (concurrent || 0) < 1 ? Infinity : concurrent;
2251     return operate(function (source, subscriber) {
2252         return mergeInternals(source, subscriber, project, concurrent, undefined, true, scheduler);
2253     });
2254 }
2255
2256 function finalize(callback) {
2257     return operate(function (source, subscriber) {
2258         try {
2259             source.subscribe(subscriber);
2260         }
2261         finally {
2262             subscriber.add(callback);
2263         }
2264     });
2265 }
2266
2267 function first(predicate, defaultValue) {
2268     var hasDefaultValue = arguments.length >= 2;
2269     return function (source) {
2270         return source.pipe(predicate ? filter(function (v, i) { return predicate(v, i, source); }) : identity, take(1), hasDefaultValue ? defaultIfEmpty(defaultValue) : throwIfEmpty(function () { return new EmptyError(); }));
2271     };
2272 }
2273
2274 function takeLast(count) {
2275     return count <= 0
2276         ? function () { return EMPTY$1; }
2277         : operate(function (source, subscriber) {
2278             var buffer = [];
2279             source.subscribe(new OperatorSubscriber(subscriber, function (value) {
2280                 buffer.push(value);
2281                 count < buffer.length && buffer.shift();
2282             }, function () {
2283                 var e_1, _a;
2284                 try {
2285                     for (var buffer_1 = __values(buffer), buffer_1_1 = buffer_1.next(); !buffer_1_1.done; buffer_1_1 = buffer_1.next()) {
2286                         var value = buffer_1_1.value;
2287                         subscriber.next(value);
2288                     }
2289                 }
2290                 catch (e_1_1) { e_1 = { error: e_1_1 }; }
2291                 finally {
2292                     try {
2293                         if (buffer_1_1 && !buffer_1_1.done && (_a = buffer_1.return)) _a.call(buffer_1);
2294                     }
2295                     finally { if (e_1) throw e_1.error; }
2296                 }
2297                 subscriber.complete();
2298             }, undefined, function () {
2299                 buffer = null;
2300             }));
2301         });
2302 }
2303
2304 function last(predicate, defaultValue) {
2305     var hasDefaultValue = arguments.length >= 2;
2306     return function (source) {
2307         return source.pipe(predicate ? filter(function (v, i) { return predicate(v, i, source); }) : identity, takeLast(1), hasDefaultValue ? defaultIfEmpty(defaultValue) : throwIfEmpty(function () { return new EmptyError(); }));
2308     };
2309 }
2310
2311 function multicast(subjectOrSubjectFactory, selector) {
2312     var subjectFactory = isFunction(subjectOrSubjectFactory) ? subjectOrSubjectFactory : function () { return subjectOrSubjectFactory; };
2313     if (isFunction(selector)) {
2314         return connect(selector, {
2315             connector: subjectFactory,
2316         });
2317     }
2318     return function (source) { return new ConnectableObservable(source, subjectFactory); };
2319 }
2320
2321 function pairwise() {
2322     return operate(function (source, subscriber) {
2323         var prev;
2324         var hasPrev = false;
2325         source.subscribe(new OperatorSubscriber(subscriber, function (value) {
2326             var p = prev;
2327             prev = value;
2328             hasPrev && subscriber.next([p, value]);
2329             hasPrev = true;
2330         }));
2331     });
2332 }
2333
2334 function pluck() {
2335     var properties = [];
2336     for (var _i = 0; _i < arguments.length; _i++) {
2337         properties[_i] = arguments[_i];
2338     }
2339     var length = properties.length;
2340     if (length === 0) {
2341         throw new Error('list of properties cannot be empty.');
2342     }
2343     return map(function (x) {
2344         var currentProp = x;
2345         for (var i = 0; i < length; i++) {
2346             var p = currentProp === null || currentProp === void 0 ? void 0 : currentProp[properties[i]];
2347             if (typeof p !== 'undefined') {
2348                 currentProp = p;
2349             }
2350             else {
2351                 return undefined;
2352             }
2353         }
2354         return currentProp;
2355     });
2356 }
2357
2358 function publish(selector) {
2359     return selector ? function (source) { return connect(selector)(source); } : function (source) { return multicast(new Subject())(source); };
2360 }
2361
2362 function publishReplay(bufferSize, windowTime, selectorOrScheduler, timestampProvider) {
2363     if (selectorOrScheduler && !isFunction(selectorOrScheduler)) {
2364         timestampProvider = selectorOrScheduler;
2365     }
2366     var selector = isFunction(selectorOrScheduler) ? selectorOrScheduler : undefined;
2367     return function (source) { return multicast(new ReplaySubject(bufferSize, windowTime, timestampProvider), selector)(source); };
2368 }
2369
2370 function retry(configOrCount) {
2371     if (configOrCount === void 0) { configOrCount = Infinity; }
2372     var config;
2373     if (configOrCount && typeof configOrCount === 'object') {
2374         config = configOrCount;
2375     }
2376     else {
2377         config = {
2378             count: configOrCount,
2379         };
2380     }
2381     var _a = config.count, count = _a === void 0 ? Infinity : _a, delay = config.delay, _b = config.resetOnSuccess, resetOnSuccess = _b === void 0 ? false : _b;
2382     return count <= 0
2383         ? identity
2384         : operate(function (source, subscriber) {
2385             var soFar = 0;
2386             var innerSub;
2387             var subscribeForRetry = function () {
2388                 var syncUnsub = false;
2389                 innerSub = source.subscribe(new OperatorSubscriber(subscriber, function (value) {
2390                     if (resetOnSuccess) {
2391                         soFar = 0;
2392                     }
2393                     subscriber.next(value);
2394                 }, undefined, function (err) {
2395                     if (soFar++ < count) {
2396                         var resub_1 = function () {
2397                             if (innerSub) {
2398                                 innerSub.unsubscribe();
2399                                 innerSub = null;
2400                                 subscribeForRetry();
2401                             }
2402                             else {
2403                                 syncUnsub = true;
2404                             }
2405                         };
2406                         if (delay != null) {
2407                             var notifier = typeof delay === 'number' ? timer(delay) : innerFrom(delay(err, soFar));
2408                             var notifierSubscriber_1 = new OperatorSubscriber(subscriber, function () {
2409                                 notifierSubscriber_1.unsubscribe();
2410                                 resub_1();
2411                             }, function () {
2412                                 subscriber.complete();
2413                             });
2414                             notifier.subscribe(notifierSubscriber_1);
2415                         }
2416                         else {
2417                             resub_1();
2418                         }
2419                     }
2420                     else {
2421                         subscriber.error(err);
2422                     }
2423                 }));
2424                 if (syncUnsub) {
2425                     innerSub.unsubscribe();
2426                     innerSub = null;
2427                     subscribeForRetry();
2428                 }
2429             };
2430             subscribeForRetry();
2431         });
2432 }
2433
2434 function sample(notifier) {
2435     return operate(function (source, subscriber) {
2436         var hasValue = false;
2437         var lastValue = null;
2438         source.subscribe(new OperatorSubscriber(subscriber, function (value) {
2439             hasValue = true;
2440             lastValue = value;
2441         }));
2442         var emit = function () {
2443             if (hasValue) {
2444                 hasValue = false;
2445                 var value = lastValue;
2446                 lastValue = null;
2447                 subscriber.next(value);
2448             }
2449         };
2450         notifier.subscribe(new OperatorSubscriber(subscriber, emit, noop));
2451     });
2452 }
2453
2454 function scan(accumulator, seed) {
2455     return operate(scanInternals(accumulator, seed, arguments.length >= 2, true));
2456 }
2457
2458 function share(options) {
2459     if (options === void 0) { options = {}; }
2460     var _a = options.connector, connector = _a === void 0 ? function () { return new Subject(); } : _a, _b = options.resetOnError, resetOnError = _b === void 0 ? true : _b, _c = options.resetOnComplete, resetOnComplete = _c === void 0 ? true : _c, _d = options.resetOnRefCountZero, resetOnRefCountZero = _d === void 0 ? true : _d;
2461     return function (wrapperSource) {
2462         var connection = null;
2463         var resetConnection = null;
2464         var subject = null;
2465         var refCount = 0;
2466         var hasCompleted = false;
2467         var hasErrored = false;
2468         var cancelReset = function () {
2469             resetConnection === null || resetConnection === void 0 ? void 0 : resetConnection.unsubscribe();
2470             resetConnection = null;
2471         };
2472         var reset = function () {
2473             cancelReset();
2474             connection = subject = null;
2475             hasCompleted = hasErrored = false;
2476         };
2477         var resetAndUnsubscribe = function () {
2478             var conn = connection;
2479             reset();
2480             conn === null || conn === void 0 ? void 0 : conn.unsubscribe();
2481         };
2482         return operate(function (source, subscriber) {
2483             refCount++;
2484             if (!hasErrored && !hasCompleted) {
2485                 cancelReset();
2486             }
2487             var dest = (subject = subject !== null && subject !== void 0 ? subject : connector());
2488             subscriber.add(function () {
2489                 refCount--;
2490                 if (refCount === 0 && !hasErrored && !hasCompleted) {
2491                     resetConnection = handleReset(resetAndUnsubscribe, resetOnRefCountZero);
2492                 }
2493             });
2494             dest.subscribe(subscriber);
2495             if (!connection) {
2496                 connection = new SafeSubscriber({
2497                     next: function (value) { return dest.next(value); },
2498                     error: function (err) {
2499                         hasErrored = true;
2500                         cancelReset();
2501                         resetConnection = handleReset(reset, resetOnError, err);
2502                         dest.error(err);
2503                     },
2504                     complete: function () {
2505                         hasCompleted = true;
2506                         cancelReset();
2507                         resetConnection = handleReset(reset, resetOnComplete);
2508                         dest.complete();
2509                     },
2510                 });
2511                 from(source).subscribe(connection);
2512             }
2513         })(wrapperSource);
2514     };
2515 }
2516 function handleReset(reset, on) {
2517     var args = [];
2518     for (var _i = 2; _i < arguments.length; _i++) {
2519         args[_i - 2] = arguments[_i];
2520     }
2521     if (on === true) {
2522         reset();
2523         return null;
2524     }
2525     if (on === false) {
2526         return null;
2527     }
2528     return on.apply(void 0, __spreadArray([], __read(args))).pipe(take(1))
2529         .subscribe(function () { return reset(); });
2530 }
2531
2532 function skip(count) {
2533     return filter(function (_, index) { return count <= index; });
2534 }
2535
2536 function skipWhile(predicate) {
2537     return operate(function (source, subscriber) {
2538         var taking = false;
2539         var index = 0;
2540         source.subscribe(new OperatorSubscriber(subscriber, function (value) { return (taking || (taking = !predicate(value, index++))) && subscriber.next(value); }));
2541     });
2542 }
2543
2544 function startWith() {
2545     var values = [];
2546     for (var _i = 0; _i < arguments.length; _i++) {
2547         values[_i] = arguments[_i];
2548     }
2549     var scheduler = popScheduler(values);
2550     return operate(function (source, subscriber) {
2551         (scheduler ? concat(values, source, scheduler) : concat(values, source)).subscribe(subscriber);
2552     });
2553 }
2554
2555 function switchMap(project, resultSelector) {
2556     return operate(function (source, subscriber) {
2557         var innerSubscriber = null;
2558         var index = 0;
2559         var isComplete = false;
2560         var checkComplete = function () { return isComplete && !innerSubscriber && subscriber.complete(); };
2561         source.subscribe(new OperatorSubscriber(subscriber, function (value) {
2562             innerSubscriber === null || innerSubscriber === void 0 ? void 0 : innerSubscriber.unsubscribe();
2563             var innerIndex = 0;
2564             var outerIndex = index++;
2565             innerFrom(project(value, outerIndex)).subscribe((innerSubscriber = new OperatorSubscriber(subscriber, function (innerValue) { return subscriber.next(resultSelector ? resultSelector(value, innerValue, outerIndex, innerIndex++) : innerValue); }, function () {
2566                 innerSubscriber = null;
2567                 checkComplete();
2568             })));
2569         }, function () {
2570             isComplete = true;
2571             checkComplete();
2572         }));
2573     });
2574 }
2575
2576 function takeUntil(notifier) {
2577     return operate(function (source, subscriber) {
2578         innerFrom(notifier).subscribe(new OperatorSubscriber(subscriber, function () { return subscriber.complete(); }, noop));
2579         !subscriber.closed && source.subscribe(subscriber);
2580     });
2581 }
2582
2583 function takeWhile(predicate, inclusive) {
2584     if (inclusive === void 0) { inclusive = false; }
2585     return operate(function (source, subscriber) {
2586         var index = 0;
2587         source.subscribe(new OperatorSubscriber(subscriber, function (value) {
2588             var result = predicate(value, index++);
2589             (result || inclusive) && subscriber.next(value);
2590             !result && subscriber.complete();
2591         }));
2592     });
2593 }
2594
2595 function tap(observerOrNext, error, complete) {
2596     var tapObserver = isFunction(observerOrNext) || error || complete
2597         ?
2598             { next: observerOrNext, error: error, complete: complete }
2599         : observerOrNext;
2600     return tapObserver
2601         ? operate(function (source, subscriber) {
2602             var _a;
2603             (_a = tapObserver.subscribe) === null || _a === void 0 ? void 0 : _a.call(tapObserver);
2604             var isUnsub = true;
2605             source.subscribe(new OperatorSubscriber(subscriber, function (value) {
2606                 var _a;
2607                 (_a = tapObserver.next) === null || _a === void 0 ? void 0 : _a.call(tapObserver, value);
2608                 subscriber.next(value);
2609             }, function () {
2610                 var _a;
2611                 isUnsub = false;
2612                 (_a = tapObserver.complete) === null || _a === void 0 ? void 0 : _a.call(tapObserver);
2613                 subscriber.complete();
2614             }, function (err) {
2615                 var _a;
2616                 isUnsub = false;
2617                 (_a = tapObserver.error) === null || _a === void 0 ? void 0 : _a.call(tapObserver, err);
2618                 subscriber.error(err);
2619             }, function () {
2620                 var _a, _b;
2621                 if (isUnsub) {
2622                     (_a = tapObserver.unsubscribe) === null || _a === void 0 ? void 0 : _a.call(tapObserver);
2623                 }
2624                 (_b = tapObserver.finalize) === null || _b === void 0 ? void 0 : _b.call(tapObserver);
2625             }));
2626         })
2627         :
2628             identity;
2629 }
2630
2631 function withLatestFrom() {
2632     var inputs = [];
2633     for (var _i = 0; _i < arguments.length; _i++) {
2634         inputs[_i] = arguments[_i];
2635     }
2636     var project = popResultSelector(inputs);
2637     return operate(function (source, subscriber) {
2638         var len = inputs.length;
2639         var otherValues = new Array(len);
2640         var hasValue = inputs.map(function () { return false; });
2641         var ready = false;
2642         var _loop_1 = function (i) {
2643             innerFrom(inputs[i]).subscribe(new OperatorSubscriber(subscriber, function (value) {
2644                 otherValues[i] = value;
2645                 if (!ready && !hasValue[i]) {
2646                     hasValue[i] = true;
2647                     (ready = hasValue.every(identity)) && (hasValue = null);
2648                 }
2649             }, noop));
2650         };
2651         for (var i = 0; i < len; i++) {
2652             _loop_1(i);
2653         }
2654         source.subscribe(new OperatorSubscriber(subscriber, function (value) {
2655             if (ready) {
2656                 var values = __spreadArray([value], __read(otherValues));
2657                 subscriber.next(project ? project.apply(void 0, __spreadArray([], __read(values))) : values);
2658             }
2659         }));
2660     });
2661 }
2662
2663 /**
2664  * @class Filter
2665  *
2666  * @classdesc Represents a class for creating image filters. Implementation and
2667  * definitions based on https://github.com/mapbox/feature-filter.
2668  */
2669 class FilterCreator {
2670     /**
2671      * Create a filter from a filter expression.
2672      *
2673      * @description The following filters are supported:
2674      *
2675      * Comparison
2676      * `==`
2677      * `!=`
2678      * `<`
2679      * `<=`
2680      * `>`
2681      * `>=`
2682      *
2683      * Set membership
2684      * `in`
2685      * `!in`
2686      *
2687      * Combining
2688      * `all`
2689      *
2690      * @param {FilterExpression} filter - Comparison, set membership or combinding filter
2691      * expression.
2692      * @returns {FilterFunction} Function taking a image and returning a boolean that
2693      * indicates whether the image passed the test or not.
2694      */
2695     createFilter(filter) {
2696         return new Function("node", "return " + this._compile(filter) + ";");
2697     }
2698     _compile(filter) {
2699         if (filter == null || filter.length <= 1) {
2700             return "true";
2701         }
2702         const operator = filter[0];
2703         const operation = operator === "==" ? this._compileComparisonOp("===", filter[1], filter[2], false) :
2704             operator === "!=" ? this._compileComparisonOp("!==", filter[1], filter[2], false) :
2705                 operator === ">" ||
2706                     operator === ">=" ||
2707                     operator === "<" ||
2708                     operator === "<=" ? this._compileComparisonOp(operator, filter[1], filter[2], true) :
2709                     operator === "in" ?
2710                         this._compileInOp(filter[1], filter.slice(2)) :
2711                         operator === "!in" ?
2712                             this._compileNegation(this._compileInOp(filter[1], filter.slice(2))) :
2713                             operator === "all" ? this._compileLogicalOp(filter.slice(1), "&&") :
2714                                 "true";
2715         return "(" + operation + ")";
2716     }
2717     _compare(a, b) {
2718         return a < b ? -1 : a > b ? 1 : 0;
2719     }
2720     _compileComparisonOp(operator, property, value, checkType) {
2721         const left = this._compilePropertyReference(property);
2722         const right = JSON.stringify(value);
2723         return (checkType ? "typeof " + left + "===typeof " + right + "&&" : "") + left + operator + right;
2724     }
2725     _compileInOp(property, values) {
2726         const compare = this._compare;
2727         const left = JSON.stringify(values.sort(compare));
2728         const right = this._compilePropertyReference(property);
2729         return left + ".indexOf(" + right + ")!==-1";
2730     }
2731     _compileLogicalOp(filters, operator) {
2732         const compile = this._compile.bind(this);
2733         return filters.map(compile).join(operator);
2734     }
2735     _compileNegation(expression) {
2736         return "!(" + expression + ")";
2737     }
2738     _compilePropertyReference(property) {
2739         return "node[" + JSON.stringify(property) + "]";
2740     }
2741 }
2742
2743 /**
2744  * @license
2745  * Copyright 2010-2021 Three.js Authors
2746  * SPDX-License-Identifier: MIT
2747  */
2748 const REVISION = '134';
2749 const CullFaceNone = 0;
2750 const CullFaceBack = 1;
2751 const CullFaceFront = 2;
2752 const PCFShadowMap = 1;
2753 const PCFSoftShadowMap = 2;
2754 const VSMShadowMap = 3;
2755 const FrontSide = 0;
2756 const BackSide = 1;
2757 const DoubleSide = 2;
2758 const FlatShading = 1;
2759 const NoBlending = 0;
2760 const NormalBlending = 1;
2761 const AdditiveBlending = 2;
2762 const SubtractiveBlending = 3;
2763 const MultiplyBlending = 4;
2764 const CustomBlending = 5;
2765 const AddEquation = 100;
2766 const SubtractEquation = 101;
2767 const ReverseSubtractEquation = 102;
2768 const MinEquation = 103;
2769 const MaxEquation = 104;
2770 const ZeroFactor = 200;
2771 const OneFactor = 201;
2772 const SrcColorFactor = 202;
2773 const OneMinusSrcColorFactor = 203;
2774 const SrcAlphaFactor = 204;
2775 const OneMinusSrcAlphaFactor = 205;
2776 const DstAlphaFactor = 206;
2777 const OneMinusDstAlphaFactor = 207;
2778 const DstColorFactor = 208;
2779 const OneMinusDstColorFactor = 209;
2780 const SrcAlphaSaturateFactor = 210;
2781 const NeverDepth = 0;
2782 const AlwaysDepth = 1;
2783 const LessDepth = 2;
2784 const LessEqualDepth = 3;
2785 const EqualDepth = 4;
2786 const GreaterEqualDepth = 5;
2787 const GreaterDepth = 6;
2788 const NotEqualDepth = 7;
2789 const MultiplyOperation = 0;
2790 const MixOperation = 1;
2791 const AddOperation = 2;
2792 const NoToneMapping = 0;
2793 const LinearToneMapping = 1;
2794 const ReinhardToneMapping = 2;
2795 const CineonToneMapping = 3;
2796 const ACESFilmicToneMapping = 4;
2797 const CustomToneMapping = 5;
2798
2799 const UVMapping = 300;
2800 const CubeReflectionMapping = 301;
2801 const CubeRefractionMapping = 302;
2802 const EquirectangularReflectionMapping = 303;
2803 const EquirectangularRefractionMapping = 304;
2804 const CubeUVReflectionMapping = 306;
2805 const CubeUVRefractionMapping = 307;
2806 const RepeatWrapping = 1000;
2807 const ClampToEdgeWrapping = 1001;
2808 const MirroredRepeatWrapping = 1002;
2809 const NearestFilter = 1003;
2810 const NearestMipmapNearestFilter = 1004;
2811 const NearestMipmapLinearFilter = 1005;
2812 const LinearFilter = 1006;
2813 const LinearMipmapNearestFilter = 1007;
2814 const LinearMipmapLinearFilter = 1008;
2815 const UnsignedByteType = 1009;
2816 const ByteType = 1010;
2817 const ShortType = 1011;
2818 const UnsignedShortType = 1012;
2819 const IntType = 1013;
2820 const UnsignedIntType = 1014;
2821 const FloatType = 1015;
2822 const HalfFloatType = 1016;
2823 const UnsignedShort4444Type = 1017;
2824 const UnsignedShort5551Type = 1018;
2825 const UnsignedShort565Type = 1019;
2826 const UnsignedInt248Type = 1020;
2827 const AlphaFormat = 1021;
2828 const RGBFormat = 1022;
2829 const RGBAFormat = 1023;
2830 const LuminanceFormat = 1024;
2831 const LuminanceAlphaFormat = 1025;
2832 const RGBEFormat = RGBAFormat;
2833 const DepthFormat = 1026;
2834 const DepthStencilFormat = 1027;
2835 const RedFormat = 1028;
2836 const RedIntegerFormat = 1029;
2837 const RGFormat = 1030;
2838 const RGIntegerFormat = 1031;
2839 const RGBIntegerFormat = 1032;
2840 const RGBAIntegerFormat = 1033;
2841
2842 const RGB_S3TC_DXT1_Format = 33776;
2843 const RGBA_S3TC_DXT1_Format = 33777;
2844 const RGBA_S3TC_DXT3_Format = 33778;
2845 const RGBA_S3TC_DXT5_Format = 33779;
2846 const RGB_PVRTC_4BPPV1_Format = 35840;
2847 const RGB_PVRTC_2BPPV1_Format = 35841;
2848 const RGBA_PVRTC_4BPPV1_Format = 35842;
2849 const RGBA_PVRTC_2BPPV1_Format = 35843;
2850 const RGB_ETC1_Format = 36196;
2851 const RGB_ETC2_Format = 37492;
2852 const RGBA_ETC2_EAC_Format = 37496;
2853 const RGBA_ASTC_4x4_Format = 37808;
2854 const RGBA_ASTC_5x4_Format = 37809;
2855 const RGBA_ASTC_5x5_Format = 37810;
2856 const RGBA_ASTC_6x5_Format = 37811;
2857 const RGBA_ASTC_6x6_Format = 37812;
2858 const RGBA_ASTC_8x5_Format = 37813;
2859 const RGBA_ASTC_8x6_Format = 37814;
2860 const RGBA_ASTC_8x8_Format = 37815;
2861 const RGBA_ASTC_10x5_Format = 37816;
2862 const RGBA_ASTC_10x6_Format = 37817;
2863 const RGBA_ASTC_10x8_Format = 37818;
2864 const RGBA_ASTC_10x10_Format = 37819;
2865 const RGBA_ASTC_12x10_Format = 37820;
2866 const RGBA_ASTC_12x12_Format = 37821;
2867 const RGBA_BPTC_Format = 36492;
2868 const SRGB8_ALPHA8_ASTC_4x4_Format = 37840;
2869 const SRGB8_ALPHA8_ASTC_5x4_Format = 37841;
2870 const SRGB8_ALPHA8_ASTC_5x5_Format = 37842;
2871 const SRGB8_ALPHA8_ASTC_6x5_Format = 37843;
2872 const SRGB8_ALPHA8_ASTC_6x6_Format = 37844;
2873 const SRGB8_ALPHA8_ASTC_8x5_Format = 37845;
2874 const SRGB8_ALPHA8_ASTC_8x6_Format = 37846;
2875 const SRGB8_ALPHA8_ASTC_8x8_Format = 37847;
2876 const SRGB8_ALPHA8_ASTC_10x5_Format = 37848;
2877 const SRGB8_ALPHA8_ASTC_10x6_Format = 37849;
2878 const SRGB8_ALPHA8_ASTC_10x8_Format = 37850;
2879 const SRGB8_ALPHA8_ASTC_10x10_Format = 37851;
2880 const SRGB8_ALPHA8_ASTC_12x10_Format = 37852;
2881 const SRGB8_ALPHA8_ASTC_12x12_Format = 37853;
2882 const LoopOnce = 2200;
2883 const LoopRepeat = 2201;
2884 const LoopPingPong = 2202;
2885 const InterpolateDiscrete = 2300;
2886 const InterpolateLinear = 2301;
2887 const InterpolateSmooth = 2302;
2888 const ZeroCurvatureEnding = 2400;
2889 const ZeroSlopeEnding = 2401;
2890 const WrapAroundEnding = 2402;
2891 const NormalAnimationBlendMode = 2500;
2892 const AdditiveAnimationBlendMode = 2501;
2893 const TrianglesDrawMode = 0;
2894 const LinearEncoding = 3000;
2895 const sRGBEncoding = 3001;
2896 const GammaEncoding = 3007;
2897 const RGBEEncoding = 3002;
2898 const LogLuvEncoding = 3003;
2899 const RGBM7Encoding = 3004;
2900 const RGBM16Encoding = 3005;
2901 const RGBDEncoding = 3006;
2902 const BasicDepthPacking = 3200;
2903 const RGBADepthPacking = 3201;
2904 const TangentSpaceNormalMap = 0;
2905 const ObjectSpaceNormalMap = 1;
2906 const KeepStencilOp = 7680;
2907 const AlwaysStencilFunc = 519;
2908
2909 const StaticDrawUsage = 35044;
2910 const DynamicDrawUsage = 35048;
2911 const GLSL3 = '300 es';
2912
2913 /**
2914  * https://github.com/mrdoob/eventdispatcher.js/
2915  */
2916
2917 class EventDispatcher {
2918
2919         addEventListener( type, listener ) {
2920
2921                 if ( this._listeners === undefined ) this._listeners = {};
2922
2923                 const listeners = this._listeners;
2924
2925                 if ( listeners[ type ] === undefined ) {
2926
2927                         listeners[ type ] = [];
2928
2929                 }
2930
2931                 if ( listeners[ type ].indexOf( listener ) === - 1 ) {
2932
2933                         listeners[ type ].push( listener );
2934
2935                 }
2936
2937         }
2938
2939         hasEventListener( type, listener ) {
2940
2941                 if ( this._listeners === undefined ) return false;
2942
2943                 const listeners = this._listeners;
2944
2945                 return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1;
2946
2947         }
2948
2949         removeEventListener( type, listener ) {
2950
2951                 if ( this._listeners === undefined ) return;
2952
2953                 const listeners = this._listeners;
2954                 const listenerArray = listeners[ type ];
2955
2956                 if ( listenerArray !== undefined ) {
2957
2958                         const index = listenerArray.indexOf( listener );
2959
2960                         if ( index !== - 1 ) {
2961
2962                                 listenerArray.splice( index, 1 );
2963
2964                         }
2965
2966                 }
2967
2968         }
2969
2970         dispatchEvent( event ) {
2971
2972                 if ( this._listeners === undefined ) return;
2973
2974                 const listeners = this._listeners;
2975                 const listenerArray = listeners[ event.type ];
2976
2977                 if ( listenerArray !== undefined ) {
2978
2979                         event.target = this;
2980
2981                         // Make a copy, in case listeners are removed while iterating.
2982                         const array = listenerArray.slice( 0 );
2983
2984                         for ( let i = 0, l = array.length; i < l; i ++ ) {
2985
2986                                 array[ i ].call( this, event );
2987
2988                         }
2989
2990                         event.target = null;
2991
2992                 }
2993
2994         }
2995
2996 }
2997
2998 let _seed = 1234567;
2999
3000 const DEG2RAD$1 = Math.PI / 180;
3001 const RAD2DEG$1 = 180 / Math.PI;
3002
3003 //
3004
3005 const _lut = [];
3006
3007 for ( let i = 0; i < 256; i ++ ) {
3008
3009         _lut[ i ] = ( i < 16 ? '0' : '' ) + ( i ).toString( 16 );
3010
3011 }
3012
3013 const hasRandomUUID = typeof crypto !== 'undefined' && 'randomUUID' in crypto;
3014
3015 function generateUUID() {
3016
3017         if ( hasRandomUUID ) {
3018
3019                 return crypto.randomUUID().toUpperCase();
3020
3021         }
3022
3023         // TODO Remove this code when crypto.randomUUID() is available everywhere
3024         // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136
3025
3026         const d0 = Math.random() * 0xffffffff | 0;
3027         const d1 = Math.random() * 0xffffffff | 0;
3028         const d2 = Math.random() * 0xffffffff | 0;
3029         const d3 = Math.random() * 0xffffffff | 0;
3030         const uuid = _lut[ d0 & 0xff ] + _lut[ d0 >> 8 & 0xff ] + _lut[ d0 >> 16 & 0xff ] + _lut[ d0 >> 24 & 0xff ] + '-' +
3031                         _lut[ d1 & 0xff ] + _lut[ d1 >> 8 & 0xff ] + '-' + _lut[ d1 >> 16 & 0x0f | 0x40 ] + _lut[ d1 >> 24 & 0xff ] + '-' +
3032                         _lut[ d2 & 0x3f | 0x80 ] + _lut[ d2 >> 8 & 0xff ] + '-' + _lut[ d2 >> 16 & 0xff ] + _lut[ d2 >> 24 & 0xff ] +
3033                         _lut[ d3 & 0xff ] + _lut[ d3 >> 8 & 0xff ] + _lut[ d3 >> 16 & 0xff ] + _lut[ d3 >> 24 & 0xff ];
3034
3035         // .toUpperCase() here flattens concatenated strings to save heap memory space.
3036         return uuid.toUpperCase();
3037
3038 }
3039
3040 function clamp$1( value, min, max ) {
3041
3042         return Math.max( min, Math.min( max, value ) );
3043
3044 }
3045
3046 // compute euclidian modulo of m % n
3047 // https://en.wikipedia.org/wiki/Modulo_operation
3048 function euclideanModulo( n, m ) {
3049
3050         return ( ( n % m ) + m ) % m;
3051
3052 }
3053
3054 // Linear mapping from range <a1, a2> to range <b1, b2>
3055 function mapLinear( x, a1, a2, b1, b2 ) {
3056
3057         return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );
3058
3059 }
3060
3061 // https://www.gamedev.net/tutorials/programming/general-and-gameplay-programming/inverse-lerp-a-super-useful-yet-often-overlooked-function-r5230/
3062 function inverseLerp( x, y, value ) {
3063
3064         if ( x !== y ) {
3065
3066                 return ( value - x ) / ( y - x );
3067
3068         } else {
3069
3070                 return 0;
3071
3072         }
3073
3074 }
3075
3076 // https://en.wikipedia.org/wiki/Linear_interpolation
3077 function lerp( x, y, t ) {
3078
3079         return ( 1 - t ) * x + t * y;
3080
3081 }
3082
3083 // http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/
3084 function damp( x, y, lambda, dt ) {
3085
3086         return lerp( x, y, 1 - Math.exp( - lambda * dt ) );
3087
3088 }
3089
3090 // https://www.desmos.com/calculator/vcsjnyz7x4
3091 function pingpong( x, length = 1 ) {
3092
3093         return length - Math.abs( euclideanModulo( x, length * 2 ) - length );
3094
3095 }
3096
3097 // http://en.wikipedia.org/wiki/Smoothstep
3098 function smoothstep( x, min, max ) {
3099
3100         if ( x <= min ) return 0;
3101         if ( x >= max ) return 1;
3102
3103         x = ( x - min ) / ( max - min );
3104
3105         return x * x * ( 3 - 2 * x );
3106
3107 }
3108
3109 function smootherstep( x, min, max ) {
3110
3111         if ( x <= min ) return 0;
3112         if ( x >= max ) return 1;
3113
3114         x = ( x - min ) / ( max - min );
3115
3116         return x * x * x * ( x * ( x * 6 - 15 ) + 10 );
3117
3118 }
3119
3120 // Random integer from <low, high> interval
3121 function randInt( low, high ) {
3122
3123         return low + Math.floor( Math.random() * ( high - low + 1 ) );
3124
3125 }
3126
3127 // Random float from <low, high> interval
3128 function randFloat( low, high ) {
3129
3130         return low + Math.random() * ( high - low );
3131
3132 }
3133
3134 // Random float from <-range/2, range/2> interval
3135 function randFloatSpread( range ) {
3136
3137         return range * ( 0.5 - Math.random() );
3138
3139 }
3140
3141 // Deterministic pseudo-random float in the interval [ 0, 1 ]
3142 function seededRandom( s ) {
3143
3144         if ( s !== undefined ) _seed = s % 2147483647;
3145
3146         // Park-Miller algorithm
3147
3148         _seed = _seed * 16807 % 2147483647;
3149
3150         return ( _seed - 1 ) / 2147483646;
3151
3152 }
3153
3154 function degToRad( degrees ) {
3155
3156         return degrees * DEG2RAD$1;
3157
3158 }
3159
3160 function radToDeg( radians ) {
3161
3162         return radians * RAD2DEG$1;
3163
3164 }
3165
3166 function isPowerOfTwo( value ) {
3167
3168         return ( value & ( value - 1 ) ) === 0 && value !== 0;
3169
3170 }
3171
3172 function ceilPowerOfTwo( value ) {
3173
3174         return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) );
3175
3176 }
3177
3178 function floorPowerOfTwo( value ) {
3179
3180         return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) );
3181
3182 }
3183
3184 function setQuaternionFromProperEuler( q, a, b, c, order ) {
3185
3186         // Intrinsic Proper Euler Angles - see https://en.wikipedia.org/wiki/Euler_angles
3187
3188         // rotations are applied to the axes in the order specified by 'order'
3189         // rotation by angle 'a' is applied first, then by angle 'b', then by angle 'c'
3190         // angles are in radians
3191
3192         const cos = Math.cos;
3193         const sin = Math.sin;
3194
3195         const c2 = cos( b / 2 );
3196         const s2 = sin( b / 2 );
3197
3198         const c13 = cos( ( a + c ) / 2 );
3199         const s13 = sin( ( a + c ) / 2 );
3200
3201         const c1_3 = cos( ( a - c ) / 2 );
3202         const s1_3 = sin( ( a - c ) / 2 );
3203
3204         const c3_1 = cos( ( c - a ) / 2 );
3205         const s3_1 = sin( ( c - a ) / 2 );
3206
3207         switch ( order ) {
3208
3209                 case 'XYX':
3210                         q.set( c2 * s13, s2 * c1_3, s2 * s1_3, c2 * c13 );
3211                         break;
3212
3213                 case 'YZY':
3214                         q.set( s2 * s1_3, c2 * s13, s2 * c1_3, c2 * c13 );
3215                         break;
3216
3217                 case 'ZXZ':
3218                         q.set( s2 * c1_3, s2 * s1_3, c2 * s13, c2 * c13 );
3219                         break;
3220
3221                 case 'XZX':
3222                         q.set( c2 * s13, s2 * s3_1, s2 * c3_1, c2 * c13 );
3223                         break;
3224
3225                 case 'YXY':
3226                         q.set( s2 * c3_1, c2 * s13, s2 * s3_1, c2 * c13 );
3227                         break;
3228
3229                 case 'ZYZ':
3230                         q.set( s2 * s3_1, s2 * c3_1, c2 * s13, c2 * c13 );
3231                         break;
3232
3233                 default:
3234                         console.warn( 'THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: ' + order );
3235
3236         }
3237
3238 }
3239
3240 var MathUtils = /*#__PURE__*/Object.freeze({
3241         __proto__: null,
3242         DEG2RAD: DEG2RAD$1,
3243         RAD2DEG: RAD2DEG$1,
3244         generateUUID: generateUUID,
3245         clamp: clamp$1,
3246         euclideanModulo: euclideanModulo,
3247         mapLinear: mapLinear,
3248         inverseLerp: inverseLerp,
3249         lerp: lerp,
3250         damp: damp,
3251         pingpong: pingpong,
3252         smoothstep: smoothstep,
3253         smootherstep: smootherstep,
3254         randInt: randInt,
3255         randFloat: randFloat,
3256         randFloatSpread: randFloatSpread,
3257         seededRandom: seededRandom,
3258         degToRad: degToRad,
3259         radToDeg: radToDeg,
3260         isPowerOfTwo: isPowerOfTwo,
3261         ceilPowerOfTwo: ceilPowerOfTwo,
3262         floorPowerOfTwo: floorPowerOfTwo,
3263         setQuaternionFromProperEuler: setQuaternionFromProperEuler
3264 });
3265
3266 class Vector2 {
3267
3268         constructor( x = 0, y = 0 ) {
3269
3270                 this.x = x;
3271                 this.y = y;
3272
3273         }
3274
3275         get width() {
3276
3277                 return this.x;
3278
3279         }
3280
3281         set width( value ) {
3282
3283                 this.x = value;
3284
3285         }
3286
3287         get height() {
3288
3289                 return this.y;
3290
3291         }
3292
3293         set height( value ) {
3294
3295                 this.y = value;
3296
3297         }
3298
3299         set( x, y ) {
3300
3301                 this.x = x;
3302                 this.y = y;
3303
3304                 return this;
3305
3306         }
3307
3308         setScalar( scalar ) {
3309
3310                 this.x = scalar;
3311                 this.y = scalar;
3312
3313                 return this;
3314
3315         }
3316
3317         setX( x ) {
3318
3319                 this.x = x;
3320
3321                 return this;
3322
3323         }
3324
3325         setY( y ) {
3326
3327                 this.y = y;
3328
3329                 return this;
3330
3331         }
3332
3333         setComponent( index, value ) {
3334
3335                 switch ( index ) {
3336
3337                         case 0: this.x = value; break;
3338                         case 1: this.y = value; break;
3339                         default: throw new Error( 'index is out of range: ' + index );
3340
3341                 }
3342
3343                 return this;
3344
3345         }
3346
3347         getComponent( index ) {
3348
3349                 switch ( index ) {
3350
3351                         case 0: return this.x;
3352                         case 1: return this.y;
3353                         default: throw new Error( 'index is out of range: ' + index );
3354
3355                 }
3356
3357         }
3358
3359         clone() {
3360
3361                 return new this.constructor( this.x, this.y );
3362
3363         }
3364
3365         copy( v ) {
3366
3367                 this.x = v.x;
3368                 this.y = v.y;
3369
3370                 return this;
3371
3372         }
3373
3374         add( v, w ) {
3375
3376                 if ( w !== undefined ) {
3377
3378                         console.warn( 'THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
3379                         return this.addVectors( v, w );
3380
3381                 }
3382
3383                 this.x += v.x;
3384                 this.y += v.y;
3385
3386                 return this;
3387
3388         }
3389
3390         addScalar( s ) {
3391
3392                 this.x += s;
3393                 this.y += s;
3394
3395                 return this;
3396
3397         }
3398
3399         addVectors( a, b ) {
3400
3401                 this.x = a.x + b.x;
3402                 this.y = a.y + b.y;
3403
3404                 return this;
3405
3406         }
3407
3408         addScaledVector( v, s ) {
3409
3410                 this.x += v.x * s;
3411                 this.y += v.y * s;
3412
3413                 return this;
3414
3415         }
3416
3417         sub( v, w ) {
3418
3419                 if ( w !== undefined ) {
3420
3421                         console.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
3422                         return this.subVectors( v, w );
3423
3424                 }
3425
3426                 this.x -= v.x;
3427                 this.y -= v.y;
3428
3429                 return this;
3430
3431         }
3432
3433         subScalar( s ) {
3434
3435                 this.x -= s;
3436                 this.y -= s;
3437
3438                 return this;
3439
3440         }
3441
3442         subVectors( a, b ) {
3443
3444                 this.x = a.x - b.x;
3445                 this.y = a.y - b.y;
3446
3447                 return this;
3448
3449         }
3450
3451         multiply( v ) {
3452
3453                 this.x *= v.x;
3454                 this.y *= v.y;
3455
3456                 return this;
3457
3458         }
3459
3460         multiplyScalar( scalar ) {
3461
3462                 this.x *= scalar;
3463                 this.y *= scalar;
3464
3465                 return this;
3466
3467         }
3468
3469         divide( v ) {
3470
3471                 this.x /= v.x;
3472                 this.y /= v.y;
3473
3474                 return this;
3475
3476         }
3477
3478         divideScalar( scalar ) {
3479
3480                 return this.multiplyScalar( 1 / scalar );
3481
3482         }
3483
3484         applyMatrix3( m ) {
3485
3486                 const x = this.x, y = this.y;
3487                 const e = m.elements;
3488
3489                 this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ];
3490                 this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ];
3491
3492                 return this;
3493
3494         }
3495
3496         min( v ) {
3497
3498                 this.x = Math.min( this.x, v.x );
3499                 this.y = Math.min( this.y, v.y );
3500
3501                 return this;
3502
3503         }
3504
3505         max( v ) {
3506
3507                 this.x = Math.max( this.x, v.x );
3508                 this.y = Math.max( this.y, v.y );
3509
3510                 return this;
3511
3512         }
3513
3514         clamp( min, max ) {
3515
3516                 // assumes min < max, componentwise
3517
3518                 this.x = Math.max( min.x, Math.min( max.x, this.x ) );
3519                 this.y = Math.max( min.y, Math.min( max.y, this.y ) );
3520
3521                 return this;
3522
3523         }
3524
3525         clampScalar( minVal, maxVal ) {
3526
3527                 this.x = Math.max( minVal, Math.min( maxVal, this.x ) );
3528                 this.y = Math.max( minVal, Math.min( maxVal, this.y ) );
3529
3530                 return this;
3531
3532         }
3533
3534         clampLength( min, max ) {
3535
3536                 const length = this.length();
3537
3538                 return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
3539
3540         }
3541
3542         floor() {
3543
3544                 this.x = Math.floor( this.x );
3545                 this.y = Math.floor( this.y );
3546
3547                 return this;
3548
3549         }
3550
3551         ceil() {
3552
3553                 this.x = Math.ceil( this.x );
3554                 this.y = Math.ceil( this.y );
3555
3556                 return this;
3557
3558         }
3559
3560         round() {
3561
3562                 this.x = Math.round( this.x );
3563                 this.y = Math.round( this.y );
3564
3565                 return this;
3566
3567         }
3568
3569         roundToZero() {
3570
3571                 this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
3572                 this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
3573
3574                 return this;
3575
3576         }
3577
3578         negate() {
3579
3580                 this.x = - this.x;
3581                 this.y = - this.y;
3582
3583                 return this;
3584
3585         }
3586
3587         dot( v ) {
3588
3589                 return this.x * v.x + this.y * v.y;
3590
3591         }
3592
3593         cross( v ) {
3594
3595                 return this.x * v.y - this.y * v.x;
3596
3597         }
3598
3599         lengthSq() {
3600
3601                 return this.x * this.x + this.y * this.y;
3602
3603         }
3604
3605         length() {
3606
3607                 return Math.sqrt( this.x * this.x + this.y * this.y );
3608
3609         }
3610
3611         manhattanLength() {
3612
3613                 return Math.abs( this.x ) + Math.abs( this.y );
3614
3615         }
3616
3617         normalize() {
3618
3619                 return this.divideScalar( this.length() || 1 );
3620
3621         }
3622
3623         angle() {
3624
3625                 // computes the angle in radians with respect to the positive x-axis
3626
3627                 const angle = Math.atan2( - this.y, - this.x ) + Math.PI;
3628
3629                 return angle;
3630
3631         }
3632
3633         distanceTo( v ) {
3634
3635                 return Math.sqrt( this.distanceToSquared( v ) );
3636
3637         }
3638
3639         distanceToSquared( v ) {
3640
3641                 const dx = this.x - v.x, dy = this.y - v.y;
3642                 return dx * dx + dy * dy;
3643
3644         }
3645
3646         manhattanDistanceTo( v ) {
3647
3648                 return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y );
3649
3650         }
3651
3652         setLength( length ) {
3653
3654                 return this.normalize().multiplyScalar( length );
3655
3656         }
3657
3658         lerp( v, alpha ) {
3659
3660                 this.x += ( v.x - this.x ) * alpha;
3661                 this.y += ( v.y - this.y ) * alpha;
3662
3663                 return this;
3664
3665         }
3666
3667         lerpVectors( v1, v2, alpha ) {
3668
3669                 this.x = v1.x + ( v2.x - v1.x ) * alpha;
3670                 this.y = v1.y + ( v2.y - v1.y ) * alpha;
3671
3672                 return this;
3673
3674         }
3675
3676         equals( v ) {
3677
3678                 return ( ( v.x === this.x ) && ( v.y === this.y ) );
3679
3680         }
3681
3682         fromArray( array, offset = 0 ) {
3683
3684                 this.x = array[ offset ];
3685                 this.y = array[ offset + 1 ];
3686
3687                 return this;
3688
3689         }
3690
3691         toArray( array = [], offset = 0 ) {
3692
3693                 array[ offset ] = this.x;
3694                 array[ offset + 1 ] = this.y;
3695
3696                 return array;
3697
3698         }
3699
3700         fromBufferAttribute( attribute, index, offset ) {
3701
3702                 if ( offset !== undefined ) {
3703
3704                         console.warn( 'THREE.Vector2: offset has been removed from .fromBufferAttribute().' );
3705
3706                 }
3707
3708                 this.x = attribute.getX( index );
3709                 this.y = attribute.getY( index );
3710
3711                 return this;
3712
3713         }
3714
3715         rotateAround( center, angle ) {
3716
3717                 const c = Math.cos( angle ), s = Math.sin( angle );
3718
3719                 const x = this.x - center.x;
3720                 const y = this.y - center.y;
3721
3722                 this.x = x * c - y * s + center.x;
3723                 this.y = x * s + y * c + center.y;
3724
3725                 return this;
3726
3727         }
3728
3729         random() {
3730
3731                 this.x = Math.random();
3732                 this.y = Math.random();
3733
3734                 return this;
3735
3736         }
3737
3738         *[ Symbol.iterator ]() {
3739
3740                 yield this.x;
3741                 yield this.y;
3742
3743         }
3744
3745 }
3746
3747 Vector2.prototype.isVector2 = true;
3748
3749 class Matrix3 {
3750
3751         constructor() {
3752
3753                 this.elements = [
3754
3755                         1, 0, 0,
3756                         0, 1, 0,
3757                         0, 0, 1
3758
3759                 ];
3760
3761                 if ( arguments.length > 0 ) {
3762
3763                         console.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' );
3764
3765                 }
3766
3767         }
3768
3769         set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {
3770
3771                 const te = this.elements;
3772
3773                 te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31;
3774                 te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32;
3775                 te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33;
3776
3777                 return this;
3778
3779         }
3780
3781         identity() {
3782
3783                 this.set(
3784
3785                         1, 0, 0,
3786                         0, 1, 0,
3787                         0, 0, 1
3788
3789                 );
3790
3791                 return this;
3792
3793         }
3794
3795         copy( m ) {
3796
3797                 const te = this.elements;
3798                 const me = m.elements;
3799
3800                 te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ];
3801                 te[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ];
3802                 te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ];
3803
3804                 return this;
3805
3806         }
3807
3808         extractBasis( xAxis, yAxis, zAxis ) {
3809
3810                 xAxis.setFromMatrix3Column( this, 0 );
3811                 yAxis.setFromMatrix3Column( this, 1 );
3812                 zAxis.setFromMatrix3Column( this, 2 );
3813
3814                 return this;
3815
3816         }
3817
3818         setFromMatrix4( m ) {
3819
3820                 const me = m.elements;
3821
3822                 this.set(
3823
3824                         me[ 0 ], me[ 4 ], me[ 8 ],
3825                         me[ 1 ], me[ 5 ], me[ 9 ],
3826                         me[ 2 ], me[ 6 ], me[ 10 ]
3827
3828                 );
3829
3830                 return this;
3831
3832         }
3833
3834         multiply( m ) {
3835
3836                 return this.multiplyMatrices( this, m );
3837
3838         }
3839
3840         premultiply( m ) {
3841
3842                 return this.multiplyMatrices( m, this );
3843
3844         }
3845
3846         multiplyMatrices( a, b ) {
3847
3848                 const ae = a.elements;
3849                 const be = b.elements;
3850                 const te = this.elements;
3851
3852                 const a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ];
3853                 const a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ];
3854                 const a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ];
3855
3856                 const b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ];
3857                 const b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ];
3858                 const b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ];
3859
3860                 te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31;
3861                 te[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32;
3862                 te[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33;
3863
3864                 te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31;
3865                 te[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32;
3866                 te[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33;
3867
3868                 te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31;
3869                 te[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32;
3870                 te[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33;
3871
3872                 return this;
3873
3874         }
3875
3876         multiplyScalar( s ) {
3877
3878                 const te = this.elements;
3879
3880                 te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s;
3881                 te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s;
3882                 te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s;
3883
3884                 return this;
3885
3886         }
3887
3888         determinant() {
3889
3890                 const te = this.elements;
3891
3892                 const a = te[ 0 ], b = te[ 1 ], c = te[ 2 ],
3893                         d = te[ 3 ], e = te[ 4 ], f = te[ 5 ],
3894                         g = te[ 6 ], h = te[ 7 ], i = te[ 8 ];
3895
3896                 return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g;
3897
3898         }
3899
3900         invert() {
3901
3902                 const te = this.elements,
3903
3904                         n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ],
3905                         n12 = te[ 3 ], n22 = te[ 4 ], n32 = te[ 5 ],
3906                         n13 = te[ 6 ], n23 = te[ 7 ], n33 = te[ 8 ],
3907
3908                         t11 = n33 * n22 - n32 * n23,
3909                         t12 = n32 * n13 - n33 * n12,
3910                         t13 = n23 * n12 - n22 * n13,
3911
3912                         det = n11 * t11 + n21 * t12 + n31 * t13;
3913
3914                 if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0 );
3915
3916                 const detInv = 1 / det;
3917
3918                 te[ 0 ] = t11 * detInv;
3919                 te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv;
3920                 te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv;
3921
3922                 te[ 3 ] = t12 * detInv;
3923                 te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv;
3924                 te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv;
3925
3926                 te[ 6 ] = t13 * detInv;
3927                 te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv;
3928                 te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv;
3929
3930                 return this;
3931
3932         }
3933
3934         transpose() {
3935
3936                 let tmp;
3937                 const m = this.elements;
3938
3939                 tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp;
3940                 tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp;
3941                 tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp;
3942
3943                 return this;
3944
3945         }
3946
3947         getNormalMatrix( matrix4 ) {
3948
3949                 return this.setFromMatrix4( matrix4 ).invert().transpose();
3950
3951         }
3952
3953         transposeIntoArray( r ) {
3954
3955                 const m = this.elements;
3956
3957                 r[ 0 ] = m[ 0 ];
3958                 r[ 1 ] = m[ 3 ];
3959                 r[ 2 ] = m[ 6 ];
3960                 r[ 3 ] = m[ 1 ];
3961                 r[ 4 ] = m[ 4 ];
3962                 r[ 5 ] = m[ 7 ];
3963                 r[ 6 ] = m[ 2 ];
3964                 r[ 7 ] = m[ 5 ];
3965                 r[ 8 ] = m[ 8 ];
3966
3967                 return this;
3968
3969         }
3970
3971         setUvTransform( tx, ty, sx, sy, rotation, cx, cy ) {
3972
3973                 const c = Math.cos( rotation );
3974                 const s = Math.sin( rotation );
3975
3976                 this.set(
3977                         sx * c, sx * s, - sx * ( c * cx + s * cy ) + cx + tx,
3978                         - sy * s, sy * c, - sy * ( - s * cx + c * cy ) + cy + ty,
3979                         0, 0, 1
3980                 );
3981
3982                 return this;
3983
3984         }
3985
3986         scale( sx, sy ) {
3987
3988                 const te = this.elements;
3989
3990                 te[ 0 ] *= sx; te[ 3 ] *= sx; te[ 6 ] *= sx;
3991                 te[ 1 ] *= sy; te[ 4 ] *= sy; te[ 7 ] *= sy;
3992
3993                 return this;
3994
3995         }
3996
3997         rotate( theta ) {
3998
3999                 const c = Math.cos( theta );
4000                 const s = Math.sin( theta );
4001
4002                 const te = this.elements;
4003
4004                 const a11 = te[ 0 ], a12 = te[ 3 ], a13 = te[ 6 ];
4005                 const a21 = te[ 1 ], a22 = te[ 4 ], a23 = te[ 7 ];
4006
4007                 te[ 0 ] = c * a11 + s * a21;
4008                 te[ 3 ] = c * a12 + s * a22;
4009                 te[ 6 ] = c * a13 + s * a23;
4010
4011                 te[ 1 ] = - s * a11 + c * a21;
4012                 te[ 4 ] = - s * a12 + c * a22;
4013                 te[ 7 ] = - s * a13 + c * a23;
4014
4015                 return this;
4016
4017         }
4018
4019         translate( tx, ty ) {
4020
4021                 const te = this.elements;
4022
4023                 te[ 0 ] += tx * te[ 2 ]; te[ 3 ] += tx * te[ 5 ]; te[ 6 ] += tx * te[ 8 ];
4024                 te[ 1 ] += ty * te[ 2 ]; te[ 4 ] += ty * te[ 5 ]; te[ 7 ] += ty * te[ 8 ];
4025
4026                 return this;
4027
4028         }
4029
4030         equals( matrix ) {
4031
4032                 const te = this.elements;
4033                 const me = matrix.elements;
4034
4035                 for ( let i = 0; i < 9; i ++ ) {
4036
4037                         if ( te[ i ] !== me[ i ] ) return false;
4038
4039                 }
4040
4041                 return true;
4042
4043         }
4044
4045         fromArray( array, offset = 0 ) {
4046
4047                 for ( let i = 0; i < 9; i ++ ) {
4048
4049                         this.elements[ i ] = array[ i + offset ];
4050
4051                 }
4052
4053                 return this;
4054
4055         }
4056
4057         toArray( array = [], offset = 0 ) {
4058
4059                 const te = this.elements;
4060
4061                 array[ offset ] = te[ 0 ];
4062                 array[ offset + 1 ] = te[ 1 ];
4063                 array[ offset + 2 ] = te[ 2 ];
4064
4065                 array[ offset + 3 ] = te[ 3 ];
4066                 array[ offset + 4 ] = te[ 4 ];
4067                 array[ offset + 5 ] = te[ 5 ];
4068
4069                 array[ offset + 6 ] = te[ 6 ];
4070                 array[ offset + 7 ] = te[ 7 ];
4071                 array[ offset + 8 ] = te[ 8 ];
4072
4073                 return array;
4074
4075         }
4076
4077         clone() {
4078
4079                 return new this.constructor().fromArray( this.elements );
4080
4081         }
4082
4083 }
4084
4085 Matrix3.prototype.isMatrix3 = true;
4086
4087 function arrayMax( array ) {
4088
4089         if ( array.length === 0 ) return - Infinity;
4090
4091         let max = array[ 0 ];
4092
4093         for ( let i = 1, l = array.length; i < l; ++ i ) {
4094
4095                 if ( array[ i ] > max ) max = array[ i ];
4096
4097         }
4098
4099         return max;
4100
4101 }
4102
4103 function createElementNS( name ) {
4104
4105         return document.createElementNS( 'http://www.w3.org/1999/xhtml', name );
4106
4107 }
4108
4109 /**
4110   * cyrb53 hash for string from: https://stackoverflow.com/a/52171480
4111   *
4112   * Public Domain, @bryc - https://stackoverflow.com/users/815680/bryc
4113   *
4114   * It is roughly similar to the well-known MurmurHash/xxHash algorithms. It uses a combination
4115   * of multiplication and Xorshift to generate the hash, but not as thorough. As a result it's
4116   * faster than either would be in JavaScript and significantly simpler to implement. Keep in
4117   * mind this is not a secure algorithm, if privacy/security is a concern, this is not for you.
4118   *
4119   * @param {string} str
4120   * @param {number} seed, default 0
4121   * @returns number
4122   */
4123 function hashString( str, seed = 0 ) {
4124
4125         let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed;
4126
4127         for ( let i = 0, ch; i < str.length; i ++ ) {
4128
4129                 ch = str.charCodeAt( i );
4130
4131                 h1 = Math.imul( h1 ^ ch, 2654435761 );
4132
4133                 h2 = Math.imul( h2 ^ ch, 1597334677 );
4134
4135         }
4136
4137         h1 = Math.imul( h1 ^ ( h1 >>> 16 ), 2246822507 ) ^ Math.imul( h2 ^ ( h2 >>> 13 ), 3266489909 );
4138
4139         h2 = Math.imul( h2 ^ ( h2 >>> 16 ), 2246822507 ) ^ Math.imul( h1 ^ ( h1 >>> 13 ), 3266489909 );
4140
4141         return 4294967296 * ( 2097151 & h2 ) + ( h1 >>> 0 );
4142
4143 }
4144
4145 let _canvas;
4146
4147 class ImageUtils {
4148
4149         static getDataURL( image ) {
4150
4151                 if ( /^data:/i.test( image.src ) ) {
4152
4153                         return image.src;
4154
4155                 }
4156
4157                 if ( typeof HTMLCanvasElement == 'undefined' ) {
4158
4159                         return image.src;
4160
4161                 }
4162
4163                 let canvas;
4164
4165                 if ( image instanceof HTMLCanvasElement ) {
4166
4167                         canvas = image;
4168
4169                 } else {
4170
4171                         if ( _canvas === undefined ) _canvas = createElementNS( 'canvas' );
4172
4173                         _canvas.width = image.width;
4174                         _canvas.height = image.height;
4175
4176                         const context = _canvas.getContext( '2d' );
4177
4178                         if ( image instanceof ImageData ) {
4179
4180                                 context.putImageData( image, 0, 0 );
4181
4182                         } else {
4183
4184                                 context.drawImage( image, 0, 0, image.width, image.height );
4185
4186                         }
4187
4188                         canvas = _canvas;
4189
4190                 }
4191
4192                 if ( canvas.width > 2048 || canvas.height > 2048 ) {
4193
4194                         console.warn( 'THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons', image );
4195
4196                         return canvas.toDataURL( 'image/jpeg', 0.6 );
4197
4198                 } else {
4199
4200                         return canvas.toDataURL( 'image/png' );
4201
4202                 }
4203
4204         }
4205
4206 }
4207
4208 let textureId = 0;
4209
4210 class Texture extends EventDispatcher {
4211
4212         constructor( image = Texture.DEFAULT_IMAGE, mapping = Texture.DEFAULT_MAPPING, wrapS = ClampToEdgeWrapping, wrapT = ClampToEdgeWrapping, magFilter = LinearFilter, minFilter = LinearMipmapLinearFilter, format = RGBAFormat, type = UnsignedByteType, anisotropy = 1, encoding = LinearEncoding ) {
4213
4214                 super();
4215
4216                 Object.defineProperty( this, 'id', { value: textureId ++ } );
4217
4218                 this.uuid = generateUUID();
4219
4220                 this.name = '';
4221
4222                 this.image = image;
4223                 this.mipmaps = [];
4224
4225                 this.mapping = mapping;
4226
4227                 this.wrapS = wrapS;
4228                 this.wrapT = wrapT;
4229
4230                 this.magFilter = magFilter;
4231                 this.minFilter = minFilter;
4232
4233                 this.anisotropy = anisotropy;
4234
4235                 this.format = format;
4236                 this.internalFormat = null;
4237                 this.type = type;
4238
4239                 this.offset = new Vector2( 0, 0 );
4240                 this.repeat = new Vector2( 1, 1 );
4241                 this.center = new Vector2( 0, 0 );
4242                 this.rotation = 0;
4243
4244                 this.matrixAutoUpdate = true;
4245                 this.matrix = new Matrix3();
4246
4247                 this.generateMipmaps = true;
4248                 this.premultiplyAlpha = false;
4249                 this.flipY = true;
4250                 this.unpackAlignment = 4;       // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)
4251
4252                 // Values of encoding !== THREE.LinearEncoding only supported on map, envMap and emissiveMap.
4253                 //
4254                 // Also changing the encoding after already used by a Material will not automatically make the Material
4255                 // update. You need to explicitly call Material.needsUpdate to trigger it to recompile.
4256                 this.encoding = encoding;
4257
4258                 this.userData = {};
4259
4260                 this.version = 0;
4261                 this.onUpdate = null;
4262
4263                 this.isRenderTargetTexture = false;
4264
4265         }
4266
4267         updateMatrix() {
4268
4269                 this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y );
4270
4271         }
4272
4273         clone() {
4274
4275                 return new this.constructor().copy( this );
4276
4277         }
4278
4279         copy( source ) {
4280
4281                 this.name = source.name;
4282
4283                 this.image = source.image;
4284                 this.mipmaps = source.mipmaps.slice( 0 );
4285
4286                 this.mapping = source.mapping;
4287
4288                 this.wrapS = source.wrapS;
4289                 this.wrapT = source.wrapT;
4290
4291                 this.magFilter = source.magFilter;
4292                 this.minFilter = source.minFilter;
4293
4294                 this.anisotropy = source.anisotropy;
4295
4296                 this.format = source.format;
4297                 this.internalFormat = source.internalFormat;
4298                 this.type = source.type;
4299
4300                 this.offset.copy( source.offset );
4301                 this.repeat.copy( source.repeat );
4302                 this.center.copy( source.center );
4303                 this.rotation = source.rotation;
4304
4305                 this.matrixAutoUpdate = source.matrixAutoUpdate;
4306                 this.matrix.copy( source.matrix );
4307
4308                 this.generateMipmaps = source.generateMipmaps;
4309                 this.premultiplyAlpha = source.premultiplyAlpha;
4310                 this.flipY = source.flipY;
4311                 this.unpackAlignment = source.unpackAlignment;
4312                 this.encoding = source.encoding;
4313
4314                 this.userData = JSON.parse( JSON.stringify( source.userData ) );
4315
4316                 return this;
4317
4318         }
4319
4320         toJSON( meta ) {
4321
4322                 const isRootObject = ( meta === undefined || typeof meta === 'string' );
4323
4324                 if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) {
4325
4326                         return meta.textures[ this.uuid ];
4327
4328                 }
4329
4330                 const output = {
4331
4332                         metadata: {
4333                                 version: 4.5,
4334                                 type: 'Texture',
4335                                 generator: 'Texture.toJSON'
4336                         },
4337
4338                         uuid: this.uuid,
4339                         name: this.name,
4340
4341                         mapping: this.mapping,
4342
4343                         repeat: [ this.repeat.x, this.repeat.y ],
4344                         offset: [ this.offset.x, this.offset.y ],
4345                         center: [ this.center.x, this.center.y ],
4346                         rotation: this.rotation,
4347
4348                         wrap: [ this.wrapS, this.wrapT ],
4349
4350                         format: this.format,
4351                         type: this.type,
4352                         encoding: this.encoding,
4353
4354                         minFilter: this.minFilter,
4355                         magFilter: this.magFilter,
4356                         anisotropy: this.anisotropy,
4357
4358                         flipY: this.flipY,
4359
4360                         premultiplyAlpha: this.premultiplyAlpha,
4361                         unpackAlignment: this.unpackAlignment
4362
4363                 };
4364
4365                 if ( this.image !== undefined ) {
4366
4367                         // TODO: Move to THREE.Image
4368
4369                         const image = this.image;
4370
4371                         if ( image.uuid === undefined ) {
4372
4373                                 image.uuid = generateUUID(); // UGH
4374
4375                         }
4376
4377                         if ( ! isRootObject && meta.images[ image.uuid ] === undefined ) {
4378
4379                                 let url;
4380
4381                                 if ( Array.isArray( image ) ) {
4382
4383                                         // process array of images e.g. CubeTexture
4384
4385                                         url = [];
4386
4387                                         for ( let i = 0, l = image.length; i < l; i ++ ) {
4388
4389                                                 // check cube texture with data textures
4390
4391                                                 if ( image[ i ].isDataTexture ) {
4392
4393                                                         url.push( serializeImage( image[ i ].image ) );
4394
4395                                                 } else {
4396
4397                                                         url.push( serializeImage( image[ i ] ) );
4398
4399                                                 }
4400
4401                                         }
4402
4403                                 } else {
4404
4405                                         // process single image
4406
4407                                         url = serializeImage( image );
4408
4409                                 }
4410
4411                                 meta.images[ image.uuid ] = {
4412                                         uuid: image.uuid,
4413                                         url: url
4414                                 };
4415
4416                         }
4417
4418                         output.image = image.uuid;
4419
4420                 }
4421
4422                 if ( JSON.stringify( this.userData ) !== '{}' ) output.userData = this.userData;
4423
4424                 if ( ! isRootObject ) {
4425
4426                         meta.textures[ this.uuid ] = output;
4427
4428                 }
4429
4430                 return output;
4431
4432         }
4433
4434         dispose() {
4435
4436                 this.dispatchEvent( { type: 'dispose' } );
4437
4438         }
4439
4440         transformUv( uv ) {
4441
4442                 if ( this.mapping !== UVMapping ) return uv;
4443
4444                 uv.applyMatrix3( this.matrix );
4445
4446                 if ( uv.x < 0 || uv.x > 1 ) {
4447
4448                         switch ( this.wrapS ) {
4449
4450                                 case RepeatWrapping:
4451
4452                                         uv.x = uv.x - Math.floor( uv.x );
4453                                         break;
4454
4455                                 case ClampToEdgeWrapping:
4456
4457                                         uv.x = uv.x < 0 ? 0 : 1;
4458                                         break;
4459
4460                                 case MirroredRepeatWrapping:
4461
4462                                         if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) {
4463
4464                                                 uv.x = Math.ceil( uv.x ) - uv.x;
4465
4466                                         } else {
4467
4468                                                 uv.x = uv.x - Math.floor( uv.x );
4469
4470                                         }
4471
4472                                         break;
4473
4474                         }
4475
4476                 }
4477
4478                 if ( uv.y < 0 || uv.y > 1 ) {
4479
4480                         switch ( this.wrapT ) {
4481
4482                                 case RepeatWrapping:
4483
4484                                         uv.y = uv.y - Math.floor( uv.y );
4485                                         break;
4486
4487                                 case ClampToEdgeWrapping:
4488
4489                                         uv.y = uv.y < 0 ? 0 : 1;
4490                                         break;
4491
4492                                 case MirroredRepeatWrapping:
4493
4494                                         if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) {
4495
4496                                                 uv.y = Math.ceil( uv.y ) - uv.y;
4497
4498                                         } else {
4499
4500                                                 uv.y = uv.y - Math.floor( uv.y );
4501
4502                                         }
4503
4504                                         break;
4505
4506                         }
4507
4508                 }
4509
4510                 if ( this.flipY ) {
4511
4512                         uv.y = 1 - uv.y;
4513
4514                 }
4515
4516                 return uv;
4517
4518         }
4519
4520         set needsUpdate( value ) {
4521
4522                 if ( value === true ) this.version ++;
4523
4524         }
4525
4526 }
4527
4528 Texture.DEFAULT_IMAGE = undefined;
4529 Texture.DEFAULT_MAPPING = UVMapping;
4530
4531 Texture.prototype.isTexture = true;
4532
4533 function serializeImage( image ) {
4534
4535         if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||
4536                 ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||
4537                 ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) {
4538
4539                 // default images
4540
4541                 return ImageUtils.getDataURL( image );
4542
4543         } else {
4544
4545                 if ( image.data ) {
4546
4547                         // images of DataTexture
4548
4549                         return {
4550                                 data: Array.prototype.slice.call( image.data ),
4551                                 width: image.width,
4552                                 height: image.height,
4553                                 type: image.data.constructor.name
4554                         };
4555
4556                 } else {
4557
4558                         console.warn( 'THREE.Texture: Unable to serialize Texture.' );
4559                         return {};
4560
4561                 }
4562
4563         }
4564
4565 }
4566
4567 class Vector4 {
4568
4569         constructor( x = 0, y = 0, z = 0, w = 1 ) {
4570
4571                 this.x = x;
4572                 this.y = y;
4573                 this.z = z;
4574                 this.w = w;
4575
4576         }
4577
4578         get width() {
4579
4580                 return this.z;
4581
4582         }
4583
4584         set width( value ) {
4585
4586                 this.z = value;
4587
4588         }
4589
4590         get height() {
4591
4592                 return this.w;
4593
4594         }
4595
4596         set height( value ) {
4597
4598                 this.w = value;
4599
4600         }
4601
4602         set( x, y, z, w ) {
4603
4604                 this.x = x;
4605                 this.y = y;
4606                 this.z = z;
4607                 this.w = w;
4608
4609                 return this;
4610
4611         }
4612
4613         setScalar( scalar ) {
4614
4615                 this.x = scalar;
4616                 this.y = scalar;
4617                 this.z = scalar;
4618                 this.w = scalar;
4619
4620                 return this;
4621
4622         }
4623
4624         setX( x ) {
4625
4626                 this.x = x;
4627
4628                 return this;
4629
4630         }
4631
4632         setY( y ) {
4633
4634                 this.y = y;
4635
4636                 return this;
4637
4638         }
4639
4640         setZ( z ) {
4641
4642                 this.z = z;
4643
4644                 return this;
4645
4646         }
4647
4648         setW( w ) {
4649
4650                 this.w = w;
4651
4652                 return this;
4653
4654         }
4655
4656         setComponent( index, value ) {
4657
4658                 switch ( index ) {
4659
4660                         case 0: this.x = value; break;
4661                         case 1: this.y = value; break;
4662                         case 2: this.z = value; break;
4663                         case 3: this.w = value; break;
4664                         default: throw new Error( 'index is out of range: ' + index );
4665
4666                 }
4667
4668                 return this;
4669
4670         }
4671
4672         getComponent( index ) {
4673
4674                 switch ( index ) {
4675
4676                         case 0: return this.x;
4677                         case 1: return this.y;
4678                         case 2: return this.z;
4679                         case 3: return this.w;
4680                         default: throw new Error( 'index is out of range: ' + index );
4681
4682                 }
4683
4684         }
4685
4686         clone() {
4687
4688                 return new this.constructor( this.x, this.y, this.z, this.w );
4689
4690         }
4691
4692         copy( v ) {
4693
4694                 this.x = v.x;
4695                 this.y = v.y;
4696                 this.z = v.z;
4697                 this.w = ( v.w !== undefined ) ? v.w : 1;
4698
4699                 return this;
4700
4701         }
4702
4703         add( v, w ) {
4704
4705                 if ( w !== undefined ) {
4706
4707                         console.warn( 'THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
4708                         return this.addVectors( v, w );
4709
4710                 }
4711
4712                 this.x += v.x;
4713                 this.y += v.y;
4714                 this.z += v.z;
4715                 this.w += v.w;
4716
4717                 return this;
4718
4719         }
4720
4721         addScalar( s ) {
4722
4723                 this.x += s;
4724                 this.y += s;
4725                 this.z += s;
4726                 this.w += s;
4727
4728                 return this;
4729
4730         }
4731
4732         addVectors( a, b ) {
4733
4734                 this.x = a.x + b.x;
4735                 this.y = a.y + b.y;
4736                 this.z = a.z + b.z;
4737                 this.w = a.w + b.w;
4738
4739                 return this;
4740
4741         }
4742
4743         addScaledVector( v, s ) {
4744
4745                 this.x += v.x * s;
4746                 this.y += v.y * s;
4747                 this.z += v.z * s;
4748                 this.w += v.w * s;
4749
4750                 return this;
4751
4752         }
4753
4754         sub( v, w ) {
4755
4756                 if ( w !== undefined ) {
4757
4758                         console.warn( 'THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
4759                         return this.subVectors( v, w );
4760
4761                 }
4762
4763                 this.x -= v.x;
4764                 this.y -= v.y;
4765                 this.z -= v.z;
4766                 this.w -= v.w;
4767
4768                 return this;
4769
4770         }
4771
4772         subScalar( s ) {
4773
4774                 this.x -= s;
4775                 this.y -= s;
4776                 this.z -= s;
4777                 this.w -= s;
4778
4779                 return this;
4780
4781         }
4782
4783         subVectors( a, b ) {
4784
4785                 this.x = a.x - b.x;
4786                 this.y = a.y - b.y;
4787                 this.z = a.z - b.z;
4788                 this.w = a.w - b.w;
4789
4790                 return this;
4791
4792         }
4793
4794         multiply( v ) {
4795
4796                 this.x *= v.x;
4797                 this.y *= v.y;
4798                 this.z *= v.z;
4799                 this.w *= v.w;
4800
4801                 return this;
4802
4803         }
4804
4805         multiplyScalar( scalar ) {
4806
4807                 this.x *= scalar;
4808                 this.y *= scalar;
4809                 this.z *= scalar;
4810                 this.w *= scalar;
4811
4812                 return this;
4813
4814         }
4815
4816         applyMatrix4( m ) {
4817
4818                 const x = this.x, y = this.y, z = this.z, w = this.w;
4819                 const e = m.elements;
4820
4821                 this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w;
4822                 this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w;
4823                 this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w;
4824                 this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w;
4825
4826                 return this;
4827
4828         }
4829
4830         divideScalar( scalar ) {
4831
4832                 return this.multiplyScalar( 1 / scalar );
4833
4834         }
4835
4836         setAxisAngleFromQuaternion( q ) {
4837
4838                 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm
4839
4840                 // q is assumed to be normalized
4841
4842                 this.w = 2 * Math.acos( q.w );
4843
4844                 const s = Math.sqrt( 1 - q.w * q.w );
4845
4846                 if ( s < 0.0001 ) {
4847
4848                         this.x = 1;
4849                         this.y = 0;
4850                         this.z = 0;
4851
4852                 } else {
4853
4854                         this.x = q.x / s;
4855                         this.y = q.y / s;
4856                         this.z = q.z / s;
4857
4858                 }
4859
4860                 return this;
4861
4862         }
4863
4864         setAxisAngleFromRotationMatrix( m ) {
4865
4866                 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm
4867
4868                 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
4869
4870                 let angle, x, y, z; // variables for result
4871                 const epsilon = 0.01,           // margin to allow for rounding errors
4872                         epsilon2 = 0.1,         // margin to distinguish between 0 and 180 degrees
4873
4874                         te = m.elements,
4875
4876                         m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
4877                         m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
4878                         m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
4879
4880                 if ( ( Math.abs( m12 - m21 ) < epsilon ) &&
4881                      ( Math.abs( m13 - m31 ) < epsilon ) &&
4882                      ( Math.abs( m23 - m32 ) < epsilon ) ) {
4883
4884                         // singularity found
4885                         // first check for identity matrix which must have +1 for all terms
4886                         // in leading diagonal and zero in other terms
4887
4888                         if ( ( Math.abs( m12 + m21 ) < epsilon2 ) &&
4889                              ( Math.abs( m13 + m31 ) < epsilon2 ) &&
4890                              ( Math.abs( m23 + m32 ) < epsilon2 ) &&
4891                              ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) {
4892
4893                                 // this singularity is identity matrix so angle = 0
4894
4895                                 this.set( 1, 0, 0, 0 );
4896
4897                                 return this; // zero angle, arbitrary axis
4898
4899                         }
4900
4901                         // otherwise this singularity is angle = 180
4902
4903                         angle = Math.PI;
4904
4905                         const xx = ( m11 + 1 ) / 2;
4906                         const yy = ( m22 + 1 ) / 2;
4907                         const zz = ( m33 + 1 ) / 2;
4908                         const xy = ( m12 + m21 ) / 4;
4909                         const xz = ( m13 + m31 ) / 4;
4910                         const yz = ( m23 + m32 ) / 4;
4911
4912                         if ( ( xx > yy ) && ( xx > zz ) ) {
4913
4914                                 // m11 is the largest diagonal term
4915
4916                                 if ( xx < epsilon ) {
4917
4918                                         x = 0;
4919                                         y = 0.707106781;
4920                                         z = 0.707106781;
4921
4922                                 } else {
4923
4924                                         x = Math.sqrt( xx );
4925                                         y = xy / x;
4926                                         z = xz / x;
4927
4928                                 }
4929
4930                         } else if ( yy > zz ) {
4931
4932                                 // m22 is the largest diagonal term
4933
4934                                 if ( yy < epsilon ) {
4935
4936                                         x = 0.707106781;
4937                                         y = 0;
4938                                         z = 0.707106781;
4939
4940                                 } else {
4941
4942                                         y = Math.sqrt( yy );
4943                                         x = xy / y;
4944                                         z = yz / y;
4945
4946                                 }
4947
4948                         } else {
4949
4950                                 // m33 is the largest diagonal term so base result on this
4951
4952                                 if ( zz < epsilon ) {
4953
4954                                         x = 0.707106781;
4955                                         y = 0.707106781;
4956                                         z = 0;
4957
4958                                 } else {
4959
4960                                         z = Math.sqrt( zz );
4961                                         x = xz / z;
4962                                         y = yz / z;
4963
4964                                 }
4965
4966                         }
4967
4968                         this.set( x, y, z, angle );
4969
4970                         return this; // return 180 deg rotation
4971
4972                 }
4973
4974                 // as we have reached here there are no singularities so we can handle normally
4975
4976                 let s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) +
4977                         ( m13 - m31 ) * ( m13 - m31 ) +
4978                         ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize
4979
4980                 if ( Math.abs( s ) < 0.001 ) s = 1;
4981
4982                 // prevent divide by zero, should not happen if matrix is orthogonal and should be
4983                 // caught by singularity test above, but I've left it in just in case
4984
4985                 this.x = ( m32 - m23 ) / s;
4986                 this.y = ( m13 - m31 ) / s;
4987                 this.z = ( m21 - m12 ) / s;
4988                 this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 );
4989
4990                 return this;
4991
4992         }
4993
4994         min( v ) {
4995
4996                 this.x = Math.min( this.x, v.x );
4997                 this.y = Math.min( this.y, v.y );
4998                 this.z = Math.min( this.z, v.z );
4999                 this.w = Math.min( this.w, v.w );
5000
5001                 return this;
5002
5003         }
5004
5005         max( v ) {
5006
5007                 this.x = Math.max( this.x, v.x );
5008                 this.y = Math.max( this.y, v.y );
5009                 this.z = Math.max( this.z, v.z );
5010                 this.w = Math.max( this.w, v.w );
5011
5012                 return this;
5013
5014         }
5015
5016         clamp( min, max ) {
5017
5018                 // assumes min < max, componentwise
5019
5020                 this.x = Math.max( min.x, Math.min( max.x, this.x ) );
5021                 this.y = Math.max( min.y, Math.min( max.y, this.y ) );
5022                 this.z = Math.max( min.z, Math.min( max.z, this.z ) );
5023                 this.w = Math.max( min.w, Math.min( max.w, this.w ) );
5024
5025                 return this;
5026
5027         }
5028
5029         clampScalar( minVal, maxVal ) {
5030
5031                 this.x = Math.max( minVal, Math.min( maxVal, this.x ) );
5032                 this.y = Math.max( minVal, Math.min( maxVal, this.y ) );
5033                 this.z = Math.max( minVal, Math.min( maxVal, this.z ) );
5034                 this.w = Math.max( minVal, Math.min( maxVal, this.w ) );
5035
5036                 return this;
5037
5038         }
5039
5040         clampLength( min, max ) {
5041
5042                 const length = this.length();
5043
5044                 return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
5045
5046         }
5047
5048         floor() {
5049
5050                 this.x = Math.floor( this.x );
5051                 this.y = Math.floor( this.y );
5052                 this.z = Math.floor( this.z );
5053                 this.w = Math.floor( this.w );
5054
5055                 return this;
5056
5057         }
5058
5059         ceil() {
5060
5061                 this.x = Math.ceil( this.x );
5062                 this.y = Math.ceil( this.y );
5063                 this.z = Math.ceil( this.z );
5064                 this.w = Math.ceil( this.w );
5065
5066                 return this;
5067
5068         }
5069
5070         round() {
5071
5072                 this.x = Math.round( this.x );
5073                 this.y = Math.round( this.y );
5074                 this.z = Math.round( this.z );
5075                 this.w = Math.round( this.w );
5076
5077                 return this;
5078
5079         }
5080
5081         roundToZero() {
5082
5083                 this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
5084                 this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
5085                 this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
5086                 this.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w );
5087
5088                 return this;
5089
5090         }
5091
5092         negate() {
5093
5094                 this.x = - this.x;
5095                 this.y = - this.y;
5096                 this.z = - this.z;
5097                 this.w = - this.w;
5098
5099                 return this;
5100
5101         }
5102
5103         dot( v ) {
5104
5105                 return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;
5106
5107         }
5108
5109         lengthSq() {
5110
5111                 return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;
5112
5113         }
5114
5115         length() {
5116
5117                 return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w );
5118
5119         }
5120
5121         manhattanLength() {
5122
5123                 return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w );
5124
5125         }
5126
5127         normalize() {
5128
5129                 return this.divideScalar( this.length() || 1 );
5130
5131         }
5132
5133         setLength( length ) {
5134
5135                 return this.normalize().multiplyScalar( length );
5136
5137         }
5138
5139         lerp( v, alpha ) {
5140
5141                 this.x += ( v.x - this.x ) * alpha;
5142                 this.y += ( v.y - this.y ) * alpha;
5143                 this.z += ( v.z - this.z ) * alpha;
5144                 this.w += ( v.w - this.w ) * alpha;
5145
5146                 return this;
5147
5148         }
5149
5150         lerpVectors( v1, v2, alpha ) {
5151
5152                 this.x = v1.x + ( v2.x - v1.x ) * alpha;
5153                 this.y = v1.y + ( v2.y - v1.y ) * alpha;
5154                 this.z = v1.z + ( v2.z - v1.z ) * alpha;
5155                 this.w = v1.w + ( v2.w - v1.w ) * alpha;
5156
5157                 return this;
5158
5159         }
5160
5161         equals( v ) {
5162
5163                 return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) );
5164
5165         }
5166
5167         fromArray( array, offset = 0 ) {
5168
5169                 this.x = array[ offset ];
5170                 this.y = array[ offset + 1 ];
5171                 this.z = array[ offset + 2 ];
5172                 this.w = array[ offset + 3 ];
5173
5174                 return this;
5175
5176         }
5177
5178         toArray( array = [], offset = 0 ) {
5179
5180                 array[ offset ] = this.x;
5181                 array[ offset + 1 ] = this.y;
5182                 array[ offset + 2 ] = this.z;
5183                 array[ offset + 3 ] = this.w;
5184
5185                 return array;
5186
5187         }
5188
5189         fromBufferAttribute( attribute, index, offset ) {
5190
5191                 if ( offset !== undefined ) {
5192
5193                         console.warn( 'THREE.Vector4: offset has been removed from .fromBufferAttribute().' );
5194
5195                 }
5196
5197                 this.x = attribute.getX( index );
5198                 this.y = attribute.getY( index );
5199                 this.z = attribute.getZ( index );
5200                 this.w = attribute.getW( index );
5201
5202                 return this;
5203
5204         }
5205
5206         random() {
5207
5208                 this.x = Math.random();
5209                 this.y = Math.random();
5210                 this.z = Math.random();
5211                 this.w = Math.random();
5212
5213                 return this;
5214
5215         }
5216
5217         *[ Symbol.iterator ]() {
5218
5219                 yield this.x;
5220                 yield this.y;
5221                 yield this.z;
5222                 yield this.w;
5223
5224         }
5225
5226 }
5227
5228 Vector4.prototype.isVector4 = true;
5229
5230 /*
5231  In options, we can specify:
5232  * Texture parameters for an auto-generated target texture
5233  * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers
5234 */
5235 class WebGLRenderTarget extends EventDispatcher {
5236
5237         constructor( width, height, options = {} ) {
5238
5239                 super();
5240
5241                 this.width = width;
5242                 this.height = height;
5243                 this.depth = 1;
5244
5245                 this.scissor = new Vector4( 0, 0, width, height );
5246                 this.scissorTest = false;
5247
5248                 this.viewport = new Vector4( 0, 0, width, height );
5249
5250                 this.texture = new Texture( undefined, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding );
5251                 this.texture.isRenderTargetTexture = true;
5252
5253                 this.texture.image = { width: width, height: height, depth: 1 };
5254
5255                 this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false;
5256                 this.texture.internalFormat = options.internalFormat !== undefined ? options.internalFormat : null;
5257                 this.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter;
5258
5259                 this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true;
5260                 this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : false;
5261                 this.depthTexture = options.depthTexture !== undefined ? options.depthTexture : null;
5262
5263         }
5264
5265         setTexture( texture ) {
5266
5267                 texture.image = {
5268                         width: this.width,
5269                         height: this.height,
5270                         depth: this.depth
5271                 };
5272
5273                 this.texture = texture;
5274
5275         }
5276
5277         setSize( width, height, depth = 1 ) {
5278
5279                 if ( this.width !== width || this.height !== height || this.depth !== depth ) {
5280
5281                         this.width = width;
5282                         this.height = height;
5283                         this.depth = depth;
5284
5285                         this.texture.image.width = width;
5286                         this.texture.image.height = height;
5287                         this.texture.image.depth = depth;
5288
5289                         this.dispose();
5290
5291                 }
5292
5293                 this.viewport.set( 0, 0, width, height );
5294                 this.scissor.set( 0, 0, width, height );
5295
5296         }
5297
5298         clone() {
5299
5300                 return new this.constructor().copy( this );
5301
5302         }
5303
5304         copy( source ) {
5305
5306                 this.width = source.width;
5307                 this.height = source.height;
5308                 this.depth = source.depth;
5309
5310                 this.viewport.copy( source.viewport );
5311
5312                 this.texture = source.texture.clone();
5313                 this.texture.image = { ...this.texture.image }; // See #20328.
5314
5315                 this.depthBuffer = source.depthBuffer;
5316                 this.stencilBuffer = source.stencilBuffer;
5317                 this.depthTexture = source.depthTexture;
5318
5319                 return this;
5320
5321         }
5322
5323         dispose() {
5324
5325                 this.dispatchEvent( { type: 'dispose' } );
5326
5327         }
5328
5329 }
5330
5331 WebGLRenderTarget.prototype.isWebGLRenderTarget = true;
5332
5333 class WebGLMultipleRenderTargets extends WebGLRenderTarget {
5334
5335         constructor( width, height, count ) {
5336
5337                 super( width, height );
5338
5339                 const texture = this.texture;
5340
5341                 this.texture = [];
5342
5343                 for ( let i = 0; i < count; i ++ ) {
5344
5345                         this.texture[ i ] = texture.clone();
5346
5347                 }
5348
5349         }
5350
5351         setSize( width, height, depth = 1 ) {
5352
5353                 if ( this.width !== width || this.height !== height || this.depth !== depth ) {
5354
5355                         this.width = width;
5356                         this.height = height;
5357                         this.depth = depth;
5358
5359                         for ( let i = 0, il = this.texture.length; i < il; i ++ ) {
5360
5361                                 this.texture[ i ].image.width = width;
5362                                 this.texture[ i ].image.height = height;
5363                                 this.texture[ i ].image.depth = depth;
5364
5365                         }
5366
5367                         this.dispose();
5368
5369                 }
5370
5371                 this.viewport.set( 0, 0, width, height );
5372                 this.scissor.set( 0, 0, width, height );
5373
5374                 return this;
5375
5376         }
5377
5378         copy( source ) {
5379
5380                 this.dispose();
5381
5382                 this.width = source.width;
5383                 this.height = source.height;
5384                 this.depth = source.depth;
5385
5386                 this.viewport.set( 0, 0, this.width, this.height );
5387                 this.scissor.set( 0, 0, this.width, this.height );
5388
5389                 this.depthBuffer = source.depthBuffer;
5390                 this.stencilBuffer = source.stencilBuffer;
5391                 this.depthTexture = source.depthTexture;
5392
5393                 this.texture.length = 0;
5394
5395                 for ( let i = 0, il = source.texture.length; i < il; i ++ ) {
5396
5397                         this.texture[ i ] = source.texture[ i ].clone();
5398
5399                 }
5400
5401                 return this;
5402
5403         }
5404
5405 }
5406
5407 WebGLMultipleRenderTargets.prototype.isWebGLMultipleRenderTargets = true;
5408
5409 class WebGLMultisampleRenderTarget extends WebGLRenderTarget {
5410
5411         constructor( width, height, options ) {
5412
5413                 super( width, height, options );
5414
5415                 this.samples = 4;
5416
5417         }
5418
5419         copy( source ) {
5420
5421                 super.copy.call( this, source );
5422
5423                 this.samples = source.samples;
5424
5425                 return this;
5426
5427         }
5428
5429 }
5430
5431 WebGLMultisampleRenderTarget.prototype.isWebGLMultisampleRenderTarget = true;
5432
5433 class Quaternion {
5434
5435         constructor( x = 0, y = 0, z = 0, w = 1 ) {
5436
5437                 this._x = x;
5438                 this._y = y;
5439                 this._z = z;
5440                 this._w = w;
5441
5442         }
5443
5444         static slerp( qa, qb, qm, t ) {
5445
5446                 console.warn( 'THREE.Quaternion: Static .slerp() has been deprecated. Use qm.slerpQuaternions( qa, qb, t ) instead.' );
5447                 return qm.slerpQuaternions( qa, qb, t );
5448
5449         }
5450
5451         static slerpFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) {
5452
5453                 // fuzz-free, array-based Quaternion SLERP operation
5454
5455                 let x0 = src0[ srcOffset0 + 0 ],
5456                         y0 = src0[ srcOffset0 + 1 ],
5457                         z0 = src0[ srcOffset0 + 2 ],
5458                         w0 = src0[ srcOffset0 + 3 ];
5459
5460                 const x1 = src1[ srcOffset1 + 0 ],
5461                         y1 = src1[ srcOffset1 + 1 ],
5462                         z1 = src1[ srcOffset1 + 2 ],
5463                         w1 = src1[ srcOffset1 + 3 ];
5464
5465                 if ( t === 0 ) {
5466
5467                         dst[ dstOffset + 0 ] = x0;
5468                         dst[ dstOffset + 1 ] = y0;
5469                         dst[ dstOffset + 2 ] = z0;
5470                         dst[ dstOffset + 3 ] = w0;
5471                         return;
5472
5473                 }
5474
5475                 if ( t === 1 ) {
5476
5477                         dst[ dstOffset + 0 ] = x1;
5478                         dst[ dstOffset + 1 ] = y1;
5479                         dst[ dstOffset + 2 ] = z1;
5480                         dst[ dstOffset + 3 ] = w1;
5481                         return;
5482
5483                 }
5484
5485                 if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) {
5486
5487                         let s = 1 - t;
5488                         const cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,
5489                                 dir = ( cos >= 0 ? 1 : - 1 ),
5490                                 sqrSin = 1 - cos * cos;
5491
5492                         // Skip the Slerp for tiny steps to avoid numeric problems:
5493                         if ( sqrSin > Number.EPSILON ) {
5494
5495                                 const sin = Math.sqrt( sqrSin ),
5496                                         len = Math.atan2( sin, cos * dir );
5497
5498                                 s = Math.sin( s * len ) / sin;
5499                                 t = Math.sin( t * len ) / sin;
5500
5501                         }
5502
5503                         const tDir = t * dir;
5504
5505                         x0 = x0 * s + x1 * tDir;
5506                         y0 = y0 * s + y1 * tDir;
5507                         z0 = z0 * s + z1 * tDir;
5508                         w0 = w0 * s + w1 * tDir;
5509
5510                         // Normalize in case we just did a lerp:
5511                         if ( s === 1 - t ) {
5512
5513                                 const f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 );
5514
5515                                 x0 *= f;
5516                                 y0 *= f;
5517                                 z0 *= f;
5518                                 w0 *= f;
5519
5520                         }
5521
5522                 }
5523
5524                 dst[ dstOffset ] = x0;
5525                 dst[ dstOffset + 1 ] = y0;
5526                 dst[ dstOffset + 2 ] = z0;
5527                 dst[ dstOffset + 3 ] = w0;
5528
5529         }
5530
5531         static multiplyQuaternionsFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1 ) {
5532
5533                 const x0 = src0[ srcOffset0 ];
5534                 const y0 = src0[ srcOffset0 + 1 ];
5535                 const z0 = src0[ srcOffset0 + 2 ];
5536                 const w0 = src0[ srcOffset0 + 3 ];
5537
5538                 const x1 = src1[ srcOffset1 ];
5539                 const y1 = src1[ srcOffset1 + 1 ];
5540                 const z1 = src1[ srcOffset1 + 2 ];
5541                 const w1 = src1[ srcOffset1 + 3 ];
5542
5543                 dst[ dstOffset ] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1;
5544                 dst[ dstOffset + 1 ] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1;
5545                 dst[ dstOffset + 2 ] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1;
5546                 dst[ dstOffset + 3 ] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1;
5547
5548                 return dst;
5549
5550         }
5551
5552         get x() {
5553
5554                 return this._x;
5555
5556         }
5557
5558         set x( value ) {
5559
5560                 this._x = value;
5561                 this._onChangeCallback();
5562
5563         }
5564
5565         get y() {
5566
5567                 return this._y;
5568
5569         }
5570
5571         set y( value ) {
5572
5573                 this._y = value;
5574                 this._onChangeCallback();
5575
5576         }
5577
5578         get z() {
5579
5580                 return this._z;
5581
5582         }
5583
5584         set z( value ) {
5585
5586                 this._z = value;
5587                 this._onChangeCallback();
5588
5589         }
5590
5591         get w() {
5592
5593                 return this._w;
5594
5595         }
5596
5597         set w( value ) {
5598
5599                 this._w = value;
5600                 this._onChangeCallback();
5601
5602         }
5603
5604         set( x, y, z, w ) {
5605
5606                 this._x = x;
5607                 this._y = y;
5608                 this._z = z;
5609                 this._w = w;
5610
5611                 this._onChangeCallback();
5612
5613                 return this;
5614
5615         }
5616
5617         clone() {
5618
5619                 return new this.constructor( this._x, this._y, this._z, this._w );
5620
5621         }
5622
5623         copy( quaternion ) {
5624
5625                 this._x = quaternion.x;
5626                 this._y = quaternion.y;
5627                 this._z = quaternion.z;
5628                 this._w = quaternion.w;
5629
5630                 this._onChangeCallback();
5631
5632                 return this;
5633
5634         }
5635
5636         setFromEuler( euler, update ) {
5637
5638                 if ( ! ( euler && euler.isEuler ) ) {
5639
5640                         throw new Error( 'THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.' );
5641
5642                 }
5643
5644                 const x = euler._x, y = euler._y, z = euler._z, order = euler._order;
5645
5646                 // http://www.mathworks.com/matlabcentral/fileexchange/
5647                 //      20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
5648                 //      content/SpinCalc.m
5649
5650                 const cos = Math.cos;
5651                 const sin = Math.sin;
5652
5653                 const c1 = cos( x / 2 );
5654                 const c2 = cos( y / 2 );
5655                 const c3 = cos( z / 2 );
5656
5657                 const s1 = sin( x / 2 );
5658                 const s2 = sin( y / 2 );
5659                 const s3 = sin( z / 2 );
5660
5661                 switch ( order ) {
5662
5663                         case 'XYZ':
5664                                 this._x = s1 * c2 * c3 + c1 * s2 * s3;
5665                                 this._y = c1 * s2 * c3 - s1 * c2 * s3;
5666                                 this._z = c1 * c2 * s3 + s1 * s2 * c3;
5667                                 this._w = c1 * c2 * c3 - s1 * s2 * s3;
5668                                 break;
5669
5670                         case 'YXZ':
5671                                 this._x = s1 * c2 * c3 + c1 * s2 * s3;
5672                                 this._y = c1 * s2 * c3 - s1 * c2 * s3;
5673                                 this._z = c1 * c2 * s3 - s1 * s2 * c3;
5674                                 this._w = c1 * c2 * c3 + s1 * s2 * s3;
5675                                 break;
5676
5677                         case 'ZXY':
5678                                 this._x = s1 * c2 * c3 - c1 * s2 * s3;
5679                                 this._y = c1 * s2 * c3 + s1 * c2 * s3;
5680                                 this._z = c1 * c2 * s3 + s1 * s2 * c3;
5681                                 this._w = c1 * c2 * c3 - s1 * s2 * s3;
5682                                 break;
5683
5684                         case 'ZYX':
5685                                 this._x = s1 * c2 * c3 - c1 * s2 * s3;
5686                                 this._y = c1 * s2 * c3 + s1 * c2 * s3;
5687                                 this._z = c1 * c2 * s3 - s1 * s2 * c3;
5688                                 this._w = c1 * c2 * c3 + s1 * s2 * s3;
5689                                 break;
5690
5691                         case 'YZX':
5692                                 this._x = s1 * c2 * c3 + c1 * s2 * s3;
5693                                 this._y = c1 * s2 * c3 + s1 * c2 * s3;
5694                                 this._z = c1 * c2 * s3 - s1 * s2 * c3;
5695                                 this._w = c1 * c2 * c3 - s1 * s2 * s3;
5696                                 break;
5697
5698                         case 'XZY':
5699                                 this._x = s1 * c2 * c3 - c1 * s2 * s3;
5700                                 this._y = c1 * s2 * c3 - s1 * c2 * s3;
5701                                 this._z = c1 * c2 * s3 + s1 * s2 * c3;
5702                                 this._w = c1 * c2 * c3 + s1 * s2 * s3;
5703                                 break;
5704
5705                         default:
5706                                 console.warn( 'THREE.Quaternion: .setFromEuler() encountered an unknown order: ' + order );
5707
5708                 }
5709
5710                 if ( update !== false ) this._onChangeCallback();
5711
5712                 return this;
5713
5714         }
5715
5716         setFromAxisAngle( axis, angle ) {
5717
5718                 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
5719
5720                 // assumes axis is normalized
5721
5722                 const halfAngle = angle / 2, s = Math.sin( halfAngle );
5723
5724                 this._x = axis.x * s;
5725                 this._y = axis.y * s;
5726                 this._z = axis.z * s;
5727                 this._w = Math.cos( halfAngle );
5728
5729                 this._onChangeCallback();
5730
5731                 return this;
5732
5733         }
5734
5735         setFromRotationMatrix( m ) {
5736
5737                 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
5738
5739                 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
5740
5741                 const te = m.elements,
5742
5743                         m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
5744                         m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
5745                         m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ],
5746
5747                         trace = m11 + m22 + m33;
5748
5749                 if ( trace > 0 ) {
5750
5751                         const s = 0.5 / Math.sqrt( trace + 1.0 );
5752
5753                         this._w = 0.25 / s;
5754                         this._x = ( m32 - m23 ) * s;
5755                         this._y = ( m13 - m31 ) * s;
5756                         this._z = ( m21 - m12 ) * s;
5757
5758                 } else if ( m11 > m22 && m11 > m33 ) {
5759
5760                         const s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 );
5761
5762                         this._w = ( m32 - m23 ) / s;
5763                         this._x = 0.25 * s;
5764                         this._y = ( m12 + m21 ) / s;
5765                         this._z = ( m13 + m31 ) / s;
5766
5767                 } else if ( m22 > m33 ) {
5768
5769                         const s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 );
5770
5771                         this._w = ( m13 - m31 ) / s;
5772                         this._x = ( m12 + m21 ) / s;
5773                         this._y = 0.25 * s;
5774                         this._z = ( m23 + m32 ) / s;
5775
5776                 } else {
5777
5778                         const s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 );
5779
5780                         this._w = ( m21 - m12 ) / s;
5781                         this._x = ( m13 + m31 ) / s;
5782                         this._y = ( m23 + m32 ) / s;
5783                         this._z = 0.25 * s;
5784
5785                 }
5786
5787                 this._onChangeCallback();
5788
5789                 return this;
5790
5791         }
5792
5793         setFromUnitVectors( vFrom, vTo ) {
5794
5795                 // assumes direction vectors vFrom and vTo are normalized
5796
5797                 let r = vFrom.dot( vTo ) + 1;
5798
5799                 if ( r < Number.EPSILON ) {
5800
5801                         // vFrom and vTo point in opposite directions
5802
5803                         r = 0;
5804
5805                         if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) {
5806
5807                                 this._x = - vFrom.y;
5808                                 this._y = vFrom.x;
5809                                 this._z = 0;
5810                                 this._w = r;
5811
5812                         } else {
5813
5814                                 this._x = 0;
5815                                 this._y = - vFrom.z;
5816                                 this._z = vFrom.y;
5817                                 this._w = r;
5818
5819                         }
5820
5821                 } else {
5822
5823                         // crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3
5824
5825                         this._x = vFrom.y * vTo.z - vFrom.z * vTo.y;
5826                         this._y = vFrom.z * vTo.x - vFrom.x * vTo.z;
5827                         this._z = vFrom.x * vTo.y - vFrom.y * vTo.x;
5828                         this._w = r;
5829
5830                 }
5831
5832                 return this.normalize();
5833
5834         }
5835
5836         angleTo( q ) {
5837
5838                 return 2 * Math.acos( Math.abs( clamp$1( this.dot( q ), - 1, 1 ) ) );
5839
5840         }
5841
5842         rotateTowards( q, step ) {
5843
5844                 const angle = this.angleTo( q );
5845
5846                 if ( angle === 0 ) return this;
5847
5848                 const t = Math.min( 1, step / angle );
5849
5850                 this.slerp( q, t );
5851
5852                 return this;
5853
5854         }
5855
5856         identity() {
5857
5858                 return this.set( 0, 0, 0, 1 );
5859
5860         }
5861
5862         invert() {
5863
5864                 // quaternion is assumed to have unit length
5865
5866                 return this.conjugate();
5867
5868         }
5869
5870         conjugate() {
5871
5872                 this._x *= - 1;
5873                 this._y *= - 1;
5874                 this._z *= - 1;
5875
5876                 this._onChangeCallback();
5877
5878                 return this;
5879
5880         }
5881
5882         dot( v ) {
5883
5884                 return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w;
5885
5886         }
5887
5888         lengthSq() {
5889
5890                 return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;
5891
5892         }
5893
5894         length() {
5895
5896                 return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w );
5897
5898         }
5899
5900         normalize() {
5901
5902                 let l = this.length();
5903
5904                 if ( l === 0 ) {
5905
5906                         this._x = 0;
5907                         this._y = 0;
5908                         this._z = 0;
5909                         this._w = 1;
5910
5911                 } else {
5912
5913                         l = 1 / l;
5914
5915                         this._x = this._x * l;
5916                         this._y = this._y * l;
5917                         this._z = this._z * l;
5918                         this._w = this._w * l;
5919
5920                 }
5921
5922                 this._onChangeCallback();
5923
5924                 return this;
5925
5926         }
5927
5928         multiply( q, p ) {
5929
5930                 if ( p !== undefined ) {
5931
5932                         console.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' );
5933                         return this.multiplyQuaternions( q, p );
5934
5935                 }
5936
5937                 return this.multiplyQuaternions( this, q );
5938
5939         }
5940
5941         premultiply( q ) {
5942
5943                 return this.multiplyQuaternions( q, this );
5944
5945         }
5946
5947         multiplyQuaternions( a, b ) {
5948
5949                 // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
5950
5951                 const qax = a._x, qay = a._y, qaz = a._z, qaw = a._w;
5952                 const qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w;
5953
5954                 this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
5955                 this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
5956                 this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
5957                 this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
5958
5959                 this._onChangeCallback();
5960
5961                 return this;
5962
5963         }
5964
5965         slerp( qb, t ) {
5966
5967                 if ( t === 0 ) return this;
5968                 if ( t === 1 ) return this.copy( qb );
5969
5970                 const x = this._x, y = this._y, z = this._z, w = this._w;
5971
5972                 // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
5973
5974                 let cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;
5975
5976                 if ( cosHalfTheta < 0 ) {
5977
5978                         this._w = - qb._w;
5979                         this._x = - qb._x;
5980                         this._y = - qb._y;
5981                         this._z = - qb._z;
5982
5983                         cosHalfTheta = - cosHalfTheta;
5984
5985                 } else {
5986
5987                         this.copy( qb );
5988
5989                 }
5990
5991                 if ( cosHalfTheta >= 1.0 ) {
5992
5993                         this._w = w;
5994                         this._x = x;
5995                         this._y = y;
5996                         this._z = z;
5997
5998                         return this;
5999
6000                 }
6001
6002                 const sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta;
6003
6004                 if ( sqrSinHalfTheta <= Number.EPSILON ) {
6005
6006                         const s = 1 - t;
6007                         this._w = s * w + t * this._w;
6008                         this._x = s * x + t * this._x;
6009                         this._y = s * y + t * this._y;
6010                         this._z = s * z + t * this._z;
6011
6012                         this.normalize();
6013                         this._onChangeCallback();
6014
6015                         return this;
6016
6017                 }
6018
6019                 const sinHalfTheta = Math.sqrt( sqrSinHalfTheta );
6020                 const halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta );
6021                 const ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,
6022                         ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;
6023
6024                 this._w = ( w * ratioA + this._w * ratioB );
6025                 this._x = ( x * ratioA + this._x * ratioB );
6026                 this._y = ( y * ratioA + this._y * ratioB );
6027                 this._z = ( z * ratioA + this._z * ratioB );
6028
6029                 this._onChangeCallback();
6030
6031                 return this;
6032
6033         }
6034
6035         slerpQuaternions( qa, qb, t ) {
6036
6037                 this.copy( qa ).slerp( qb, t );
6038
6039         }
6040
6041         random() {
6042
6043                 // Derived from http://planning.cs.uiuc.edu/node198.html
6044                 // Note, this source uses w, x, y, z ordering,
6045                 // so we swap the order below.
6046
6047                 const u1 = Math.random();
6048                 const sqrt1u1 = Math.sqrt( 1 - u1 );
6049                 const sqrtu1 = Math.sqrt( u1 );
6050
6051                 const u2 = 2 * Math.PI * Math.random();
6052
6053                 const u3 = 2 * Math.PI * Math.random();
6054
6055                 return this.set(
6056                         sqrt1u1 * Math.cos( u2 ),
6057                         sqrtu1 * Math.sin( u3 ),
6058                         sqrtu1 * Math.cos( u3 ),
6059                         sqrt1u1 * Math.sin( u2 ),
6060                 );
6061
6062         }
6063
6064         equals( quaternion ) {
6065
6066                 return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w );
6067
6068         }
6069
6070         fromArray( array, offset = 0 ) {
6071
6072                 this._x = array[ offset ];
6073                 this._y = array[ offset + 1 ];
6074                 this._z = array[ offset + 2 ];
6075                 this._w = array[ offset + 3 ];
6076
6077                 this._onChangeCallback();
6078
6079                 return this;
6080
6081         }
6082
6083         toArray( array = [], offset = 0 ) {
6084
6085                 array[ offset ] = this._x;
6086                 array[ offset + 1 ] = this._y;
6087                 array[ offset + 2 ] = this._z;
6088                 array[ offset + 3 ] = this._w;
6089
6090                 return array;
6091
6092         }
6093
6094         fromBufferAttribute( attribute, index ) {
6095
6096                 this._x = attribute.getX( index );
6097                 this._y = attribute.getY( index );
6098                 this._z = attribute.getZ( index );
6099                 this._w = attribute.getW( index );
6100
6101                 return this;
6102
6103         }
6104
6105         _onChange( callback ) {
6106
6107                 this._onChangeCallback = callback;
6108
6109                 return this;
6110
6111         }
6112
6113         _onChangeCallback() {}
6114
6115 }
6116
6117 Quaternion.prototype.isQuaternion = true;
6118
6119 class Vector3 {
6120
6121         constructor( x = 0, y = 0, z = 0 ) {
6122
6123                 this.x = x;
6124                 this.y = y;
6125                 this.z = z;
6126
6127         }
6128
6129         set( x, y, z ) {
6130
6131                 if ( z === undefined ) z = this.z; // sprite.scale.set(x,y)
6132
6133                 this.x = x;
6134                 this.y = y;
6135                 this.z = z;
6136
6137                 return this;
6138
6139         }
6140
6141         setScalar( scalar ) {
6142
6143                 this.x = scalar;
6144                 this.y = scalar;
6145                 this.z = scalar;
6146
6147                 return this;
6148
6149         }
6150
6151         setX( x ) {
6152
6153                 this.x = x;
6154
6155                 return this;
6156
6157         }
6158
6159         setY( y ) {
6160
6161                 this.y = y;
6162
6163                 return this;
6164
6165         }
6166
6167         setZ( z ) {
6168
6169                 this.z = z;
6170
6171                 return this;
6172
6173         }
6174
6175         setComponent( index, value ) {
6176
6177                 switch ( index ) {
6178
6179                         case 0: this.x = value; break;
6180                         case 1: this.y = value; break;
6181                         case 2: this.z = value; break;
6182                         default: throw new Error( 'index is out of range: ' + index );
6183
6184                 }
6185
6186                 return this;
6187
6188         }
6189
6190         getComponent( index ) {
6191
6192                 switch ( index ) {
6193
6194                         case 0: return this.x;
6195                         case 1: return this.y;
6196                         case 2: return this.z;
6197                         default: throw new Error( 'index is out of range: ' + index );
6198
6199                 }
6200
6201         }
6202
6203         clone() {
6204
6205                 return new this.constructor( this.x, this.y, this.z );
6206
6207         }
6208
6209         copy( v ) {
6210
6211                 this.x = v.x;
6212                 this.y = v.y;
6213                 this.z = v.z;
6214
6215                 return this;
6216
6217         }
6218
6219         add( v, w ) {
6220
6221                 if ( w !== undefined ) {
6222
6223                         console.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
6224                         return this.addVectors( v, w );
6225
6226                 }
6227
6228                 this.x += v.x;
6229                 this.y += v.y;
6230                 this.z += v.z;
6231
6232                 return this;
6233
6234         }
6235
6236         addScalar( s ) {
6237
6238                 this.x += s;
6239                 this.y += s;
6240                 this.z += s;
6241
6242                 return this;
6243
6244         }
6245
6246         addVectors( a, b ) {
6247
6248                 this.x = a.x + b.x;
6249                 this.y = a.y + b.y;
6250                 this.z = a.z + b.z;
6251
6252                 return this;
6253
6254         }
6255
6256         addScaledVector( v, s ) {
6257
6258                 this.x += v.x * s;
6259                 this.y += v.y * s;
6260                 this.z += v.z * s;
6261
6262                 return this;
6263
6264         }
6265
6266         sub( v, w ) {
6267
6268                 if ( w !== undefined ) {
6269
6270                         console.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
6271                         return this.subVectors( v, w );
6272
6273                 }
6274
6275                 this.x -= v.x;
6276                 this.y -= v.y;
6277                 this.z -= v.z;
6278
6279                 return this;
6280
6281         }
6282
6283         subScalar( s ) {
6284
6285                 this.x -= s;
6286                 this.y -= s;
6287                 this.z -= s;
6288
6289                 return this;
6290
6291         }
6292
6293         subVectors( a, b ) {
6294
6295                 this.x = a.x - b.x;
6296                 this.y = a.y - b.y;
6297                 this.z = a.z - b.z;
6298
6299                 return this;
6300
6301         }
6302
6303         multiply( v, w ) {
6304
6305                 if ( w !== undefined ) {
6306
6307                         console.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' );
6308                         return this.multiplyVectors( v, w );
6309
6310                 }
6311
6312                 this.x *= v.x;
6313                 this.y *= v.y;
6314                 this.z *= v.z;
6315
6316                 return this;
6317
6318         }
6319
6320         multiplyScalar( scalar ) {
6321
6322                 this.x *= scalar;
6323                 this.y *= scalar;
6324                 this.z *= scalar;
6325
6326                 return this;
6327
6328         }
6329
6330         multiplyVectors( a, b ) {
6331
6332                 this.x = a.x * b.x;
6333                 this.y = a.y * b.y;
6334                 this.z = a.z * b.z;
6335
6336                 return this;
6337
6338         }
6339
6340         applyEuler( euler ) {
6341
6342                 if ( ! ( euler && euler.isEuler ) ) {
6343
6344                         console.error( 'THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.' );
6345
6346                 }
6347
6348                 return this.applyQuaternion( _quaternion$4.setFromEuler( euler ) );
6349
6350         }
6351
6352         applyAxisAngle( axis, angle ) {
6353
6354                 return this.applyQuaternion( _quaternion$4.setFromAxisAngle( axis, angle ) );
6355
6356         }
6357
6358         applyMatrix3( m ) {
6359
6360                 const x = this.x, y = this.y, z = this.z;
6361                 const e = m.elements;
6362
6363                 this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z;
6364                 this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z;
6365                 this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z;
6366
6367                 return this;
6368
6369         }
6370
6371         applyNormalMatrix( m ) {
6372
6373                 return this.applyMatrix3( m ).normalize();
6374
6375         }
6376
6377         applyMatrix4( m ) {
6378
6379                 const x = this.x, y = this.y, z = this.z;
6380                 const e = m.elements;
6381
6382                 const w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] );
6383
6384                 this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * w;
6385                 this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * w;
6386                 this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * w;
6387
6388                 return this;
6389
6390         }
6391
6392         applyQuaternion( q ) {
6393
6394                 const x = this.x, y = this.y, z = this.z;
6395                 const qx = q.x, qy = q.y, qz = q.z, qw = q.w;
6396
6397                 // calculate quat * vector
6398
6399                 const ix = qw * x + qy * z - qz * y;
6400                 const iy = qw * y + qz * x - qx * z;
6401                 const iz = qw * z + qx * y - qy * x;
6402                 const iw = - qx * x - qy * y - qz * z;
6403
6404                 // calculate result * inverse quat
6405
6406                 this.x = ix * qw + iw * - qx + iy * - qz - iz * - qy;
6407                 this.y = iy * qw + iw * - qy + iz * - qx - ix * - qz;
6408                 this.z = iz * qw + iw * - qz + ix * - qy - iy * - qx;
6409
6410                 return this;
6411
6412         }
6413
6414         project( camera ) {
6415
6416                 return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix );
6417
6418         }
6419
6420         unproject( camera ) {
6421
6422                 return this.applyMatrix4( camera.projectionMatrixInverse ).applyMatrix4( camera.matrixWorld );
6423
6424         }
6425
6426         transformDirection( m ) {
6427
6428                 // input: THREE.Matrix4 affine matrix
6429                 // vector interpreted as a direction
6430
6431                 const x = this.x, y = this.y, z = this.z;
6432                 const e = m.elements;
6433
6434                 this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z;
6435                 this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z;
6436                 this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;
6437
6438                 return this.normalize();
6439
6440         }
6441
6442         divide( v ) {
6443
6444                 this.x /= v.x;
6445                 this.y /= v.y;
6446                 this.z /= v.z;
6447
6448                 return this;
6449
6450         }
6451
6452         divideScalar( scalar ) {
6453
6454                 return this.multiplyScalar( 1 / scalar );
6455
6456         }
6457
6458         min( v ) {
6459
6460                 this.x = Math.min( this.x, v.x );
6461                 this.y = Math.min( this.y, v.y );
6462                 this.z = Math.min( this.z, v.z );
6463
6464                 return this;
6465
6466         }
6467
6468         max( v ) {
6469
6470                 this.x = Math.max( this.x, v.x );
6471                 this.y = Math.max( this.y, v.y );
6472                 this.z = Math.max( this.z, v.z );
6473
6474                 return this;
6475
6476         }
6477
6478         clamp( min, max ) {
6479
6480                 // assumes min < max, componentwise
6481
6482                 this.x = Math.max( min.x, Math.min( max.x, this.x ) );
6483                 this.y = Math.max( min.y, Math.min( max.y, this.y ) );
6484                 this.z = Math.max( min.z, Math.min( max.z, this.z ) );
6485
6486                 return this;
6487
6488         }
6489
6490         clampScalar( minVal, maxVal ) {
6491
6492                 this.x = Math.max( minVal, Math.min( maxVal, this.x ) );
6493                 this.y = Math.max( minVal, Math.min( maxVal, this.y ) );
6494                 this.z = Math.max( minVal, Math.min( maxVal, this.z ) );
6495
6496                 return this;
6497
6498         }
6499
6500         clampLength( min, max ) {
6501
6502                 const length = this.length();
6503
6504                 return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
6505
6506         }
6507
6508         floor() {
6509
6510                 this.x = Math.floor( this.x );
6511                 this.y = Math.floor( this.y );
6512                 this.z = Math.floor( this.z );
6513
6514                 return this;
6515
6516         }
6517
6518         ceil() {
6519
6520                 this.x = Math.ceil( this.x );
6521                 this.y = Math.ceil( this.y );
6522                 this.z = Math.ceil( this.z );
6523
6524                 return this;
6525
6526         }
6527
6528         round() {
6529
6530                 this.x = Math.round( this.x );
6531                 this.y = Math.round( this.y );
6532                 this.z = Math.round( this.z );
6533
6534                 return this;
6535
6536         }
6537
6538         roundToZero() {
6539
6540                 this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
6541                 this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
6542                 this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
6543
6544                 return this;
6545
6546         }
6547
6548         negate() {
6549
6550                 this.x = - this.x;
6551                 this.y = - this.y;
6552                 this.z = - this.z;
6553
6554                 return this;
6555
6556         }
6557
6558         dot( v ) {
6559
6560                 return this.x * v.x + this.y * v.y + this.z * v.z;
6561
6562         }
6563
6564         // TODO lengthSquared?
6565
6566         lengthSq() {
6567
6568                 return this.x * this.x + this.y * this.y + this.z * this.z;
6569
6570         }
6571
6572         length() {
6573
6574                 return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );
6575
6576         }
6577
6578         manhattanLength() {
6579
6580                 return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z );
6581
6582         }
6583
6584         normalize() {
6585
6586                 return this.divideScalar( this.length() || 1 );
6587
6588         }
6589
6590         setLength( length ) {
6591
6592                 return this.normalize().multiplyScalar( length );
6593
6594         }
6595
6596         lerp( v, alpha ) {
6597
6598                 this.x += ( v.x - this.x ) * alpha;
6599                 this.y += ( v.y - this.y ) * alpha;
6600                 this.z += ( v.z - this.z ) * alpha;
6601
6602                 return this;
6603
6604         }
6605
6606         lerpVectors( v1, v2, alpha ) {
6607
6608                 this.x = v1.x + ( v2.x - v1.x ) * alpha;
6609                 this.y = v1.y + ( v2.y - v1.y ) * alpha;
6610                 this.z = v1.z + ( v2.z - v1.z ) * alpha;
6611
6612                 return this;
6613
6614         }
6615
6616         cross( v, w ) {
6617
6618                 if ( w !== undefined ) {
6619
6620                         console.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' );
6621                         return this.crossVectors( v, w );
6622
6623                 }
6624
6625                 return this.crossVectors( this, v );
6626
6627         }
6628
6629         crossVectors( a, b ) {
6630
6631                 const ax = a.x, ay = a.y, az = a.z;
6632                 const bx = b.x, by = b.y, bz = b.z;
6633
6634                 this.x = ay * bz - az * by;
6635                 this.y = az * bx - ax * bz;
6636                 this.z = ax * by - ay * bx;
6637
6638                 return this;
6639
6640         }
6641
6642         projectOnVector( v ) {
6643
6644                 const denominator = v.lengthSq();
6645
6646                 if ( denominator === 0 ) return this.set( 0, 0, 0 );
6647
6648                 const scalar = v.dot( this ) / denominator;
6649
6650                 return this.copy( v ).multiplyScalar( scalar );
6651
6652         }
6653
6654         projectOnPlane( planeNormal ) {
6655
6656                 _vector$c.copy( this ).projectOnVector( planeNormal );
6657
6658                 return this.sub( _vector$c );
6659
6660         }
6661
6662         reflect( normal ) {
6663
6664                 // reflect incident vector off plane orthogonal to normal
6665                 // normal is assumed to have unit length
6666
6667                 return this.sub( _vector$c.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) );
6668
6669         }
6670
6671         angleTo( v ) {
6672
6673                 const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() );
6674
6675                 if ( denominator === 0 ) return Math.PI / 2;
6676
6677                 const theta = this.dot( v ) / denominator;
6678
6679                 // clamp, to handle numerical problems
6680
6681                 return Math.acos( clamp$1( theta, - 1, 1 ) );
6682
6683         }
6684
6685         distanceTo( v ) {
6686
6687                 return Math.sqrt( this.distanceToSquared( v ) );
6688
6689         }
6690
6691         distanceToSquared( v ) {
6692
6693                 const dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z;
6694
6695                 return dx * dx + dy * dy + dz * dz;
6696
6697         }
6698
6699         manhattanDistanceTo( v ) {
6700
6701                 return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z );
6702
6703         }
6704
6705         setFromSpherical( s ) {
6706
6707                 return this.setFromSphericalCoords( s.radius, s.phi, s.theta );
6708
6709         }
6710
6711         setFromSphericalCoords( radius, phi, theta ) {
6712
6713                 const sinPhiRadius = Math.sin( phi ) * radius;
6714
6715                 this.x = sinPhiRadius * Math.sin( theta );
6716                 this.y = Math.cos( phi ) * radius;
6717                 this.z = sinPhiRadius * Math.cos( theta );
6718
6719                 return this;
6720
6721         }
6722
6723         setFromCylindrical( c ) {
6724
6725                 return this.setFromCylindricalCoords( c.radius, c.theta, c.y );
6726
6727         }
6728
6729         setFromCylindricalCoords( radius, theta, y ) {
6730
6731                 this.x = radius * Math.sin( theta );
6732                 this.y = y;
6733                 this.z = radius * Math.cos( theta );
6734
6735                 return this;
6736
6737         }
6738
6739         setFromMatrixPosition( m ) {
6740
6741                 const e = m.elements;
6742
6743                 this.x = e[ 12 ];
6744                 this.y = e[ 13 ];
6745                 this.z = e[ 14 ];
6746
6747                 return this;
6748
6749         }
6750
6751         setFromMatrixScale( m ) {
6752
6753                 const sx = this.setFromMatrixColumn( m, 0 ).length();
6754                 const sy = this.setFromMatrixColumn( m, 1 ).length();
6755                 const sz = this.setFromMatrixColumn( m, 2 ).length();
6756
6757                 this.x = sx;
6758                 this.y = sy;
6759                 this.z = sz;
6760
6761                 return this;
6762
6763         }
6764
6765         setFromMatrixColumn( m, index ) {
6766
6767                 return this.fromArray( m.elements, index * 4 );
6768
6769         }
6770
6771         setFromMatrix3Column( m, index ) {
6772
6773                 return this.fromArray( m.elements, index * 3 );
6774
6775         }
6776
6777         equals( v ) {
6778
6779                 return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) );
6780
6781         }
6782
6783         fromArray( array, offset = 0 ) {
6784
6785                 this.x = array[ offset ];
6786                 this.y = array[ offset + 1 ];
6787                 this.z = array[ offset + 2 ];
6788
6789                 return this;
6790
6791         }
6792
6793         toArray( array = [], offset = 0 ) {
6794
6795                 array[ offset ] = this.x;
6796                 array[ offset + 1 ] = this.y;
6797                 array[ offset + 2 ] = this.z;
6798
6799                 return array;
6800
6801         }
6802
6803         fromBufferAttribute( attribute, index, offset ) {
6804
6805                 if ( offset !== undefined ) {
6806
6807                         console.warn( 'THREE.Vector3: offset has been removed from .fromBufferAttribute().' );
6808
6809                 }
6810
6811                 this.x = attribute.getX( index );
6812                 this.y = attribute.getY( index );
6813                 this.z = attribute.getZ( index );
6814
6815                 return this;
6816
6817         }
6818
6819         random() {
6820
6821                 this.x = Math.random();
6822                 this.y = Math.random();
6823                 this.z = Math.random();
6824
6825                 return this;
6826
6827         }
6828
6829         randomDirection() {
6830
6831                 // Derived from https://mathworld.wolfram.com/SpherePointPicking.html
6832
6833                 const u = ( Math.random() - 0.5 ) * 2;
6834                 const t = Math.random() * Math.PI * 2;
6835                 const f = Math.sqrt( 1 - u ** 2 );
6836
6837                 this.x = f * Math.cos( t );
6838                 this.y = f * Math.sin( t );
6839                 this.z = u;
6840
6841                 return this;
6842
6843         }
6844
6845         *[ Symbol.iterator ]() {
6846
6847                 yield this.x;
6848                 yield this.y;
6849                 yield this.z;
6850
6851         }
6852
6853 }
6854
6855 Vector3.prototype.isVector3 = true;
6856
6857 const _vector$c = /*@__PURE__*/ new Vector3();
6858 const _quaternion$4 = /*@__PURE__*/ new Quaternion();
6859
6860 class Box3 {
6861
6862         constructor( min = new Vector3( + Infinity, + Infinity, + Infinity ), max = new Vector3( - Infinity, - Infinity, - Infinity ) ) {
6863
6864                 this.min = min;
6865                 this.max = max;
6866
6867         }
6868
6869         set( min, max ) {
6870
6871                 this.min.copy( min );
6872                 this.max.copy( max );
6873
6874                 return this;
6875
6876         }
6877
6878         setFromArray( array ) {
6879
6880                 let minX = + Infinity;
6881                 let minY = + Infinity;
6882                 let minZ = + Infinity;
6883
6884                 let maxX = - Infinity;
6885                 let maxY = - Infinity;
6886                 let maxZ = - Infinity;
6887
6888                 for ( let i = 0, l = array.length; i < l; i += 3 ) {
6889
6890                         const x = array[ i ];
6891                         const y = array[ i + 1 ];
6892                         const z = array[ i + 2 ];
6893
6894                         if ( x < minX ) minX = x;
6895                         if ( y < minY ) minY = y;
6896                         if ( z < minZ ) minZ = z;
6897
6898                         if ( x > maxX ) maxX = x;
6899                         if ( y > maxY ) maxY = y;
6900                         if ( z > maxZ ) maxZ = z;
6901
6902                 }
6903
6904                 this.min.set( minX, minY, minZ );
6905                 this.max.set( maxX, maxY, maxZ );
6906
6907                 return this;
6908
6909         }
6910
6911         setFromBufferAttribute( attribute ) {
6912
6913                 let minX = + Infinity;
6914                 let minY = + Infinity;
6915                 let minZ = + Infinity;
6916
6917                 let maxX = - Infinity;
6918                 let maxY = - Infinity;
6919                 let maxZ = - Infinity;
6920
6921                 for ( let i = 0, l = attribute.count; i < l; i ++ ) {
6922
6923                         const x = attribute.getX( i );
6924                         const y = attribute.getY( i );
6925                         const z = attribute.getZ( i );
6926
6927                         if ( x < minX ) minX = x;
6928                         if ( y < minY ) minY = y;
6929                         if ( z < minZ ) minZ = z;
6930
6931                         if ( x > maxX ) maxX = x;
6932                         if ( y > maxY ) maxY = y;
6933                         if ( z > maxZ ) maxZ = z;
6934
6935                 }
6936
6937                 this.min.set( minX, minY, minZ );
6938                 this.max.set( maxX, maxY, maxZ );
6939
6940                 return this;
6941
6942         }
6943
6944         setFromPoints( points ) {
6945
6946                 this.makeEmpty();
6947
6948                 for ( let i = 0, il = points.length; i < il; i ++ ) {
6949
6950                         this.expandByPoint( points[ i ] );
6951
6952                 }
6953
6954                 return this;
6955
6956         }
6957
6958         setFromCenterAndSize( center, size ) {
6959
6960                 const halfSize = _vector$b.copy( size ).multiplyScalar( 0.5 );
6961
6962                 this.min.copy( center ).sub( halfSize );
6963                 this.max.copy( center ).add( halfSize );
6964
6965                 return this;
6966
6967         }
6968
6969         setFromObject( object ) {
6970
6971                 this.makeEmpty();
6972
6973                 return this.expandByObject( object );
6974
6975         }
6976
6977         clone() {
6978
6979                 return new this.constructor().copy( this );
6980
6981         }
6982
6983         copy( box ) {
6984
6985                 this.min.copy( box.min );
6986                 this.max.copy( box.max );
6987
6988                 return this;
6989
6990         }
6991
6992         makeEmpty() {
6993
6994                 this.min.x = this.min.y = this.min.z = + Infinity;
6995                 this.max.x = this.max.y = this.max.z = - Infinity;
6996
6997                 return this;
6998
6999         }
7000
7001         isEmpty() {
7002
7003                 // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
7004
7005                 return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z );
7006
7007         }
7008
7009         getCenter( target ) {
7010
7011                 return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 );
7012
7013         }
7014
7015         getSize( target ) {
7016
7017                 return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min );
7018
7019         }
7020
7021         expandByPoint( point ) {
7022
7023                 this.min.min( point );
7024                 this.max.max( point );
7025
7026                 return this;
7027
7028         }
7029
7030         expandByVector( vector ) {
7031
7032                 this.min.sub( vector );
7033                 this.max.add( vector );
7034
7035                 return this;
7036
7037         }
7038
7039         expandByScalar( scalar ) {
7040
7041                 this.min.addScalar( - scalar );
7042                 this.max.addScalar( scalar );
7043
7044                 return this;
7045
7046         }
7047
7048         expandByObject( object ) {
7049
7050                 // Computes the world-axis-aligned bounding box of an object (including its children),
7051                 // accounting for both the object's, and children's, world transforms
7052
7053                 object.updateWorldMatrix( false, false );
7054
7055                 const geometry = object.geometry;
7056
7057                 if ( geometry !== undefined ) {
7058
7059                         if ( geometry.boundingBox === null ) {
7060
7061                                 geometry.computeBoundingBox();
7062
7063                         }
7064
7065                         _box$3.copy( geometry.boundingBox );
7066                         _box$3.applyMatrix4( object.matrixWorld );
7067
7068                         this.union( _box$3 );
7069
7070                 }
7071
7072                 const children = object.children;
7073
7074                 for ( let i = 0, l = children.length; i < l; i ++ ) {
7075
7076                         this.expandByObject( children[ i ] );
7077
7078                 }
7079
7080                 return this;
7081
7082         }
7083
7084         containsPoint( point ) {
7085
7086                 return point.x < this.min.x || point.x > this.max.x ||
7087                         point.y < this.min.y || point.y > this.max.y ||
7088                         point.z < this.min.z || point.z > this.max.z ? false : true;
7089
7090         }
7091
7092         containsBox( box ) {
7093
7094                 return this.min.x <= box.min.x && box.max.x <= this.max.x &&
7095                         this.min.y <= box.min.y && box.max.y <= this.max.y &&
7096                         this.min.z <= box.min.z && box.max.z <= this.max.z;
7097
7098         }
7099
7100         getParameter( point, target ) {
7101
7102                 // This can potentially have a divide by zero if the box
7103                 // has a size dimension of 0.
7104
7105                 return target.set(
7106                         ( point.x - this.min.x ) / ( this.max.x - this.min.x ),
7107                         ( point.y - this.min.y ) / ( this.max.y - this.min.y ),
7108                         ( point.z - this.min.z ) / ( this.max.z - this.min.z )
7109                 );
7110
7111         }
7112
7113         intersectsBox( box ) {
7114
7115                 // using 6 splitting planes to rule out intersections.
7116                 return box.max.x < this.min.x || box.min.x > this.max.x ||
7117                         box.max.y < this.min.y || box.min.y > this.max.y ||
7118                         box.max.z < this.min.z || box.min.z > this.max.z ? false : true;
7119
7120         }
7121
7122         intersectsSphere( sphere ) {
7123
7124                 // Find the point on the AABB closest to the sphere center.
7125                 this.clampPoint( sphere.center, _vector$b );
7126
7127                 // If that point is inside the sphere, the AABB and sphere intersect.
7128                 return _vector$b.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius );
7129
7130         }
7131
7132         intersectsPlane( plane ) {
7133
7134                 // We compute the minimum and maximum dot product values. If those values
7135                 // are on the same side (back or front) of the plane, then there is no intersection.
7136
7137                 let min, max;
7138
7139                 if ( plane.normal.x > 0 ) {
7140
7141                         min = plane.normal.x * this.min.x;
7142                         max = plane.normal.x * this.max.x;
7143
7144                 } else {
7145
7146                         min = plane.normal.x * this.max.x;
7147                         max = plane.normal.x * this.min.x;
7148
7149                 }
7150
7151                 if ( plane.normal.y > 0 ) {
7152
7153                         min += plane.normal.y * this.min.y;
7154                         max += plane.normal.y * this.max.y;
7155
7156                 } else {
7157
7158                         min += plane.normal.y * this.max.y;
7159                         max += plane.normal.y * this.min.y;
7160
7161                 }
7162
7163                 if ( plane.normal.z > 0 ) {
7164
7165                         min += plane.normal.z * this.min.z;
7166                         max += plane.normal.z * this.max.z;
7167
7168                 } else {
7169
7170                         min += plane.normal.z * this.max.z;
7171                         max += plane.normal.z * this.min.z;
7172
7173                 }
7174
7175                 return ( min <= - plane.constant && max >= - plane.constant );
7176
7177         }
7178
7179         intersectsTriangle( triangle ) {
7180
7181                 if ( this.isEmpty() ) {
7182
7183                         return false;
7184
7185                 }
7186
7187                 // compute box center and extents
7188                 this.getCenter( _center );
7189                 _extents.subVectors( this.max, _center );
7190
7191                 // translate triangle to aabb origin
7192                 _v0$2.subVectors( triangle.a, _center );
7193                 _v1$7.subVectors( triangle.b, _center );
7194                 _v2$3.subVectors( triangle.c, _center );
7195
7196                 // compute edge vectors for triangle
7197                 _f0.subVectors( _v1$7, _v0$2 );
7198                 _f1.subVectors( _v2$3, _v1$7 );
7199                 _f2.subVectors( _v0$2, _v2$3 );
7200
7201                 // test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb
7202                 // 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
7203                 // axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned)
7204                 let axes = [
7205                         0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y,
7206                         _f0.z, 0, - _f0.x, _f1.z, 0, - _f1.x, _f2.z, 0, - _f2.x,
7207                         - _f0.y, _f0.x, 0, - _f1.y, _f1.x, 0, - _f2.y, _f2.x, 0
7208                 ];
7209                 if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$3, _extents ) ) {
7210
7211                         return false;
7212
7213                 }
7214
7215                 // test 3 face normals from the aabb
7216                 axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ];
7217                 if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$3, _extents ) ) {
7218
7219                         return false;
7220
7221                 }
7222
7223                 // finally testing the face normal of the triangle
7224                 // use already existing triangle edge vectors here
7225                 _triangleNormal.crossVectors( _f0, _f1 );
7226                 axes = [ _triangleNormal.x, _triangleNormal.y, _triangleNormal.z ];
7227
7228                 return satForAxes( axes, _v0$2, _v1$7, _v2$3, _extents );
7229
7230         }
7231
7232         clampPoint( point, target ) {
7233
7234                 return target.copy( point ).clamp( this.min, this.max );
7235
7236         }
7237
7238         distanceToPoint( point ) {
7239
7240                 const clampedPoint = _vector$b.copy( point ).clamp( this.min, this.max );
7241
7242                 return clampedPoint.sub( point ).length();
7243
7244         }
7245
7246         getBoundingSphere( target ) {
7247
7248                 this.getCenter( target.center );
7249
7250                 target.radius = this.getSize( _vector$b ).length() * 0.5;
7251
7252                 return target;
7253
7254         }
7255
7256         intersect( box ) {
7257
7258                 this.min.max( box.min );
7259                 this.max.min( box.max );
7260
7261                 // 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.
7262                 if ( this.isEmpty() ) this.makeEmpty();
7263
7264                 return this;
7265
7266         }
7267
7268         union( box ) {
7269
7270                 this.min.min( box.min );
7271                 this.max.max( box.max );
7272
7273                 return this;
7274
7275         }
7276
7277         applyMatrix4( matrix ) {
7278
7279                 // transform of empty box is an empty box.
7280                 if ( this.isEmpty() ) return this;
7281
7282                 // NOTE: I am using a binary pattern to specify all 2^3 combinations below
7283                 _points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000
7284                 _points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001
7285                 _points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010
7286                 _points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011
7287                 _points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100
7288                 _points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101
7289                 _points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110
7290                 _points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111
7291
7292                 this.setFromPoints( _points );
7293
7294                 return this;
7295
7296         }
7297
7298         translate( offset ) {
7299
7300                 this.min.add( offset );
7301                 this.max.add( offset );
7302
7303                 return this;
7304
7305         }
7306
7307         equals( box ) {
7308
7309                 return box.min.equals( this.min ) && box.max.equals( this.max );
7310
7311         }
7312
7313 }
7314
7315 Box3.prototype.isBox3 = true;
7316
7317 const _points = [
7318         /*@__PURE__*/ new Vector3(),
7319         /*@__PURE__*/ new Vector3(),
7320         /*@__PURE__*/ new Vector3(),
7321         /*@__PURE__*/ new Vector3(),
7322         /*@__PURE__*/ new Vector3(),
7323         /*@__PURE__*/ new Vector3(),
7324         /*@__PURE__*/ new Vector3(),
7325         /*@__PURE__*/ new Vector3()
7326 ];
7327
7328 const _vector$b = /*@__PURE__*/ new Vector3();
7329
7330 const _box$3 = /*@__PURE__*/ new Box3();
7331
7332 // triangle centered vertices
7333
7334 const _v0$2 = /*@__PURE__*/ new Vector3();
7335 const _v1$7 = /*@__PURE__*/ new Vector3();
7336 const _v2$3 = /*@__PURE__*/ new Vector3();
7337
7338 // triangle edge vectors
7339
7340 const _f0 = /*@__PURE__*/ new Vector3();
7341 const _f1 = /*@__PURE__*/ new Vector3();
7342 const _f2 = /*@__PURE__*/ new Vector3();
7343
7344 const _center = /*@__PURE__*/ new Vector3();
7345 const _extents = /*@__PURE__*/ new Vector3();
7346 const _triangleNormal = /*@__PURE__*/ new Vector3();
7347 const _testAxis = /*@__PURE__*/ new Vector3();
7348
7349 function satForAxes( axes, v0, v1, v2, extents ) {
7350
7351         for ( let i = 0, j = axes.length - 3; i <= j; i += 3 ) {
7352
7353                 _testAxis.fromArray( axes, i );
7354                 // project the aabb onto the seperating axis
7355                 const r = extents.x * Math.abs( _testAxis.x ) + extents.y * Math.abs( _testAxis.y ) + extents.z * Math.abs( _testAxis.z );
7356                 // project all 3 vertices of the triangle onto the seperating axis
7357                 const p0 = v0.dot( _testAxis );
7358                 const p1 = v1.dot( _testAxis );
7359                 const p2 = v2.dot( _testAxis );
7360                 // actual test, basically see if either of the most extreme of the triangle points intersects r
7361                 if ( Math.max( - Math.max( p0, p1, p2 ), Math.min( p0, p1, p2 ) ) > r ) {
7362
7363                         // points of the projected triangle are outside the projected half-length of the aabb
7364                         // the axis is seperating and we can exit
7365                         return false;
7366
7367                 }
7368
7369         }
7370
7371         return true;
7372
7373 }
7374
7375 const _box$2 = /*@__PURE__*/ new Box3();
7376 const _v1$6 = /*@__PURE__*/ new Vector3();
7377 const _toFarthestPoint = /*@__PURE__*/ new Vector3();
7378 const _toPoint = /*@__PURE__*/ new Vector3();
7379
7380 class Sphere {
7381
7382         constructor( center = new Vector3(), radius = - 1 ) {
7383
7384                 this.center = center;
7385                 this.radius = radius;
7386
7387         }
7388
7389         set( center, radius ) {
7390
7391                 this.center.copy( center );
7392                 this.radius = radius;
7393
7394                 return this;
7395
7396         }
7397
7398         setFromPoints( points, optionalCenter ) {
7399
7400                 const center = this.center;
7401
7402                 if ( optionalCenter !== undefined ) {
7403
7404                         center.copy( optionalCenter );
7405
7406                 } else {
7407
7408                         _box$2.setFromPoints( points ).getCenter( center );
7409
7410                 }
7411
7412                 let maxRadiusSq = 0;
7413
7414                 for ( let i = 0, il = points.length; i < il; i ++ ) {
7415
7416                         maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) );
7417
7418                 }
7419
7420                 this.radius = Math.sqrt( maxRadiusSq );
7421
7422                 return this;
7423
7424         }
7425
7426         copy( sphere ) {
7427
7428                 this.center.copy( sphere.center );
7429                 this.radius = sphere.radius;
7430
7431                 return this;
7432
7433         }
7434
7435         isEmpty() {
7436
7437                 return ( this.radius < 0 );
7438
7439         }
7440
7441         makeEmpty() {
7442
7443                 this.center.set( 0, 0, 0 );
7444                 this.radius = - 1;
7445
7446                 return this;
7447
7448         }
7449
7450         containsPoint( point ) {
7451
7452                 return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) );
7453
7454         }
7455
7456         distanceToPoint( point ) {
7457
7458                 return ( point.distanceTo( this.center ) - this.radius );
7459
7460         }
7461
7462         intersectsSphere( sphere ) {
7463
7464                 const radiusSum = this.radius + sphere.radius;
7465
7466                 return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum );
7467
7468         }
7469
7470         intersectsBox( box ) {
7471
7472                 return box.intersectsSphere( this );
7473
7474         }
7475
7476         intersectsPlane( plane ) {
7477
7478                 return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius;
7479
7480         }
7481
7482         clampPoint( point, target ) {
7483
7484                 const deltaLengthSq = this.center.distanceToSquared( point );
7485
7486                 target.copy( point );
7487
7488                 if ( deltaLengthSq > ( this.radius * this.radius ) ) {
7489
7490                         target.sub( this.center ).normalize();
7491                         target.multiplyScalar( this.radius ).add( this.center );
7492
7493                 }
7494
7495                 return target;
7496
7497         }
7498
7499         getBoundingBox( target ) {
7500
7501                 if ( this.isEmpty() ) {
7502
7503                         // Empty sphere produces empty bounding box
7504                         target.makeEmpty();
7505                         return target;
7506
7507                 }
7508
7509                 target.set( this.center, this.center );
7510                 target.expandByScalar( this.radius );
7511
7512                 return target;
7513
7514         }
7515
7516         applyMatrix4( matrix ) {
7517
7518                 this.center.applyMatrix4( matrix );
7519                 this.radius = this.radius * matrix.getMaxScaleOnAxis();
7520
7521                 return this;
7522
7523         }
7524
7525         translate( offset ) {
7526
7527                 this.center.add( offset );
7528
7529                 return this;
7530
7531         }
7532
7533         expandByPoint( point ) {
7534
7535                 // from https://github.com/juj/MathGeoLib/blob/2940b99b99cfe575dd45103ef20f4019dee15b54/src/Geometry/Sphere.cpp#L649-L671
7536
7537                 _toPoint.subVectors( point, this.center );
7538
7539                 const lengthSq = _toPoint.lengthSq();
7540
7541                 if ( lengthSq > ( this.radius * this.radius ) ) {
7542
7543                         const length = Math.sqrt( lengthSq );
7544                         const missingRadiusHalf = ( length - this.radius ) * 0.5;
7545
7546                         // Nudge this sphere towards the target point. Add half the missing distance to radius,
7547                         // and the other half to position. This gives a tighter enclosure, instead of if
7548                         // the whole missing distance were just added to radius.
7549
7550                         this.center.add( _toPoint.multiplyScalar( missingRadiusHalf / length ) );
7551                         this.radius += missingRadiusHalf;
7552
7553                 }
7554
7555                 return this;
7556
7557         }
7558
7559         union( sphere ) {
7560
7561                 // from https://github.com/juj/MathGeoLib/blob/2940b99b99cfe575dd45103ef20f4019dee15b54/src/Geometry/Sphere.cpp#L759-L769
7562
7563                 // To enclose another sphere into this sphere, we only need to enclose two points:
7564                 // 1) Enclose the farthest point on the other sphere into this sphere.
7565                 // 2) Enclose the opposite point of the farthest point into this sphere.
7566
7567                 _toFarthestPoint.subVectors( sphere.center, this.center ).normalize().multiplyScalar( sphere.radius );
7568
7569                 this.expandByPoint( _v1$6.copy( sphere.center ).add( _toFarthestPoint ) );
7570                 this.expandByPoint( _v1$6.copy( sphere.center ).sub( _toFarthestPoint ) );
7571
7572                 return this;
7573
7574         }
7575
7576         equals( sphere ) {
7577
7578                 return sphere.center.equals( this.center ) && ( sphere.radius === this.radius );
7579
7580         }
7581
7582         clone() {
7583
7584                 return new this.constructor().copy( this );
7585
7586         }
7587
7588 }
7589
7590 const _vector$a = /*@__PURE__*/ new Vector3();
7591 const _segCenter = /*@__PURE__*/ new Vector3();
7592 const _segDir = /*@__PURE__*/ new Vector3();
7593 const _diff = /*@__PURE__*/ new Vector3();
7594
7595 const _edge1 = /*@__PURE__*/ new Vector3();
7596 const _edge2 = /*@__PURE__*/ new Vector3();
7597 const _normal$1 = /*@__PURE__*/ new Vector3();
7598
7599 class Ray {
7600
7601         constructor( origin = new Vector3(), direction = new Vector3( 0, 0, - 1 ) ) {
7602
7603                 this.origin = origin;
7604                 this.direction = direction;
7605
7606         }
7607
7608         set( origin, direction ) {
7609
7610                 this.origin.copy( origin );
7611                 this.direction.copy( direction );
7612
7613                 return this;
7614
7615         }
7616
7617         copy( ray ) {
7618
7619                 this.origin.copy( ray.origin );
7620                 this.direction.copy( ray.direction );
7621
7622                 return this;
7623
7624         }
7625
7626         at( t, target ) {
7627
7628                 return target.copy( this.direction ).multiplyScalar( t ).add( this.origin );
7629
7630         }
7631
7632         lookAt( v ) {
7633
7634                 this.direction.copy( v ).sub( this.origin ).normalize();
7635
7636                 return this;
7637
7638         }
7639
7640         recast( t ) {
7641
7642                 this.origin.copy( this.at( t, _vector$a ) );
7643
7644                 return this;
7645
7646         }
7647
7648         closestPointToPoint( point, target ) {
7649
7650                 target.subVectors( point, this.origin );
7651
7652                 const directionDistance = target.dot( this.direction );
7653
7654                 if ( directionDistance < 0 ) {
7655
7656                         return target.copy( this.origin );
7657
7658                 }
7659
7660                 return target.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
7661
7662         }
7663
7664         distanceToPoint( point ) {
7665
7666                 return Math.sqrt( this.distanceSqToPoint( point ) );
7667
7668         }
7669
7670         distanceSqToPoint( point ) {
7671
7672                 const directionDistance = _vector$a.subVectors( point, this.origin ).dot( this.direction );
7673
7674                 // point behind the ray
7675
7676                 if ( directionDistance < 0 ) {
7677
7678                         return this.origin.distanceToSquared( point );
7679
7680                 }
7681
7682                 _vector$a.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
7683
7684                 return _vector$a.distanceToSquared( point );
7685
7686         }
7687
7688         distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {
7689
7690                 // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteDistRaySegment.h
7691                 // It returns the min distance between the ray and the segment
7692                 // defined by v0 and v1
7693                 // It can also set two optional targets :
7694                 // - The closest point on the ray
7695                 // - The closest point on the segment
7696
7697                 _segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 );
7698                 _segDir.copy( v1 ).sub( v0 ).normalize();
7699                 _diff.copy( this.origin ).sub( _segCenter );
7700
7701                 const segExtent = v0.distanceTo( v1 ) * 0.5;
7702                 const a01 = - this.direction.dot( _segDir );
7703                 const b0 = _diff.dot( this.direction );
7704                 const b1 = - _diff.dot( _segDir );
7705                 const c = _diff.lengthSq();
7706                 const det = Math.abs( 1 - a01 * a01 );
7707                 let s0, s1, sqrDist, extDet;
7708
7709                 if ( det > 0 ) {
7710
7711                         // The ray and segment are not parallel.
7712
7713                         s0 = a01 * b1 - b0;
7714                         s1 = a01 * b0 - b1;
7715                         extDet = segExtent * det;
7716
7717                         if ( s0 >= 0 ) {
7718
7719                                 if ( s1 >= - extDet ) {
7720
7721                                         if ( s1 <= extDet ) {
7722
7723                                                 // region 0
7724                                                 // Minimum at interior points of ray and segment.
7725
7726                                                 const invDet = 1 / det;
7727                                                 s0 *= invDet;
7728                                                 s1 *= invDet;
7729                                                 sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;
7730
7731                                         } else {
7732
7733                                                 // region 1
7734
7735                                                 s1 = segExtent;
7736                                                 s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
7737                                                 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
7738
7739                                         }
7740
7741                                 } else {
7742
7743                                         // region 5
7744
7745                                         s1 = - segExtent;
7746                                         s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
7747                                         sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
7748
7749                                 }
7750
7751                         } else {
7752
7753                                 if ( s1 <= - extDet ) {
7754
7755                                         // region 4
7756
7757                                         s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) );
7758                                         s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
7759                                         sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
7760
7761                                 } else if ( s1 <= extDet ) {
7762
7763                                         // region 3
7764
7765                                         s0 = 0;
7766                                         s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent );
7767                                         sqrDist = s1 * ( s1 + 2 * b1 ) + c;
7768
7769                                 } else {
7770
7771                                         // region 2
7772
7773                                         s0 = Math.max( 0, - ( a01 * segExtent + b0 ) );
7774                                         s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
7775                                         sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
7776
7777                                 }
7778
7779                         }
7780
7781                 } else {
7782
7783                         // Ray and segment are parallel.
7784
7785                         s1 = ( a01 > 0 ) ? - segExtent : segExtent;
7786                         s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
7787                         sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
7788
7789                 }
7790
7791                 if ( optionalPointOnRay ) {
7792
7793                         optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin );
7794
7795                 }
7796
7797                 if ( optionalPointOnSegment ) {
7798
7799                         optionalPointOnSegment.copy( _segDir ).multiplyScalar( s1 ).add( _segCenter );
7800
7801                 }
7802
7803                 return sqrDist;
7804
7805         }
7806
7807         intersectSphere( sphere, target ) {
7808
7809                 _vector$a.subVectors( sphere.center, this.origin );
7810                 const tca = _vector$a.dot( this.direction );
7811                 const d2 = _vector$a.dot( _vector$a ) - tca * tca;
7812                 const radius2 = sphere.radius * sphere.radius;
7813
7814                 if ( d2 > radius2 ) return null;
7815
7816                 const thc = Math.sqrt( radius2 - d2 );
7817
7818                 // t0 = first intersect point - entrance on front of sphere
7819                 const t0 = tca - thc;
7820
7821                 // t1 = second intersect point - exit point on back of sphere
7822                 const t1 = tca + thc;
7823
7824                 // test to see if both t0 and t1 are behind the ray - if so, return null
7825                 if ( t0 < 0 && t1 < 0 ) return null;
7826
7827                 // test to see if t0 is behind the ray:
7828                 // if it is, the ray is inside the sphere, so return the second exit point scaled by t1,
7829                 // in order to always return an intersect point that is in front of the ray.
7830                 if ( t0 < 0 ) return this.at( t1, target );
7831
7832                 // else t0 is in front of the ray, so return the first collision point scaled by t0
7833                 return this.at( t0, target );
7834
7835         }
7836
7837         intersectsSphere( sphere ) {
7838
7839                 return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius );
7840
7841         }
7842
7843         distanceToPlane( plane ) {
7844
7845                 const denominator = plane.normal.dot( this.direction );
7846
7847                 if ( denominator === 0 ) {
7848
7849                         // line is coplanar, return origin
7850                         if ( plane.distanceToPoint( this.origin ) === 0 ) {
7851
7852                                 return 0;
7853
7854                         }
7855
7856                         // Null is preferable to undefined since undefined means.... it is undefined
7857
7858                         return null;
7859
7860                 }
7861
7862                 const t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator;
7863
7864                 // Return if the ray never intersects the plane
7865
7866                 return t >= 0 ? t : null;
7867
7868         }
7869
7870         intersectPlane( plane, target ) {
7871
7872                 const t = this.distanceToPlane( plane );
7873
7874                 if ( t === null ) {
7875
7876                         return null;
7877
7878                 }
7879
7880                 return this.at( t, target );
7881
7882         }
7883
7884         intersectsPlane( plane ) {
7885
7886                 // check if the ray lies on the plane first
7887
7888                 const distToPoint = plane.distanceToPoint( this.origin );
7889
7890                 if ( distToPoint === 0 ) {
7891
7892                         return true;
7893
7894                 }
7895
7896                 const denominator = plane.normal.dot( this.direction );
7897
7898                 if ( denominator * distToPoint < 0 ) {
7899
7900                         return true;
7901
7902                 }
7903
7904                 // ray origin is behind the plane (and is pointing behind it)
7905
7906                 return false;
7907
7908         }
7909
7910         intersectBox( box, target ) {
7911
7912                 let tmin, tmax, tymin, tymax, tzmin, tzmax;
7913
7914                 const invdirx = 1 / this.direction.x,
7915                         invdiry = 1 / this.direction.y,
7916                         invdirz = 1 / this.direction.z;
7917
7918                 const origin = this.origin;
7919
7920                 if ( invdirx >= 0 ) {
7921
7922                         tmin = ( box.min.x - origin.x ) * invdirx;
7923                         tmax = ( box.max.x - origin.x ) * invdirx;
7924
7925                 } else {
7926
7927                         tmin = ( box.max.x - origin.x ) * invdirx;
7928                         tmax = ( box.min.x - origin.x ) * invdirx;
7929
7930                 }
7931
7932                 if ( invdiry >= 0 ) {
7933
7934                         tymin = ( box.min.y - origin.y ) * invdiry;
7935                         tymax = ( box.max.y - origin.y ) * invdiry;
7936
7937                 } else {
7938
7939                         tymin = ( box.max.y - origin.y ) * invdiry;
7940                         tymax = ( box.min.y - origin.y ) * invdiry;
7941
7942                 }
7943
7944                 if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null;
7945
7946                 // These lines also handle the case where tmin or tmax is NaN
7947                 // (result of 0 * Infinity). x !== x returns true if x is NaN
7948
7949                 if ( tymin > tmin || tmin !== tmin ) tmin = tymin;
7950
7951                 if ( tymax < tmax || tmax !== tmax ) tmax = tymax;
7952
7953                 if ( invdirz >= 0 ) {
7954
7955                         tzmin = ( box.min.z - origin.z ) * invdirz;
7956                         tzmax = ( box.max.z - origin.z ) * invdirz;
7957
7958                 } else {
7959
7960                         tzmin = ( box.max.z - origin.z ) * invdirz;
7961                         tzmax = ( box.min.z - origin.z ) * invdirz;
7962
7963                 }
7964
7965                 if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null;
7966
7967                 if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin;
7968
7969                 if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax;
7970
7971                 //return point closest to the ray (positive side)
7972
7973                 if ( tmax < 0 ) return null;
7974
7975                 return this.at( tmin >= 0 ? tmin : tmax, target );
7976
7977         }
7978
7979         intersectsBox( box ) {
7980
7981                 return this.intersectBox( box, _vector$a ) !== null;
7982
7983         }
7984
7985         intersectTriangle( a, b, c, backfaceCulling, target ) {
7986
7987                 // Compute the offset origin, edges, and normal.
7988
7989                 // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h
7990
7991                 _edge1.subVectors( b, a );
7992                 _edge2.subVectors( c, a );
7993                 _normal$1.crossVectors( _edge1, _edge2 );
7994
7995                 // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
7996                 // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
7997                 //   |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
7998                 //   |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
7999                 //   |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
8000                 let DdN = this.direction.dot( _normal$1 );
8001                 let sign;
8002
8003                 if ( DdN > 0 ) {
8004
8005                         if ( backfaceCulling ) return null;
8006                         sign = 1;
8007
8008                 } else if ( DdN < 0 ) {
8009
8010                         sign = - 1;
8011                         DdN = - DdN;
8012
8013                 } else {
8014
8015                         return null;
8016
8017                 }
8018
8019                 _diff.subVectors( this.origin, a );
8020                 const DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) );
8021
8022                 // b1 < 0, no intersection
8023                 if ( DdQxE2 < 0 ) {
8024
8025                         return null;
8026
8027                 }
8028
8029                 const DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) );
8030
8031                 // b2 < 0, no intersection
8032                 if ( DdE1xQ < 0 ) {
8033
8034                         return null;
8035
8036                 }
8037
8038                 // b1+b2 > 1, no intersection
8039                 if ( DdQxE2 + DdE1xQ > DdN ) {
8040
8041                         return null;
8042
8043                 }
8044
8045                 // Line intersects triangle, check if ray does.
8046                 const QdN = - sign * _diff.dot( _normal$1 );
8047
8048                 // t < 0, no intersection
8049                 if ( QdN < 0 ) {
8050
8051                         return null;
8052
8053                 }
8054
8055                 // Ray intersects triangle.
8056                 return this.at( QdN / DdN, target );
8057
8058         }
8059
8060         applyMatrix4( matrix4 ) {
8061
8062                 this.origin.applyMatrix4( matrix4 );
8063                 this.direction.transformDirection( matrix4 );
8064
8065                 return this;
8066
8067         }
8068
8069         equals( ray ) {
8070
8071                 return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction );
8072
8073         }
8074
8075         clone() {
8076
8077                 return new this.constructor().copy( this );
8078
8079         }
8080
8081 }
8082
8083 class Matrix4 {
8084
8085         constructor() {
8086
8087                 this.elements = [
8088
8089                         1, 0, 0, 0,
8090                         0, 1, 0, 0,
8091                         0, 0, 1, 0,
8092                         0, 0, 0, 1
8093
8094                 ];
8095
8096                 if ( arguments.length > 0 ) {
8097
8098                         console.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' );
8099
8100                 }
8101
8102         }
8103
8104         set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
8105
8106                 const te = this.elements;
8107
8108                 te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14;
8109                 te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24;
8110                 te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34;
8111                 te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44;
8112
8113                 return this;
8114
8115         }
8116
8117         identity() {
8118
8119                 this.set(
8120
8121                         1, 0, 0, 0,
8122                         0, 1, 0, 0,
8123                         0, 0, 1, 0,
8124                         0, 0, 0, 1
8125
8126                 );
8127
8128                 return this;
8129
8130         }
8131
8132         clone() {
8133
8134                 return new Matrix4().fromArray( this.elements );
8135
8136         }
8137
8138         copy( m ) {
8139
8140                 const te = this.elements;
8141                 const me = m.elements;
8142
8143                 te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ];
8144                 te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ];
8145                 te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ];
8146                 te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ];
8147
8148                 return this;
8149
8150         }
8151
8152         copyPosition( m ) {
8153
8154                 const te = this.elements, me = m.elements;
8155
8156                 te[ 12 ] = me[ 12 ];
8157                 te[ 13 ] = me[ 13 ];
8158                 te[ 14 ] = me[ 14 ];
8159
8160                 return this;
8161
8162         }
8163
8164         setFromMatrix3( m ) {
8165
8166                 const me = m.elements;
8167
8168                 this.set(
8169
8170                         me[ 0 ], me[ 3 ], me[ 6 ], 0,
8171                         me[ 1 ], me[ 4 ], me[ 7 ], 0,
8172                         me[ 2 ], me[ 5 ], me[ 8 ], 0,
8173                         0, 0, 0, 1
8174
8175                 );
8176
8177                 return this;
8178
8179         }
8180
8181         extractBasis( xAxis, yAxis, zAxis ) {
8182
8183                 xAxis.setFromMatrixColumn( this, 0 );
8184                 yAxis.setFromMatrixColumn( this, 1 );
8185                 zAxis.setFromMatrixColumn( this, 2 );
8186
8187                 return this;
8188
8189         }
8190
8191         makeBasis( xAxis, yAxis, zAxis ) {
8192
8193                 this.set(
8194                         xAxis.x, yAxis.x, zAxis.x, 0,
8195                         xAxis.y, yAxis.y, zAxis.y, 0,
8196                         xAxis.z, yAxis.z, zAxis.z, 0,
8197                         0, 0, 0, 1
8198                 );
8199
8200                 return this;
8201
8202         }
8203
8204         extractRotation( m ) {
8205
8206                 // this method does not support reflection matrices
8207
8208                 const te = this.elements;
8209                 const me = m.elements;
8210
8211                 const scaleX = 1 / _v1$5.setFromMatrixColumn( m, 0 ).length();
8212                 const scaleY = 1 / _v1$5.setFromMatrixColumn( m, 1 ).length();
8213                 const scaleZ = 1 / _v1$5.setFromMatrixColumn( m, 2 ).length();
8214
8215                 te[ 0 ] = me[ 0 ] * scaleX;
8216                 te[ 1 ] = me[ 1 ] * scaleX;
8217                 te[ 2 ] = me[ 2 ] * scaleX;
8218                 te[ 3 ] = 0;
8219
8220                 te[ 4 ] = me[ 4 ] * scaleY;
8221                 te[ 5 ] = me[ 5 ] * scaleY;
8222                 te[ 6 ] = me[ 6 ] * scaleY;
8223                 te[ 7 ] = 0;
8224
8225                 te[ 8 ] = me[ 8 ] * scaleZ;
8226                 te[ 9 ] = me[ 9 ] * scaleZ;
8227                 te[ 10 ] = me[ 10 ] * scaleZ;
8228                 te[ 11 ] = 0;
8229
8230                 te[ 12 ] = 0;
8231                 te[ 13 ] = 0;
8232                 te[ 14 ] = 0;
8233                 te[ 15 ] = 1;
8234
8235                 return this;
8236
8237         }
8238
8239         makeRotationFromEuler( euler ) {
8240
8241                 if ( ! ( euler && euler.isEuler ) ) {
8242
8243                         console.error( 'THREE.Matrix4: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' );
8244
8245                 }
8246
8247                 const te = this.elements;
8248
8249                 const x = euler.x, y = euler.y, z = euler.z;
8250                 const a = Math.cos( x ), b = Math.sin( x );
8251                 const c = Math.cos( y ), d = Math.sin( y );
8252                 const e = Math.cos( z ), f = Math.sin( z );
8253
8254                 if ( euler.order === 'XYZ' ) {
8255
8256                         const ae = a * e, af = a * f, be = b * e, bf = b * f;
8257
8258                         te[ 0 ] = c * e;
8259                         te[ 4 ] = - c * f;
8260                         te[ 8 ] = d;
8261
8262                         te[ 1 ] = af + be * d;
8263                         te[ 5 ] = ae - bf * d;
8264                         te[ 9 ] = - b * c;
8265
8266                         te[ 2 ] = bf - ae * d;
8267                         te[ 6 ] = be + af * d;
8268                         te[ 10 ] = a * c;
8269
8270                 } else if ( euler.order === 'YXZ' ) {
8271
8272                         const ce = c * e, cf = c * f, de = d * e, df = d * f;
8273
8274                         te[ 0 ] = ce + df * b;
8275                         te[ 4 ] = de * b - cf;
8276                         te[ 8 ] = a * d;
8277
8278                         te[ 1 ] = a * f;
8279                         te[ 5 ] = a * e;
8280                         te[ 9 ] = - b;
8281
8282                         te[ 2 ] = cf * b - de;
8283                         te[ 6 ] = df + ce * b;
8284                         te[ 10 ] = a * c;
8285
8286                 } else if ( euler.order === 'ZXY' ) {
8287
8288                         const ce = c * e, cf = c * f, de = d * e, df = d * f;
8289
8290                         te[ 0 ] = ce - df * b;
8291                         te[ 4 ] = - a * f;
8292                         te[ 8 ] = de + cf * b;
8293
8294                         te[ 1 ] = cf + de * b;
8295                         te[ 5 ] = a * e;
8296                         te[ 9 ] = df - ce * b;
8297
8298                         te[ 2 ] = - a * d;
8299                         te[ 6 ] = b;
8300                         te[ 10 ] = a * c;
8301
8302                 } else if ( euler.order === 'ZYX' ) {
8303
8304                         const ae = a * e, af = a * f, be = b * e, bf = b * f;
8305
8306                         te[ 0 ] = c * e;
8307                         te[ 4 ] = be * d - af;
8308                         te[ 8 ] = ae * d + bf;
8309
8310                         te[ 1 ] = c * f;
8311                         te[ 5 ] = bf * d + ae;
8312                         te[ 9 ] = af * d - be;
8313
8314                         te[ 2 ] = - d;
8315                         te[ 6 ] = b * c;
8316                         te[ 10 ] = a * c;
8317
8318                 } else if ( euler.order === 'YZX' ) {
8319
8320                         const ac = a * c, ad = a * d, bc = b * c, bd = b * d;
8321
8322                         te[ 0 ] = c * e;
8323                         te[ 4 ] = bd - ac * f;
8324                         te[ 8 ] = bc * f + ad;
8325
8326                         te[ 1 ] = f;
8327                         te[ 5 ] = a * e;
8328                         te[ 9 ] = - b * e;
8329
8330                         te[ 2 ] = - d * e;
8331                         te[ 6 ] = ad * f + bc;
8332                         te[ 10 ] = ac - bd * f;
8333
8334                 } else if ( euler.order === 'XZY' ) {
8335
8336                         const ac = a * c, ad = a * d, bc = b * c, bd = b * d;
8337
8338                         te[ 0 ] = c * e;
8339                         te[ 4 ] = - f;
8340                         te[ 8 ] = d * e;
8341
8342                         te[ 1 ] = ac * f + bd;
8343                         te[ 5 ] = a * e;
8344                         te[ 9 ] = ad * f - bc;
8345
8346                         te[ 2 ] = bc * f - ad;
8347                         te[ 6 ] = b * e;
8348                         te[ 10 ] = bd * f + ac;
8349
8350                 }
8351
8352                 // bottom row
8353                 te[ 3 ] = 0;
8354                 te[ 7 ] = 0;
8355                 te[ 11 ] = 0;
8356
8357                 // last column
8358                 te[ 12 ] = 0;
8359                 te[ 13 ] = 0;
8360                 te[ 14 ] = 0;
8361                 te[ 15 ] = 1;
8362
8363                 return this;
8364
8365         }
8366
8367         makeRotationFromQuaternion( q ) {
8368
8369                 return this.compose( _zero, q, _one );
8370
8371         }
8372
8373         lookAt( eye, target, up ) {
8374
8375                 const te = this.elements;
8376
8377                 _z.subVectors( eye, target );
8378
8379                 if ( _z.lengthSq() === 0 ) {
8380
8381                         // eye and target are in the same position
8382
8383                         _z.z = 1;
8384
8385                 }
8386
8387                 _z.normalize();
8388                 _x.crossVectors( up, _z );
8389
8390                 if ( _x.lengthSq() === 0 ) {
8391
8392                         // up and z are parallel
8393
8394                         if ( Math.abs( up.z ) === 1 ) {
8395
8396                                 _z.x += 0.0001;
8397
8398                         } else {
8399
8400                                 _z.z += 0.0001;
8401
8402                         }
8403
8404                         _z.normalize();
8405                         _x.crossVectors( up, _z );
8406
8407                 }
8408
8409                 _x.normalize();
8410                 _y.crossVectors( _z, _x );
8411
8412                 te[ 0 ] = _x.x; te[ 4 ] = _y.x; te[ 8 ] = _z.x;
8413                 te[ 1 ] = _x.y; te[ 5 ] = _y.y; te[ 9 ] = _z.y;
8414                 te[ 2 ] = _x.z; te[ 6 ] = _y.z; te[ 10 ] = _z.z;
8415
8416                 return this;
8417
8418         }
8419
8420         multiply( m, n ) {
8421
8422                 if ( n !== undefined ) {
8423
8424                         console.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' );
8425                         return this.multiplyMatrices( m, n );
8426
8427                 }
8428
8429                 return this.multiplyMatrices( this, m );
8430
8431         }
8432
8433         premultiply( m ) {
8434
8435                 return this.multiplyMatrices( m, this );
8436
8437         }
8438
8439         multiplyMatrices( a, b ) {
8440
8441                 const ae = a.elements;
8442                 const be = b.elements;
8443                 const te = this.elements;
8444
8445                 const a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ];
8446                 const a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ];
8447                 const a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ];
8448                 const a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ];
8449
8450                 const b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ];
8451                 const b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ];
8452                 const b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ];
8453                 const b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ];
8454
8455                 te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
8456                 te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
8457                 te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
8458                 te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
8459
8460                 te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
8461                 te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
8462                 te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
8463                 te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
8464
8465                 te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
8466                 te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
8467                 te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
8468                 te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
8469
8470                 te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
8471                 te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
8472                 te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
8473                 te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
8474
8475                 return this;
8476
8477         }
8478
8479         multiplyScalar( s ) {
8480
8481                 const te = this.elements;
8482
8483                 te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s;
8484                 te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s;
8485                 te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s;
8486                 te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s;
8487
8488                 return this;
8489
8490         }
8491
8492         determinant() {
8493
8494                 const te = this.elements;
8495
8496                 const n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ];
8497                 const n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ];
8498                 const n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ];
8499                 const n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ];
8500
8501                 //TODO: make this more efficient
8502                 //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )
8503
8504                 return (
8505                         n41 * (
8506                                 + n14 * n23 * n32
8507                                  - n13 * n24 * n32
8508                                  - n14 * n22 * n33
8509                                  + n12 * n24 * n33
8510                                  + n13 * n22 * n34
8511                                  - n12 * n23 * n34
8512                         ) +
8513                         n42 * (
8514                                 + n11 * n23 * n34
8515                                  - n11 * n24 * n33
8516                                  + n14 * n21 * n33
8517                                  - n13 * n21 * n34
8518                                  + n13 * n24 * n31
8519                                  - n14 * n23 * n31
8520                         ) +
8521                         n43 * (
8522                                 + n11 * n24 * n32
8523                                  - n11 * n22 * n34
8524                                  - n14 * n21 * n32
8525                                  + n12 * n21 * n34
8526                                  + n14 * n22 * n31
8527                                  - n12 * n24 * n31
8528                         ) +
8529                         n44 * (
8530                                 - n13 * n22 * n31
8531                                  - n11 * n23 * n32
8532                                  + n11 * n22 * n33
8533                                  + n13 * n21 * n32
8534                                  - n12 * n21 * n33
8535                                  + n12 * n23 * n31
8536                         )
8537
8538                 );
8539
8540         }
8541
8542         transpose() {
8543
8544                 const te = this.elements;
8545                 let tmp;
8546
8547                 tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp;
8548                 tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp;
8549                 tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp;
8550
8551                 tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp;
8552                 tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp;
8553                 tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp;
8554
8555                 return this;
8556
8557         }
8558
8559         setPosition( x, y, z ) {
8560
8561                 const te = this.elements;
8562
8563                 if ( x.isVector3 ) {
8564
8565                         te[ 12 ] = x.x;
8566                         te[ 13 ] = x.y;
8567                         te[ 14 ] = x.z;
8568
8569                 } else {
8570
8571                         te[ 12 ] = x;
8572                         te[ 13 ] = y;
8573                         te[ 14 ] = z;
8574
8575                 }
8576
8577                 return this;
8578
8579         }
8580
8581         invert() {
8582
8583                 // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm
8584                 const te = this.elements,
8585
8586                         n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], n41 = te[ 3 ],
8587                         n12 = te[ 4 ], n22 = te[ 5 ], n32 = te[ 6 ], n42 = te[ 7 ],
8588                         n13 = te[ 8 ], n23 = te[ 9 ], n33 = te[ 10 ], n43 = te[ 11 ],
8589                         n14 = te[ 12 ], n24 = te[ 13 ], n34 = te[ 14 ], n44 = te[ 15 ],
8590
8591                         t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44,
8592                         t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44,
8593                         t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44,
8594                         t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;
8595
8596                 const det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14;
8597
8598                 if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
8599
8600                 const detInv = 1 / det;
8601
8602                 te[ 0 ] = t11 * detInv;
8603                 te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv;
8604                 te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv;
8605                 te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv;
8606
8607                 te[ 4 ] = t12 * detInv;
8608                 te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv;
8609                 te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv;
8610                 te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv;
8611
8612                 te[ 8 ] = t13 * detInv;
8613                 te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv;
8614                 te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv;
8615                 te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv;
8616
8617                 te[ 12 ] = t14 * detInv;
8618                 te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv;
8619                 te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv;
8620                 te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv;
8621
8622                 return this;
8623
8624         }
8625
8626         scale( v ) {
8627
8628                 const te = this.elements;
8629                 const x = v.x, y = v.y, z = v.z;
8630
8631                 te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z;
8632                 te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z;
8633                 te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z;
8634                 te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z;
8635
8636                 return this;
8637
8638         }
8639
8640         getMaxScaleOnAxis() {
8641
8642                 const te = this.elements;
8643
8644                 const scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ];
8645                 const scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ];
8646                 const scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ];
8647
8648                 return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) );
8649
8650         }
8651
8652         makeTranslation( x, y, z ) {
8653
8654                 this.set(
8655
8656                         1, 0, 0, x,
8657                         0, 1, 0, y,
8658                         0, 0, 1, z,
8659                         0, 0, 0, 1
8660
8661                 );
8662
8663                 return this;
8664
8665         }
8666
8667         makeRotationX( theta ) {
8668
8669                 const c = Math.cos( theta ), s = Math.sin( theta );
8670
8671                 this.set(
8672
8673                         1, 0, 0, 0,
8674                         0, c, - s, 0,
8675                         0, s, c, 0,
8676                         0, 0, 0, 1
8677
8678                 );
8679
8680                 return this;
8681
8682         }
8683
8684         makeRotationY( theta ) {
8685
8686                 const c = Math.cos( theta ), s = Math.sin( theta );
8687
8688                 this.set(
8689
8690                          c, 0, s, 0,
8691                          0, 1, 0, 0,
8692                         - s, 0, c, 0,
8693                          0, 0, 0, 1
8694
8695                 );
8696
8697                 return this;
8698
8699         }
8700
8701         makeRotationZ( theta ) {
8702
8703                 const c = Math.cos( theta ), s = Math.sin( theta );
8704
8705                 this.set(
8706
8707                         c, - s, 0, 0,
8708                         s, c, 0, 0,
8709                         0, 0, 1, 0,
8710                         0, 0, 0, 1
8711
8712                 );
8713
8714                 return this;
8715
8716         }
8717
8718         makeRotationAxis( axis, angle ) {
8719
8720                 // Based on http://www.gamedev.net/reference/articles/article1199.asp
8721
8722                 const c = Math.cos( angle );
8723                 const s = Math.sin( angle );
8724                 const t = 1 - c;
8725                 const x = axis.x, y = axis.y, z = axis.z;
8726                 const tx = t * x, ty = t * y;
8727
8728                 this.set(
8729
8730                         tx * x + c, tx * y - s * z, tx * z + s * y, 0,
8731                         tx * y + s * z, ty * y + c, ty * z - s * x, 0,
8732                         tx * z - s * y, ty * z + s * x, t * z * z + c, 0,
8733                         0, 0, 0, 1
8734
8735                 );
8736
8737                 return this;
8738
8739         }
8740
8741         makeScale( x, y, z ) {
8742
8743                 this.set(
8744
8745                         x, 0, 0, 0,
8746                         0, y, 0, 0,
8747                         0, 0, z, 0,
8748                         0, 0, 0, 1
8749
8750                 );
8751
8752                 return this;
8753
8754         }
8755
8756         makeShear( xy, xz, yx, yz, zx, zy ) {
8757
8758                 this.set(
8759
8760                         1, yx, zx, 0,
8761                         xy, 1, zy, 0,
8762                         xz, yz, 1, 0,
8763                         0, 0, 0, 1
8764
8765                 );
8766
8767                 return this;
8768
8769         }
8770
8771         compose( position, quaternion, scale ) {
8772
8773                 const te = this.elements;
8774
8775                 const x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w;
8776                 const x2 = x + x,       y2 = y + y, z2 = z + z;
8777                 const xx = x * x2, xy = x * y2, xz = x * z2;
8778                 const yy = y * y2, yz = y * z2, zz = z * z2;
8779                 const wx = w * x2, wy = w * y2, wz = w * z2;
8780
8781                 const sx = scale.x, sy = scale.y, sz = scale.z;
8782
8783                 te[ 0 ] = ( 1 - ( yy + zz ) ) * sx;
8784                 te[ 1 ] = ( xy + wz ) * sx;
8785                 te[ 2 ] = ( xz - wy ) * sx;
8786                 te[ 3 ] = 0;
8787
8788                 te[ 4 ] = ( xy - wz ) * sy;
8789                 te[ 5 ] = ( 1 - ( xx + zz ) ) * sy;
8790                 te[ 6 ] = ( yz + wx ) * sy;
8791                 te[ 7 ] = 0;
8792
8793                 te[ 8 ] = ( xz + wy ) * sz;
8794                 te[ 9 ] = ( yz - wx ) * sz;
8795                 te[ 10 ] = ( 1 - ( xx + yy ) ) * sz;
8796                 te[ 11 ] = 0;
8797
8798                 te[ 12 ] = position.x;
8799                 te[ 13 ] = position.y;
8800                 te[ 14 ] = position.z;
8801                 te[ 15 ] = 1;
8802
8803                 return this;
8804
8805         }
8806
8807         decompose( position, quaternion, scale ) {
8808
8809                 const te = this.elements;
8810
8811                 let sx = _v1$5.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length();
8812                 const sy = _v1$5.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length();
8813                 const sz = _v1$5.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length();
8814
8815                 // if determine is negative, we need to invert one scale
8816                 const det = this.determinant();
8817                 if ( det < 0 ) sx = - sx;
8818
8819                 position.x = te[ 12 ];
8820                 position.y = te[ 13 ];
8821                 position.z = te[ 14 ];
8822
8823                 // scale the rotation part
8824                 _m1$2.copy( this );
8825
8826                 const invSX = 1 / sx;
8827                 const invSY = 1 / sy;
8828                 const invSZ = 1 / sz;
8829
8830                 _m1$2.elements[ 0 ] *= invSX;
8831                 _m1$2.elements[ 1 ] *= invSX;
8832                 _m1$2.elements[ 2 ] *= invSX;
8833
8834                 _m1$2.elements[ 4 ] *= invSY;
8835                 _m1$2.elements[ 5 ] *= invSY;
8836                 _m1$2.elements[ 6 ] *= invSY;
8837
8838                 _m1$2.elements[ 8 ] *= invSZ;
8839                 _m1$2.elements[ 9 ] *= invSZ;
8840                 _m1$2.elements[ 10 ] *= invSZ;
8841
8842                 quaternion.setFromRotationMatrix( _m1$2 );
8843
8844                 scale.x = sx;
8845                 scale.y = sy;
8846                 scale.z = sz;
8847
8848                 return this;
8849
8850         }
8851
8852         makePerspective( left, right, top, bottom, near, far ) {
8853
8854                 if ( far === undefined ) {
8855
8856                         console.warn( 'THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.' );
8857
8858                 }
8859
8860                 const te = this.elements;
8861                 const x = 2 * near / ( right - left );
8862                 const y = 2 * near / ( top - bottom );
8863
8864                 const a = ( right + left ) / ( right - left );
8865                 const b = ( top + bottom ) / ( top - bottom );
8866                 const c = - ( far + near ) / ( far - near );
8867                 const d = - 2 * far * near / ( far - near );
8868
8869                 te[ 0 ] = x;    te[ 4 ] = 0;    te[ 8 ] = a;    te[ 12 ] = 0;
8870                 te[ 1 ] = 0;    te[ 5 ] = y;    te[ 9 ] = b;    te[ 13 ] = 0;
8871                 te[ 2 ] = 0;    te[ 6 ] = 0;    te[ 10 ] = c;   te[ 14 ] = d;
8872                 te[ 3 ] = 0;    te[ 7 ] = 0;    te[ 11 ] = - 1; te[ 15 ] = 0;
8873
8874                 return this;
8875
8876         }
8877
8878         makeOrthographic( left, right, top, bottom, near, far ) {
8879
8880                 const te = this.elements;
8881                 const w = 1.0 / ( right - left );
8882                 const h = 1.0 / ( top - bottom );
8883                 const p = 1.0 / ( far - near );
8884
8885                 const x = ( right + left ) * w;
8886                 const y = ( top + bottom ) * h;
8887                 const z = ( far + near ) * p;
8888
8889                 te[ 0 ] = 2 * w;        te[ 4 ] = 0;    te[ 8 ] = 0;    te[ 12 ] = - x;
8890                 te[ 1 ] = 0;    te[ 5 ] = 2 * h;        te[ 9 ] = 0;    te[ 13 ] = - y;
8891                 te[ 2 ] = 0;    te[ 6 ] = 0;    te[ 10 ] = - 2 * p;     te[ 14 ] = - z;
8892                 te[ 3 ] = 0;    te[ 7 ] = 0;    te[ 11 ] = 0;   te[ 15 ] = 1;
8893
8894                 return this;
8895
8896         }
8897
8898         equals( matrix ) {
8899
8900                 const te = this.elements;
8901                 const me = matrix.elements;
8902
8903                 for ( let i = 0; i < 16; i ++ ) {
8904
8905                         if ( te[ i ] !== me[ i ] ) return false;
8906
8907                 }
8908
8909                 return true;
8910
8911         }
8912
8913         fromArray( array, offset = 0 ) {
8914
8915                 for ( let i = 0; i < 16; i ++ ) {
8916
8917                         this.elements[ i ] = array[ i + offset ];
8918
8919                 }
8920
8921                 return this;
8922
8923         }
8924
8925         toArray( array = [], offset = 0 ) {
8926
8927                 const te = this.elements;
8928
8929                 array[ offset ] = te[ 0 ];
8930                 array[ offset + 1 ] = te[ 1 ];
8931                 array[ offset + 2 ] = te[ 2 ];
8932                 array[ offset + 3 ] = te[ 3 ];
8933
8934                 array[ offset + 4 ] = te[ 4 ];
8935                 array[ offset + 5 ] = te[ 5 ];
8936                 array[ offset + 6 ] = te[ 6 ];
8937                 array[ offset + 7 ] = te[ 7 ];
8938
8939                 array[ offset + 8 ] = te[ 8 ];
8940                 array[ offset + 9 ] = te[ 9 ];
8941                 array[ offset + 10 ] = te[ 10 ];
8942                 array[ offset + 11 ] = te[ 11 ];
8943
8944                 array[ offset + 12 ] = te[ 12 ];
8945                 array[ offset + 13 ] = te[ 13 ];
8946                 array[ offset + 14 ] = te[ 14 ];
8947                 array[ offset + 15 ] = te[ 15 ];
8948
8949                 return array;
8950
8951         }
8952
8953 }
8954
8955 Matrix4.prototype.isMatrix4 = true;
8956
8957 const _v1$5 = /*@__PURE__*/ new Vector3();
8958 const _m1$2 = /*@__PURE__*/ new Matrix4();
8959 const _zero = /*@__PURE__*/ new Vector3( 0, 0, 0 );
8960 const _one = /*@__PURE__*/ new Vector3( 1, 1, 1 );
8961 const _x = /*@__PURE__*/ new Vector3();
8962 const _y = /*@__PURE__*/ new Vector3();
8963 const _z = /*@__PURE__*/ new Vector3();
8964
8965 const _matrix$1 = /*@__PURE__*/ new Matrix4();
8966 const _quaternion$3 = /*@__PURE__*/ new Quaternion();
8967
8968 class Euler {
8969
8970         constructor( x = 0, y = 0, z = 0, order = Euler.DefaultOrder ) {
8971
8972                 this._x = x;
8973                 this._y = y;
8974                 this._z = z;
8975                 this._order = order;
8976
8977         }
8978
8979         get x() {
8980
8981                 return this._x;
8982
8983         }
8984
8985         set x( value ) {
8986
8987                 this._x = value;
8988                 this._onChangeCallback();
8989
8990         }
8991
8992         get y() {
8993
8994                 return this._y;
8995
8996         }
8997
8998         set y( value ) {
8999
9000                 this._y = value;
9001                 this._onChangeCallback();
9002
9003         }
9004
9005         get z() {
9006
9007                 return this._z;
9008
9009         }
9010
9011         set z( value ) {
9012
9013                 this._z = value;
9014                 this._onChangeCallback();
9015
9016         }
9017
9018         get order() {
9019
9020                 return this._order;
9021
9022         }
9023
9024         set order( value ) {
9025
9026                 this._order = value;
9027                 this._onChangeCallback();
9028
9029         }
9030
9031         set( x, y, z, order = this._order ) {
9032
9033                 this._x = x;
9034                 this._y = y;
9035                 this._z = z;
9036                 this._order = order;
9037
9038                 this._onChangeCallback();
9039
9040                 return this;
9041
9042         }
9043
9044         clone() {
9045
9046                 return new this.constructor( this._x, this._y, this._z, this._order );
9047
9048         }
9049
9050         copy( euler ) {
9051
9052                 this._x = euler._x;
9053                 this._y = euler._y;
9054                 this._z = euler._z;
9055                 this._order = euler._order;
9056
9057                 this._onChangeCallback();
9058
9059                 return this;
9060
9061         }
9062
9063         setFromRotationMatrix( m, order = this._order, update = true ) {
9064
9065                 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
9066
9067                 const te = m.elements;
9068                 const m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ];
9069                 const m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ];
9070                 const m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
9071
9072                 switch ( order ) {
9073
9074                         case 'XYZ':
9075
9076                                 this._y = Math.asin( clamp$1( m13, - 1, 1 ) );
9077
9078                                 if ( Math.abs( m13 ) < 0.9999999 ) {
9079
9080                                         this._x = Math.atan2( - m23, m33 );
9081                                         this._z = Math.atan2( - m12, m11 );
9082
9083                                 } else {
9084
9085                                         this._x = Math.atan2( m32, m22 );
9086                                         this._z = 0;
9087
9088                                 }
9089
9090                                 break;
9091
9092                         case 'YXZ':
9093
9094                                 this._x = Math.asin( - clamp$1( m23, - 1, 1 ) );
9095
9096                                 if ( Math.abs( m23 ) < 0.9999999 ) {
9097
9098                                         this._y = Math.atan2( m13, m33 );
9099                                         this._z = Math.atan2( m21, m22 );
9100
9101                                 } else {
9102
9103                                         this._y = Math.atan2( - m31, m11 );
9104                                         this._z = 0;
9105
9106                                 }
9107
9108                                 break;
9109
9110                         case 'ZXY':
9111
9112                                 this._x = Math.asin( clamp$1( m32, - 1, 1 ) );
9113
9114                                 if ( Math.abs( m32 ) < 0.9999999 ) {
9115
9116                                         this._y = Math.atan2( - m31, m33 );
9117                                         this._z = Math.atan2( - m12, m22 );
9118
9119                                 } else {
9120
9121                                         this._y = 0;
9122                                         this._z = Math.atan2( m21, m11 );
9123
9124                                 }
9125
9126                                 break;
9127
9128                         case 'ZYX':
9129
9130                                 this._y = Math.asin( - clamp$1( m31, - 1, 1 ) );
9131
9132                                 if ( Math.abs( m31 ) < 0.9999999 ) {
9133
9134                                         this._x = Math.atan2( m32, m33 );
9135                                         this._z = Math.atan2( m21, m11 );
9136
9137                                 } else {
9138
9139                                         this._x = 0;
9140                                         this._z = Math.atan2( - m12, m22 );
9141
9142                                 }
9143
9144                                 break;
9145
9146                         case 'YZX':
9147
9148                                 this._z = Math.asin( clamp$1( m21, - 1, 1 ) );
9149
9150                                 if ( Math.abs( m21 ) < 0.9999999 ) {
9151
9152                                         this._x = Math.atan2( - m23, m22 );
9153                                         this._y = Math.atan2( - m31, m11 );
9154
9155                                 } else {
9156
9157                                         this._x = 0;
9158                                         this._y = Math.atan2( m13, m33 );
9159
9160                                 }
9161
9162                                 break;
9163
9164                         case 'XZY':
9165
9166                                 this._z = Math.asin( - clamp$1( m12, - 1, 1 ) );
9167
9168                                 if ( Math.abs( m12 ) < 0.9999999 ) {
9169
9170                                         this._x = Math.atan2( m32, m22 );
9171                                         this._y = Math.atan2( m13, m11 );
9172
9173                                 } else {
9174
9175                                         this._x = Math.atan2( - m23, m33 );
9176                                         this._y = 0;
9177
9178                                 }
9179
9180                                 break;
9181
9182                         default:
9183
9184                                 console.warn( 'THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order );
9185
9186                 }
9187
9188                 this._order = order;
9189
9190                 if ( update === true ) this._onChangeCallback();
9191
9192                 return this;
9193
9194         }
9195
9196         setFromQuaternion( q, order, update ) {
9197
9198                 _matrix$1.makeRotationFromQuaternion( q );
9199
9200                 return this.setFromRotationMatrix( _matrix$1, order, update );
9201
9202         }
9203
9204         setFromVector3( v, order = this._order ) {
9205
9206                 return this.set( v.x, v.y, v.z, order );
9207
9208         }
9209
9210         reorder( newOrder ) {
9211
9212                 // WARNING: this discards revolution information -bhouston
9213
9214                 _quaternion$3.setFromEuler( this );
9215
9216                 return this.setFromQuaternion( _quaternion$3, newOrder );
9217
9218         }
9219
9220         equals( euler ) {
9221
9222                 return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order );
9223
9224         }
9225
9226         fromArray( array ) {
9227
9228                 this._x = array[ 0 ];
9229                 this._y = array[ 1 ];
9230                 this._z = array[ 2 ];
9231                 if ( array[ 3 ] !== undefined ) this._order = array[ 3 ];
9232
9233                 this._onChangeCallback();
9234
9235                 return this;
9236
9237         }
9238
9239         toArray( array = [], offset = 0 ) {
9240
9241                 array[ offset ] = this._x;
9242                 array[ offset + 1 ] = this._y;
9243                 array[ offset + 2 ] = this._z;
9244                 array[ offset + 3 ] = this._order;
9245
9246                 return array;
9247
9248         }
9249
9250         toVector3( optionalResult ) {
9251
9252                 if ( optionalResult ) {
9253
9254                         return optionalResult.set( this._x, this._y, this._z );
9255
9256                 } else {
9257
9258                         return new Vector3( this._x, this._y, this._z );
9259
9260                 }
9261
9262         }
9263
9264         _onChange( callback ) {
9265
9266                 this._onChangeCallback = callback;
9267
9268                 return this;
9269
9270         }
9271
9272         _onChangeCallback() {}
9273
9274 }
9275
9276 Euler.prototype.isEuler = true;
9277
9278 Euler.DefaultOrder = 'XYZ';
9279 Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ];
9280
9281 class Layers {
9282
9283         constructor() {
9284
9285                 this.mask = 1 | 0;
9286
9287         }
9288
9289         set( channel ) {
9290
9291                 this.mask = 1 << channel | 0;
9292
9293         }
9294
9295         enable( channel ) {
9296
9297                 this.mask |= 1 << channel | 0;
9298
9299         }
9300
9301         enableAll() {
9302
9303                 this.mask = 0xffffffff | 0;
9304
9305         }
9306
9307         toggle( channel ) {
9308
9309                 this.mask ^= 1 << channel | 0;
9310
9311         }
9312
9313         disable( channel ) {
9314
9315                 this.mask &= ~ ( 1 << channel | 0 );
9316
9317         }
9318
9319         disableAll() {
9320
9321                 this.mask = 0;
9322
9323         }
9324
9325         test( layers ) {
9326
9327                 return ( this.mask & layers.mask ) !== 0;
9328
9329         }
9330
9331 }
9332
9333 let _object3DId = 0;
9334
9335 const _v1$4 = /*@__PURE__*/ new Vector3();
9336 const _q1 = /*@__PURE__*/ new Quaternion();
9337 const _m1$1 = /*@__PURE__*/ new Matrix4();
9338 const _target = /*@__PURE__*/ new Vector3();
9339
9340 const _position$3 = /*@__PURE__*/ new Vector3();
9341 const _scale$2 = /*@__PURE__*/ new Vector3();
9342 const _quaternion$2 = /*@__PURE__*/ new Quaternion();
9343
9344 const _xAxis = /*@__PURE__*/ new Vector3( 1, 0, 0 );
9345 const _yAxis = /*@__PURE__*/ new Vector3( 0, 1, 0 );
9346 const _zAxis = /*@__PURE__*/ new Vector3( 0, 0, 1 );
9347
9348 const _addedEvent = { type: 'added' };
9349 const _removedEvent = { type: 'removed' };
9350
9351 class Object3D extends EventDispatcher {
9352
9353         constructor() {
9354
9355                 super();
9356
9357                 Object.defineProperty( this, 'id', { value: _object3DId ++ } );
9358
9359                 this.uuid = generateUUID();
9360
9361                 this.name = '';
9362                 this.type = 'Object3D';
9363
9364                 this.parent = null;
9365                 this.children = [];
9366
9367                 this.up = Object3D.DefaultUp.clone();
9368
9369                 const position = new Vector3();
9370                 const rotation = new Euler();
9371                 const quaternion = new Quaternion();
9372                 const scale = new Vector3( 1, 1, 1 );
9373
9374                 function onRotationChange() {
9375
9376                         quaternion.setFromEuler( rotation, false );
9377
9378                 }
9379
9380                 function onQuaternionChange() {
9381
9382                         rotation.setFromQuaternion( quaternion, undefined, false );
9383
9384                 }
9385
9386                 rotation._onChange( onRotationChange );
9387                 quaternion._onChange( onQuaternionChange );
9388
9389                 Object.defineProperties( this, {
9390                         position: {
9391                                 configurable: true,
9392                                 enumerable: true,
9393                                 value: position
9394                         },
9395                         rotation: {
9396                                 configurable: true,
9397                                 enumerable: true,
9398                                 value: rotation
9399                         },
9400                         quaternion: {
9401                                 configurable: true,
9402                                 enumerable: true,
9403                                 value: quaternion
9404                         },
9405                         scale: {
9406                                 configurable: true,
9407                                 enumerable: true,
9408                                 value: scale
9409                         },
9410                         modelViewMatrix: {
9411                                 value: new Matrix4()
9412                         },
9413                         normalMatrix: {
9414                                 value: new Matrix3()
9415                         }
9416                 } );
9417
9418                 this.matrix = new Matrix4();
9419                 this.matrixWorld = new Matrix4();
9420
9421                 this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate;
9422                 this.matrixWorldNeedsUpdate = false;
9423
9424                 this.layers = new Layers();
9425                 this.visible = true;
9426
9427                 this.castShadow = false;
9428                 this.receiveShadow = false;
9429
9430                 this.frustumCulled = true;
9431                 this.renderOrder = 0;
9432
9433                 this.animations = [];
9434
9435                 this.userData = {};
9436
9437         }
9438
9439         onBeforeRender( /* renderer, scene, camera, geometry, material, group */ ) {}
9440
9441         onAfterRender( /* renderer, scene, camera, geometry, material, group */ ) {}
9442
9443         applyMatrix4( matrix ) {
9444
9445                 if ( this.matrixAutoUpdate ) this.updateMatrix();
9446
9447                 this.matrix.premultiply( matrix );
9448
9449                 this.matrix.decompose( this.position, this.quaternion, this.scale );
9450
9451         }
9452
9453         applyQuaternion( q ) {
9454
9455                 this.quaternion.premultiply( q );
9456
9457                 return this;
9458
9459         }
9460
9461         setRotationFromAxisAngle( axis, angle ) {
9462
9463                 // assumes axis is normalized
9464
9465                 this.quaternion.setFromAxisAngle( axis, angle );
9466
9467         }
9468
9469         setRotationFromEuler( euler ) {
9470
9471                 this.quaternion.setFromEuler( euler, true );
9472
9473         }
9474
9475         setRotationFromMatrix( m ) {
9476
9477                 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
9478
9479                 this.quaternion.setFromRotationMatrix( m );
9480
9481         }
9482
9483         setRotationFromQuaternion( q ) {
9484
9485                 // assumes q is normalized
9486
9487                 this.quaternion.copy( q );
9488
9489         }
9490
9491         rotateOnAxis( axis, angle ) {
9492
9493                 // rotate object on axis in object space
9494                 // axis is assumed to be normalized
9495
9496                 _q1.setFromAxisAngle( axis, angle );
9497
9498                 this.quaternion.multiply( _q1 );
9499
9500                 return this;
9501
9502         }
9503
9504         rotateOnWorldAxis( axis, angle ) {
9505
9506                 // rotate object on axis in world space
9507                 // axis is assumed to be normalized
9508                 // method assumes no rotated parent
9509
9510                 _q1.setFromAxisAngle( axis, angle );
9511
9512                 this.quaternion.premultiply( _q1 );
9513
9514                 return this;
9515
9516         }
9517
9518         rotateX( angle ) {
9519
9520                 return this.rotateOnAxis( _xAxis, angle );
9521
9522         }
9523
9524         rotateY( angle ) {
9525
9526                 return this.rotateOnAxis( _yAxis, angle );
9527
9528         }
9529
9530         rotateZ( angle ) {
9531
9532                 return this.rotateOnAxis( _zAxis, angle );
9533
9534         }
9535
9536         translateOnAxis( axis, distance ) {
9537
9538                 // translate object by distance along axis in object space
9539                 // axis is assumed to be normalized
9540
9541                 _v1$4.copy( axis ).applyQuaternion( this.quaternion );
9542
9543                 this.position.add( _v1$4.multiplyScalar( distance ) );
9544
9545                 return this;
9546
9547         }
9548
9549         translateX( distance ) {
9550
9551                 return this.translateOnAxis( _xAxis, distance );
9552
9553         }
9554
9555         translateY( distance ) {
9556
9557                 return this.translateOnAxis( _yAxis, distance );
9558
9559         }
9560
9561         translateZ( distance ) {
9562
9563                 return this.translateOnAxis( _zAxis, distance );
9564
9565         }
9566
9567         localToWorld( vector ) {
9568
9569                 return vector.applyMatrix4( this.matrixWorld );
9570
9571         }
9572
9573         worldToLocal( vector ) {
9574
9575                 return vector.applyMatrix4( _m1$1.copy( this.matrixWorld ).invert() );
9576
9577         }
9578
9579         lookAt( x, y, z ) {
9580
9581                 // This method does not support objects having non-uniformly-scaled parent(s)
9582
9583                 if ( x.isVector3 ) {
9584
9585                         _target.copy( x );
9586
9587                 } else {
9588
9589                         _target.set( x, y, z );
9590
9591                 }
9592
9593                 const parent = this.parent;
9594
9595                 this.updateWorldMatrix( true, false );
9596
9597                 _position$3.setFromMatrixPosition( this.matrixWorld );
9598
9599                 if ( this.isCamera || this.isLight ) {
9600
9601                         _m1$1.lookAt( _position$3, _target, this.up );
9602
9603                 } else {
9604
9605                         _m1$1.lookAt( _target, _position$3, this.up );
9606
9607                 }
9608
9609                 this.quaternion.setFromRotationMatrix( _m1$1 );
9610
9611                 if ( parent ) {
9612
9613                         _m1$1.extractRotation( parent.matrixWorld );
9614                         _q1.setFromRotationMatrix( _m1$1 );
9615                         this.quaternion.premultiply( _q1.invert() );
9616
9617                 }
9618
9619         }
9620
9621         add( object ) {
9622
9623                 if ( arguments.length > 1 ) {
9624
9625                         for ( let i = 0; i < arguments.length; i ++ ) {
9626
9627                                 this.add( arguments[ i ] );
9628
9629                         }
9630
9631                         return this;
9632
9633                 }
9634
9635                 if ( object === this ) {
9636
9637                         console.error( 'THREE.Object3D.add: object can\'t be added as a child of itself.', object );
9638                         return this;
9639
9640                 }
9641
9642                 if ( object && object.isObject3D ) {
9643
9644                         if ( object.parent !== null ) {
9645
9646                                 object.parent.remove( object );
9647
9648                         }
9649
9650                         object.parent = this;
9651                         this.children.push( object );
9652
9653                         object.dispatchEvent( _addedEvent );
9654
9655                 } else {
9656
9657                         console.error( 'THREE.Object3D.add: object not an instance of THREE.Object3D.', object );
9658
9659                 }
9660
9661                 return this;
9662
9663         }
9664
9665         remove( object ) {
9666
9667                 if ( arguments.length > 1 ) {
9668
9669                         for ( let i = 0; i < arguments.length; i ++ ) {
9670
9671                                 this.remove( arguments[ i ] );
9672
9673                         }
9674
9675                         return this;
9676
9677                 }
9678
9679                 const index = this.children.indexOf( object );
9680
9681                 if ( index !== - 1 ) {
9682
9683                         object.parent = null;
9684                         this.children.splice( index, 1 );
9685
9686                         object.dispatchEvent( _removedEvent );
9687
9688                 }
9689
9690                 return this;
9691
9692         }
9693
9694         removeFromParent() {
9695
9696                 const parent = this.parent;
9697
9698                 if ( parent !== null ) {
9699
9700                         parent.remove( this );
9701
9702                 }
9703
9704                 return this;
9705
9706         }
9707
9708         clear() {
9709
9710                 for ( let i = 0; i < this.children.length; i ++ ) {
9711
9712                         const object = this.children[ i ];
9713
9714                         object.parent = null;
9715
9716                         object.dispatchEvent( _removedEvent );
9717
9718                 }
9719
9720                 this.children.length = 0;
9721
9722                 return this;
9723
9724
9725         }
9726
9727         attach( object ) {
9728
9729                 // adds object as a child of this, while maintaining the object's world transform
9730
9731                 this.updateWorldMatrix( true, false );
9732
9733                 _m1$1.copy( this.matrixWorld ).invert();
9734
9735                 if ( object.parent !== null ) {
9736
9737                         object.parent.updateWorldMatrix( true, false );
9738
9739                         _m1$1.multiply( object.parent.matrixWorld );
9740
9741                 }
9742
9743                 object.applyMatrix4( _m1$1 );
9744
9745                 this.add( object );
9746
9747                 object.updateWorldMatrix( false, true );
9748
9749                 return this;
9750
9751         }
9752
9753         getObjectById( id ) {
9754
9755                 return this.getObjectByProperty( 'id', id );
9756
9757         }
9758
9759         getObjectByName( name ) {
9760
9761                 return this.getObjectByProperty( 'name', name );
9762
9763         }
9764
9765         getObjectByProperty( name, value ) {
9766
9767                 if ( this[ name ] === value ) return this;
9768
9769                 for ( let i = 0, l = this.children.length; i < l; i ++ ) {
9770
9771                         const child = this.children[ i ];
9772                         const object = child.getObjectByProperty( name, value );
9773
9774                         if ( object !== undefined ) {
9775
9776                                 return object;
9777
9778                         }
9779
9780                 }
9781
9782                 return undefined;
9783
9784         }
9785
9786         getWorldPosition( target ) {
9787
9788                 this.updateWorldMatrix( true, false );
9789
9790                 return target.setFromMatrixPosition( this.matrixWorld );
9791
9792         }
9793
9794         getWorldQuaternion( target ) {
9795
9796                 this.updateWorldMatrix( true, false );
9797
9798                 this.matrixWorld.decompose( _position$3, target, _scale$2 );
9799
9800                 return target;
9801
9802         }
9803
9804         getWorldScale( target ) {
9805
9806                 this.updateWorldMatrix( true, false );
9807
9808                 this.matrixWorld.decompose( _position$3, _quaternion$2, target );
9809
9810                 return target;
9811
9812         }
9813
9814         getWorldDirection( target ) {
9815
9816                 this.updateWorldMatrix( true, false );
9817
9818                 const e = this.matrixWorld.elements;
9819
9820                 return target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize();
9821
9822         }
9823
9824         raycast() {}
9825
9826         traverse( callback ) {
9827
9828                 callback( this );
9829
9830                 const children = this.children;
9831
9832                 for ( let i = 0, l = children.length; i < l; i ++ ) {
9833
9834                         children[ i ].traverse( callback );
9835
9836                 }
9837
9838         }
9839
9840         traverseVisible( callback ) {
9841
9842                 if ( this.visible === false ) return;
9843
9844                 callback( this );
9845
9846                 const children = this.children;
9847
9848                 for ( let i = 0, l = children.length; i < l; i ++ ) {
9849
9850                         children[ i ].traverseVisible( callback );
9851
9852                 }
9853
9854         }
9855
9856         traverseAncestors( callback ) {
9857
9858                 const parent = this.parent;
9859
9860                 if ( parent !== null ) {
9861
9862                         callback( parent );
9863
9864                         parent.traverseAncestors( callback );
9865
9866                 }
9867
9868         }
9869
9870         updateMatrix() {
9871
9872                 this.matrix.compose( this.position, this.quaternion, this.scale );
9873
9874                 this.matrixWorldNeedsUpdate = true;
9875
9876         }
9877
9878         updateMatrixWorld( force ) {
9879
9880                 if ( this.matrixAutoUpdate ) this.updateMatrix();
9881
9882                 if ( this.matrixWorldNeedsUpdate || force ) {
9883
9884                         if ( this.parent === null ) {
9885
9886                                 this.matrixWorld.copy( this.matrix );
9887
9888                         } else {
9889
9890                                 this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
9891
9892                         }
9893
9894                         this.matrixWorldNeedsUpdate = false;
9895
9896                         force = true;
9897
9898                 }
9899
9900                 // update children
9901
9902                 const children = this.children;
9903
9904                 for ( let i = 0, l = children.length; i < l; i ++ ) {
9905
9906                         children[ i ].updateMatrixWorld( force );
9907
9908                 }
9909
9910         }
9911
9912         updateWorldMatrix( updateParents, updateChildren ) {
9913
9914                 const parent = this.parent;
9915
9916                 if ( updateParents === true && parent !== null ) {
9917
9918                         parent.updateWorldMatrix( true, false );
9919
9920                 }
9921
9922                 if ( this.matrixAutoUpdate ) this.updateMatrix();
9923
9924                 if ( this.parent === null ) {
9925
9926                         this.matrixWorld.copy( this.matrix );
9927
9928                 } else {
9929
9930                         this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
9931
9932                 }
9933
9934                 // update children
9935
9936                 if ( updateChildren === true ) {
9937
9938                         const children = this.children;
9939
9940                         for ( let i = 0, l = children.length; i < l; i ++ ) {
9941
9942                                 children[ i ].updateWorldMatrix( false, true );
9943
9944                         }
9945
9946                 }
9947
9948         }
9949
9950         toJSON( meta ) {
9951
9952                 // meta is a string when called from JSON.stringify
9953                 const isRootObject = ( meta === undefined || typeof meta === 'string' );
9954
9955                 const output = {};
9956
9957                 // meta is a hash used to collect geometries, materials.
9958                 // not providing it implies that this is the root object
9959                 // being serialized.
9960                 if ( isRootObject ) {
9961
9962                         // initialize meta obj
9963                         meta = {
9964                                 geometries: {},
9965                                 materials: {},
9966                                 textures: {},
9967                                 images: {},
9968                                 shapes: {},
9969                                 skeletons: {},
9970                                 animations: {}
9971                         };
9972
9973                         output.metadata = {
9974                                 version: 4.5,
9975                                 type: 'Object',
9976                                 generator: 'Object3D.toJSON'
9977                         };
9978
9979                 }
9980
9981                 // standard Object3D serialization
9982
9983                 const object = {};
9984
9985                 object.uuid = this.uuid;
9986                 object.type = this.type;
9987
9988                 if ( this.name !== '' ) object.name = this.name;
9989                 if ( this.castShadow === true ) object.castShadow = true;
9990                 if ( this.receiveShadow === true ) object.receiveShadow = true;
9991                 if ( this.visible === false ) object.visible = false;
9992                 if ( this.frustumCulled === false ) object.frustumCulled = false;
9993                 if ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder;
9994                 if ( JSON.stringify( this.userData ) !== '{}' ) object.userData = this.userData;
9995
9996                 object.layers = this.layers.mask;
9997                 object.matrix = this.matrix.toArray();
9998
9999                 if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false;
10000
10001                 // object specific properties
10002
10003                 if ( this.isInstancedMesh ) {
10004
10005                         object.type = 'InstancedMesh';
10006                         object.count = this.count;
10007                         object.instanceMatrix = this.instanceMatrix.toJSON();
10008                         if ( this.instanceColor !== null ) object.instanceColor = this.instanceColor.toJSON();
10009
10010                 }
10011
10012                 //
10013
10014                 function serialize( library, element ) {
10015
10016                         if ( library[ element.uuid ] === undefined ) {
10017
10018                                 library[ element.uuid ] = element.toJSON( meta );
10019
10020                         }
10021
10022                         return element.uuid;
10023
10024                 }
10025
10026                 if ( this.isScene ) {
10027
10028                         if ( this.background ) {
10029
10030                                 if ( this.background.isColor ) {
10031
10032                                         object.background = this.background.toJSON();
10033
10034                                 } else if ( this.background.isTexture ) {
10035
10036                                         object.background = this.background.toJSON( meta ).uuid;
10037
10038                                 }
10039
10040                         }
10041
10042                         if ( this.environment && this.environment.isTexture ) {
10043
10044                                 object.environment = this.environment.toJSON( meta ).uuid;
10045
10046                         }
10047
10048                 } else if ( this.isMesh || this.isLine || this.isPoints ) {
10049
10050                         object.geometry = serialize( meta.geometries, this.geometry );
10051
10052                         const parameters = this.geometry.parameters;
10053
10054                         if ( parameters !== undefined && parameters.shapes !== undefined ) {
10055
10056                                 const shapes = parameters.shapes;
10057
10058                                 if ( Array.isArray( shapes ) ) {
10059
10060                                         for ( let i = 0, l = shapes.length; i < l; i ++ ) {
10061
10062                                                 const shape = shapes[ i ];
10063
10064                                                 serialize( meta.shapes, shape );
10065
10066                                         }
10067
10068                                 } else {
10069
10070                                         serialize( meta.shapes, shapes );
10071
10072                                 }
10073
10074                         }
10075
10076                 }
10077
10078                 if ( this.isSkinnedMesh ) {
10079
10080                         object.bindMode = this.bindMode;
10081                         object.bindMatrix = this.bindMatrix.toArray();
10082
10083                         if ( this.skeleton !== undefined ) {
10084
10085                                 serialize( meta.skeletons, this.skeleton );
10086
10087                                 object.skeleton = this.skeleton.uuid;
10088
10089                         }
10090
10091                 }
10092
10093                 if ( this.material !== undefined ) {
10094
10095                         if ( Array.isArray( this.material ) ) {
10096
10097                                 const uuids = [];
10098
10099                                 for ( let i = 0, l = this.material.length; i < l; i ++ ) {
10100
10101                                         uuids.push( serialize( meta.materials, this.material[ i ] ) );
10102
10103                                 }
10104
10105                                 object.material = uuids;
10106
10107                         } else {
10108
10109                                 object.material = serialize( meta.materials, this.material );
10110
10111                         }
10112
10113                 }
10114
10115                 //
10116
10117                 if ( this.children.length > 0 ) {
10118
10119                         object.children = [];
10120
10121                         for ( let i = 0; i < this.children.length; i ++ ) {
10122
10123                                 object.children.push( this.children[ i ].toJSON( meta ).object );
10124
10125                         }
10126
10127                 }
10128
10129                 //
10130
10131                 if ( this.animations.length > 0 ) {
10132
10133                         object.animations = [];
10134
10135                         for ( let i = 0; i < this.animations.length; i ++ ) {
10136
10137                                 const animation = this.animations[ i ];
10138
10139                                 object.animations.push( serialize( meta.animations, animation ) );
10140
10141                         }
10142
10143                 }
10144
10145                 if ( isRootObject ) {
10146
10147                         const geometries = extractFromCache( meta.geometries );
10148                         const materials = extractFromCache( meta.materials );
10149                         const textures = extractFromCache( meta.textures );
10150                         const images = extractFromCache( meta.images );
10151                         const shapes = extractFromCache( meta.shapes );
10152                         const skeletons = extractFromCache( meta.skeletons );
10153                         const animations = extractFromCache( meta.animations );
10154
10155                         if ( geometries.length > 0 ) output.geometries = geometries;
10156                         if ( materials.length > 0 ) output.materials = materials;
10157                         if ( textures.length > 0 ) output.textures = textures;
10158                         if ( images.length > 0 ) output.images = images;
10159                         if ( shapes.length > 0 ) output.shapes = shapes;
10160                         if ( skeletons.length > 0 ) output.skeletons = skeletons;
10161                         if ( animations.length > 0 ) output.animations = animations;
10162
10163                 }
10164
10165                 output.object = object;
10166
10167                 return output;
10168
10169                 // extract data from the cache hash
10170                 // remove metadata on each item
10171                 // and return as array
10172                 function extractFromCache( cache ) {
10173
10174                         const values = [];
10175                         for ( const key in cache ) {
10176
10177                                 const data = cache[ key ];
10178                                 delete data.metadata;
10179                                 values.push( data );
10180
10181                         }
10182
10183                         return values;
10184
10185                 }
10186
10187         }
10188
10189         clone( recursive ) {
10190
10191                 return new this.constructor().copy( this, recursive );
10192
10193         }
10194
10195         copy( source, recursive = true ) {
10196
10197                 this.name = source.name;
10198
10199                 this.up.copy( source.up );
10200
10201                 this.position.copy( source.position );
10202                 this.rotation.order = source.rotation.order;
10203                 this.quaternion.copy( source.quaternion );
10204                 this.scale.copy( source.scale );
10205
10206                 this.matrix.copy( source.matrix );
10207                 this.matrixWorld.copy( source.matrixWorld );
10208
10209                 this.matrixAutoUpdate = source.matrixAutoUpdate;
10210                 this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;
10211
10212                 this.layers.mask = source.layers.mask;
10213                 this.visible = source.visible;
10214
10215                 this.castShadow = source.castShadow;
10216                 this.receiveShadow = source.receiveShadow;
10217
10218                 this.frustumCulled = source.frustumCulled;
10219                 this.renderOrder = source.renderOrder;
10220
10221                 this.userData = JSON.parse( JSON.stringify( source.userData ) );
10222
10223                 if ( recursive === true ) {
10224
10225                         for ( let i = 0; i < source.children.length; i ++ ) {
10226
10227                                 const child = source.children[ i ];
10228                                 this.add( child.clone() );
10229
10230                         }
10231
10232                 }
10233
10234                 return this;
10235
10236         }
10237
10238 }
10239
10240 Object3D.DefaultUp = new Vector3( 0, 1, 0 );
10241 Object3D.DefaultMatrixAutoUpdate = true;
10242
10243 Object3D.prototype.isObject3D = true;
10244
10245 const _v0$1 = /*@__PURE__*/ new Vector3();
10246 const _v1$3 = /*@__PURE__*/ new Vector3();
10247 const _v2$2 = /*@__PURE__*/ new Vector3();
10248 const _v3$1 = /*@__PURE__*/ new Vector3();
10249
10250 const _vab = /*@__PURE__*/ new Vector3();
10251 const _vac = /*@__PURE__*/ new Vector3();
10252 const _vbc = /*@__PURE__*/ new Vector3();
10253 const _vap = /*@__PURE__*/ new Vector3();
10254 const _vbp = /*@__PURE__*/ new Vector3();
10255 const _vcp = /*@__PURE__*/ new Vector3();
10256
10257 class Triangle {
10258
10259         constructor( a = new Vector3(), b = new Vector3(), c = new Vector3() ) {
10260
10261                 this.a = a;
10262                 this.b = b;
10263                 this.c = c;
10264
10265         }
10266
10267         static getNormal( a, b, c, target ) {
10268
10269                 target.subVectors( c, b );
10270                 _v0$1.subVectors( a, b );
10271                 target.cross( _v0$1 );
10272
10273                 const targetLengthSq = target.lengthSq();
10274                 if ( targetLengthSq > 0 ) {
10275
10276                         return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) );
10277
10278                 }
10279
10280                 return target.set( 0, 0, 0 );
10281
10282         }
10283
10284         // static/instance method to calculate barycentric coordinates
10285         // based on: http://www.blackpawn.com/texts/pointinpoly/default.html
10286         static getBarycoord( point, a, b, c, target ) {
10287
10288                 _v0$1.subVectors( c, a );
10289                 _v1$3.subVectors( b, a );
10290                 _v2$2.subVectors( point, a );
10291
10292                 const dot00 = _v0$1.dot( _v0$1 );
10293                 const dot01 = _v0$1.dot( _v1$3 );
10294                 const dot02 = _v0$1.dot( _v2$2 );
10295                 const dot11 = _v1$3.dot( _v1$3 );
10296                 const dot12 = _v1$3.dot( _v2$2 );
10297
10298                 const denom = ( dot00 * dot11 - dot01 * dot01 );
10299
10300                 // collinear or singular triangle
10301                 if ( denom === 0 ) {
10302
10303                         // arbitrary location outside of triangle?
10304                         // not sure if this is the best idea, maybe should be returning undefined
10305                         return target.set( - 2, - 1, - 1 );
10306
10307                 }
10308
10309                 const invDenom = 1 / denom;
10310                 const u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
10311                 const v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
10312
10313                 // barycentric coordinates must always sum to 1
10314                 return target.set( 1 - u - v, v, u );
10315
10316         }
10317
10318         static containsPoint( point, a, b, c ) {
10319
10320                 this.getBarycoord( point, a, b, c, _v3$1 );
10321
10322                 return ( _v3$1.x >= 0 ) && ( _v3$1.y >= 0 ) && ( ( _v3$1.x + _v3$1.y ) <= 1 );
10323
10324         }
10325
10326         static getUV( point, p1, p2, p3, uv1, uv2, uv3, target ) {
10327
10328                 this.getBarycoord( point, p1, p2, p3, _v3$1 );
10329
10330                 target.set( 0, 0 );
10331                 target.addScaledVector( uv1, _v3$1.x );
10332                 target.addScaledVector( uv2, _v3$1.y );
10333                 target.addScaledVector( uv3, _v3$1.z );
10334
10335                 return target;
10336
10337         }
10338
10339         static isFrontFacing( a, b, c, direction ) {
10340
10341                 _v0$1.subVectors( c, b );
10342                 _v1$3.subVectors( a, b );
10343
10344                 // strictly front facing
10345                 return ( _v0$1.cross( _v1$3 ).dot( direction ) < 0 ) ? true : false;
10346
10347         }
10348
10349         set( a, b, c ) {
10350
10351                 this.a.copy( a );
10352                 this.b.copy( b );
10353                 this.c.copy( c );
10354
10355                 return this;
10356
10357         }
10358
10359         setFromPointsAndIndices( points, i0, i1, i2 ) {
10360
10361                 this.a.copy( points[ i0 ] );
10362                 this.b.copy( points[ i1 ] );
10363                 this.c.copy( points[ i2 ] );
10364
10365                 return this;
10366
10367         }
10368
10369         setFromAttributeAndIndices( attribute, i0, i1, i2 ) {
10370
10371                 this.a.fromBufferAttribute( attribute, i0 );
10372                 this.b.fromBufferAttribute( attribute, i1 );
10373                 this.c.fromBufferAttribute( attribute, i2 );
10374
10375                 return this;
10376
10377         }
10378
10379         clone() {
10380
10381                 return new this.constructor().copy( this );
10382
10383         }
10384
10385         copy( triangle ) {
10386
10387                 this.a.copy( triangle.a );
10388                 this.b.copy( triangle.b );
10389                 this.c.copy( triangle.c );
10390
10391                 return this;
10392
10393         }
10394
10395         getArea() {
10396
10397                 _v0$1.subVectors( this.c, this.b );
10398                 _v1$3.subVectors( this.a, this.b );
10399
10400                 return _v0$1.cross( _v1$3 ).length() * 0.5;
10401
10402         }
10403
10404         getMidpoint( target ) {
10405
10406                 return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 );
10407
10408         }
10409
10410         getNormal( target ) {
10411
10412                 return Triangle.getNormal( this.a, this.b, this.c, target );
10413
10414         }
10415
10416         getPlane( target ) {
10417
10418                 return target.setFromCoplanarPoints( this.a, this.b, this.c );
10419
10420         }
10421
10422         getBarycoord( point, target ) {
10423
10424                 return Triangle.getBarycoord( point, this.a, this.b, this.c, target );
10425
10426         }
10427
10428         getUV( point, uv1, uv2, uv3, target ) {
10429
10430                 return Triangle.getUV( point, this.a, this.b, this.c, uv1, uv2, uv3, target );
10431
10432         }
10433
10434         containsPoint( point ) {
10435
10436                 return Triangle.containsPoint( point, this.a, this.b, this.c );
10437
10438         }
10439
10440         isFrontFacing( direction ) {
10441
10442                 return Triangle.isFrontFacing( this.a, this.b, this.c, direction );
10443
10444         }
10445
10446         intersectsBox( box ) {
10447
10448                 return box.intersectsTriangle( this );
10449
10450         }
10451
10452         closestPointToPoint( p, target ) {
10453
10454                 const a = this.a, b = this.b, c = this.c;
10455                 let v, w;
10456
10457                 // algorithm thanks to Real-Time Collision Detection by Christer Ericson,
10458                 // published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc.,
10459                 // under the accompanying license; see chapter 5.1.5 for detailed explanation.
10460                 // basically, we're distinguishing which of the voronoi regions of the triangle
10461                 // the point lies in with the minimum amount of redundant computation.
10462
10463                 _vab.subVectors( b, a );
10464                 _vac.subVectors( c, a );
10465                 _vap.subVectors( p, a );
10466                 const d1 = _vab.dot( _vap );
10467                 const d2 = _vac.dot( _vap );
10468                 if ( d1 <= 0 && d2 <= 0 ) {
10469
10470                         // vertex region of A; barycentric coords (1, 0, 0)
10471                         return target.copy( a );
10472
10473                 }
10474
10475                 _vbp.subVectors( p, b );
10476                 const d3 = _vab.dot( _vbp );
10477                 const d4 = _vac.dot( _vbp );
10478                 if ( d3 >= 0 && d4 <= d3 ) {
10479
10480                         // vertex region of B; barycentric coords (0, 1, 0)
10481                         return target.copy( b );
10482
10483                 }
10484
10485                 const vc = d1 * d4 - d3 * d2;
10486                 if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) {
10487
10488                         v = d1 / ( d1 - d3 );
10489                         // edge region of AB; barycentric coords (1-v, v, 0)
10490                         return target.copy( a ).addScaledVector( _vab, v );
10491
10492                 }
10493
10494                 _vcp.subVectors( p, c );
10495                 const d5 = _vab.dot( _vcp );
10496                 const d6 = _vac.dot( _vcp );
10497                 if ( d6 >= 0 && d5 <= d6 ) {
10498
10499                         // vertex region of C; barycentric coords (0, 0, 1)
10500                         return target.copy( c );
10501
10502                 }
10503
10504                 const vb = d5 * d2 - d1 * d6;
10505                 if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) {
10506
10507                         w = d2 / ( d2 - d6 );
10508                         // edge region of AC; barycentric coords (1-w, 0, w)
10509                         return target.copy( a ).addScaledVector( _vac, w );
10510
10511                 }
10512
10513                 const va = d3 * d6 - d5 * d4;
10514                 if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) {
10515
10516                         _vbc.subVectors( c, b );
10517                         w = ( d4 - d3 ) / ( ( d4 - d3 ) + ( d5 - d6 ) );
10518                         // edge region of BC; barycentric coords (0, 1-w, w)
10519                         return target.copy( b ).addScaledVector( _vbc, w ); // edge region of BC
10520
10521                 }
10522
10523                 // face region
10524                 const denom = 1 / ( va + vb + vc );
10525                 // u = va * denom
10526                 v = vb * denom;
10527                 w = vc * denom;
10528
10529                 return target.copy( a ).addScaledVector( _vab, v ).addScaledVector( _vac, w );
10530
10531         }
10532
10533         equals( triangle ) {
10534
10535                 return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c );
10536
10537         }
10538
10539 }
10540
10541 let materialId = 0;
10542
10543 class Material extends EventDispatcher {
10544
10545         constructor() {
10546
10547                 super();
10548
10549                 Object.defineProperty( this, 'id', { value: materialId ++ } );
10550
10551                 this.uuid = generateUUID();
10552
10553                 this.name = '';
10554                 this.type = 'Material';
10555
10556                 this.fog = true;
10557
10558                 this.blending = NormalBlending;
10559                 this.side = FrontSide;
10560                 this.vertexColors = false;
10561
10562                 this.opacity = 1;
10563                 this.format = RGBAFormat;
10564                 this.transparent = false;
10565
10566                 this.blendSrc = SrcAlphaFactor;
10567                 this.blendDst = OneMinusSrcAlphaFactor;
10568                 this.blendEquation = AddEquation;
10569                 this.blendSrcAlpha = null;
10570                 this.blendDstAlpha = null;
10571                 this.blendEquationAlpha = null;
10572
10573                 this.depthFunc = LessEqualDepth;
10574                 this.depthTest = true;
10575                 this.depthWrite = true;
10576
10577                 this.stencilWriteMask = 0xff;
10578                 this.stencilFunc = AlwaysStencilFunc;
10579                 this.stencilRef = 0;
10580                 this.stencilFuncMask = 0xff;
10581                 this.stencilFail = KeepStencilOp;
10582                 this.stencilZFail = KeepStencilOp;
10583                 this.stencilZPass = KeepStencilOp;
10584                 this.stencilWrite = false;
10585
10586                 this.clippingPlanes = null;
10587                 this.clipIntersection = false;
10588                 this.clipShadows = false;
10589
10590                 this.shadowSide = null;
10591
10592                 this.colorWrite = true;
10593
10594                 this.precision = null; // override the renderer's default precision for this material
10595
10596                 this.polygonOffset = false;
10597                 this.polygonOffsetFactor = 0;
10598                 this.polygonOffsetUnits = 0;
10599
10600                 this.dithering = false;
10601
10602                 this.alphaToCoverage = false;
10603                 this.premultipliedAlpha = false;
10604
10605                 this.visible = true;
10606
10607                 this.toneMapped = true;
10608
10609                 this.userData = {};
10610
10611                 this.version = 0;
10612
10613                 this._alphaTest = 0;
10614
10615         }
10616
10617         get alphaTest() {
10618
10619                 return this._alphaTest;
10620
10621         }
10622
10623         set alphaTest( value ) {
10624
10625                 if ( this._alphaTest > 0 !== value > 0 ) {
10626
10627                         this.version ++;
10628
10629                 }
10630
10631                 this._alphaTest = value;
10632
10633         }
10634
10635         onBuild( /* shaderobject, renderer */ ) {}
10636
10637         onBeforeRender( /* renderer, scene, camera, geometry, object, group */ ) {}
10638
10639         onBeforeCompile( /* shaderobject, renderer */ ) {}
10640
10641         customProgramCacheKey() {
10642
10643                 return this.onBeforeCompile.toString();
10644
10645         }
10646
10647         setValues( values ) {
10648
10649                 if ( values === undefined ) return;
10650
10651                 for ( const key in values ) {
10652
10653                         const newValue = values[ key ];
10654
10655                         if ( newValue === undefined ) {
10656
10657                                 console.warn( 'THREE.Material: \'' + key + '\' parameter is undefined.' );
10658                                 continue;
10659
10660                         }
10661
10662                         // for backward compatability if shading is set in the constructor
10663                         if ( key === 'shading' ) {
10664
10665                                 console.warn( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' );
10666                                 this.flatShading = ( newValue === FlatShading ) ? true : false;
10667                                 continue;
10668
10669                         }
10670
10671                         const currentValue = this[ key ];
10672
10673                         if ( currentValue === undefined ) {
10674
10675                                 console.warn( 'THREE.' + this.type + ': \'' + key + '\' is not a property of this material.' );
10676                                 continue;
10677
10678                         }
10679
10680                         if ( currentValue && currentValue.isColor ) {
10681
10682                                 currentValue.set( newValue );
10683
10684                         } else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) {
10685
10686                                 currentValue.copy( newValue );
10687
10688                         } else {
10689
10690                                 this[ key ] = newValue;
10691
10692                         }
10693
10694                 }
10695
10696         }
10697
10698         toJSON( meta ) {
10699
10700                 const isRoot = ( meta === undefined || typeof meta === 'string' );
10701
10702                 if ( isRoot ) {
10703
10704                         meta = {
10705                                 textures: {},
10706                                 images: {}
10707                         };
10708
10709                 }
10710
10711                 const data = {
10712                         metadata: {
10713                                 version: 4.5,
10714                                 type: 'Material',
10715                                 generator: 'Material.toJSON'
10716                         }
10717                 };
10718
10719                 // standard Material serialization
10720                 data.uuid = this.uuid;
10721                 data.type = this.type;
10722
10723                 if ( this.name !== '' ) data.name = this.name;
10724
10725                 if ( this.color && this.color.isColor ) data.color = this.color.getHex();
10726
10727                 if ( this.roughness !== undefined ) data.roughness = this.roughness;
10728                 if ( this.metalness !== undefined ) data.metalness = this.metalness;
10729
10730                 if ( this.sheen !== undefined ) data.sheen = this.sheen;
10731                 if ( this.sheenColor && this.sheenColor.isColor ) data.sheenColor = this.sheenColor.getHex();
10732                 if ( this.sheenRoughness !== undefined ) data.sheenRoughness = this.sheenRoughness;
10733                 if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex();
10734                 if ( this.emissiveIntensity && this.emissiveIntensity !== 1 ) data.emissiveIntensity = this.emissiveIntensity;
10735
10736                 if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex();
10737                 if ( this.specularIntensity !== undefined ) data.specularIntensity = this.specularIntensity;
10738                 if ( this.specularColor && this.specularColor.isColor ) data.specularColor = this.specularColor.getHex();
10739                 if ( this.shininess !== undefined ) data.shininess = this.shininess;
10740                 if ( this.clearcoat !== undefined ) data.clearcoat = this.clearcoat;
10741                 if ( this.clearcoatRoughness !== undefined ) data.clearcoatRoughness = this.clearcoatRoughness;
10742
10743                 if ( this.clearcoatMap && this.clearcoatMap.isTexture ) {
10744
10745                         data.clearcoatMap = this.clearcoatMap.toJSON( meta ).uuid;
10746
10747                 }
10748
10749                 if ( this.clearcoatRoughnessMap && this.clearcoatRoughnessMap.isTexture ) {
10750
10751                         data.clearcoatRoughnessMap = this.clearcoatRoughnessMap.toJSON( meta ).uuid;
10752
10753                 }
10754
10755                 if ( this.clearcoatNormalMap && this.clearcoatNormalMap.isTexture ) {
10756
10757                         data.clearcoatNormalMap = this.clearcoatNormalMap.toJSON( meta ).uuid;
10758                         data.clearcoatNormalScale = this.clearcoatNormalScale.toArray();
10759
10760                 }
10761
10762                 if ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid;
10763                 if ( this.matcap && this.matcap.isTexture ) data.matcap = this.matcap.toJSON( meta ).uuid;
10764                 if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid;
10765
10766                 if ( this.lightMap && this.lightMap.isTexture ) {
10767
10768                         data.lightMap = this.lightMap.toJSON( meta ).uuid;
10769                         data.lightMapIntensity = this.lightMapIntensity;
10770
10771                 }
10772
10773                 if ( this.aoMap && this.aoMap.isTexture ) {
10774
10775                         data.aoMap = this.aoMap.toJSON( meta ).uuid;
10776                         data.aoMapIntensity = this.aoMapIntensity;
10777
10778                 }
10779
10780                 if ( this.bumpMap && this.bumpMap.isTexture ) {
10781
10782                         data.bumpMap = this.bumpMap.toJSON( meta ).uuid;
10783                         data.bumpScale = this.bumpScale;
10784
10785                 }
10786
10787                 if ( this.normalMap && this.normalMap.isTexture ) {
10788
10789                         data.normalMap = this.normalMap.toJSON( meta ).uuid;
10790                         data.normalMapType = this.normalMapType;
10791                         data.normalScale = this.normalScale.toArray();
10792
10793                 }
10794
10795                 if ( this.displacementMap && this.displacementMap.isTexture ) {
10796
10797                         data.displacementMap = this.displacementMap.toJSON( meta ).uuid;
10798                         data.displacementScale = this.displacementScale;
10799                         data.displacementBias = this.displacementBias;
10800
10801                 }
10802
10803                 if ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid;
10804                 if ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid;
10805
10806                 if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid;
10807                 if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid;
10808                 if ( this.specularIntensityMap && this.specularIntensityMap.isTexture ) data.specularIntensityMap = this.specularIntensityMap.toJSON( meta ).uuid;
10809                 if ( this.specularColorMap && this.specularColorMap.isTexture ) data.specularColorMap = this.specularColorMap.toJSON( meta ).uuid;
10810
10811                 if ( this.envMap && this.envMap.isTexture ) {
10812
10813                         data.envMap = this.envMap.toJSON( meta ).uuid;
10814
10815                         if ( this.combine !== undefined ) data.combine = this.combine;
10816
10817                 }
10818
10819                 if ( this.envMapIntensity !== undefined ) data.envMapIntensity = this.envMapIntensity;
10820                 if ( this.reflectivity !== undefined ) data.reflectivity = this.reflectivity;
10821                 if ( this.refractionRatio !== undefined ) data.refractionRatio = this.refractionRatio;
10822
10823                 if ( this.gradientMap && this.gradientMap.isTexture ) {
10824
10825                         data.gradientMap = this.gradientMap.toJSON( meta ).uuid;
10826
10827                 }
10828
10829                 if ( this.transmission !== undefined ) data.transmission = this.transmission;
10830                 if ( this.transmissionMap && this.transmissionMap.isTexture ) data.transmissionMap = this.transmissionMap.toJSON( meta ).uuid;
10831                 if ( this.thickness !== undefined ) data.thickness = this.thickness;
10832                 if ( this.thicknessMap && this.thicknessMap.isTexture ) data.thicknessMap = this.thicknessMap.toJSON( meta ).uuid;
10833                 if ( this.attenuationDistance !== undefined ) data.attenuationDistance = this.attenuationDistance;
10834                 if ( this.attenuationColor !== undefined ) data.attenuationColor = this.attenuationColor.getHex();
10835
10836                 if ( this.size !== undefined ) data.size = this.size;
10837                 if ( this.shadowSide !== null ) data.shadowSide = this.shadowSide;
10838                 if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation;
10839
10840                 if ( this.blending !== NormalBlending ) data.blending = this.blending;
10841                 if ( this.side !== FrontSide ) data.side = this.side;
10842                 if ( this.vertexColors ) data.vertexColors = true;
10843
10844                 if ( this.opacity < 1 ) data.opacity = this.opacity;
10845                 if ( this.format !== RGBAFormat ) data.format = this.format;
10846                 if ( this.transparent === true ) data.transparent = this.transparent;
10847
10848                 data.depthFunc = this.depthFunc;
10849                 data.depthTest = this.depthTest;
10850                 data.depthWrite = this.depthWrite;
10851                 data.colorWrite = this.colorWrite;
10852
10853                 data.stencilWrite = this.stencilWrite;
10854                 data.stencilWriteMask = this.stencilWriteMask;
10855                 data.stencilFunc = this.stencilFunc;
10856                 data.stencilRef = this.stencilRef;
10857                 data.stencilFuncMask = this.stencilFuncMask;
10858                 data.stencilFail = this.stencilFail;
10859                 data.stencilZFail = this.stencilZFail;
10860                 data.stencilZPass = this.stencilZPass;
10861
10862                 // rotation (SpriteMaterial)
10863                 if ( this.rotation && this.rotation !== 0 ) data.rotation = this.rotation;
10864
10865                 if ( this.polygonOffset === true ) data.polygonOffset = true;
10866                 if ( this.polygonOffsetFactor !== 0 ) data.polygonOffsetFactor = this.polygonOffsetFactor;
10867                 if ( this.polygonOffsetUnits !== 0 ) data.polygonOffsetUnits = this.polygonOffsetUnits;
10868
10869                 if ( this.linewidth && this.linewidth !== 1 ) data.linewidth = this.linewidth;
10870                 if ( this.dashSize !== undefined ) data.dashSize = this.dashSize;
10871                 if ( this.gapSize !== undefined ) data.gapSize = this.gapSize;
10872                 if ( this.scale !== undefined ) data.scale = this.scale;
10873
10874                 if ( this.dithering === true ) data.dithering = true;
10875
10876                 if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest;
10877                 if ( this.alphaToCoverage === true ) data.alphaToCoverage = this.alphaToCoverage;
10878                 if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = this.premultipliedAlpha;
10879
10880                 if ( this.wireframe === true ) data.wireframe = this.wireframe;
10881                 if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth;
10882                 if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap;
10883                 if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin;
10884
10885                 if ( this.flatShading === true ) data.flatShading = this.flatShading;
10886
10887                 if ( this.visible === false ) data.visible = false;
10888
10889                 if ( this.toneMapped === false ) data.toneMapped = false;
10890
10891                 if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData;
10892
10893                 // TODO: Copied from Object3D.toJSON
10894
10895                 function extractFromCache( cache ) {
10896
10897                         const values = [];
10898
10899                         for ( const key in cache ) {
10900
10901                                 const data = cache[ key ];
10902                                 delete data.metadata;
10903                                 values.push( data );
10904
10905                         }
10906
10907                         return values;
10908
10909                 }
10910
10911                 if ( isRoot ) {
10912
10913                         const textures = extractFromCache( meta.textures );
10914                         const images = extractFromCache( meta.images );
10915
10916                         if ( textures.length > 0 ) data.textures = textures;
10917                         if ( images.length > 0 ) data.images = images;
10918
10919                 }
10920
10921                 return data;
10922
10923         }
10924
10925         clone() {
10926
10927                 return new this.constructor().copy( this );
10928
10929         }
10930
10931         copy( source ) {
10932
10933                 this.name = source.name;
10934
10935                 this.fog = source.fog;
10936
10937                 this.blending = source.blending;
10938                 this.side = source.side;
10939                 this.vertexColors = source.vertexColors;
10940
10941                 this.opacity = source.opacity;
10942                 this.format = source.format;
10943                 this.transparent = source.transparent;
10944
10945                 this.blendSrc = source.blendSrc;
10946                 this.blendDst = source.blendDst;
10947                 this.blendEquation = source.blendEquation;
10948                 this.blendSrcAlpha = source.blendSrcAlpha;
10949                 this.blendDstAlpha = source.blendDstAlpha;
10950                 this.blendEquationAlpha = source.blendEquationAlpha;
10951
10952                 this.depthFunc = source.depthFunc;
10953                 this.depthTest = source.depthTest;
10954                 this.depthWrite = source.depthWrite;
10955
10956                 this.stencilWriteMask = source.stencilWriteMask;
10957                 this.stencilFunc = source.stencilFunc;
10958                 this.stencilRef = source.stencilRef;
10959                 this.stencilFuncMask = source.stencilFuncMask;
10960                 this.stencilFail = source.stencilFail;
10961                 this.stencilZFail = source.stencilZFail;
10962                 this.stencilZPass = source.stencilZPass;
10963                 this.stencilWrite = source.stencilWrite;
10964
10965                 const srcPlanes = source.clippingPlanes;
10966                 let dstPlanes = null;
10967
10968                 if ( srcPlanes !== null ) {
10969
10970                         const n = srcPlanes.length;
10971                         dstPlanes = new Array( n );
10972
10973                         for ( let i = 0; i !== n; ++ i ) {
10974
10975                                 dstPlanes[ i ] = srcPlanes[ i ].clone();
10976
10977                         }
10978
10979                 }
10980
10981                 this.clippingPlanes = dstPlanes;
10982                 this.clipIntersection = source.clipIntersection;
10983                 this.clipShadows = source.clipShadows;
10984
10985                 this.shadowSide = source.shadowSide;
10986
10987                 this.colorWrite = source.colorWrite;
10988
10989                 this.precision = source.precision;
10990
10991                 this.polygonOffset = source.polygonOffset;
10992                 this.polygonOffsetFactor = source.polygonOffsetFactor;
10993                 this.polygonOffsetUnits = source.polygonOffsetUnits;
10994
10995                 this.dithering = source.dithering;
10996
10997                 this.alphaTest = source.alphaTest;
10998                 this.alphaToCoverage = source.alphaToCoverage;
10999                 this.premultipliedAlpha = source.premultipliedAlpha;
11000
11001                 this.visible = source.visible;
11002
11003                 this.toneMapped = source.toneMapped;
11004
11005                 this.userData = JSON.parse( JSON.stringify( source.userData ) );
11006
11007                 return this;
11008
11009         }
11010
11011         dispose() {
11012
11013                 this.dispatchEvent( { type: 'dispose' } );
11014
11015         }
11016
11017         set needsUpdate( value ) {
11018
11019                 if ( value === true ) this.version ++;
11020
11021         }
11022
11023 }
11024
11025 Material.prototype.isMaterial = true;
11026
11027 const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,
11028         'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,
11029         'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50,
11030         'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B,
11031         'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B,
11032         'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F,
11033         'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3,
11034         'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222,
11035         'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700,
11036         'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4,
11037         'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00,
11038         'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3,
11039         'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA,
11040         'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32,
11041         'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3,
11042         'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC,
11043         'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD,
11044         'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6,
11045         'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9,
11046         'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F,
11047         'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE,
11048         'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA,
11049         'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,
11050         'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };
11051
11052 const _hslA = { h: 0, s: 0, l: 0 };
11053 const _hslB = { h: 0, s: 0, l: 0 };
11054
11055 function hue2rgb( p, q, t ) {
11056
11057         if ( t < 0 ) t += 1;
11058         if ( t > 1 ) t -= 1;
11059         if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t;
11060         if ( t < 1 / 2 ) return q;
11061         if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t );
11062         return p;
11063
11064 }
11065
11066 function SRGBToLinear( c ) {
11067
11068         return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 );
11069
11070 }
11071
11072 function LinearToSRGB( c ) {
11073
11074         return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055;
11075
11076 }
11077
11078 class Color {
11079
11080         constructor( r, g, b ) {
11081
11082                 if ( g === undefined && b === undefined ) {
11083
11084                         // r is THREE.Color, hex or string
11085                         return this.set( r );
11086
11087                 }
11088
11089                 return this.setRGB( r, g, b );
11090
11091         }
11092
11093         set( value ) {
11094
11095                 if ( value && value.isColor ) {
11096
11097                         this.copy( value );
11098
11099                 } else if ( typeof value === 'number' ) {
11100
11101                         this.setHex( value );
11102
11103                 } else if ( typeof value === 'string' ) {
11104
11105                         this.setStyle( value );
11106
11107                 }
11108
11109                 return this;
11110
11111         }
11112
11113         setScalar( scalar ) {
11114
11115                 this.r = scalar;
11116                 this.g = scalar;
11117                 this.b = scalar;
11118
11119                 return this;
11120
11121         }
11122
11123         setHex( hex ) {
11124
11125                 hex = Math.floor( hex );
11126
11127                 this.r = ( hex >> 16 & 255 ) / 255;
11128                 this.g = ( hex >> 8 & 255 ) / 255;
11129                 this.b = ( hex & 255 ) / 255;
11130
11131                 return this;
11132
11133         }
11134
11135         setRGB( r, g, b ) {
11136
11137                 this.r = r;
11138                 this.g = g;
11139                 this.b = b;
11140
11141                 return this;
11142
11143         }
11144
11145         setHSL( h, s, l ) {
11146
11147                 // h,s,l ranges are in 0.0 - 1.0
11148                 h = euclideanModulo( h, 1 );
11149                 s = clamp$1( s, 0, 1 );
11150                 l = clamp$1( l, 0, 1 );
11151
11152                 if ( s === 0 ) {
11153
11154                         this.r = this.g = this.b = l;
11155
11156                 } else {
11157
11158                         const p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s );
11159                         const q = ( 2 * l ) - p;
11160
11161                         this.r = hue2rgb( q, p, h + 1 / 3 );
11162                         this.g = hue2rgb( q, p, h );
11163                         this.b = hue2rgb( q, p, h - 1 / 3 );
11164
11165                 }
11166
11167                 return this;
11168
11169         }
11170
11171         setStyle( style ) {
11172
11173                 function handleAlpha( string ) {
11174
11175                         if ( string === undefined ) return;
11176
11177                         if ( parseFloat( string ) < 1 ) {
11178
11179                                 console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' );
11180
11181                         }
11182
11183                 }
11184
11185
11186                 let m;
11187
11188                 if ( m = /^((?:rgb|hsl)a?)\(([^\)]*)\)/.exec( style ) ) {
11189
11190                         // rgb / hsl
11191
11192                         let color;
11193                         const name = m[ 1 ];
11194                         const components = m[ 2 ];
11195
11196                         switch ( name ) {
11197
11198                                 case 'rgb':
11199                                 case 'rgba':
11200
11201                                         if ( color = /^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) {
11202
11203                                                 // rgb(255,0,0) rgba(255,0,0,0.5)
11204                                                 this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255;
11205                                                 this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255;
11206                                                 this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255;
11207
11208                                                 handleAlpha( color[ 4 ] );
11209
11210                                                 return this;
11211
11212                                         }
11213
11214                                         if ( color = /^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) {
11215
11216                                                 // rgb(100%,0%,0%) rgba(100%,0%,0%,0.5)
11217                                                 this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100;
11218                                                 this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100;
11219                                                 this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100;
11220
11221                                                 handleAlpha( color[ 4 ] );
11222
11223                                                 return this;
11224
11225                                         }
11226
11227                                         break;
11228
11229                                 case 'hsl':
11230                                 case 'hsla':
11231
11232                                         if ( color = /^\s*(\d*\.?\d+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) {
11233
11234                                                 // hsl(120,50%,50%) hsla(120,50%,50%,0.5)
11235                                                 const h = parseFloat( color[ 1 ] ) / 360;
11236                                                 const s = parseInt( color[ 2 ], 10 ) / 100;
11237                                                 const l = parseInt( color[ 3 ], 10 ) / 100;
11238
11239                                                 handleAlpha( color[ 4 ] );
11240
11241                                                 return this.setHSL( h, s, l );
11242
11243                                         }
11244
11245                                         break;
11246
11247                         }
11248
11249                 } else if ( m = /^\#([A-Fa-f\d]+)$/.exec( style ) ) {
11250
11251                         // hex color
11252
11253                         const hex = m[ 1 ];
11254                         const size = hex.length;
11255
11256                         if ( size === 3 ) {
11257
11258                                 // #ff0
11259                                 this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 0 ), 16 ) / 255;
11260                                 this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255;
11261                                 this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255;
11262
11263                                 return this;
11264
11265                         } else if ( size === 6 ) {
11266
11267                                 // #ff0000
11268                                 this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 1 ), 16 ) / 255;
11269                                 this.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255;
11270                                 this.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255;
11271
11272                                 return this;
11273
11274                         }
11275
11276                 }
11277
11278                 if ( style && style.length > 0 ) {
11279
11280                         return this.setColorName( style );
11281
11282                 }
11283
11284                 return this;
11285
11286         }
11287
11288         setColorName( style ) {
11289
11290                 // color keywords
11291                 const hex = _colorKeywords[ style.toLowerCase() ];
11292
11293                 if ( hex !== undefined ) {
11294
11295                         // red
11296                         this.setHex( hex );
11297
11298                 } else {
11299
11300                         // unknown color
11301                         console.warn( 'THREE.Color: Unknown color ' + style );
11302
11303                 }
11304
11305                 return this;
11306
11307         }
11308
11309         clone() {
11310
11311                 return new this.constructor( this.r, this.g, this.b );
11312
11313         }
11314
11315         copy( color ) {
11316
11317                 this.r = color.r;
11318                 this.g = color.g;
11319                 this.b = color.b;
11320
11321                 return this;
11322
11323         }
11324
11325         copyGammaToLinear( color, gammaFactor = 2.0 ) {
11326
11327                 this.r = Math.pow( color.r, gammaFactor );
11328                 this.g = Math.pow( color.g, gammaFactor );
11329                 this.b = Math.pow( color.b, gammaFactor );
11330
11331                 return this;
11332
11333         }
11334
11335         copyLinearToGamma( color, gammaFactor = 2.0 ) {
11336
11337                 const safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0;
11338
11339                 this.r = Math.pow( color.r, safeInverse );
11340                 this.g = Math.pow( color.g, safeInverse );
11341                 this.b = Math.pow( color.b, safeInverse );
11342
11343                 return this;
11344
11345         }
11346
11347         convertGammaToLinear( gammaFactor ) {
11348
11349                 this.copyGammaToLinear( this, gammaFactor );
11350
11351                 return this;
11352
11353         }
11354
11355         convertLinearToGamma( gammaFactor ) {
11356
11357                 this.copyLinearToGamma( this, gammaFactor );
11358
11359                 return this;
11360
11361         }
11362
11363         copySRGBToLinear( color ) {
11364
11365                 this.r = SRGBToLinear( color.r );
11366                 this.g = SRGBToLinear( color.g );
11367                 this.b = SRGBToLinear( color.b );
11368
11369                 return this;
11370
11371         }
11372
11373         copyLinearToSRGB( color ) {
11374
11375                 this.r = LinearToSRGB( color.r );
11376                 this.g = LinearToSRGB( color.g );
11377                 this.b = LinearToSRGB( color.b );
11378
11379                 return this;
11380
11381         }
11382
11383         convertSRGBToLinear() {
11384
11385                 this.copySRGBToLinear( this );
11386
11387                 return this;
11388
11389         }
11390
11391         convertLinearToSRGB() {
11392
11393                 this.copyLinearToSRGB( this );
11394
11395                 return this;
11396
11397         }
11398
11399         getHex() {
11400
11401                 return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0;
11402
11403         }
11404
11405         getHexString() {
11406
11407                 return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 );
11408
11409         }
11410
11411         getHSL( target ) {
11412
11413                 // h,s,l ranges are in 0.0 - 1.0
11414
11415                 const r = this.r, g = this.g, b = this.b;
11416
11417                 const max = Math.max( r, g, b );
11418                 const min = Math.min( r, g, b );
11419
11420                 let hue, saturation;
11421                 const lightness = ( min + max ) / 2.0;
11422
11423                 if ( min === max ) {
11424
11425                         hue = 0;
11426                         saturation = 0;
11427
11428                 } else {
11429
11430                         const delta = max - min;
11431
11432                         saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min );
11433
11434                         switch ( max ) {
11435
11436                                 case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break;
11437                                 case g: hue = ( b - r ) / delta + 2; break;
11438                                 case b: hue = ( r - g ) / delta + 4; break;
11439
11440                         }
11441
11442                         hue /= 6;
11443
11444                 }
11445
11446                 target.h = hue;
11447                 target.s = saturation;
11448                 target.l = lightness;
11449
11450                 return target;
11451
11452         }
11453
11454         getStyle() {
11455
11456                 return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')';
11457
11458         }
11459
11460         offsetHSL( h, s, l ) {
11461
11462                 this.getHSL( _hslA );
11463
11464                 _hslA.h += h; _hslA.s += s; _hslA.l += l;
11465
11466                 this.setHSL( _hslA.h, _hslA.s, _hslA.l );
11467
11468                 return this;
11469
11470         }
11471
11472         add( color ) {
11473
11474                 this.r += color.r;
11475                 this.g += color.g;
11476                 this.b += color.b;
11477
11478                 return this;
11479
11480         }
11481
11482         addColors( color1, color2 ) {
11483
11484                 this.r = color1.r + color2.r;
11485                 this.g = color1.g + color2.g;
11486                 this.b = color1.b + color2.b;
11487
11488                 return this;
11489
11490         }
11491
11492         addScalar( s ) {
11493
11494                 this.r += s;
11495                 this.g += s;
11496                 this.b += s;
11497
11498                 return this;
11499
11500         }
11501
11502         sub( color ) {
11503
11504                 this.r = Math.max( 0, this.r - color.r );
11505                 this.g = Math.max( 0, this.g - color.g );
11506                 this.b = Math.max( 0, this.b - color.b );
11507
11508                 return this;
11509
11510         }
11511
11512         multiply( color ) {
11513
11514                 this.r *= color.r;
11515                 this.g *= color.g;
11516                 this.b *= color.b;
11517
11518                 return this;
11519
11520         }
11521
11522         multiplyScalar( s ) {
11523
11524                 this.r *= s;
11525                 this.g *= s;
11526                 this.b *= s;
11527
11528                 return this;
11529
11530         }
11531
11532         lerp( color, alpha ) {
11533
11534                 this.r += ( color.r - this.r ) * alpha;
11535                 this.g += ( color.g - this.g ) * alpha;
11536                 this.b += ( color.b - this.b ) * alpha;
11537
11538                 return this;
11539
11540         }
11541
11542         lerpColors( color1, color2, alpha ) {
11543
11544                 this.r = color1.r + ( color2.r - color1.r ) * alpha;
11545                 this.g = color1.g + ( color2.g - color1.g ) * alpha;
11546                 this.b = color1.b + ( color2.b - color1.b ) * alpha;
11547
11548                 return this;
11549
11550         }
11551
11552         lerpHSL( color, alpha ) {
11553
11554                 this.getHSL( _hslA );
11555                 color.getHSL( _hslB );
11556
11557                 const h = lerp( _hslA.h, _hslB.h, alpha );
11558                 const s = lerp( _hslA.s, _hslB.s, alpha );
11559                 const l = lerp( _hslA.l, _hslB.l, alpha );
11560
11561                 this.setHSL( h, s, l );
11562
11563                 return this;
11564
11565         }
11566
11567         equals( c ) {
11568
11569                 return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b );
11570
11571         }
11572
11573         fromArray( array, offset = 0 ) {
11574
11575                 this.r = array[ offset ];
11576                 this.g = array[ offset + 1 ];
11577                 this.b = array[ offset + 2 ];
11578
11579                 return this;
11580
11581         }
11582
11583         toArray( array = [], offset = 0 ) {
11584
11585                 array[ offset ] = this.r;
11586                 array[ offset + 1 ] = this.g;
11587                 array[ offset + 2 ] = this.b;
11588
11589                 return array;
11590
11591         }
11592
11593         fromBufferAttribute( attribute, index ) {
11594
11595                 this.r = attribute.getX( index );
11596                 this.g = attribute.getY( index );
11597                 this.b = attribute.getZ( index );
11598
11599                 if ( attribute.normalized === true ) {
11600
11601                         // assuming Uint8Array
11602
11603                         this.r /= 255;
11604                         this.g /= 255;
11605                         this.b /= 255;
11606
11607                 }
11608
11609                 return this;
11610
11611         }
11612
11613         toJSON() {
11614
11615                 return this.getHex();
11616
11617         }
11618
11619 }
11620
11621 Color.NAMES = _colorKeywords;
11622
11623 Color.prototype.isColor = true;
11624 Color.prototype.r = 1;
11625 Color.prototype.g = 1;
11626 Color.prototype.b = 1;
11627
11628 /**
11629  * parameters = {
11630  *  color: <hex>,
11631  *  opacity: <float>,
11632  *  map: new THREE.Texture( <Image> ),
11633  *
11634  *  lightMap: new THREE.Texture( <Image> ),
11635  *  lightMapIntensity: <float>
11636  *
11637  *  aoMap: new THREE.Texture( <Image> ),
11638  *  aoMapIntensity: <float>
11639  *
11640  *  specularMap: new THREE.Texture( <Image> ),
11641  *
11642  *  alphaMap: new THREE.Texture( <Image> ),
11643  *
11644  *  envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
11645  *  combine: THREE.Multiply,
11646  *  reflectivity: <float>,
11647  *  refractionRatio: <float>,
11648  *
11649  *  depthTest: <bool>,
11650  *  depthWrite: <bool>,
11651  *
11652  *  wireframe: <boolean>,
11653  *  wireframeLinewidth: <float>,
11654  * }
11655  */
11656
11657 class MeshBasicMaterial extends Material {
11658
11659         constructor( parameters ) {
11660
11661                 super();
11662
11663                 this.type = 'MeshBasicMaterial';
11664
11665                 this.color = new Color( 0xffffff ); // emissive
11666
11667                 this.map = null;
11668
11669                 this.lightMap = null;
11670                 this.lightMapIntensity = 1.0;
11671
11672                 this.aoMap = null;
11673                 this.aoMapIntensity = 1.0;
11674
11675                 this.specularMap = null;
11676
11677                 this.alphaMap = null;
11678
11679                 this.envMap = null;
11680                 this.combine = MultiplyOperation;
11681                 this.reflectivity = 1;
11682                 this.refractionRatio = 0.98;
11683
11684                 this.wireframe = false;
11685                 this.wireframeLinewidth = 1;
11686                 this.wireframeLinecap = 'round';
11687                 this.wireframeLinejoin = 'round';
11688
11689                 this.setValues( parameters );
11690
11691         }
11692
11693         copy( source ) {
11694
11695                 super.copy( source );
11696
11697                 this.color.copy( source.color );
11698
11699                 this.map = source.map;
11700
11701                 this.lightMap = source.lightMap;
11702                 this.lightMapIntensity = source.lightMapIntensity;
11703
11704                 this.aoMap = source.aoMap;
11705                 this.aoMapIntensity = source.aoMapIntensity;
11706
11707                 this.specularMap = source.specularMap;
11708
11709                 this.alphaMap = source.alphaMap;
11710
11711                 this.envMap = source.envMap;
11712                 this.combine = source.combine;
11713                 this.reflectivity = source.reflectivity;
11714                 this.refractionRatio = source.refractionRatio;
11715
11716                 this.wireframe = source.wireframe;
11717                 this.wireframeLinewidth = source.wireframeLinewidth;
11718                 this.wireframeLinecap = source.wireframeLinecap;
11719                 this.wireframeLinejoin = source.wireframeLinejoin;
11720
11721                 return this;
11722
11723         }
11724
11725 }
11726
11727 MeshBasicMaterial.prototype.isMeshBasicMaterial = true;
11728
11729 const _vector$9 = /*@__PURE__*/ new Vector3();
11730 const _vector2$1 = /*@__PURE__*/ new Vector2();
11731
11732 class BufferAttribute {
11733
11734         constructor( array, itemSize, normalized ) {
11735
11736                 if ( Array.isArray( array ) ) {
11737
11738                         throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );
11739
11740                 }
11741
11742                 this.name = '';
11743
11744                 this.array = array;
11745                 this.itemSize = itemSize;
11746                 this.count = array !== undefined ? array.length / itemSize : 0;
11747                 this.normalized = normalized === true;
11748
11749                 this.usage = StaticDrawUsage;
11750                 this.updateRange = { offset: 0, count: - 1 };
11751
11752                 this.version = 0;
11753
11754         }
11755
11756         onUploadCallback() {}
11757
11758         set needsUpdate( value ) {
11759
11760                 if ( value === true ) this.version ++;
11761
11762         }
11763
11764         setUsage( value ) {
11765
11766                 this.usage = value;
11767
11768                 return this;
11769
11770         }
11771
11772         copy( source ) {
11773
11774                 this.name = source.name;
11775                 this.array = new source.array.constructor( source.array );
11776                 this.itemSize = source.itemSize;
11777                 this.count = source.count;
11778                 this.normalized = source.normalized;
11779
11780                 this.usage = source.usage;
11781
11782                 return this;
11783
11784         }
11785
11786         copyAt( index1, attribute, index2 ) {
11787
11788                 index1 *= this.itemSize;
11789                 index2 *= attribute.itemSize;
11790
11791                 for ( let i = 0, l = this.itemSize; i < l; i ++ ) {
11792
11793                         this.array[ index1 + i ] = attribute.array[ index2 + i ];
11794
11795                 }
11796
11797                 return this;
11798
11799         }
11800
11801         copyArray( array ) {
11802
11803                 this.array.set( array );
11804
11805                 return this;
11806
11807         }
11808
11809         copyColorsArray( colors ) {
11810
11811                 const array = this.array;
11812                 let offset = 0;
11813
11814                 for ( let i = 0, l = colors.length; i < l; i ++ ) {
11815
11816                         let color = colors[ i ];
11817
11818                         if ( color === undefined ) {
11819
11820                                 console.warn( 'THREE.BufferAttribute.copyColorsArray(): color is undefined', i );
11821                                 color = new Color();
11822
11823                         }
11824
11825                         array[ offset ++ ] = color.r;
11826                         array[ offset ++ ] = color.g;
11827                         array[ offset ++ ] = color.b;
11828
11829                 }
11830
11831                 return this;
11832
11833         }
11834
11835         copyVector2sArray( vectors ) {
11836
11837                 const array = this.array;
11838                 let offset = 0;
11839
11840                 for ( let i = 0, l = vectors.length; i < l; i ++ ) {
11841
11842                         let vector = vectors[ i ];
11843
11844                         if ( vector === undefined ) {
11845
11846                                 console.warn( 'THREE.BufferAttribute.copyVector2sArray(): vector is undefined', i );
11847                                 vector = new Vector2();
11848
11849                         }
11850
11851                         array[ offset ++ ] = vector.x;
11852                         array[ offset ++ ] = vector.y;
11853
11854                 }
11855
11856                 return this;
11857
11858         }
11859
11860         copyVector3sArray( vectors ) {
11861
11862                 const array = this.array;
11863                 let offset = 0;
11864
11865                 for ( let i = 0, l = vectors.length; i < l; i ++ ) {
11866
11867                         let vector = vectors[ i ];
11868
11869                         if ( vector === undefined ) {
11870
11871                                 console.warn( 'THREE.BufferAttribute.copyVector3sArray(): vector is undefined', i );
11872                                 vector = new Vector3();
11873
11874                         }
11875
11876                         array[ offset ++ ] = vector.x;
11877                         array[ offset ++ ] = vector.y;
11878                         array[ offset ++ ] = vector.z;
11879
11880                 }
11881
11882                 return this;
11883
11884         }
11885
11886         copyVector4sArray( vectors ) {
11887
11888                 const array = this.array;
11889                 let offset = 0;
11890
11891                 for ( let i = 0, l = vectors.length; i < l; i ++ ) {
11892
11893                         let vector = vectors[ i ];
11894
11895                         if ( vector === undefined ) {
11896
11897                                 console.warn( 'THREE.BufferAttribute.copyVector4sArray(): vector is undefined', i );
11898                                 vector = new Vector4();
11899
11900                         }
11901
11902                         array[ offset ++ ] = vector.x;
11903                         array[ offset ++ ] = vector.y;
11904                         array[ offset ++ ] = vector.z;
11905                         array[ offset ++ ] = vector.w;
11906
11907                 }
11908
11909                 return this;
11910
11911         }
11912
11913         applyMatrix3( m ) {
11914
11915                 if ( this.itemSize === 2 ) {
11916
11917                         for ( let i = 0, l = this.count; i < l; i ++ ) {
11918
11919                                 _vector2$1.fromBufferAttribute( this, i );
11920                                 _vector2$1.applyMatrix3( m );
11921
11922                                 this.setXY( i, _vector2$1.x, _vector2$1.y );
11923
11924                         }
11925
11926                 } else if ( this.itemSize === 3 ) {
11927
11928                         for ( let i = 0, l = this.count; i < l; i ++ ) {
11929
11930                                 _vector$9.fromBufferAttribute( this, i );
11931                                 _vector$9.applyMatrix3( m );
11932
11933                                 this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z );
11934
11935                         }
11936
11937                 }
11938
11939                 return this;
11940
11941         }
11942
11943         applyMatrix4( m ) {
11944
11945                 for ( let i = 0, l = this.count; i < l; i ++ ) {
11946
11947                         _vector$9.x = this.getX( i );
11948                         _vector$9.y = this.getY( i );
11949                         _vector$9.z = this.getZ( i );
11950
11951                         _vector$9.applyMatrix4( m );
11952
11953                         this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z );
11954
11955                 }
11956
11957                 return this;
11958
11959         }
11960
11961         applyNormalMatrix( m ) {
11962
11963                 for ( let i = 0, l = this.count; i < l; i ++ ) {
11964
11965                         _vector$9.x = this.getX( i );
11966                         _vector$9.y = this.getY( i );
11967                         _vector$9.z = this.getZ( i );
11968
11969                         _vector$9.applyNormalMatrix( m );
11970
11971                         this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z );
11972
11973                 }
11974
11975                 return this;
11976
11977         }
11978
11979         transformDirection( m ) {
11980
11981                 for ( let i = 0, l = this.count; i < l; i ++ ) {
11982
11983                         _vector$9.x = this.getX( i );
11984                         _vector$9.y = this.getY( i );
11985                         _vector$9.z = this.getZ( i );
11986
11987                         _vector$9.transformDirection( m );
11988
11989                         this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z );
11990
11991                 }
11992
11993                 return this;
11994
11995         }
11996
11997         set( value, offset = 0 ) {
11998
11999                 this.array.set( value, offset );
12000
12001                 return this;
12002
12003         }
12004
12005         getX( index ) {
12006
12007                 return this.array[ index * this.itemSize ];
12008
12009         }
12010
12011         setX( index, x ) {
12012
12013                 this.array[ index * this.itemSize ] = x;
12014
12015                 return this;
12016
12017         }
12018
12019         getY( index ) {
12020
12021                 return this.array[ index * this.itemSize + 1 ];
12022
12023         }
12024
12025         setY( index, y ) {
12026
12027                 this.array[ index * this.itemSize + 1 ] = y;
12028
12029                 return this;
12030
12031         }
12032
12033         getZ( index ) {
12034
12035                 return this.array[ index * this.itemSize + 2 ];
12036
12037         }
12038
12039         setZ( index, z ) {
12040
12041                 this.array[ index * this.itemSize + 2 ] = z;
12042
12043                 return this;
12044
12045         }
12046
12047         getW( index ) {
12048
12049                 return this.array[ index * this.itemSize + 3 ];
12050
12051         }
12052
12053         setW( index, w ) {
12054
12055                 this.array[ index * this.itemSize + 3 ] = w;
12056
12057                 return this;
12058
12059         }
12060
12061         setXY( index, x, y ) {
12062
12063                 index *= this.itemSize;
12064
12065                 this.array[ index + 0 ] = x;
12066                 this.array[ index + 1 ] = y;
12067
12068                 return this;
12069
12070         }
12071
12072         setXYZ( index, x, y, z ) {
12073
12074                 index *= this.itemSize;
12075
12076                 this.array[ index + 0 ] = x;
12077                 this.array[ index + 1 ] = y;
12078                 this.array[ index + 2 ] = z;
12079
12080                 return this;
12081
12082         }
12083
12084         setXYZW( index, x, y, z, w ) {
12085
12086                 index *= this.itemSize;
12087
12088                 this.array[ index + 0 ] = x;
12089                 this.array[ index + 1 ] = y;
12090                 this.array[ index + 2 ] = z;
12091                 this.array[ index + 3 ] = w;
12092
12093                 return this;
12094
12095         }
12096
12097         onUpload( callback ) {
12098
12099                 this.onUploadCallback = callback;
12100
12101                 return this;
12102
12103         }
12104
12105         clone() {
12106
12107                 return new this.constructor( this.array, this.itemSize ).copy( this );
12108
12109         }
12110
12111         toJSON() {
12112
12113                 const data = {
12114                         itemSize: this.itemSize,
12115                         type: this.array.constructor.name,
12116                         array: Array.prototype.slice.call( this.array ),
12117                         normalized: this.normalized
12118                 };
12119
12120                 if ( this.name !== '' ) data.name = this.name;
12121                 if ( this.usage !== StaticDrawUsage ) data.usage = this.usage;
12122                 if ( this.updateRange.offset !== 0 || this.updateRange.count !== - 1 ) data.updateRange = this.updateRange;
12123
12124                 return data;
12125
12126         }
12127
12128 }
12129
12130 BufferAttribute.prototype.isBufferAttribute = true;
12131
12132 class Uint16BufferAttribute extends BufferAttribute {
12133
12134         constructor( array, itemSize, normalized ) {
12135
12136                 super( new Uint16Array( array ), itemSize, normalized );
12137
12138         }
12139
12140 }
12141
12142 class Uint32BufferAttribute extends BufferAttribute {
12143
12144         constructor( array, itemSize, normalized ) {
12145
12146                 super( new Uint32Array( array ), itemSize, normalized );
12147
12148         }
12149
12150 }
12151
12152 class Float16BufferAttribute extends BufferAttribute {
12153
12154         constructor( array, itemSize, normalized ) {
12155
12156                 super( new Uint16Array( array ), itemSize, normalized );
12157
12158         }
12159
12160 }
12161
12162 Float16BufferAttribute.prototype.isFloat16BufferAttribute = true;
12163
12164 class Float32BufferAttribute extends BufferAttribute {
12165
12166         constructor( array, itemSize, normalized ) {
12167
12168                 super( new Float32Array( array ), itemSize, normalized );
12169
12170         }
12171
12172 }
12173
12174 let _id = 0;
12175
12176 const _m1 = /*@__PURE__*/ new Matrix4();
12177 const _obj = /*@__PURE__*/ new Object3D();
12178 const _offset = /*@__PURE__*/ new Vector3();
12179 const _box$1 = /*@__PURE__*/ new Box3();
12180 const _boxMorphTargets = /*@__PURE__*/ new Box3();
12181 const _vector$8 = /*@__PURE__*/ new Vector3();
12182
12183 class BufferGeometry extends EventDispatcher {
12184
12185         constructor() {
12186
12187                 super();
12188
12189                 Object.defineProperty( this, 'id', { value: _id ++ } );
12190
12191                 this.uuid = generateUUID();
12192
12193                 this.name = '';
12194                 this.type = 'BufferGeometry';
12195
12196                 this.index = null;
12197                 this.attributes = {};
12198
12199                 this.morphAttributes = {};
12200                 this.morphTargetsRelative = false;
12201
12202                 this.groups = [];
12203
12204                 this.boundingBox = null;
12205                 this.boundingSphere = null;
12206
12207                 this.drawRange = { start: 0, count: Infinity };
12208
12209                 this.userData = {};
12210
12211         }
12212
12213         getIndex() {
12214
12215                 return this.index;
12216
12217         }
12218
12219         setIndex( index ) {
12220
12221                 if ( Array.isArray( index ) ) {
12222
12223                         this.index = new ( arrayMax( index ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 );
12224
12225                 } else {
12226
12227                         this.index = index;
12228
12229                 }
12230
12231                 return this;
12232
12233         }
12234
12235         getAttribute( name ) {
12236
12237                 return this.attributes[ name ];
12238
12239         }
12240
12241         setAttribute( name, attribute ) {
12242
12243                 this.attributes[ name ] = attribute;
12244
12245                 return this;
12246
12247         }
12248
12249         deleteAttribute( name ) {
12250
12251                 delete this.attributes[ name ];
12252
12253                 return this;
12254
12255         }
12256
12257         hasAttribute( name ) {
12258
12259                 return this.attributes[ name ] !== undefined;
12260
12261         }
12262
12263         addGroup( start, count, materialIndex = 0 ) {
12264
12265                 this.groups.push( {
12266
12267                         start: start,
12268                         count: count,
12269                         materialIndex: materialIndex
12270
12271                 } );
12272
12273         }
12274
12275         clearGroups() {
12276
12277                 this.groups = [];
12278
12279         }
12280
12281         setDrawRange( start, count ) {
12282
12283                 this.drawRange.start = start;
12284                 this.drawRange.count = count;
12285
12286         }
12287
12288         applyMatrix4( matrix ) {
12289
12290                 const position = this.attributes.position;
12291
12292                 if ( position !== undefined ) {
12293
12294                         position.applyMatrix4( matrix );
12295
12296                         position.needsUpdate = true;
12297
12298                 }
12299
12300                 const normal = this.attributes.normal;
12301
12302                 if ( normal !== undefined ) {
12303
12304                         const normalMatrix = new Matrix3().getNormalMatrix( matrix );
12305
12306                         normal.applyNormalMatrix( normalMatrix );
12307
12308                         normal.needsUpdate = true;
12309
12310                 }
12311
12312                 const tangent = this.attributes.tangent;
12313
12314                 if ( tangent !== undefined ) {
12315
12316                         tangent.transformDirection( matrix );
12317
12318                         tangent.needsUpdate = true;
12319
12320                 }
12321
12322                 if ( this.boundingBox !== null ) {
12323
12324                         this.computeBoundingBox();
12325
12326                 }
12327
12328                 if ( this.boundingSphere !== null ) {
12329
12330                         this.computeBoundingSphere();
12331
12332                 }
12333
12334                 return this;
12335
12336         }
12337
12338         applyQuaternion( q ) {
12339
12340                 _m1.makeRotationFromQuaternion( q );
12341
12342                 this.applyMatrix4( _m1 );
12343
12344                 return this;
12345
12346         }
12347
12348         rotateX( angle ) {
12349
12350                 // rotate geometry around world x-axis
12351
12352                 _m1.makeRotationX( angle );
12353
12354                 this.applyMatrix4( _m1 );
12355
12356                 return this;
12357
12358         }
12359
12360         rotateY( angle ) {
12361
12362                 // rotate geometry around world y-axis
12363
12364                 _m1.makeRotationY( angle );
12365
12366                 this.applyMatrix4( _m1 );
12367
12368                 return this;
12369
12370         }
12371
12372         rotateZ( angle ) {
12373
12374                 // rotate geometry around world z-axis
12375
12376                 _m1.makeRotationZ( angle );
12377
12378                 this.applyMatrix4( _m1 );
12379
12380                 return this;
12381
12382         }
12383
12384         translate( x, y, z ) {
12385
12386                 // translate geometry
12387
12388                 _m1.makeTranslation( x, y, z );
12389
12390                 this.applyMatrix4( _m1 );
12391
12392                 return this;
12393
12394         }
12395
12396         scale( x, y, z ) {
12397
12398                 // scale geometry
12399
12400                 _m1.makeScale( x, y, z );
12401
12402                 this.applyMatrix4( _m1 );
12403
12404                 return this;
12405
12406         }
12407
12408         lookAt( vector ) {
12409
12410                 _obj.lookAt( vector );
12411
12412                 _obj.updateMatrix();
12413
12414                 this.applyMatrix4( _obj.matrix );
12415
12416                 return this;
12417
12418         }
12419
12420         center() {
12421
12422                 this.computeBoundingBox();
12423
12424                 this.boundingBox.getCenter( _offset ).negate();
12425
12426                 this.translate( _offset.x, _offset.y, _offset.z );
12427
12428                 return this;
12429
12430         }
12431
12432         setFromPoints( points ) {
12433
12434                 const position = [];
12435
12436                 for ( let i = 0, l = points.length; i < l; i ++ ) {
12437
12438                         const point = points[ i ];
12439                         position.push( point.x, point.y, point.z || 0 );
12440
12441                 }
12442
12443                 this.setAttribute( 'position', new Float32BufferAttribute( position, 3 ) );
12444
12445                 return this;
12446
12447         }
12448
12449         computeBoundingBox() {
12450
12451                 if ( this.boundingBox === null ) {
12452
12453                         this.boundingBox = new Box3();
12454
12455                 }
12456
12457                 const position = this.attributes.position;
12458                 const morphAttributesPosition = this.morphAttributes.position;
12459
12460                 if ( position && position.isGLBufferAttribute ) {
12461
12462                         console.error( 'THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box. Alternatively set "mesh.frustumCulled" to "false".', this );
12463
12464                         this.boundingBox.set(
12465                                 new Vector3( - Infinity, - Infinity, - Infinity ),
12466                                 new Vector3( + Infinity, + Infinity, + Infinity )
12467                         );
12468
12469                         return;
12470
12471                 }
12472
12473                 if ( position !== undefined ) {
12474
12475                         this.boundingBox.setFromBufferAttribute( position );
12476
12477                         // process morph attributes if present
12478
12479                         if ( morphAttributesPosition ) {
12480
12481                                 for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
12482
12483                                         const morphAttribute = morphAttributesPosition[ i ];
12484                                         _box$1.setFromBufferAttribute( morphAttribute );
12485
12486                                         if ( this.morphTargetsRelative ) {
12487
12488                                                 _vector$8.addVectors( this.boundingBox.min, _box$1.min );
12489                                                 this.boundingBox.expandByPoint( _vector$8 );
12490
12491                                                 _vector$8.addVectors( this.boundingBox.max, _box$1.max );
12492                                                 this.boundingBox.expandByPoint( _vector$8 );
12493
12494                                         } else {
12495
12496                                                 this.boundingBox.expandByPoint( _box$1.min );
12497                                                 this.boundingBox.expandByPoint( _box$1.max );
12498
12499                                         }
12500
12501                                 }
12502
12503                         }
12504
12505                 } else {
12506
12507                         this.boundingBox.makeEmpty();
12508
12509                 }
12510
12511                 if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {
12512
12513                         console.error( 'THREE.BufferGeometry.computeBoundingBox(): Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this );
12514
12515                 }
12516
12517         }
12518
12519         computeBoundingSphere() {
12520
12521                 if ( this.boundingSphere === null ) {
12522
12523                         this.boundingSphere = new Sphere();
12524
12525                 }
12526
12527                 const position = this.attributes.position;
12528                 const morphAttributesPosition = this.morphAttributes.position;
12529
12530                 if ( position && position.isGLBufferAttribute ) {
12531
12532                         console.error( 'THREE.BufferGeometry.computeBoundingSphere(): GLBufferAttribute requires a manual bounding sphere. Alternatively set "mesh.frustumCulled" to "false".', this );
12533
12534                         this.boundingSphere.set( new Vector3(), Infinity );
12535
12536                         return;
12537
12538                 }
12539
12540                 if ( position ) {
12541
12542                         // first, find the center of the bounding sphere
12543
12544                         const center = this.boundingSphere.center;
12545
12546                         _box$1.setFromBufferAttribute( position );
12547
12548                         // process morph attributes if present
12549
12550                         if ( morphAttributesPosition ) {
12551
12552                                 for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
12553
12554                                         const morphAttribute = morphAttributesPosition[ i ];
12555                                         _boxMorphTargets.setFromBufferAttribute( morphAttribute );
12556
12557                                         if ( this.morphTargetsRelative ) {
12558
12559                                                 _vector$8.addVectors( _box$1.min, _boxMorphTargets.min );
12560                                                 _box$1.expandByPoint( _vector$8 );
12561
12562                                                 _vector$8.addVectors( _box$1.max, _boxMorphTargets.max );
12563                                                 _box$1.expandByPoint( _vector$8 );
12564
12565                                         } else {
12566
12567                                                 _box$1.expandByPoint( _boxMorphTargets.min );
12568                                                 _box$1.expandByPoint( _boxMorphTargets.max );
12569
12570                                         }
12571
12572                                 }
12573
12574                         }
12575
12576                         _box$1.getCenter( center );
12577
12578                         // second, try to find a boundingSphere with a radius smaller than the
12579                         // boundingSphere of the boundingBox: sqrt(3) smaller in the best case
12580
12581                         let maxRadiusSq = 0;
12582
12583                         for ( let i = 0, il = position.count; i < il; i ++ ) {
12584
12585                                 _vector$8.fromBufferAttribute( position, i );
12586
12587                                 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) );
12588
12589                         }
12590
12591                         // process morph attributes if present
12592
12593                         if ( morphAttributesPosition ) {
12594
12595                                 for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
12596
12597                                         const morphAttribute = morphAttributesPosition[ i ];
12598                                         const morphTargetsRelative = this.morphTargetsRelative;
12599
12600                                         for ( let j = 0, jl = morphAttribute.count; j < jl; j ++ ) {
12601
12602                                                 _vector$8.fromBufferAttribute( morphAttribute, j );
12603
12604                                                 if ( morphTargetsRelative ) {
12605
12606                                                         _offset.fromBufferAttribute( position, j );
12607                                                         _vector$8.add( _offset );
12608
12609                                                 }
12610
12611                                                 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) );
12612
12613                                         }
12614
12615                                 }
12616
12617                         }
12618
12619                         this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
12620
12621                         if ( isNaN( this.boundingSphere.radius ) ) {
12622
12623                                 console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this );
12624
12625                         }
12626
12627                 }
12628
12629         }
12630
12631         computeTangents() {
12632
12633                 const index = this.index;
12634                 const attributes = this.attributes;
12635
12636                 // based on http://www.terathon.com/code/tangent.html
12637                 // (per vertex tangents)
12638
12639                 if ( index === null ||
12640                          attributes.position === undefined ||
12641                          attributes.normal === undefined ||
12642                          attributes.uv === undefined ) {
12643
12644                         console.error( 'THREE.BufferGeometry: .computeTangents() failed. Missing required attributes (index, position, normal or uv)' );
12645                         return;
12646
12647                 }
12648
12649                 const indices = index.array;
12650                 const positions = attributes.position.array;
12651                 const normals = attributes.normal.array;
12652                 const uvs = attributes.uv.array;
12653
12654                 const nVertices = positions.length / 3;
12655
12656                 if ( attributes.tangent === undefined ) {
12657
12658                         this.setAttribute( 'tangent', new BufferAttribute( new Float32Array( 4 * nVertices ), 4 ) );
12659
12660                 }
12661
12662                 const tangents = attributes.tangent.array;
12663
12664                 const tan1 = [], tan2 = [];
12665
12666                 for ( let i = 0; i < nVertices; i ++ ) {
12667
12668                         tan1[ i ] = new Vector3();
12669                         tan2[ i ] = new Vector3();
12670
12671                 }
12672
12673                 const vA = new Vector3(),
12674                         vB = new Vector3(),
12675                         vC = new Vector3(),
12676
12677                         uvA = new Vector2(),
12678                         uvB = new Vector2(),
12679                         uvC = new Vector2(),
12680
12681                         sdir = new Vector3(),
12682                         tdir = new Vector3();
12683
12684                 function handleTriangle( a, b, c ) {
12685
12686                         vA.fromArray( positions, a * 3 );
12687                         vB.fromArray( positions, b * 3 );
12688                         vC.fromArray( positions, c * 3 );
12689
12690                         uvA.fromArray( uvs, a * 2 );
12691                         uvB.fromArray( uvs, b * 2 );
12692                         uvC.fromArray( uvs, c * 2 );
12693
12694                         vB.sub( vA );
12695                         vC.sub( vA );
12696
12697                         uvB.sub( uvA );
12698                         uvC.sub( uvA );
12699
12700                         const r = 1.0 / ( uvB.x * uvC.y - uvC.x * uvB.y );
12701
12702                         // silently ignore degenerate uv triangles having coincident or colinear vertices
12703
12704                         if ( ! isFinite( r ) ) return;
12705
12706                         sdir.copy( vB ).multiplyScalar( uvC.y ).addScaledVector( vC, - uvB.y ).multiplyScalar( r );
12707                         tdir.copy( vC ).multiplyScalar( uvB.x ).addScaledVector( vB, - uvC.x ).multiplyScalar( r );
12708
12709                         tan1[ a ].add( sdir );
12710                         tan1[ b ].add( sdir );
12711                         tan1[ c ].add( sdir );
12712
12713                         tan2[ a ].add( tdir );
12714                         tan2[ b ].add( tdir );
12715                         tan2[ c ].add( tdir );
12716
12717                 }
12718
12719                 let groups = this.groups;
12720
12721                 if ( groups.length === 0 ) {
12722
12723                         groups = [ {
12724                                 start: 0,
12725                                 count: indices.length
12726                         } ];
12727
12728                 }
12729
12730                 for ( let i = 0, il = groups.length; i < il; ++ i ) {
12731
12732                         const group = groups[ i ];
12733
12734                         const start = group.start;
12735                         const count = group.count;
12736
12737                         for ( let j = start, jl = start + count; j < jl; j += 3 ) {
12738
12739                                 handleTriangle(
12740                                         indices[ j + 0 ],
12741                                         indices[ j + 1 ],
12742                                         indices[ j + 2 ]
12743                                 );
12744
12745                         }
12746
12747                 }
12748
12749                 const tmp = new Vector3(), tmp2 = new Vector3();
12750                 const n = new Vector3(), n2 = new Vector3();
12751
12752                 function handleVertex( v ) {
12753
12754                         n.fromArray( normals, v * 3 );
12755                         n2.copy( n );
12756
12757                         const t = tan1[ v ];
12758
12759                         // Gram-Schmidt orthogonalize
12760
12761                         tmp.copy( t );
12762                         tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();
12763
12764                         // Calculate handedness
12765
12766                         tmp2.crossVectors( n2, t );
12767                         const test = tmp2.dot( tan2[ v ] );
12768                         const w = ( test < 0.0 ) ? - 1.0 : 1.0;
12769
12770                         tangents[ v * 4 ] = tmp.x;
12771                         tangents[ v * 4 + 1 ] = tmp.y;
12772                         tangents[ v * 4 + 2 ] = tmp.z;
12773                         tangents[ v * 4 + 3 ] = w;
12774
12775                 }
12776
12777                 for ( let i = 0, il = groups.length; i < il; ++ i ) {
12778
12779                         const group = groups[ i ];
12780
12781                         const start = group.start;
12782                         const count = group.count;
12783
12784                         for ( let j = start, jl = start + count; j < jl; j += 3 ) {
12785
12786                                 handleVertex( indices[ j + 0 ] );
12787                                 handleVertex( indices[ j + 1 ] );
12788                                 handleVertex( indices[ j + 2 ] );
12789
12790                         }
12791
12792                 }
12793
12794         }
12795
12796         computeVertexNormals() {
12797
12798                 const index = this.index;
12799                 const positionAttribute = this.getAttribute( 'position' );
12800
12801                 if ( positionAttribute !== undefined ) {
12802
12803                         let normalAttribute = this.getAttribute( 'normal' );
12804
12805                         if ( normalAttribute === undefined ) {
12806
12807                                 normalAttribute = new BufferAttribute( new Float32Array( positionAttribute.count * 3 ), 3 );
12808                                 this.setAttribute( 'normal', normalAttribute );
12809
12810                         } else {
12811
12812                                 // reset existing normals to zero
12813
12814                                 for ( let i = 0, il = normalAttribute.count; i < il; i ++ ) {
12815
12816                                         normalAttribute.setXYZ( i, 0, 0, 0 );
12817
12818                                 }
12819
12820                         }
12821
12822                         const pA = new Vector3(), pB = new Vector3(), pC = new Vector3();
12823                         const nA = new Vector3(), nB = new Vector3(), nC = new Vector3();
12824                         const cb = new Vector3(), ab = new Vector3();
12825
12826                         // indexed elements
12827
12828                         if ( index ) {
12829
12830                                 for ( let i = 0, il = index.count; i < il; i += 3 ) {
12831
12832                                         const vA = index.getX( i + 0 );
12833                                         const vB = index.getX( i + 1 );
12834                                         const vC = index.getX( i + 2 );
12835
12836                                         pA.fromBufferAttribute( positionAttribute, vA );
12837                                         pB.fromBufferAttribute( positionAttribute, vB );
12838                                         pC.fromBufferAttribute( positionAttribute, vC );
12839
12840                                         cb.subVectors( pC, pB );
12841                                         ab.subVectors( pA, pB );
12842                                         cb.cross( ab );
12843
12844                                         nA.fromBufferAttribute( normalAttribute, vA );
12845                                         nB.fromBufferAttribute( normalAttribute, vB );
12846                                         nC.fromBufferAttribute( normalAttribute, vC );
12847
12848                                         nA.add( cb );
12849                                         nB.add( cb );
12850                                         nC.add( cb );
12851
12852                                         normalAttribute.setXYZ( vA, nA.x, nA.y, nA.z );
12853                                         normalAttribute.setXYZ( vB, nB.x, nB.y, nB.z );
12854                                         normalAttribute.setXYZ( vC, nC.x, nC.y, nC.z );
12855
12856                                 }
12857
12858                         } else {
12859
12860                                 // non-indexed elements (unconnected triangle soup)
12861
12862                                 for ( let i = 0, il = positionAttribute.count; i < il; i += 3 ) {
12863
12864                                         pA.fromBufferAttribute( positionAttribute, i + 0 );
12865                                         pB.fromBufferAttribute( positionAttribute, i + 1 );
12866                                         pC.fromBufferAttribute( positionAttribute, i + 2 );
12867
12868                                         cb.subVectors( pC, pB );
12869                                         ab.subVectors( pA, pB );
12870                                         cb.cross( ab );
12871
12872                                         normalAttribute.setXYZ( i + 0, cb.x, cb.y, cb.z );
12873                                         normalAttribute.setXYZ( i + 1, cb.x, cb.y, cb.z );
12874                                         normalAttribute.setXYZ( i + 2, cb.x, cb.y, cb.z );
12875
12876                                 }
12877
12878                         }
12879
12880                         this.normalizeNormals();
12881
12882                         normalAttribute.needsUpdate = true;
12883
12884                 }
12885
12886         }
12887
12888         merge( geometry, offset ) {
12889
12890                 if ( ! ( geometry && geometry.isBufferGeometry ) ) {
12891
12892                         console.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry );
12893                         return;
12894
12895                 }
12896
12897                 if ( offset === undefined ) {
12898
12899                         offset = 0;
12900
12901                         console.warn(
12902                                 'THREE.BufferGeometry.merge(): Overwriting original geometry, starting at offset=0. '
12903                                 + 'Use BufferGeometryUtils.mergeBufferGeometries() for lossless merge.'
12904                         );
12905
12906                 }
12907
12908                 const attributes = this.attributes;
12909
12910                 for ( const key in attributes ) {
12911
12912                         if ( geometry.attributes[ key ] === undefined ) continue;
12913
12914                         const attribute1 = attributes[ key ];
12915                         const attributeArray1 = attribute1.array;
12916
12917                         const attribute2 = geometry.attributes[ key ];
12918                         const attributeArray2 = attribute2.array;
12919
12920                         const attributeOffset = attribute2.itemSize * offset;
12921                         const length = Math.min( attributeArray2.length, attributeArray1.length - attributeOffset );
12922
12923                         for ( let i = 0, j = attributeOffset; i < length; i ++, j ++ ) {
12924
12925                                 attributeArray1[ j ] = attributeArray2[ i ];
12926
12927                         }
12928
12929                 }
12930
12931                 return this;
12932
12933         }
12934
12935         normalizeNormals() {
12936
12937                 const normals = this.attributes.normal;
12938
12939                 for ( let i = 0, il = normals.count; i < il; i ++ ) {
12940
12941                         _vector$8.fromBufferAttribute( normals, i );
12942
12943                         _vector$8.normalize();
12944
12945                         normals.setXYZ( i, _vector$8.x, _vector$8.y, _vector$8.z );
12946
12947                 }
12948
12949         }
12950
12951         toNonIndexed() {
12952
12953                 function convertBufferAttribute( attribute, indices ) {
12954
12955                         const array = attribute.array;
12956                         const itemSize = attribute.itemSize;
12957                         const normalized = attribute.normalized;
12958
12959                         const array2 = new array.constructor( indices.length * itemSize );
12960
12961                         let index = 0, index2 = 0;
12962
12963                         for ( let i = 0, l = indices.length; i < l; i ++ ) {
12964
12965                                 if ( attribute.isInterleavedBufferAttribute ) {
12966
12967                                         index = indices[ i ] * attribute.data.stride + attribute.offset;
12968
12969                                 } else {
12970
12971                                         index = indices[ i ] * itemSize;
12972
12973                                 }
12974
12975                                 for ( let j = 0; j < itemSize; j ++ ) {
12976
12977                                         array2[ index2 ++ ] = array[ index ++ ];
12978
12979                                 }
12980
12981                         }
12982
12983                         return new BufferAttribute( array2, itemSize, normalized );
12984
12985                 }
12986
12987                 //
12988
12989                 if ( this.index === null ) {
12990
12991                         console.warn( 'THREE.BufferGeometry.toNonIndexed(): BufferGeometry is already non-indexed.' );
12992                         return this;
12993
12994                 }
12995
12996                 const geometry2 = new BufferGeometry();
12997
12998                 const indices = this.index.array;
12999                 const attributes = this.attributes;
13000
13001                 // attributes
13002
13003                 for ( const name in attributes ) {
13004
13005                         const attribute = attributes[ name ];
13006
13007                         const newAttribute = convertBufferAttribute( attribute, indices );
13008
13009                         geometry2.setAttribute( name, newAttribute );
13010
13011                 }
13012
13013                 // morph attributes
13014
13015                 const morphAttributes = this.morphAttributes;
13016
13017                 for ( const name in morphAttributes ) {
13018
13019                         const morphArray = [];
13020                         const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes
13021
13022                         for ( let i = 0, il = morphAttribute.length; i < il; i ++ ) {
13023
13024                                 const attribute = morphAttribute[ i ];
13025
13026                                 const newAttribute = convertBufferAttribute( attribute, indices );
13027
13028                                 morphArray.push( newAttribute );
13029
13030                         }
13031
13032                         geometry2.morphAttributes[ name ] = morphArray;
13033
13034                 }
13035
13036                 geometry2.morphTargetsRelative = this.morphTargetsRelative;
13037
13038                 // groups
13039
13040                 const groups = this.groups;
13041
13042                 for ( let i = 0, l = groups.length; i < l; i ++ ) {
13043
13044                         const group = groups[ i ];
13045                         geometry2.addGroup( group.start, group.count, group.materialIndex );
13046
13047                 }
13048
13049                 return geometry2;
13050
13051         }
13052
13053         toJSON() {
13054
13055                 const data = {
13056                         metadata: {
13057                                 version: 4.5,
13058                                 type: 'BufferGeometry',
13059                                 generator: 'BufferGeometry.toJSON'
13060                         }
13061                 };
13062
13063                 // standard BufferGeometry serialization
13064
13065                 data.uuid = this.uuid;
13066                 data.type = this.type;
13067                 if ( this.name !== '' ) data.name = this.name;
13068                 if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData;
13069
13070                 if ( this.parameters !== undefined ) {
13071
13072                         const parameters = this.parameters;
13073
13074                         for ( const key in parameters ) {
13075
13076                                 if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];
13077
13078                         }
13079
13080                         return data;
13081
13082                 }
13083
13084                 // for simplicity the code assumes attributes are not shared across geometries, see #15811
13085
13086                 data.data = { attributes: {} };
13087
13088                 const index = this.index;
13089
13090                 if ( index !== null ) {
13091
13092                         data.data.index = {
13093                                 type: index.array.constructor.name,
13094                                 array: Array.prototype.slice.call( index.array )
13095                         };
13096
13097                 }
13098
13099                 const attributes = this.attributes;
13100
13101                 for ( const key in attributes ) {
13102
13103                         const attribute = attributes[ key ];
13104
13105                         data.data.attributes[ key ] = attribute.toJSON( data.data );
13106
13107                 }
13108
13109                 const morphAttributes = {};
13110                 let hasMorphAttributes = false;
13111
13112                 for ( const key in this.morphAttributes ) {
13113
13114                         const attributeArray = this.morphAttributes[ key ];
13115
13116                         const array = [];
13117
13118                         for ( let i = 0, il = attributeArray.length; i < il; i ++ ) {
13119
13120                                 const attribute = attributeArray[ i ];
13121
13122                                 array.push( attribute.toJSON( data.data ) );
13123
13124                         }
13125
13126                         if ( array.length > 0 ) {
13127
13128                                 morphAttributes[ key ] = array;
13129
13130                                 hasMorphAttributes = true;
13131
13132                         }
13133
13134                 }
13135
13136                 if ( hasMorphAttributes ) {
13137
13138                         data.data.morphAttributes = morphAttributes;
13139                         data.data.morphTargetsRelative = this.morphTargetsRelative;
13140
13141                 }
13142
13143                 const groups = this.groups;
13144
13145                 if ( groups.length > 0 ) {
13146
13147                         data.data.groups = JSON.parse( JSON.stringify( groups ) );
13148
13149                 }
13150
13151                 const boundingSphere = this.boundingSphere;
13152
13153                 if ( boundingSphere !== null ) {
13154
13155                         data.data.boundingSphere = {
13156                                 center: boundingSphere.center.toArray(),
13157                                 radius: boundingSphere.radius
13158                         };
13159
13160                 }
13161
13162                 return data;
13163
13164         }
13165
13166         clone() {
13167
13168                  return new this.constructor().copy( this );
13169
13170         }
13171
13172         copy( source ) {
13173
13174                 // reset
13175
13176                 this.index = null;
13177                 this.attributes = {};
13178                 this.morphAttributes = {};
13179                 this.groups = [];
13180                 this.boundingBox = null;
13181                 this.boundingSphere = null;
13182
13183                 // used for storing cloned, shared data
13184
13185                 const data = {};
13186
13187                 // name
13188
13189                 this.name = source.name;
13190
13191                 // index
13192
13193                 const index = source.index;
13194
13195                 if ( index !== null ) {
13196
13197                         this.setIndex( index.clone( data ) );
13198
13199                 }
13200
13201                 // attributes
13202
13203                 const attributes = source.attributes;
13204
13205                 for ( const name in attributes ) {
13206
13207                         const attribute = attributes[ name ];
13208                         this.setAttribute( name, attribute.clone( data ) );
13209
13210                 }
13211
13212                 // morph attributes
13213
13214                 const morphAttributes = source.morphAttributes;
13215
13216                 for ( const name in morphAttributes ) {
13217
13218                         const array = [];
13219                         const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes
13220
13221                         for ( let i = 0, l = morphAttribute.length; i < l; i ++ ) {
13222
13223                                 array.push( morphAttribute[ i ].clone( data ) );
13224
13225                         }
13226
13227                         this.morphAttributes[ name ] = array;
13228
13229                 }
13230
13231                 this.morphTargetsRelative = source.morphTargetsRelative;
13232
13233                 // groups
13234
13235                 const groups = source.groups;
13236
13237                 for ( let i = 0, l = groups.length; i < l; i ++ ) {
13238
13239                         const group = groups[ i ];
13240                         this.addGroup( group.start, group.count, group.materialIndex );
13241
13242                 }
13243
13244                 // bounding box
13245
13246                 const boundingBox = source.boundingBox;
13247
13248                 if ( boundingBox !== null ) {
13249
13250                         this.boundingBox = boundingBox.clone();
13251
13252                 }
13253
13254                 // bounding sphere
13255
13256                 const boundingSphere = source.boundingSphere;
13257
13258                 if ( boundingSphere !== null ) {
13259
13260                         this.boundingSphere = boundingSphere.clone();
13261
13262                 }
13263
13264                 // draw range
13265
13266                 this.drawRange.start = source.drawRange.start;
13267                 this.drawRange.count = source.drawRange.count;
13268
13269                 // user data
13270
13271                 this.userData = source.userData;
13272
13273                 // geometry generator parameters
13274
13275                 if ( source.parameters !== undefined ) this.parameters = Object.assign( {}, source.parameters );
13276
13277                 return this;
13278
13279         }
13280
13281         dispose() {
13282
13283                 this.dispatchEvent( { type: 'dispose' } );
13284
13285         }
13286
13287 }
13288
13289 BufferGeometry.prototype.isBufferGeometry = true;
13290
13291 const _inverseMatrix$2 = /*@__PURE__*/ new Matrix4();
13292 const _ray$2 = /*@__PURE__*/ new Ray();
13293 const _sphere$3 = /*@__PURE__*/ new Sphere();
13294
13295 const _vA$1 = /*@__PURE__*/ new Vector3();
13296 const _vB$1 = /*@__PURE__*/ new Vector3();
13297 const _vC$1 = /*@__PURE__*/ new Vector3();
13298
13299 const _tempA = /*@__PURE__*/ new Vector3();
13300 const _tempB = /*@__PURE__*/ new Vector3();
13301 const _tempC = /*@__PURE__*/ new Vector3();
13302
13303 const _morphA = /*@__PURE__*/ new Vector3();
13304 const _morphB = /*@__PURE__*/ new Vector3();
13305 const _morphC = /*@__PURE__*/ new Vector3();
13306
13307 const _uvA$1 = /*@__PURE__*/ new Vector2();
13308 const _uvB$1 = /*@__PURE__*/ new Vector2();
13309 const _uvC$1 = /*@__PURE__*/ new Vector2();
13310
13311 const _intersectionPoint = /*@__PURE__*/ new Vector3();
13312 const _intersectionPointWorld = /*@__PURE__*/ new Vector3();
13313
13314 class Mesh extends Object3D {
13315
13316         constructor( geometry = new BufferGeometry(), material = new MeshBasicMaterial() ) {
13317
13318                 super();
13319
13320                 this.type = 'Mesh';
13321
13322                 this.geometry = geometry;
13323                 this.material = material;
13324
13325                 this.updateMorphTargets();
13326
13327         }
13328
13329         copy( source ) {
13330
13331                 super.copy( source );
13332
13333                 if ( source.morphTargetInfluences !== undefined ) {
13334
13335                         this.morphTargetInfluences = source.morphTargetInfluences.slice();
13336
13337                 }
13338
13339                 if ( source.morphTargetDictionary !== undefined ) {
13340
13341                         this.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary );
13342
13343                 }
13344
13345                 this.material = source.material;
13346                 this.geometry = source.geometry;
13347
13348                 return this;
13349
13350         }
13351
13352         updateMorphTargets() {
13353
13354                 const geometry = this.geometry;
13355
13356                 if ( geometry.isBufferGeometry ) {
13357
13358                         const morphAttributes = geometry.morphAttributes;
13359                         const keys = Object.keys( morphAttributes );
13360
13361                         if ( keys.length > 0 ) {
13362
13363                                 const morphAttribute = morphAttributes[ keys[ 0 ] ];
13364
13365                                 if ( morphAttribute !== undefined ) {
13366
13367                                         this.morphTargetInfluences = [];
13368                                         this.morphTargetDictionary = {};
13369
13370                                         for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {
13371
13372                                                 const name = morphAttribute[ m ].name || String( m );
13373
13374                                                 this.morphTargetInfluences.push( 0 );
13375                                                 this.morphTargetDictionary[ name ] = m;
13376
13377                                         }
13378
13379                                 }
13380
13381                         }
13382
13383                 } else {
13384
13385                         const morphTargets = geometry.morphTargets;
13386
13387                         if ( morphTargets !== undefined && morphTargets.length > 0 ) {
13388
13389                                 console.error( 'THREE.Mesh.updateMorphTargets() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' );
13390
13391                         }
13392
13393                 }
13394
13395         }
13396
13397         raycast( raycaster, intersects ) {
13398
13399                 const geometry = this.geometry;
13400                 const material = this.material;
13401                 const matrixWorld = this.matrixWorld;
13402
13403                 if ( material === undefined ) return;
13404
13405                 // Checking boundingSphere distance to ray
13406
13407                 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
13408
13409                 _sphere$3.copy( geometry.boundingSphere );
13410                 _sphere$3.applyMatrix4( matrixWorld );
13411
13412                 if ( raycaster.ray.intersectsSphere( _sphere$3 ) === false ) return;
13413
13414                 //
13415
13416                 _inverseMatrix$2.copy( matrixWorld ).invert();
13417                 _ray$2.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$2 );
13418
13419                 // Check boundingBox before continuing
13420
13421                 if ( geometry.boundingBox !== null ) {
13422
13423                         if ( _ray$2.intersectsBox( geometry.boundingBox ) === false ) return;
13424
13425                 }
13426
13427                 let intersection;
13428
13429                 if ( geometry.isBufferGeometry ) {
13430
13431                         const index = geometry.index;
13432                         const position = geometry.attributes.position;
13433                         const morphPosition = geometry.morphAttributes.position;
13434                         const morphTargetsRelative = geometry.morphTargetsRelative;
13435                         const uv = geometry.attributes.uv;
13436                         const uv2 = geometry.attributes.uv2;
13437                         const groups = geometry.groups;
13438                         const drawRange = geometry.drawRange;
13439
13440                         if ( index !== null ) {
13441
13442                                 // indexed buffer geometry
13443
13444                                 if ( Array.isArray( material ) ) {
13445
13446                                         for ( let i = 0, il = groups.length; i < il; i ++ ) {
13447
13448                                                 const group = groups[ i ];
13449                                                 const groupMaterial = material[ group.materialIndex ];
13450
13451                                                 const start = Math.max( group.start, drawRange.start );
13452                                                 const end = Math.min( index.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) );
13453
13454                                                 for ( let j = start, jl = end; j < jl; j += 3 ) {
13455
13456                                                         const a = index.getX( j );
13457                                                         const b = index.getX( j + 1 );
13458                                                         const c = index.getX( j + 2 );
13459
13460                                                         intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray$2, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c );
13461
13462                                                         if ( intersection ) {
13463
13464                                                                 intersection.faceIndex = Math.floor( j / 3 ); // triangle number in indexed buffer semantics
13465                                                                 intersection.face.materialIndex = group.materialIndex;
13466                                                                 intersects.push( intersection );
13467
13468                                                         }
13469
13470                                                 }
13471
13472                                         }
13473
13474                                 } else {
13475
13476                                         const start = Math.max( 0, drawRange.start );
13477                                         const end = Math.min( index.count, ( drawRange.start + drawRange.count ) );
13478
13479                                         for ( let i = start, il = end; i < il; i += 3 ) {
13480
13481                                                 const a = index.getX( i );
13482                                                 const b = index.getX( i + 1 );
13483                                                 const c = index.getX( i + 2 );
13484
13485                                                 intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray$2, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c );
13486
13487                                                 if ( intersection ) {
13488
13489                                                         intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indexed buffer semantics
13490                                                         intersects.push( intersection );
13491
13492                                                 }
13493
13494                                         }
13495
13496                                 }
13497
13498                         } else if ( position !== undefined ) {
13499
13500                                 // non-indexed buffer geometry
13501
13502                                 if ( Array.isArray( material ) ) {
13503
13504                                         for ( let i = 0, il = groups.length; i < il; i ++ ) {
13505
13506                                                 const group = groups[ i ];
13507                                                 const groupMaterial = material[ group.materialIndex ];
13508
13509                                                 const start = Math.max( group.start, drawRange.start );
13510                                                 const end = Math.min( position.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) );
13511
13512                                                 for ( let j = start, jl = end; j < jl; j += 3 ) {
13513
13514                                                         const a = j;
13515                                                         const b = j + 1;
13516                                                         const c = j + 2;
13517
13518                                                         intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray$2, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c );
13519
13520                                                         if ( intersection ) {
13521
13522                                                                 intersection.faceIndex = Math.floor( j / 3 ); // triangle number in non-indexed buffer semantics
13523                                                                 intersection.face.materialIndex = group.materialIndex;
13524                                                                 intersects.push( intersection );
13525
13526                                                         }
13527
13528                                                 }
13529
13530                                         }
13531
13532                                 } else {
13533
13534                                         const start = Math.max( 0, drawRange.start );
13535                                         const end = Math.min( position.count, ( drawRange.start + drawRange.count ) );
13536
13537                                         for ( let i = start, il = end; i < il; i += 3 ) {
13538
13539                                                 const a = i;
13540                                                 const b = i + 1;
13541                                                 const c = i + 2;
13542
13543                                                 intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray$2, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c );
13544
13545                                                 if ( intersection ) {
13546
13547                                                         intersection.faceIndex = Math.floor( i / 3 ); // triangle number in non-indexed buffer semantics
13548                                                         intersects.push( intersection );
13549
13550                                                 }
13551
13552                                         }
13553
13554                                 }
13555
13556                         }
13557
13558                 } else if ( geometry.isGeometry ) {
13559
13560                         console.error( 'THREE.Mesh.raycast() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' );
13561
13562                 }
13563
13564         }
13565
13566 }
13567
13568 Mesh.prototype.isMesh = true;
13569
13570 function checkIntersection( object, material, raycaster, ray, pA, pB, pC, point ) {
13571
13572         let intersect;
13573
13574         if ( material.side === BackSide ) {
13575
13576                 intersect = ray.intersectTriangle( pC, pB, pA, true, point );
13577
13578         } else {
13579
13580                 intersect = ray.intersectTriangle( pA, pB, pC, material.side !== DoubleSide, point );
13581
13582         }
13583
13584         if ( intersect === null ) return null;
13585
13586         _intersectionPointWorld.copy( point );
13587         _intersectionPointWorld.applyMatrix4( object.matrixWorld );
13588
13589         const distance = raycaster.ray.origin.distanceTo( _intersectionPointWorld );
13590
13591         if ( distance < raycaster.near || distance > raycaster.far ) return null;
13592
13593         return {
13594                 distance: distance,
13595                 point: _intersectionPointWorld.clone(),
13596                 object: object
13597         };
13598
13599 }
13600
13601 function checkBufferGeometryIntersection( object, material, raycaster, ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ) {
13602
13603         _vA$1.fromBufferAttribute( position, a );
13604         _vB$1.fromBufferAttribute( position, b );
13605         _vC$1.fromBufferAttribute( position, c );
13606
13607         const morphInfluences = object.morphTargetInfluences;
13608
13609         if ( morphPosition && morphInfluences ) {
13610
13611                 _morphA.set( 0, 0, 0 );
13612                 _morphB.set( 0, 0, 0 );
13613                 _morphC.set( 0, 0, 0 );
13614
13615                 for ( let i = 0, il = morphPosition.length; i < il; i ++ ) {
13616
13617                         const influence = morphInfluences[ i ];
13618                         const morphAttribute = morphPosition[ i ];
13619
13620                         if ( influence === 0 ) continue;
13621
13622                         _tempA.fromBufferAttribute( morphAttribute, a );
13623                         _tempB.fromBufferAttribute( morphAttribute, b );
13624                         _tempC.fromBufferAttribute( morphAttribute, c );
13625
13626                         if ( morphTargetsRelative ) {
13627
13628                                 _morphA.addScaledVector( _tempA, influence );
13629                                 _morphB.addScaledVector( _tempB, influence );
13630                                 _morphC.addScaledVector( _tempC, influence );
13631
13632                         } else {
13633
13634                                 _morphA.addScaledVector( _tempA.sub( _vA$1 ), influence );
13635                                 _morphB.addScaledVector( _tempB.sub( _vB$1 ), influence );
13636                                 _morphC.addScaledVector( _tempC.sub( _vC$1 ), influence );
13637
13638                         }
13639
13640                 }
13641
13642                 _vA$1.add( _morphA );
13643                 _vB$1.add( _morphB );
13644                 _vC$1.add( _morphC );
13645
13646         }
13647
13648         if ( object.isSkinnedMesh ) {
13649
13650                 object.boneTransform( a, _vA$1 );
13651                 object.boneTransform( b, _vB$1 );
13652                 object.boneTransform( c, _vC$1 );
13653
13654         }
13655
13656         const intersection = checkIntersection( object, material, raycaster, ray, _vA$1, _vB$1, _vC$1, _intersectionPoint );
13657
13658         if ( intersection ) {
13659
13660                 if ( uv ) {
13661
13662                         _uvA$1.fromBufferAttribute( uv, a );
13663                         _uvB$1.fromBufferAttribute( uv, b );
13664                         _uvC$1.fromBufferAttribute( uv, c );
13665
13666                         intersection.uv = Triangle.getUV( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() );
13667
13668                 }
13669
13670                 if ( uv2 ) {
13671
13672                         _uvA$1.fromBufferAttribute( uv2, a );
13673                         _uvB$1.fromBufferAttribute( uv2, b );
13674                         _uvC$1.fromBufferAttribute( uv2, c );
13675
13676                         intersection.uv2 = Triangle.getUV( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() );
13677
13678                 }
13679
13680                 const face = {
13681                         a: a,
13682                         b: b,
13683                         c: c,
13684                         normal: new Vector3(),
13685                         materialIndex: 0
13686                 };
13687
13688                 Triangle.getNormal( _vA$1, _vB$1, _vC$1, face.normal );
13689
13690                 intersection.face = face;
13691
13692         }
13693
13694         return intersection;
13695
13696 }
13697
13698 class BoxGeometry extends BufferGeometry {
13699
13700         constructor( width = 1, height = 1, depth = 1, widthSegments = 1, heightSegments = 1, depthSegments = 1 ) {
13701
13702                 super();
13703
13704                 this.type = 'BoxGeometry';
13705
13706                 this.parameters = {
13707                         width: width,
13708                         height: height,
13709                         depth: depth,
13710                         widthSegments: widthSegments,
13711                         heightSegments: heightSegments,
13712                         depthSegments: depthSegments
13713                 };
13714
13715                 const scope = this;
13716
13717                 // segments
13718
13719                 widthSegments = Math.floor( widthSegments );
13720                 heightSegments = Math.floor( heightSegments );
13721                 depthSegments = Math.floor( depthSegments );
13722
13723                 // buffers
13724
13725                 const indices = [];
13726                 const vertices = [];
13727                 const normals = [];
13728                 const uvs = [];
13729
13730                 // helper variables
13731
13732                 let numberOfVertices = 0;
13733                 let groupStart = 0;
13734
13735                 // build each side of the box geometry
13736
13737                 buildPlane( 'z', 'y', 'x', - 1, - 1, depth, height, width, depthSegments, heightSegments, 0 ); // px
13738                 buildPlane( 'z', 'y', 'x', 1, - 1, depth, height, - width, depthSegments, heightSegments, 1 ); // nx
13739                 buildPlane( 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2 ); // py
13740                 buildPlane( 'x', 'z', 'y', 1, - 1, width, depth, - height, widthSegments, depthSegments, 3 ); // ny
13741                 buildPlane( 'x', 'y', 'z', 1, - 1, width, height, depth, widthSegments, heightSegments, 4 ); // pz
13742                 buildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth, widthSegments, heightSegments, 5 ); // nz
13743
13744                 // build geometry
13745
13746                 this.setIndex( indices );
13747                 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
13748                 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
13749                 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
13750
13751                 function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) {
13752
13753                         const segmentWidth = width / gridX;
13754                         const segmentHeight = height / gridY;
13755
13756                         const widthHalf = width / 2;
13757                         const heightHalf = height / 2;
13758                         const depthHalf = depth / 2;
13759
13760                         const gridX1 = gridX + 1;
13761                         const gridY1 = gridY + 1;
13762
13763                         let vertexCounter = 0;
13764                         let groupCount = 0;
13765
13766                         const vector = new Vector3();
13767
13768                         // generate vertices, normals and uvs
13769
13770                         for ( let iy = 0; iy < gridY1; iy ++ ) {
13771
13772                                 const y = iy * segmentHeight - heightHalf;
13773
13774                                 for ( let ix = 0; ix < gridX1; ix ++ ) {
13775
13776                                         const x = ix * segmentWidth - widthHalf;
13777
13778                                         // set values to correct vector component
13779
13780                                         vector[ u ] = x * udir;
13781                                         vector[ v ] = y * vdir;
13782                                         vector[ w ] = depthHalf;
13783
13784                                         // now apply vector to vertex buffer
13785
13786                                         vertices.push( vector.x, vector.y, vector.z );
13787
13788                                         // set values to correct vector component
13789
13790                                         vector[ u ] = 0;
13791                                         vector[ v ] = 0;
13792                                         vector[ w ] = depth > 0 ? 1 : - 1;
13793
13794                                         // now apply vector to normal buffer
13795
13796                                         normals.push( vector.x, vector.y, vector.z );
13797
13798                                         // uvs
13799
13800                                         uvs.push( ix / gridX );
13801                                         uvs.push( 1 - ( iy / gridY ) );
13802
13803                                         // counters
13804
13805                                         vertexCounter += 1;
13806
13807                                 }
13808
13809                         }
13810
13811                         // indices
13812
13813                         // 1. you need three indices to draw a single face
13814                         // 2. a single segment consists of two faces
13815                         // 3. so we need to generate six (2*3) indices per segment
13816
13817                         for ( let iy = 0; iy < gridY; iy ++ ) {
13818
13819                                 for ( let ix = 0; ix < gridX; ix ++ ) {
13820
13821                                         const a = numberOfVertices + ix + gridX1 * iy;
13822                                         const b = numberOfVertices + ix + gridX1 * ( iy + 1 );
13823                                         const c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 );
13824                                         const d = numberOfVertices + ( ix + 1 ) + gridX1 * iy;
13825
13826                                         // faces
13827
13828                                         indices.push( a, b, d );
13829                                         indices.push( b, c, d );
13830
13831                                         // increase counter
13832
13833                                         groupCount += 6;
13834
13835                                 }
13836
13837                         }
13838
13839                         // add a group to the geometry. this will ensure multi material support
13840
13841                         scope.addGroup( groupStart, groupCount, materialIndex );
13842
13843                         // calculate new start value for groups
13844
13845                         groupStart += groupCount;
13846
13847                         // update total number of vertices
13848
13849                         numberOfVertices += vertexCounter;
13850
13851                 }
13852
13853         }
13854
13855         static fromJSON( data ) {
13856
13857                 return new BoxGeometry( data.width, data.height, data.depth, data.widthSegments, data.heightSegments, data.depthSegments );
13858
13859         }
13860
13861 }
13862
13863 /**
13864  * Uniform Utilities
13865  */
13866
13867 function cloneUniforms( src ) {
13868
13869         const dst = {};
13870
13871         for ( const u in src ) {
13872
13873                 dst[ u ] = {};
13874
13875                 for ( const p in src[ u ] ) {
13876
13877                         const property = src[ u ][ p ];
13878
13879                         if ( property && ( property.isColor ||
13880                                 property.isMatrix3 || property.isMatrix4 ||
13881                                 property.isVector2 || property.isVector3 || property.isVector4 ||
13882                                 property.isTexture || property.isQuaternion ) ) {
13883
13884                                 dst[ u ][ p ] = property.clone();
13885
13886                         } else if ( Array.isArray( property ) ) {
13887
13888                                 dst[ u ][ p ] = property.slice();
13889
13890                         } else {
13891
13892                                 dst[ u ][ p ] = property;
13893
13894                         }
13895
13896                 }
13897
13898         }
13899
13900         return dst;
13901
13902 }
13903
13904 function mergeUniforms( uniforms ) {
13905
13906         const merged = {};
13907
13908         for ( let u = 0; u < uniforms.length; u ++ ) {
13909
13910                 const tmp = cloneUniforms( uniforms[ u ] );
13911
13912                 for ( const p in tmp ) {
13913
13914                         merged[ p ] = tmp[ p ];
13915
13916                 }
13917
13918         }
13919
13920         return merged;
13921
13922 }
13923
13924 // Legacy
13925
13926 const UniformsUtils = { clone: cloneUniforms, merge: mergeUniforms };
13927
13928 var default_vertex = "void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}";
13929
13930 var default_fragment = "void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}";
13931
13932 /**
13933  * parameters = {
13934  *  defines: { "label" : "value" },
13935  *  uniforms: { "parameter1": { value: 1.0 }, "parameter2": { value2: 2 } },
13936  *
13937  *  fragmentShader: <string>,
13938  *  vertexShader: <string>,
13939  *
13940  *  wireframe: <boolean>,
13941  *  wireframeLinewidth: <float>,
13942  *
13943  *  lights: <bool>
13944  * }
13945  */
13946
13947 class ShaderMaterial extends Material {
13948
13949         constructor( parameters ) {
13950
13951                 super();
13952
13953                 this.type = 'ShaderMaterial';
13954
13955                 this.defines = {};
13956                 this.uniforms = {};
13957
13958                 this.vertexShader = default_vertex;
13959                 this.fragmentShader = default_fragment;
13960
13961                 this.linewidth = 1;
13962
13963                 this.wireframe = false;
13964                 this.wireframeLinewidth = 1;
13965
13966                 this.fog = false; // set to use scene fog
13967                 this.lights = false; // set to use scene lights
13968                 this.clipping = false; // set to use user-defined clipping planes
13969
13970                 this.extensions = {
13971                         derivatives: false, // set to use derivatives
13972                         fragDepth: false, // set to use fragment depth values
13973                         drawBuffers: false, // set to use draw buffers
13974                         shaderTextureLOD: false // set to use shader texture LOD
13975                 };
13976
13977                 // When rendered geometry doesn't include these attributes but the material does,
13978                 // use these default values in WebGL. This avoids errors when buffer data is missing.
13979                 this.defaultAttributeValues = {
13980                         'color': [ 1, 1, 1 ],
13981                         'uv': [ 0, 0 ],
13982                         'uv2': [ 0, 0 ]
13983                 };
13984
13985                 this.index0AttributeName = undefined;
13986                 this.uniformsNeedUpdate = false;
13987
13988                 this.glslVersion = null;
13989
13990                 if ( parameters !== undefined ) {
13991
13992                         if ( parameters.attributes !== undefined ) {
13993
13994                                 console.error( 'THREE.ShaderMaterial: attributes should now be defined in THREE.BufferGeometry instead.' );
13995
13996                         }
13997
13998                         this.setValues( parameters );
13999
14000                 }
14001
14002         }
14003
14004         copy( source ) {
14005
14006                 super.copy( source );
14007
14008                 this.fragmentShader = source.fragmentShader;
14009                 this.vertexShader = source.vertexShader;
14010
14011                 this.uniforms = cloneUniforms( source.uniforms );
14012
14013                 this.defines = Object.assign( {}, source.defines );
14014
14015                 this.wireframe = source.wireframe;
14016                 this.wireframeLinewidth = source.wireframeLinewidth;
14017
14018                 this.lights = source.lights;
14019                 this.clipping = source.clipping;
14020
14021                 this.extensions = Object.assign( {}, source.extensions );
14022
14023                 this.glslVersion = source.glslVersion;
14024
14025                 return this;
14026
14027         }
14028
14029         toJSON( meta ) {
14030
14031                 const data = super.toJSON( meta );
14032
14033                 data.glslVersion = this.glslVersion;
14034                 data.uniforms = {};
14035
14036                 for ( const name in this.uniforms ) {
14037
14038                         const uniform = this.uniforms[ name ];
14039                         const value = uniform.value;
14040
14041                         if ( value && value.isTexture ) {
14042
14043                                 data.uniforms[ name ] = {
14044                                         type: 't',
14045                                         value: value.toJSON( meta ).uuid
14046                                 };
14047
14048                         } else if ( value && value.isColor ) {
14049
14050                                 data.uniforms[ name ] = {
14051                                         type: 'c',
14052                                         value: value.getHex()
14053                                 };
14054
14055                         } else if ( value && value.isVector2 ) {
14056
14057                                 data.uniforms[ name ] = {
14058                                         type: 'v2',
14059                                         value: value.toArray()
14060                                 };
14061
14062                         } else if ( value && value.isVector3 ) {
14063
14064                                 data.uniforms[ name ] = {
14065                                         type: 'v3',
14066                                         value: value.toArray()
14067                                 };
14068
14069                         } else if ( value && value.isVector4 ) {
14070
14071                                 data.uniforms[ name ] = {
14072                                         type: 'v4',
14073                                         value: value.toArray()
14074                                 };
14075
14076                         } else if ( value && value.isMatrix3 ) {
14077
14078                                 data.uniforms[ name ] = {
14079                                         type: 'm3',
14080                                         value: value.toArray()
14081                                 };
14082
14083                         } else if ( value && value.isMatrix4 ) {
14084
14085                                 data.uniforms[ name ] = {
14086                                         type: 'm4',
14087                                         value: value.toArray()
14088                                 };
14089
14090                         } else {
14091
14092                                 data.uniforms[ name ] = {
14093                                         value: value
14094                                 };
14095
14096                                 // note: the array variants v2v, v3v, v4v, m4v and tv are not supported so far
14097
14098                         }
14099
14100                 }
14101
14102                 if ( Object.keys( this.defines ).length > 0 ) data.defines = this.defines;
14103
14104                 data.vertexShader = this.vertexShader;
14105                 data.fragmentShader = this.fragmentShader;
14106
14107                 const extensions = {};
14108
14109                 for ( const key in this.extensions ) {
14110
14111                         if ( this.extensions[ key ] === true ) extensions[ key ] = true;
14112
14113                 }
14114
14115                 if ( Object.keys( extensions ).length > 0 ) data.extensions = extensions;
14116
14117                 return data;
14118
14119         }
14120
14121 }
14122
14123 ShaderMaterial.prototype.isShaderMaterial = true;
14124
14125 class Camera$1 extends Object3D {
14126
14127         constructor() {
14128
14129                 super();
14130
14131                 this.type = 'Camera';
14132
14133                 this.matrixWorldInverse = new Matrix4();
14134
14135                 this.projectionMatrix = new Matrix4();
14136                 this.projectionMatrixInverse = new Matrix4();
14137
14138         }
14139
14140         copy( source, recursive ) {
14141
14142                 super.copy( source, recursive );
14143
14144                 this.matrixWorldInverse.copy( source.matrixWorldInverse );
14145
14146                 this.projectionMatrix.copy( source.projectionMatrix );
14147                 this.projectionMatrixInverse.copy( source.projectionMatrixInverse );
14148
14149                 return this;
14150
14151         }
14152
14153         getWorldDirection( target ) {
14154
14155                 this.updateWorldMatrix( true, false );
14156
14157                 const e = this.matrixWorld.elements;
14158
14159                 return target.set( - e[ 8 ], - e[ 9 ], - e[ 10 ] ).normalize();
14160
14161         }
14162
14163         updateMatrixWorld( force ) {
14164
14165                 super.updateMatrixWorld( force );
14166
14167                 this.matrixWorldInverse.copy( this.matrixWorld ).invert();
14168
14169         }
14170
14171         updateWorldMatrix( updateParents, updateChildren ) {
14172
14173                 super.updateWorldMatrix( updateParents, updateChildren );
14174
14175                 this.matrixWorldInverse.copy( this.matrixWorld ).invert();
14176
14177         }
14178
14179         clone() {
14180
14181                 return new this.constructor().copy( this );
14182
14183         }
14184
14185 }
14186
14187 Camera$1.prototype.isCamera = true;
14188
14189 class PerspectiveCamera extends Camera$1 {
14190
14191         constructor( fov = 50, aspect = 1, near = 0.1, far = 2000 ) {
14192
14193                 super();
14194
14195                 this.type = 'PerspectiveCamera';
14196
14197                 this.fov = fov;
14198                 this.zoom = 1;
14199
14200                 this.near = near;
14201                 this.far = far;
14202                 this.focus = 10;
14203
14204                 this.aspect = aspect;
14205                 this.view = null;
14206
14207                 this.filmGauge = 35;    // width of the film (default in millimeters)
14208                 this.filmOffset = 0;    // horizontal film offset (same unit as gauge)
14209
14210                 this.updateProjectionMatrix();
14211
14212         }
14213
14214         copy( source, recursive ) {
14215
14216                 super.copy( source, recursive );
14217
14218                 this.fov = source.fov;
14219                 this.zoom = source.zoom;
14220
14221                 this.near = source.near;
14222                 this.far = source.far;
14223                 this.focus = source.focus;
14224
14225                 this.aspect = source.aspect;
14226                 this.view = source.view === null ? null : Object.assign( {}, source.view );
14227
14228                 this.filmGauge = source.filmGauge;
14229                 this.filmOffset = source.filmOffset;
14230
14231                 return this;
14232
14233         }
14234
14235         /**
14236          * Sets the FOV by focal length in respect to the current .filmGauge.
14237          *
14238          * The default film gauge is 35, so that the focal length can be specified for
14239          * a 35mm (full frame) camera.
14240          *
14241          * Values for focal length and film gauge must have the same unit.
14242          */
14243         setFocalLength( focalLength ) {
14244
14245                 /** see {@link http://www.bobatkins.com/photography/technical/field_of_view.html} */
14246                 const vExtentSlope = 0.5 * this.getFilmHeight() / focalLength;
14247
14248                 this.fov = RAD2DEG$1 * 2 * Math.atan( vExtentSlope );
14249                 this.updateProjectionMatrix();
14250
14251         }
14252
14253         /**
14254          * Calculates the focal length from the current .fov and .filmGauge.
14255          */
14256         getFocalLength() {
14257
14258                 const vExtentSlope = Math.tan( DEG2RAD$1 * 0.5 * this.fov );
14259
14260                 return 0.5 * this.getFilmHeight() / vExtentSlope;
14261
14262         }
14263
14264         getEffectiveFOV() {
14265
14266                 return RAD2DEG$1 * 2 * Math.atan(
14267                         Math.tan( DEG2RAD$1 * 0.5 * this.fov ) / this.zoom );
14268
14269         }
14270
14271         getFilmWidth() {
14272
14273                 // film not completely covered in portrait format (aspect < 1)
14274                 return this.filmGauge * Math.min( this.aspect, 1 );
14275
14276         }
14277
14278         getFilmHeight() {
14279
14280                 // film not completely covered in landscape format (aspect > 1)
14281                 return this.filmGauge / Math.max( this.aspect, 1 );
14282
14283         }
14284
14285         /**
14286          * Sets an offset in a larger frustum. This is useful for multi-window or
14287          * multi-monitor/multi-machine setups.
14288          *
14289          * For example, if you have 3x2 monitors and each monitor is 1920x1080 and
14290          * the monitors are in grid like this
14291          *
14292          *   +---+---+---+
14293          *   | A | B | C |
14294          *   +---+---+---+
14295          *   | D | E | F |
14296          *   +---+---+---+
14297          *
14298          * then for each monitor you would call it like this
14299          *
14300          *   const w = 1920;
14301          *   const h = 1080;
14302          *   const fullWidth = w * 3;
14303          *   const fullHeight = h * 2;
14304          *
14305          *   --A--
14306          *   camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 0, w, h );
14307          *   --B--
14308          *   camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 0, w, h );
14309          *   --C--
14310          *   camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 0, w, h );
14311          *   --D--
14312          *   camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 1, w, h );
14313          *   --E--
14314          *   camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 1, w, h );
14315          *   --F--
14316          *   camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 1, w, h );
14317          *
14318          *   Note there is no reason monitors have to be the same size or in a grid.
14319          */
14320         setViewOffset( fullWidth, fullHeight, x, y, width, height ) {
14321
14322                 this.aspect = fullWidth / fullHeight;
14323
14324                 if ( this.view === null ) {
14325
14326                         this.view = {
14327                                 enabled: true,
14328                                 fullWidth: 1,
14329                                 fullHeight: 1,
14330                                 offsetX: 0,
14331                                 offsetY: 0,
14332                                 width: 1,
14333                                 height: 1
14334                         };
14335
14336                 }
14337
14338                 this.view.enabled = true;
14339                 this.view.fullWidth = fullWidth;
14340                 this.view.fullHeight = fullHeight;
14341                 this.view.offsetX = x;
14342                 this.view.offsetY = y;
14343                 this.view.width = width;
14344                 this.view.height = height;
14345
14346                 this.updateProjectionMatrix();
14347
14348         }
14349
14350         clearViewOffset() {
14351
14352                 if ( this.view !== null ) {
14353
14354                         this.view.enabled = false;
14355
14356                 }
14357
14358                 this.updateProjectionMatrix();
14359
14360         }
14361
14362         updateProjectionMatrix() {
14363
14364                 const near = this.near;
14365                 let top = near * Math.tan( DEG2RAD$1 * 0.5 * this.fov ) / this.zoom;
14366                 let height = 2 * top;
14367                 let width = this.aspect * height;
14368                 let left = - 0.5 * width;
14369                 const view = this.view;
14370
14371                 if ( this.view !== null && this.view.enabled ) {
14372
14373                         const fullWidth = view.fullWidth,
14374                                 fullHeight = view.fullHeight;
14375
14376                         left += view.offsetX * width / fullWidth;
14377                         top -= view.offsetY * height / fullHeight;
14378                         width *= view.width / fullWidth;
14379                         height *= view.height / fullHeight;
14380
14381                 }
14382
14383                 const skew = this.filmOffset;
14384                 if ( skew !== 0 ) left += near * skew / this.getFilmWidth();
14385
14386                 this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far );
14387
14388                 this.projectionMatrixInverse.copy( this.projectionMatrix ).invert();
14389
14390         }
14391
14392         toJSON( meta ) {
14393
14394                 const data = super.toJSON( meta );
14395
14396                 data.object.fov = this.fov;
14397                 data.object.zoom = this.zoom;
14398
14399                 data.object.near = this.near;
14400                 data.object.far = this.far;
14401                 data.object.focus = this.focus;
14402
14403                 data.object.aspect = this.aspect;
14404
14405                 if ( this.view !== null ) data.object.view = Object.assign( {}, this.view );
14406
14407                 data.object.filmGauge = this.filmGauge;
14408                 data.object.filmOffset = this.filmOffset;
14409
14410                 return data;
14411
14412         }
14413
14414 }
14415
14416 PerspectiveCamera.prototype.isPerspectiveCamera = true;
14417
14418 const fov = 90, aspect = 1;
14419
14420 class CubeCamera extends Object3D {
14421
14422         constructor( near, far, renderTarget ) {
14423
14424                 super();
14425
14426                 this.type = 'CubeCamera';
14427
14428                 if ( renderTarget.isWebGLCubeRenderTarget !== true ) {
14429
14430                         console.error( 'THREE.CubeCamera: The constructor now expects an instance of WebGLCubeRenderTarget as third parameter.' );
14431                         return;
14432
14433                 }
14434
14435                 this.renderTarget = renderTarget;
14436
14437                 const cameraPX = new PerspectiveCamera( fov, aspect, near, far );
14438                 cameraPX.layers = this.layers;
14439                 cameraPX.up.set( 0, - 1, 0 );
14440                 cameraPX.lookAt( new Vector3( 1, 0, 0 ) );
14441                 this.add( cameraPX );
14442
14443                 const cameraNX = new PerspectiveCamera( fov, aspect, near, far );
14444                 cameraNX.layers = this.layers;
14445                 cameraNX.up.set( 0, - 1, 0 );
14446                 cameraNX.lookAt( new Vector3( - 1, 0, 0 ) );
14447                 this.add( cameraNX );
14448
14449                 const cameraPY = new PerspectiveCamera( fov, aspect, near, far );
14450                 cameraPY.layers = this.layers;
14451                 cameraPY.up.set( 0, 0, 1 );
14452                 cameraPY.lookAt( new Vector3( 0, 1, 0 ) );
14453                 this.add( cameraPY );
14454
14455                 const cameraNY = new PerspectiveCamera( fov, aspect, near, far );
14456                 cameraNY.layers = this.layers;
14457                 cameraNY.up.set( 0, 0, - 1 );
14458                 cameraNY.lookAt( new Vector3( 0, - 1, 0 ) );
14459                 this.add( cameraNY );
14460
14461                 const cameraPZ = new PerspectiveCamera( fov, aspect, near, far );
14462                 cameraPZ.layers = this.layers;
14463                 cameraPZ.up.set( 0, - 1, 0 );
14464                 cameraPZ.lookAt( new Vector3( 0, 0, 1 ) );
14465                 this.add( cameraPZ );
14466
14467                 const cameraNZ = new PerspectiveCamera( fov, aspect, near, far );
14468                 cameraNZ.layers = this.layers;
14469                 cameraNZ.up.set( 0, - 1, 0 );
14470                 cameraNZ.lookAt( new Vector3( 0, 0, - 1 ) );
14471                 this.add( cameraNZ );
14472
14473         }
14474
14475         update( renderer, scene ) {
14476
14477                 if ( this.parent === null ) this.updateMatrixWorld();
14478
14479                 const renderTarget = this.renderTarget;
14480
14481                 const [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = this.children;
14482
14483                 const currentXrEnabled = renderer.xr.enabled;
14484                 const currentRenderTarget = renderer.getRenderTarget();
14485
14486                 renderer.xr.enabled = false;
14487
14488                 const generateMipmaps = renderTarget.texture.generateMipmaps;
14489
14490                 renderTarget.texture.generateMipmaps = false;
14491
14492                 renderer.setRenderTarget( renderTarget, 0 );
14493                 renderer.render( scene, cameraPX );
14494
14495                 renderer.setRenderTarget( renderTarget, 1 );
14496                 renderer.render( scene, cameraNX );
14497
14498                 renderer.setRenderTarget( renderTarget, 2 );
14499                 renderer.render( scene, cameraPY );
14500
14501                 renderer.setRenderTarget( renderTarget, 3 );
14502                 renderer.render( scene, cameraNY );
14503
14504                 renderer.setRenderTarget( renderTarget, 4 );
14505                 renderer.render( scene, cameraPZ );
14506
14507                 renderTarget.texture.generateMipmaps = generateMipmaps;
14508
14509                 renderer.setRenderTarget( renderTarget, 5 );
14510                 renderer.render( scene, cameraNZ );
14511
14512                 renderer.setRenderTarget( currentRenderTarget );
14513
14514                 renderer.xr.enabled = currentXrEnabled;
14515
14516         }
14517
14518 }
14519
14520 class CubeTexture extends Texture {
14521
14522         constructor( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) {
14523
14524                 images = images !== undefined ? images : [];
14525                 mapping = mapping !== undefined ? mapping : CubeReflectionMapping;
14526
14527                 super( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
14528
14529                 this.flipY = false;
14530
14531         }
14532
14533         get images() {
14534
14535                 return this.image;
14536
14537         }
14538
14539         set images( value ) {
14540
14541                 this.image = value;
14542
14543         }
14544
14545 }
14546
14547 CubeTexture.prototype.isCubeTexture = true;
14548
14549 class WebGLCubeRenderTarget extends WebGLRenderTarget {
14550
14551         constructor( size, options, dummy ) {
14552
14553                 if ( Number.isInteger( options ) ) {
14554
14555                         console.warn( 'THREE.WebGLCubeRenderTarget: constructor signature is now WebGLCubeRenderTarget( size, options )' );
14556
14557                         options = dummy;
14558
14559                 }
14560
14561                 super( size, size, options );
14562
14563                 options = options || {};
14564
14565                 // By convention -- likely based on the RenderMan spec from the 1990's -- cube maps are specified by WebGL (and three.js)
14566                 // in a coordinate system in which positive-x is to the right when looking up the positive-z axis -- in other words,
14567                 // in a left-handed coordinate system. By continuing this convention, preexisting cube maps continued to render correctly.
14568
14569                 // three.js uses a right-handed coordinate system. So environment maps used in three.js appear to have px and nx swapped
14570                 // and the flag isRenderTargetTexture controls this conversion. The flip is not required when using WebGLCubeRenderTarget.texture
14571                 // as a cube texture (this is detected when isRenderTargetTexture is set to true for cube textures).
14572
14573                 this.texture = new CubeTexture( undefined, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding );
14574                 this.texture.isRenderTargetTexture = true;
14575
14576                 this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false;
14577                 this.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter;
14578
14579                 this.texture._needsFlipEnvMap = false;
14580
14581         }
14582
14583         fromEquirectangularTexture( renderer, texture ) {
14584
14585                 this.texture.type = texture.type;
14586                 this.texture.format = RGBAFormat; // see #18859
14587                 this.texture.encoding = texture.encoding;
14588
14589                 this.texture.generateMipmaps = texture.generateMipmaps;
14590                 this.texture.minFilter = texture.minFilter;
14591                 this.texture.magFilter = texture.magFilter;
14592
14593                 const shader = {
14594
14595                         uniforms: {
14596                                 tEquirect: { value: null },
14597                         },
14598
14599                         vertexShader: /* glsl */`
14600
14601                                 varying vec3 vWorldDirection;
14602
14603                                 vec3 transformDirection( in vec3 dir, in mat4 matrix ) {
14604
14605                                         return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );
14606
14607                                 }
14608
14609                                 void main() {
14610
14611                                         vWorldDirection = transformDirection( position, modelMatrix );
14612
14613                                         #include <begin_vertex>
14614                                         #include <project_vertex>
14615
14616                                 }
14617                         `,
14618
14619                         fragmentShader: /* glsl */`
14620
14621                                 uniform sampler2D tEquirect;
14622
14623                                 varying vec3 vWorldDirection;
14624
14625                                 #include <common>
14626
14627                                 void main() {
14628
14629                                         vec3 direction = normalize( vWorldDirection );
14630
14631                                         vec2 sampleUV = equirectUv( direction );
14632
14633                                         gl_FragColor = texture2D( tEquirect, sampleUV );
14634
14635                                 }
14636                         `
14637                 };
14638
14639                 const geometry = new BoxGeometry( 5, 5, 5 );
14640
14641                 const material = new ShaderMaterial( {
14642
14643                         name: 'CubemapFromEquirect',
14644
14645                         uniforms: cloneUniforms( shader.uniforms ),
14646                         vertexShader: shader.vertexShader,
14647                         fragmentShader: shader.fragmentShader,
14648                         side: BackSide,
14649                         blending: NoBlending
14650
14651                 } );
14652
14653                 material.uniforms.tEquirect.value = texture;
14654
14655                 const mesh = new Mesh( geometry, material );
14656
14657                 const currentMinFilter = texture.minFilter;
14658
14659                 // Avoid blurred poles
14660                 if ( texture.minFilter === LinearMipmapLinearFilter ) texture.minFilter = LinearFilter;
14661
14662                 const camera = new CubeCamera( 1, 10, this );
14663                 camera.update( renderer, mesh );
14664
14665                 texture.minFilter = currentMinFilter;
14666
14667                 mesh.geometry.dispose();
14668                 mesh.material.dispose();
14669
14670                 return this;
14671
14672         }
14673
14674         clear( renderer, color, depth, stencil ) {
14675
14676                 const currentRenderTarget = renderer.getRenderTarget();
14677
14678                 for ( let i = 0; i < 6; i ++ ) {
14679
14680                         renderer.setRenderTarget( this, i );
14681
14682                         renderer.clear( color, depth, stencil );
14683
14684                 }
14685
14686                 renderer.setRenderTarget( currentRenderTarget );
14687
14688         }
14689
14690 }
14691
14692 WebGLCubeRenderTarget.prototype.isWebGLCubeRenderTarget = true;
14693
14694 const _vector1 = /*@__PURE__*/ new Vector3();
14695 const _vector2 = /*@__PURE__*/ new Vector3();
14696 const _normalMatrix = /*@__PURE__*/ new Matrix3();
14697
14698 class Plane {
14699
14700         constructor( normal = new Vector3( 1, 0, 0 ), constant = 0 ) {
14701
14702                 // normal is assumed to be normalized
14703
14704                 this.normal = normal;
14705                 this.constant = constant;
14706
14707         }
14708
14709         set( normal, constant ) {
14710
14711                 this.normal.copy( normal );
14712                 this.constant = constant;
14713
14714                 return this;
14715
14716         }
14717
14718         setComponents( x, y, z, w ) {
14719
14720                 this.normal.set( x, y, z );
14721                 this.constant = w;
14722
14723                 return this;
14724
14725         }
14726
14727         setFromNormalAndCoplanarPoint( normal, point ) {
14728
14729                 this.normal.copy( normal );
14730                 this.constant = - point.dot( this.normal );
14731
14732                 return this;
14733
14734         }
14735
14736         setFromCoplanarPoints( a, b, c ) {
14737
14738                 const normal = _vector1.subVectors( c, b ).cross( _vector2.subVectors( a, b ) ).normalize();
14739
14740                 // Q: should an error be thrown if normal is zero (e.g. degenerate plane)?
14741
14742                 this.setFromNormalAndCoplanarPoint( normal, a );
14743
14744                 return this;
14745
14746         }
14747
14748         copy( plane ) {
14749
14750                 this.normal.copy( plane.normal );
14751                 this.constant = plane.constant;
14752
14753                 return this;
14754
14755         }
14756
14757         normalize() {
14758
14759                 // Note: will lead to a divide by zero if the plane is invalid.
14760
14761                 const inverseNormalLength = 1.0 / this.normal.length();
14762                 this.normal.multiplyScalar( inverseNormalLength );
14763                 this.constant *= inverseNormalLength;
14764
14765                 return this;
14766
14767         }
14768
14769         negate() {
14770
14771                 this.constant *= - 1;
14772                 this.normal.negate();
14773
14774                 return this;
14775
14776         }
14777
14778         distanceToPoint( point ) {
14779
14780                 return this.normal.dot( point ) + this.constant;
14781
14782         }
14783
14784         distanceToSphere( sphere ) {
14785
14786                 return this.distanceToPoint( sphere.center ) - sphere.radius;
14787
14788         }
14789
14790         projectPoint( point, target ) {
14791
14792                 return target.copy( this.normal ).multiplyScalar( - this.distanceToPoint( point ) ).add( point );
14793
14794         }
14795
14796         intersectLine( line, target ) {
14797
14798                 const direction = line.delta( _vector1 );
14799
14800                 const denominator = this.normal.dot( direction );
14801
14802                 if ( denominator === 0 ) {
14803
14804                         // line is coplanar, return origin
14805                         if ( this.distanceToPoint( line.start ) === 0 ) {
14806
14807                                 return target.copy( line.start );
14808
14809                         }
14810
14811                         // Unsure if this is the correct method to handle this case.
14812                         return null;
14813
14814                 }
14815
14816                 const t = - ( line.start.dot( this.normal ) + this.constant ) / denominator;
14817
14818                 if ( t < 0 || t > 1 ) {
14819
14820                         return null;
14821
14822                 }
14823
14824                 return target.copy( direction ).multiplyScalar( t ).add( line.start );
14825
14826         }
14827
14828         intersectsLine( line ) {
14829
14830                 // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it.
14831
14832                 const startSign = this.distanceToPoint( line.start );
14833                 const endSign = this.distanceToPoint( line.end );
14834
14835                 return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 );
14836
14837         }
14838
14839         intersectsBox( box ) {
14840
14841                 return box.intersectsPlane( this );
14842
14843         }
14844
14845         intersectsSphere( sphere ) {
14846
14847                 return sphere.intersectsPlane( this );
14848
14849         }
14850
14851         coplanarPoint( target ) {
14852
14853                 return target.copy( this.normal ).multiplyScalar( - this.constant );
14854
14855         }
14856
14857         applyMatrix4( matrix, optionalNormalMatrix ) {
14858
14859                 const normalMatrix = optionalNormalMatrix || _normalMatrix.getNormalMatrix( matrix );
14860
14861                 const referencePoint = this.coplanarPoint( _vector1 ).applyMatrix4( matrix );
14862
14863                 const normal = this.normal.applyMatrix3( normalMatrix ).normalize();
14864
14865                 this.constant = - referencePoint.dot( normal );
14866
14867                 return this;
14868
14869         }
14870
14871         translate( offset ) {
14872
14873                 this.constant -= offset.dot( this.normal );
14874
14875                 return this;
14876
14877         }
14878
14879         equals( plane ) {
14880
14881                 return plane.normal.equals( this.normal ) && ( plane.constant === this.constant );
14882
14883         }
14884
14885         clone() {
14886
14887                 return new this.constructor().copy( this );
14888
14889         }
14890
14891 }
14892
14893 Plane.prototype.isPlane = true;
14894
14895 const _sphere$2 = /*@__PURE__*/ new Sphere();
14896 const _vector$7 = /*@__PURE__*/ new Vector3();
14897
14898 class Frustum {
14899
14900         constructor( p0 = new Plane(), p1 = new Plane(), p2 = new Plane(), p3 = new Plane(), p4 = new Plane(), p5 = new Plane() ) {
14901
14902                 this.planes = [ p0, p1, p2, p3, p4, p5 ];
14903
14904         }
14905
14906         set( p0, p1, p2, p3, p4, p5 ) {
14907
14908                 const planes = this.planes;
14909
14910                 planes[ 0 ].copy( p0 );
14911                 planes[ 1 ].copy( p1 );
14912                 planes[ 2 ].copy( p2 );
14913                 planes[ 3 ].copy( p3 );
14914                 planes[ 4 ].copy( p4 );
14915                 planes[ 5 ].copy( p5 );
14916
14917                 return this;
14918
14919         }
14920
14921         copy( frustum ) {
14922
14923                 const planes = this.planes;
14924
14925                 for ( let i = 0; i < 6; i ++ ) {
14926
14927                         planes[ i ].copy( frustum.planes[ i ] );
14928
14929                 }
14930
14931                 return this;
14932
14933         }
14934
14935         setFromProjectionMatrix( m ) {
14936
14937                 const planes = this.planes;
14938                 const me = m.elements;
14939                 const me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ];
14940                 const me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ];
14941                 const me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ];
14942                 const me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ];
14943
14944                 planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize();
14945                 planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize();
14946                 planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize();
14947                 planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize();
14948                 planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize();
14949                 planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize();
14950
14951                 return this;
14952
14953         }
14954
14955         intersectsObject( object ) {
14956
14957                 const geometry = object.geometry;
14958
14959                 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
14960
14961                 _sphere$2.copy( geometry.boundingSphere ).applyMatrix4( object.matrixWorld );
14962
14963                 return this.intersectsSphere( _sphere$2 );
14964
14965         }
14966
14967         intersectsSprite( sprite ) {
14968
14969                 _sphere$2.center.set( 0, 0, 0 );
14970                 _sphere$2.radius = 0.7071067811865476;
14971                 _sphere$2.applyMatrix4( sprite.matrixWorld );
14972
14973                 return this.intersectsSphere( _sphere$2 );
14974
14975         }
14976
14977         intersectsSphere( sphere ) {
14978
14979                 const planes = this.planes;
14980                 const center = sphere.center;
14981                 const negRadius = - sphere.radius;
14982
14983                 for ( let i = 0; i < 6; i ++ ) {
14984
14985                         const distance = planes[ i ].distanceToPoint( center );
14986
14987                         if ( distance < negRadius ) {
14988
14989                                 return false;
14990
14991                         }
14992
14993                 }
14994
14995                 return true;
14996
14997         }
14998
14999         intersectsBox( box ) {
15000
15001                 const planes = this.planes;
15002
15003                 for ( let i = 0; i < 6; i ++ ) {
15004
15005                         const plane = planes[ i ];
15006
15007                         // corner at max distance
15008
15009                         _vector$7.x = plane.normal.x > 0 ? box.max.x : box.min.x;
15010                         _vector$7.y = plane.normal.y > 0 ? box.max.y : box.min.y;
15011                         _vector$7.z = plane.normal.z > 0 ? box.max.z : box.min.z;
15012
15013                         if ( plane.distanceToPoint( _vector$7 ) < 0 ) {
15014
15015                                 return false;
15016
15017                         }
15018
15019                 }
15020
15021                 return true;
15022
15023         }
15024
15025         containsPoint( point ) {
15026
15027                 const planes = this.planes;
15028
15029                 for ( let i = 0; i < 6; i ++ ) {
15030
15031                         if ( planes[ i ].distanceToPoint( point ) < 0 ) {
15032
15033                                 return false;
15034
15035                         }
15036
15037                 }
15038
15039                 return true;
15040
15041         }
15042
15043         clone() {
15044
15045                 return new this.constructor().copy( this );
15046
15047         }
15048
15049 }
15050
15051 function WebGLAnimation() {
15052
15053         let context = null;
15054         let isAnimating = false;
15055         let animationLoop = null;
15056         let requestId = null;
15057
15058         function onAnimationFrame( time, frame ) {
15059
15060                 animationLoop( time, frame );
15061
15062                 requestId = context.requestAnimationFrame( onAnimationFrame );
15063
15064         }
15065
15066         return {
15067
15068                 start: function () {
15069
15070                         if ( isAnimating === true ) return;
15071                         if ( animationLoop === null ) return;
15072
15073                         requestId = context.requestAnimationFrame( onAnimationFrame );
15074
15075                         isAnimating = true;
15076
15077                 },
15078
15079                 stop: function () {
15080
15081                         context.cancelAnimationFrame( requestId );
15082
15083                         isAnimating = false;
15084
15085                 },
15086
15087                 setAnimationLoop: function ( callback ) {
15088
15089                         animationLoop = callback;
15090
15091                 },
15092
15093                 setContext: function ( value ) {
15094
15095                         context = value;
15096
15097                 }
15098
15099         };
15100
15101 }
15102
15103 function WebGLAttributes( gl, capabilities ) {
15104
15105         const isWebGL2 = capabilities.isWebGL2;
15106
15107         const buffers = new WeakMap();
15108
15109         function createBuffer( attribute, bufferType ) {
15110
15111                 const array = attribute.array;
15112                 const usage = attribute.usage;
15113
15114                 const buffer = gl.createBuffer();
15115
15116                 gl.bindBuffer( bufferType, buffer );
15117                 gl.bufferData( bufferType, array, usage );
15118
15119                 attribute.onUploadCallback();
15120
15121                 let type = 5126;
15122
15123                 if ( array instanceof Float32Array ) {
15124
15125                         type = 5126;
15126
15127                 } else if ( array instanceof Float64Array ) {
15128
15129                         console.warn( 'THREE.WebGLAttributes: Unsupported data buffer format: Float64Array.' );
15130
15131                 } else if ( array instanceof Uint16Array ) {
15132
15133                         if ( attribute.isFloat16BufferAttribute ) {
15134
15135                                 if ( isWebGL2 ) {
15136
15137                                         type = 5131;
15138
15139                                 } else {
15140
15141                                         console.warn( 'THREE.WebGLAttributes: Usage of Float16BufferAttribute requires WebGL2.' );
15142
15143                                 }
15144
15145                         } else {
15146
15147                                 type = 5123;
15148
15149                         }
15150
15151                 } else if ( array instanceof Int16Array ) {
15152
15153                         type = 5122;
15154
15155                 } else if ( array instanceof Uint32Array ) {
15156
15157                         type = 5125;
15158
15159                 } else if ( array instanceof Int32Array ) {
15160
15161                         type = 5124;
15162
15163                 } else if ( array instanceof Int8Array ) {
15164
15165                         type = 5120;
15166
15167                 } else if ( array instanceof Uint8Array ) {
15168
15169                         type = 5121;
15170
15171                 } else if ( array instanceof Uint8ClampedArray ) {
15172
15173                         type = 5121;
15174
15175                 }
15176
15177                 return {
15178                         buffer: buffer,
15179                         type: type,
15180                         bytesPerElement: array.BYTES_PER_ELEMENT,
15181                         version: attribute.version
15182                 };
15183
15184         }
15185
15186         function updateBuffer( buffer, attribute, bufferType ) {
15187
15188                 const array = attribute.array;
15189                 const updateRange = attribute.updateRange;
15190
15191                 gl.bindBuffer( bufferType, buffer );
15192
15193                 if ( updateRange.count === - 1 ) {
15194
15195                         // Not using update ranges
15196
15197                         gl.bufferSubData( bufferType, 0, array );
15198
15199                 } else {
15200
15201                         if ( isWebGL2 ) {
15202
15203                                 gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT,
15204                                         array, updateRange.offset, updateRange.count );
15205
15206                         } else {
15207
15208                                 gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT,
15209                                         array.subarray( updateRange.offset, updateRange.offset + updateRange.count ) );
15210
15211                         }
15212
15213                         updateRange.count = - 1; // reset range
15214
15215                 }
15216
15217         }
15218
15219         //
15220
15221         function get( attribute ) {
15222
15223                 if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
15224
15225                 return buffers.get( attribute );
15226
15227         }
15228
15229         function remove( attribute ) {
15230
15231                 if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
15232
15233                 const data = buffers.get( attribute );
15234
15235                 if ( data ) {
15236
15237                         gl.deleteBuffer( data.buffer );
15238
15239                         buffers.delete( attribute );
15240
15241                 }
15242
15243         }
15244
15245         function update( attribute, bufferType ) {
15246
15247                 if ( attribute.isGLBufferAttribute ) {
15248
15249                         const cached = buffers.get( attribute );
15250
15251                         if ( ! cached || cached.version < attribute.version ) {
15252
15253                                 buffers.set( attribute, {
15254                                         buffer: attribute.buffer,
15255                                         type: attribute.type,
15256                                         bytesPerElement: attribute.elementSize,
15257                                         version: attribute.version
15258                                 } );
15259
15260                         }
15261
15262                         return;
15263
15264                 }
15265
15266                 if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
15267
15268                 const data = buffers.get( attribute );
15269
15270                 if ( data === undefined ) {
15271
15272                         buffers.set( attribute, createBuffer( attribute, bufferType ) );
15273
15274                 } else if ( data.version < attribute.version ) {
15275
15276                         updateBuffer( data.buffer, attribute, bufferType );
15277
15278                         data.version = attribute.version;
15279
15280                 }
15281
15282         }
15283
15284         return {
15285
15286                 get: get,
15287                 remove: remove,
15288                 update: update
15289
15290         };
15291
15292 }
15293
15294 class PlaneGeometry extends BufferGeometry {
15295
15296         constructor( width = 1, height = 1, widthSegments = 1, heightSegments = 1 ) {
15297
15298                 super();
15299                 this.type = 'PlaneGeometry';
15300
15301                 this.parameters = {
15302                         width: width,
15303                         height: height,
15304                         widthSegments: widthSegments,
15305                         heightSegments: heightSegments
15306                 };
15307
15308                 const width_half = width / 2;
15309                 const height_half = height / 2;
15310
15311                 const gridX = Math.floor( widthSegments );
15312                 const gridY = Math.floor( heightSegments );
15313
15314                 const gridX1 = gridX + 1;
15315                 const gridY1 = gridY + 1;
15316
15317                 const segment_width = width / gridX;
15318                 const segment_height = height / gridY;
15319
15320                 //
15321
15322                 const indices = [];
15323                 const vertices = [];
15324                 const normals = [];
15325                 const uvs = [];
15326
15327                 for ( let iy = 0; iy < gridY1; iy ++ ) {
15328
15329                         const y = iy * segment_height - height_half;
15330
15331                         for ( let ix = 0; ix < gridX1; ix ++ ) {
15332
15333                                 const x = ix * segment_width - width_half;
15334
15335                                 vertices.push( x, - y, 0 );
15336
15337                                 normals.push( 0, 0, 1 );
15338
15339                                 uvs.push( ix / gridX );
15340                                 uvs.push( 1 - ( iy / gridY ) );
15341
15342                         }
15343
15344                 }
15345
15346                 for ( let iy = 0; iy < gridY; iy ++ ) {
15347
15348                         for ( let ix = 0; ix < gridX; ix ++ ) {
15349
15350                                 const a = ix + gridX1 * iy;
15351                                 const b = ix + gridX1 * ( iy + 1 );
15352                                 const c = ( ix + 1 ) + gridX1 * ( iy + 1 );
15353                                 const d = ( ix + 1 ) + gridX1 * iy;
15354
15355                                 indices.push( a, b, d );
15356                                 indices.push( b, c, d );
15357
15358                         }
15359
15360                 }
15361
15362                 this.setIndex( indices );
15363                 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
15364                 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
15365                 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
15366
15367         }
15368
15369         static fromJSON( data ) {
15370
15371                 return new PlaneGeometry( data.width, data.height, data.widthSegments, data.heightSegments );
15372
15373         }
15374
15375 }
15376
15377 var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif";
15378
15379 var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif";
15380
15381 var alphatest_fragment = "#ifdef USE_ALPHATEST\n\tif ( diffuseColor.a < alphaTest ) discard;\n#endif";
15382
15383 var alphatest_pars_fragment = "#ifdef USE_ALPHATEST\n\tuniform float alphaTest;\n#endif";
15384
15385 var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_ENVMAP ) && defined( STANDARD )\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.roughness );\n\t#endif\n#endif";
15386
15387 var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif";
15388
15389 var begin_vertex = "vec3 transformed = vec3( position );";
15390
15391 var beginnormal_vertex = "vec3 objectNormal = vec3( normal );\n#ifdef USE_TANGENT\n\tvec3 objectTangent = vec3( tangent.xyz );\n#endif";
15392
15393 var bsdfs = "vec3 BRDF_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n}\nfloat V_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\nvec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 f0, const in float f90, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( f0, f90, dotVH );\n\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( V * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\nfloat G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_BlinnPhong( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, 1.0, dotVH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\n#if defined( USE_SHEEN )\nfloat D_Charlie( float roughness, float dotNH ) {\n\tfloat alpha = pow2( roughness );\n\tfloat invAlpha = 1.0 / alpha;\n\tfloat cos2h = dotNH * dotNH;\n\tfloat sin2h = max( 1.0 - cos2h, 0.0078125 );\n\treturn ( 2.0 + invAlpha ) * pow( sin2h, invAlpha * 0.5 ) / ( 2.0 * PI );\n}\nfloat V_Neubelt( float dotNV, float dotNL ) {\n\treturn saturate( 1.0 / ( 4.0 * ( dotNL + dotNV - dotNL * dotNV ) ) );\n}\nvec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, vec3 sheenColor, const in float sheenRoughness ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat D = D_Charlie( sheenRoughness, dotNH );\n\tfloat V = V_Neubelt( dotNV, dotNL );\n\treturn sheenColor * ( D * V );\n}\n#endif";
15394
15395 var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy, float faceDirection ) {\n\t\tvec3 vSigmaX = vec3( dFdx( surf_pos.x ), dFdx( surf_pos.y ), dFdx( surf_pos.z ) );\n\t\tvec3 vSigmaY = vec3( dFdy( surf_pos.x ), dFdy( surf_pos.y ), dFdy( surf_pos.z ) );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 ) * faceDirection;\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif";
15396
15397 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";
15398
15399 var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif";
15400
15401 var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n#endif";
15402
15403 var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvClipPosition = - mvPosition.xyz;\n#endif";
15404
15405 var color_fragment = "#if defined( USE_COLOR_ALPHA )\n\tdiffuseColor *= vColor;\n#elif defined( USE_COLOR )\n\tdiffuseColor.rgb *= vColor;\n#endif";
15406
15407 var color_pars_fragment = "#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR )\n\tvarying vec3 vColor;\n#endif";
15408
15409 var color_pars_vertex = "#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvarying vec3 vColor;\n#endif";
15410
15411 var color_vertex = "#if defined( USE_COLOR_ALPHA )\n\tvColor = vec4( 1.0 );\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvColor = vec3( 1.0 );\n#endif\n#ifdef USE_COLOR\n\tvColor *= color;\n#endif\n#ifdef USE_INSTANCING_COLOR\n\tvColor.xyz *= instanceColor.xyz;\n#endif";
15412
15413 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 max3( const in vec3 v ) { return max( max( v.x, v.y ), v.z ); }\nfloat average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract( sin( sn ) * c );\n}\n#ifdef HIGH_PRECISION\n\tfloat precisionSafeLength( vec3 v ) { return length( v ); }\n#else\n\tfloat precisionSafeLength( vec3 v ) {\n\t\tfloat maxComponent = max3( abs( v ) );\n\t\treturn length( v / maxComponent ) * maxComponent;\n\t}\n#endif\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\nstruct GeometricContext {\n\tvec3 position;\n\tvec3 normal;\n\tvec3 viewDir;\n#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal;\n#endif\n};\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nfloat linearToRelativeLuminance( const in vec3 color ) {\n\tvec3 weights = vec3( 0.2126, 0.7152, 0.0722 );\n\treturn dot( weights, color.rgb );\n}\nbool isPerspectiveMatrix( mat4 m ) {\n\treturn m[ 2 ][ 3 ] == - 1.0;\n}\nvec2 equirectUv( in vec3 dir ) {\n\tfloat u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5;\n\tfloat v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\treturn vec2( u, v );\n}";
15414
15415 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";
15416
15417 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";
15418
15419 var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif";
15420
15421 var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vUv ).x * displacementScale + displacementBias );\n#endif";
15422
15423 var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif";
15424
15425 var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif";
15426
15427 var encodings_fragment = "gl_FragColor = linearToOutputTexel( gl_FragColor );";
15428
15429 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}";
15430
15431 var envmap_fragment = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToFrag = normalize( vWorldPosition - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToFrag, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t\tenvColor = envMapTexelToLinear( envColor );\n\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 envColor = textureCubeUV( envMap, reflectVec, 0.0 );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif";
15432
15433 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";
15434
15435 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";
15436
15437 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";
15438
15439 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";
15440
15441 var fog_vertex = "#ifdef USE_FOG\n\tvFogDepth = - mvPosition.z;\n#endif";
15442
15443 var fog_pars_vertex = "#ifdef USE_FOG\n\tvarying float vFogDepth;\n#endif";
15444
15445 var fog_fragment = "#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = 1.0 - exp( - fogDensity * fogDensity * vFogDepth * vFogDepth );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, vFogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif";
15446
15447 var fog_pars_fragment = "#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float vFogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif";
15448
15449 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}";
15450
15451 var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\tvec4 lightMapTexel = texture2D( lightMap, vUv2 );\n\tvec3 lightMapIrradiance = lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tlightMapIrradiance *= PI;\n\t#endif\n\treflectedLight.indirectDiffuse += lightMapIrradiance;\n#endif";
15452
15453 var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif";
15454
15455 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.normal );\n#ifdef DOUBLE_SIDED\n\tvIndirectBack += getAmbientLightIrradiance( ambientLightColor );\n\tvIndirectBack += getLightProbeIrradiance( lightProbe, backGeometry.normal );\n#endif\n#if NUM_POINT_LIGHTS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tgetPointLightInfo( pointLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( - dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tgetSpotLightInfo( spotLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( - dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if NUM_DIR_LIGHTS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tgetDirectionalLightInfo( directionalLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( - dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\tvIndirectFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry.normal );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvIndirectBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry.normal );\n\t\t#endif\n\t}\n\t#pragma unroll_loop_end\n#endif";
15456
15457 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 vec3 normal ) {\n\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\treturn irradiance;\n}\nfloat getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\t#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\tif ( cutoffDistance > 0.0 ) {\n\t\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\t}\n\t\treturn distanceFalloff;\n\t#else\n\t\tif ( cutoffDistance > 0.0 && decayExponent > 0.0 ) {\n\t\t\treturn pow( saturate( - lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\t\t}\n\t\treturn 1.0;\n\t#endif\n}\nfloat getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {\n\treturn smoothstep( coneCosine, penumbraCosine, angleCosine );\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalLightInfo( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight light ) {\n\t\tlight.color = directionalLight.color;\n\t\tlight.direction = directionalLight.direction;\n\t\tlight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointLightInfo( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight light ) {\n\t\tvec3 lVector = pointLight.position - geometry.position;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tlight.color = pointLight.color;\n\t\tlight.color *= getDistanceAttenuation( lightDistance, pointLight.distance, pointLight.decay );\n\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotLightInfo( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight light ) {\n\t\tvec3 lVector = spotLight.position - geometry.position;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat angleCos = dot( light.direction, spotLight.direction );\n\t\tfloat spotAttenuation = getSpotAttenuation( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\tif ( spotAttenuation > 0.0 ) {\n\t\t\tfloat lightDistance = length( lVector );\n\t\t\tlight.color = spotLight.color * spotAttenuation;\n\t\t\tlight.color *= getDistanceAttenuation( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t\t} else {\n\t\t\tlight.color = vec3( 0.0 );\n\t\t\tlight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in vec3 normal ) {\n\t\tfloat dotNL = dot( normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\treturn irradiance;\n\t}\n#endif";
15458
15459 var envmap_physical_pars_fragment = "#if defined( USE_ENVMAP )\n\t#ifdef ENVMAP_MODE_REFRACTION\n\t\tuniform float refractionRatio;\n\t#endif\n\tvec3 getIBLIrradiance( const in vec3 normal ) {\n\t\t#if defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, worldNormal, 1.0 );\n\t\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\tvec3 getIBLRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) {\n\t\t#if defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 reflectVec;\n\t\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\t\treflectVec = reflect( - viewDir, normal );\n\t\t\t\treflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t\t#else\n\t\t\t\treflectVec = refract( - viewDir, normal, refractionRatio );\n\t\t\t#endif\n\t\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness );\n\t\t\treturn envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n#endif";
15460
15461 var lights_toon_fragment = "ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;";
15462
15463 var lights_toon_pars_fragment = "varying vec3 vViewPosition;\nstruct ToonMaterial {\n\tvec3 diffuseColor;\n};\nvoid RE_Direct_Toon( const in IncidentLight directLight, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Toon\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Toon\n#define Material_LightProbeLOD( material )\t(0)";
15464
15465 var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;";
15466
15467 var lights_phong_pars_fragment = "varying vec3 vViewPosition;\nstruct BlinnPhongMaterial {\n\tvec3 diffuseColor;\n\tvec3 specularColor;\n\tfloat specularShininess;\n\tfloat specularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight.direction, geometry.viewDir, geometry.normal, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong\n#define Material_LightProbeLOD( material )\t(0)";
15468
15469 var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nvec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.roughness = max( roughnessFactor, 0.0525 );material.roughness += geometryRoughness;\nmaterial.roughness = min( material.roughness, 1.0 );\n#ifdef IOR\n\t#ifdef SPECULAR\n\t\tfloat specularIntensityFactor = specularIntensity;\n\t\tvec3 specularColorFactor = specularColor;\n\t\t#ifdef USE_SPECULARINTENSITYMAP\n\t\t\tspecularIntensityFactor *= texture2D( specularIntensityMap, vUv ).a;\n\t\t#endif\n\t\t#ifdef USE_SPECULARCOLORMAP\n\t\t\tspecularColorFactor *= specularColorMapTexelToLinear( texture2D( specularColorMap, vUv ) ).rgb;\n\t\t#endif\n\t\tmaterial.specularF90 = mix( specularIntensityFactor, 1.0, metalnessFactor );\n\t#else\n\t\tfloat specularIntensityFactor = 1.0;\n\t\tvec3 specularColorFactor = vec3( 1.0 );\n\t\tmaterial.specularF90 = 1.0;\n\t#endif\n\tmaterial.specularColor = mix( min( pow2( ( ior - 1.0 ) / ( ior + 1.0 ) ) * specularColorFactor, vec3( 1.0 ) ) * specularIntensityFactor, diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( 0.04 ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.specularF90 = 1.0;\n#endif\n#ifdef USE_CLEARCOAT\n\tmaterial.clearcoat = clearcoat;\n\tmaterial.clearcoatRoughness = clearcoatRoughness;\n\tmaterial.clearcoatF0 = vec3( 0.04 );\n\tmaterial.clearcoatF90 = 1.0;\n\t#ifdef USE_CLEARCOATMAP\n\t\tmaterial.clearcoat *= texture2D( clearcoatMap, vUv ).x;\n\t#endif\n\t#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\t\tmaterial.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vUv ).y;\n\t#endif\n\tmaterial.clearcoat = saturate( material.clearcoat );\tmaterial.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 );\n\tmaterial.clearcoatRoughness += geometryRoughness;\n\tmaterial.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );\n#endif\n#ifdef USE_SHEEN\n\tmaterial.sheenColor = sheenColor;\n\t#ifdef USE_SHEENCOLORMAP\n\t\tmaterial.sheenColor *= sheenColorMapTexelToLinear( texture2D( sheenColorMap, vUv ) ).rgb;\n\t#endif\n\tmaterial.sheenRoughness = clamp( sheenRoughness, 0.07, 1.0 );\n\t#ifdef USE_SHEENROUGHNESSMAP\n\t\tmaterial.sheenRoughness *= texture2D( sheenRoughnessMap, vUv ).a;\n\t#endif\n#endif";
15470
15471 var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tfloat roughness;\n\tvec3 specularColor;\n\tfloat specularF90;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat clearcoat;\n\t\tfloat clearcoatRoughness;\n\t\tvec3 clearcoatF0;\n\t\tfloat clearcoatF90;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tvec3 sheenColor;\n\t\tfloat sheenRoughness;\n\t#endif\n};\nvec3 clearcoatSpecular = vec3( 0.0 );\nvec2 DFGApprox( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 fab = vec2( - 1.04, 1.04 ) * a004 + r.zw;\n\treturn fab;\n}\nvec3 EnvironmentBRDF( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness ) {\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\treturn specularColor * fab.x + specularF90 * fab.y;\n}\nvoid computeMultiscattering( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\tvec3 FssEss = specularColor * fab.x + specularF90 * fab.y;\n\tfloat Ess = fab.x + fab.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = specularColor + ( 1.0 - specularColor ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometry.normal;\n\t\tvec3 viewDir = geometry.viewDir;\n\t\tvec3 position = geometry.position;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.roughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos + halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos - halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos - halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos + halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3(    0, 1,    0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNLcc = saturate( dot( geometry.clearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = dotNLcc * directLight.color;\n\t\tclearcoatSpecular += ccIrradiance * BRDF_GGX( directLight.direction, geometry.viewDir, geometry.clearcoatNormal, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\treflectedLight.directSpecular += irradiance * BRDF_Sheen( directLight.direction, geometry.viewDir, geometry.normal, material.sheenColor, material.sheenRoughness );\n\t#endif\n\treflectedLight.directSpecular += irradiance * BRDF_GGX( directLight.direction, geometry.viewDir, geometry.normal, material.specularColor, material.specularF90, material.roughness );\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatSpecular += clearcoatRadiance * EnvironmentBRDF( geometry.clearcoatNormal, geometry.viewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\tcomputeMultiscattering( geometry.normal, geometry.viewDir, material.specularColor, material.specularF90, material.roughness, singleScattering, multiScattering );\n\tvec3 diffuse = material.diffuseColor * ( 1.0 - ( singleScattering + multiScattering ) );\n\treflectedLight.indirectSpecular += radiance * singleScattering;\n\treflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance;\n\treflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}";
15472
15473 var lights_fragment_begin = "\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\n#ifdef USE_CLEARCOAT\n\tgeometry.clearcoatNormal = clearcoatNormal;\n#endif\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointLightInfo( pointLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )\n\t\tpointLightShadow = pointLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotLightInfo( spotLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\tspotLightShadow = spotLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalLightInfo( directionalLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectionalLightShadow = directionalLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 iblIrradiance = vec3( 0.0 );\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\tirradiance += getLightProbeIrradiance( lightProbe, geometry.normal );\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.normal );\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";
15474
15475 var lights_fragment_maps = "#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vUv2 );\n\t\tvec3 lightMapIrradiance = lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tlightMapIrradiance *= PI;\n\t\t#endif\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tiblIrradiance += getIBLIrradiance( geometry.normal );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tradiance += getIBLRadiance( geometry.viewDir, geometry.normal, material.roughness );\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatRadiance += getIBLRadiance( geometry.viewDir, geometry.clearcoatNormal, material.clearcoatRoughness );\n\t#endif\n#endif";
15476
15477 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";
15478
15479 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";
15480
15481 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";
15482
15483 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";
15484
15485 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";
15486
15487 var map_fragment = "#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif";
15488
15489 var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif";
15490
15491 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";
15492
15493 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";
15494
15495 var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif";
15496
15497 var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif";
15498
15499 var morphnormal_vertex = "#ifdef USE_MORPHNORMALS\n\tobjectNormal *= morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t\tif ( morphTargetInfluences[ i ] > 0.0 ) objectNormal += getMorph( gl_VertexID, i, 1, 2 ) * morphTargetInfluences[ i ];\n\t\t}\n\t#else\n\t\tobjectNormal += morphNormal0 * morphTargetInfluences[ 0 ];\n\t\tobjectNormal += morphNormal1 * morphTargetInfluences[ 1 ];\n\t\tobjectNormal += morphNormal2 * morphTargetInfluences[ 2 ];\n\t\tobjectNormal += morphNormal3 * morphTargetInfluences[ 3 ];\n\t#endif\n#endif";
15500
15501 var morphtarget_pars_vertex = "#ifdef USE_MORPHTARGETS\n\tuniform float morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tuniform float morphTargetInfluences[ MORPHTARGETS_COUNT ];\n\t\tuniform sampler2DArray morphTargetsTexture;\n\t\tuniform vec2 morphTargetsTextureSize;\n\t\tvec3 getMorph( const in int vertexIndex, const in int morphTargetIndex, const in int offset, const in int stride ) {\n\t\t\tfloat texelIndex = float( vertexIndex * stride + offset );\n\t\t\tfloat y = floor( texelIndex / morphTargetsTextureSize.x );\n\t\t\tfloat x = texelIndex - y * morphTargetsTextureSize.x;\n\t\t\tvec3 morphUV = vec3( ( x + 0.5 ) / morphTargetsTextureSize.x, y / morphTargetsTextureSize.y, morphTargetIndex );\n\t\t\treturn texture( morphTargetsTexture, morphUV ).xyz;\n\t\t}\n\t#else\n\t\t#ifndef USE_MORPHNORMALS\n\t\t\tuniform float morphTargetInfluences[ 8 ];\n\t\t#else\n\t\t\tuniform float morphTargetInfluences[ 4 ];\n\t\t#endif\n\t#endif\n#endif";
15502
15503 var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\n\ttransformed *= morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t\t#ifndef USE_MORPHNORMALS\n\t\t\t\tif ( morphTargetInfluences[ i ] > 0.0 ) transformed += getMorph( gl_VertexID, i, 0, 1 ) * morphTargetInfluences[ i ];\n\t\t\t#else\n\t\t\t\tif ( morphTargetInfluences[ i ] > 0.0 ) transformed += getMorph( gl_VertexID, i, 0, 2 ) * morphTargetInfluences[ i ];\n\t\t\t#endif\n\t\t}\n\t#else\n\t\ttransformed += morphTarget0 * morphTargetInfluences[ 0 ];\n\t\ttransformed += morphTarget1 * morphTargetInfluences[ 1 ];\n\t\ttransformed += morphTarget2 * morphTargetInfluences[ 2 ];\n\t\ttransformed += morphTarget3 * morphTargetInfluences[ 3 ];\n\t\t#ifndef USE_MORPHNORMALS\n\t\t\ttransformed += morphTarget4 * morphTargetInfluences[ 4 ];\n\t\t\ttransformed += morphTarget5 * morphTargetInfluences[ 5 ];\n\t\t\ttransformed += morphTarget6 * morphTargetInfluences[ 6 ];\n\t\t\ttransformed += morphTarget7 * morphTargetInfluences[ 7 ];\n\t\t#endif\n\t#endif\n#endif";
15504
15505 var normal_fragment_begin = "float faceDirection = gl_FrontFacing ? 1.0 : - 1.0;\n#ifdef FLAT_SHADED\n\tvec3 fdx = vec3( dFdx( vViewPosition.x ), dFdx( vViewPosition.y ), dFdx( vViewPosition.z ) );\n\tvec3 fdy = vec3( dFdy( vViewPosition.x ), dFdy( vViewPosition.y ), dFdy( vViewPosition.z ) );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\t#ifdef USE_TANGENT\n\t\tvec3 tangent = normalize( vTangent );\n\t\tvec3 bitangent = normalize( vBitangent );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\ttangent = tangent * faceDirection;\n\t\t\tbitangent = bitangent * faceDirection;\n\t\t#endif\n\t\t#if defined( TANGENTSPACE_NORMALMAP ) || defined( USE_CLEARCOAT_NORMALMAP )\n\t\t\tmat3 vTBN = mat3( tangent, bitangent, normal );\n\t\t#endif\n\t#endif\n#endif\nvec3 geometryNormal = normal;";
15506
15507 var normal_fragment_maps = "#ifdef OBJECTSPACE_NORMALMAP\n\tnormal = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( TANGENTSPACE_NORMALMAP )\n\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\t#ifdef USE_TANGENT\n\t\tnormal = normalize( vTBN * mapN );\n\t#else\n\t\tnormal = perturbNormal2Arb( - vViewPosition, normal, mapN, faceDirection );\n\t#endif\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection );\n#endif";
15508
15509 var normal_pars_fragment = "#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif";
15510
15511 var normal_pars_vertex = "#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif";
15512
15513 var normal_vertex = "#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif";
15514
15515 var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef OBJECTSPACE_NORMALMAP\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( TANGENTSPACE_NORMALMAP ) || defined ( USE_CLEARCOAT_NORMALMAP ) )\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec3 mapN, float faceDirection ) {\n\t\tvec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );\n\t\tvec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tvec3 N = surf_norm;\n\t\tvec3 q1perp = cross( q1, N );\n\t\tvec3 q0perp = cross( N, q0 );\n\t\tvec3 T = q1perp * st0.x + q0perp * st1.x;\n\t\tvec3 B = q1perp * st0.y + q0perp * st1.y;\n\t\tfloat det = max( dot( T, T ), dot( B, B ) );\n\t\tfloat scale = ( det == 0.0 ) ? 0.0 : faceDirection * inversesqrt( det );\n\t\treturn normalize( T * ( mapN.x * scale ) + B * ( mapN.y * scale ) + N * mapN.z );\n\t}\n#endif";
15516
15517 var clearcoat_normal_fragment_begin = "#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal = geometryNormal;\n#endif";
15518
15519 var clearcoat_normal_fragment_maps = "#ifdef USE_CLEARCOAT_NORMALMAP\n\tvec3 clearcoatMapN = texture2D( clearcoatNormalMap, vUv ).xyz * 2.0 - 1.0;\n\tclearcoatMapN.xy *= clearcoatNormalScale;\n\t#ifdef USE_TANGENT\n\t\tclearcoatNormal = normalize( vTBN * clearcoatMapN );\n\t#else\n\t\tclearcoatNormal = perturbNormal2Arb( - vViewPosition, clearcoatNormal, clearcoatMapN, faceDirection );\n\t#endif\n#endif";
15520
15521 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";
15522
15523 var output_fragment = "#ifdef OPAQUE\ndiffuseColor.a = 1.0;\n#endif\n#ifdef USE_TRANSMISSION\ndiffuseColor.a *= transmissionAlpha + 0.1;\n#endif\ngl_FragColor = vec4( outgoingLight, diffuseColor.a );";
15524
15525 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}";
15526
15527 var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif";
15528
15529 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;";
15530
15531 var dithering_fragment = "#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif";
15532
15533 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";
15534
15535 var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif";
15536
15537 var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif";
15538
15539 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";
15540
15541 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";
15542
15543 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";
15544
15545 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}";
15546
15547 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";
15548
15549 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";
15550
15551 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";
15552
15553 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";
15554
15555 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";
15556
15557 var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif";
15558
15559 var tonemapping_fragment = "#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif";
15560
15561 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; }";
15562
15563 var transmission_fragment = "#ifdef USE_TRANSMISSION\n\tfloat transmissionAlpha = 1.0;\n\tfloat transmissionFactor = transmission;\n\tfloat thicknessFactor = thickness;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\ttransmissionFactor *= texture2D( transmissionMap, vUv ).r;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tthicknessFactor *= texture2D( thicknessMap, vUv ).g;\n\t#endif\n\tvec3 pos = vWorldPosition;\n\tvec3 v = normalize( cameraPosition - pos );\n\tvec3 n = inverseTransformDirection( normal, viewMatrix );\n\tvec4 transmission = getIBLVolumeRefraction(\n\t\tn, v, roughnessFactor, material.diffuseColor, material.specularColor, material.specularF90,\n\t\tpos, modelMatrix, viewMatrix, projectionMatrix, ior, thicknessFactor,\n\t\tattenuationColor, attenuationDistance );\n\ttotalDiffuse = mix( totalDiffuse, transmission.rgb, transmissionFactor );\n\ttransmissionAlpha = mix( transmissionAlpha, transmission.a, transmissionFactor );\n#endif";
15564
15565 var transmission_pars_fragment = "#ifdef USE_TRANSMISSION\n\tuniform float transmission;\n\tuniform float thickness;\n\tuniform float attenuationDistance;\n\tuniform vec3 attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tuniform sampler2D transmissionMap;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tuniform sampler2D thicknessMap;\n\t#endif\n\tuniform vec2 transmissionSamplerSize;\n\tuniform sampler2D transmissionSamplerMap;\n\tuniform mat4 modelMatrix;\n\tuniform mat4 projectionMatrix;\n\tvarying vec3 vWorldPosition;\n\tvec3 getVolumeTransmissionRay( vec3 n, vec3 v, float thickness, float ior, mat4 modelMatrix ) {\n\t\tvec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior );\n\t\tvec3 modelScale;\n\t\tmodelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) );\n\t\tmodelScale.y = length( vec3( modelMatrix[ 1 ].xyz ) );\n\t\tmodelScale.z = length( vec3( modelMatrix[ 2 ].xyz ) );\n\t\treturn normalize( refractionVector ) * thickness * modelScale;\n\t}\n\tfloat applyIorToRoughness( float roughness, float ior ) {\n\t\treturn roughness * clamp( ior * 2.0 - 2.0, 0.0, 1.0 );\n\t}\n\tvec4 getTransmissionSample( vec2 fragCoord, float roughness, float ior ) {\n\t\tfloat framebufferLod = log2( transmissionSamplerSize.x ) * applyIorToRoughness( roughness, ior );\n\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\treturn texture2DLodEXT( transmissionSamplerMap, fragCoord.xy, framebufferLod );\n\t\t#else\n\t\t\treturn texture2D( transmissionSamplerMap, fragCoord.xy, framebufferLod );\n\t\t#endif\n\t}\n\tvec3 applyVolumeAttenuation( vec3 radiance, float transmissionDistance, vec3 attenuationColor, float attenuationDistance ) {\n\t\tif ( attenuationDistance == 0.0 ) {\n\t\t\treturn radiance;\n\t\t} else {\n\t\t\tvec3 attenuationCoefficient = -log( attenuationColor ) / attenuationDistance;\n\t\t\tvec3 transmittance = exp( - attenuationCoefficient * transmissionDistance );\t\t\treturn transmittance * radiance;\n\t\t}\n\t}\n\tvec4 getIBLVolumeRefraction( vec3 n, vec3 v, float roughness, vec3 diffuseColor, vec3 specularColor, float specularF90,\n\t\tvec3 position, mat4 modelMatrix, mat4 viewMatrix, mat4 projMatrix, float ior, float thickness,\n\t\tvec3 attenuationColor, float attenuationDistance ) {\n\t\tvec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix );\n\t\tvec3 refractedRayExit = position + transmissionRay;\n\t\tvec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\n\t\tvec2 refractionCoords = ndcPos.xy / ndcPos.w;\n\t\trefractionCoords += 1.0;\n\t\trefractionCoords /= 2.0;\n\t\tvec4 transmittedLight = getTransmissionSample( refractionCoords, roughness, ior );\n\t\tvec3 attenuatedColor = applyVolumeAttenuation( transmittedLight.rgb, length( transmissionRay ), attenuationColor, attenuationDistance );\n\t\tvec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness );\n\t\treturn vec4( ( 1.0 - F ) * attenuatedColor * diffuseColor, transmittedLight.a );\n\t}\n#endif";
15566
15567 var uv_pars_fragment = "#if ( defined( USE_UV ) && ! defined( UVS_VERTEX_ONLY ) )\n\tvarying vec2 vUv;\n#endif";
15568
15569 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";
15570
15571 var uv_vertex = "#ifdef USE_UV\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n#endif";
15572
15573 var uv2_pars_fragment = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif";
15574
15575 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";
15576
15577 var uv2_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = ( uv2Transform * vec3( uv2, 1 ) ).xy;\n#endif";
15578
15579 var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION )\n\tvec4 worldPosition = vec4( transformed, 1.0 );\n\t#ifdef USE_INSTANCING\n\t\tworldPosition = instanceMatrix * worldPosition;\n\t#endif\n\tworldPosition = modelMatrix * worldPosition;\n#endif";
15580
15581 const vertex$g = "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}";
15582
15583 const fragment$g = "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}";
15584
15585 const vertex$f = "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}";
15586
15587 const fragment$f = "#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}";
15588
15589 const vertex$e = "#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}";
15590
15591 const fragment$e = "#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 <alphatest_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}";
15592
15593 const vertex$d = "#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}";
15594
15595 const fragment$d = "#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 <alphatest_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}";
15596
15597 const vertex$c = "varying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n}";
15598
15599 const fragment$c = "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}";
15600
15601 const vertex$b = "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}";
15602
15603 const fragment$b = "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\t#include <output_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n}";
15604
15605 const vertex$a = "#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#if defined ( USE_ENVMAP ) || defined ( USE_SKINNING )\n\t\t#include <beginnormal_vertex>\n\t\t#include <morphnormal_vertex>\n\t\t#include <skinbase_vertex>\n\t\t#include <skinnormal_vertex>\n\t\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 <clipping_planes_vertex>\n\t#include <worldpos_vertex>\n\t#include <envmap_vertex>\n\t#include <fog_vertex>\n}";
15606
15607 const fragment$a = "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 <alphatest_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\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\t#include <output_fragment>\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}";
15608
15609 const vertex$9 = "#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}";
15610
15611 const fragment$9 = "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 <alphatest_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_Lambert( diffuseColor.rgb );\n\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.directDiffuse = ( gl_FrontFacing ) ? vLightFront : vLightBack;\n\t#else\n\t\treflectedLight.directDiffuse = vLightFront;\n\t#endif\n\treflectedLight.directDiffuse *= BRDF_Lambert( diffuseColor.rgb ) * getShadowMask();\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include <envmap_fragment>\n\t#include <output_fragment>\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}";
15612
15613 const vertex$8 = "#define MATCAP\nvarying vec3 vViewPosition;\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 <normal_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#include <normal_vertex>\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}";
15614
15615 const fragment$8 = "#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\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 <alphatest_pars_fragment>\n#include <fog_pars_fragment>\n#include <normal_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\t#include <output_fragment>\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}";
15616
15617 const vertex$7 = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <normal_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\t#include <normal_vertex>\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}";
15618
15619 const fragment$7 = "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#include <packing>\n#include <uv_pars_fragment>\n#include <normal_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}";
15620
15621 const vertex$6 = "#define PHONG\nvarying vec3 vViewPosition;\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 <normal_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 <normal_vertex>\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}";
15622
15623 const fragment$6 = "#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 <alphatest_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 <normal_pars_fragment>\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\t#include <output_fragment>\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}";
15624
15625 const vertex$5 = "#define STANDARD\nvarying vec3 vViewPosition;\n#ifdef USE_TRANSMISSION\n\tvarying vec3 vWorldPosition;\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 <normal_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 <normal_vertex>\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#ifdef USE_TRANSMISSION\n\tvWorldPosition = worldPosition.xyz;\n#endif\n}";
15626
15627 const fragment$5 = "#define STANDARD\n#ifdef PHYSICAL\n\t#define IOR\n\t#define SPECULAR\n#endif\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifdef IOR\n\tuniform float ior;\n#endif\n#ifdef SPECULAR\n\tuniform float specularIntensity;\n\tuniform vec3 specularColor;\n\t#ifdef USE_SPECULARINTENSITYMAP\n\t\tuniform sampler2D specularIntensityMap;\n\t#endif\n\t#ifdef USE_SPECULARCOLORMAP\n\t\tuniform sampler2D specularColorMap;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT\n\tuniform float clearcoat;\n\tuniform float clearcoatRoughness;\n#endif\n#ifdef USE_SHEEN\n\tuniform vec3 sheenColor;\n\tuniform float sheenRoughness;\n\t#ifdef USE_SHEENCOLORMAP\n\t\tuniform sampler2D sheenColorMap;\n\t#endif\n\t#ifdef USE_SHEENROUGHNESSMAP\n\t\tuniform sampler2D sheenRoughnessMap;\n\t#endif\n#endif\nvarying vec3 vViewPosition;\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 <alphatest_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_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 <normal_pars_fragment>\n#include <lights_physical_pars_fragment>\n#include <transmission_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#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 <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 totalDiffuse = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse;\n\tvec3 totalSpecular = reflectedLight.directSpecular + reflectedLight.indirectSpecular;\n\t#include <transmission_fragment>\n\tvec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNVcc = saturate( dot( geometry.clearcoatNormal, geometry.viewDir ) );\n\t\tvec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc );\n\t\toutgoingLight = outgoingLight * ( 1.0 - clearcoat * Fcc ) + clearcoatSpecular * clearcoat;\n\t#endif\n\t#include <output_fragment>\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}";
15628
15629 const vertex$4 = "#define TOON\nvarying vec3 vViewPosition;\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 <normal_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 <normal_vertex>\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}";
15630
15631 const fragment$4 = "#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 <alphatest_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 <normal_pars_fragment>\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\t#include <output_fragment>\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}";
15632
15633 const vertex$3 = "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}";
15634
15635 const fragment$3 = "uniform vec3 diffuse;\nuniform float opacity;\n#include <common>\n#include <color_pars_fragment>\n#include <map_particle_pars_fragment>\n#include <alphatest_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\t#include <output_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n}";
15636
15637 const vertex$2 = "#include <common>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\nvoid main() {\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 <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}";
15638
15639 const fragment$2 = "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}";
15640
15641 const vertex$1 = "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}";
15642
15643 const fragment$1 = "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 <alphatest_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\t#include <output_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}";
15644
15645 const ShaderChunk = {
15646         alphamap_fragment: alphamap_fragment,
15647         alphamap_pars_fragment: alphamap_pars_fragment,
15648         alphatest_fragment: alphatest_fragment,
15649         alphatest_pars_fragment: alphatest_pars_fragment,
15650         aomap_fragment: aomap_fragment,
15651         aomap_pars_fragment: aomap_pars_fragment,
15652         begin_vertex: begin_vertex,
15653         beginnormal_vertex: beginnormal_vertex,
15654         bsdfs: bsdfs,
15655         bumpmap_pars_fragment: bumpmap_pars_fragment,
15656         clipping_planes_fragment: clipping_planes_fragment,
15657         clipping_planes_pars_fragment: clipping_planes_pars_fragment,
15658         clipping_planes_pars_vertex: clipping_planes_pars_vertex,
15659         clipping_planes_vertex: clipping_planes_vertex,
15660         color_fragment: color_fragment,
15661         color_pars_fragment: color_pars_fragment,
15662         color_pars_vertex: color_pars_vertex,
15663         color_vertex: color_vertex,
15664         common: common$1,
15665         cube_uv_reflection_fragment: cube_uv_reflection_fragment,
15666         defaultnormal_vertex: defaultnormal_vertex,
15667         displacementmap_pars_vertex: displacementmap_pars_vertex,
15668         displacementmap_vertex: displacementmap_vertex,
15669         emissivemap_fragment: emissivemap_fragment,
15670         emissivemap_pars_fragment: emissivemap_pars_fragment,
15671         encodings_fragment: encodings_fragment,
15672         encodings_pars_fragment: encodings_pars_fragment,
15673         envmap_fragment: envmap_fragment,
15674         envmap_common_pars_fragment: envmap_common_pars_fragment,
15675         envmap_pars_fragment: envmap_pars_fragment,
15676         envmap_pars_vertex: envmap_pars_vertex,
15677         envmap_physical_pars_fragment: envmap_physical_pars_fragment,
15678         envmap_vertex: envmap_vertex,
15679         fog_vertex: fog_vertex,
15680         fog_pars_vertex: fog_pars_vertex,
15681         fog_fragment: fog_fragment,
15682         fog_pars_fragment: fog_pars_fragment,
15683         gradientmap_pars_fragment: gradientmap_pars_fragment,
15684         lightmap_fragment: lightmap_fragment,
15685         lightmap_pars_fragment: lightmap_pars_fragment,
15686         lights_lambert_vertex: lights_lambert_vertex,
15687         lights_pars_begin: lights_pars_begin,
15688         lights_toon_fragment: lights_toon_fragment,
15689         lights_toon_pars_fragment: lights_toon_pars_fragment,
15690         lights_phong_fragment: lights_phong_fragment,
15691         lights_phong_pars_fragment: lights_phong_pars_fragment,
15692         lights_physical_fragment: lights_physical_fragment,
15693         lights_physical_pars_fragment: lights_physical_pars_fragment,
15694         lights_fragment_begin: lights_fragment_begin,
15695         lights_fragment_maps: lights_fragment_maps,
15696         lights_fragment_end: lights_fragment_end,
15697         logdepthbuf_fragment: logdepthbuf_fragment,
15698         logdepthbuf_pars_fragment: logdepthbuf_pars_fragment,
15699         logdepthbuf_pars_vertex: logdepthbuf_pars_vertex,
15700         logdepthbuf_vertex: logdepthbuf_vertex,
15701         map_fragment: map_fragment,
15702         map_pars_fragment: map_pars_fragment,
15703         map_particle_fragment: map_particle_fragment,
15704         map_particle_pars_fragment: map_particle_pars_fragment,
15705         metalnessmap_fragment: metalnessmap_fragment,
15706         metalnessmap_pars_fragment: metalnessmap_pars_fragment,
15707         morphnormal_vertex: morphnormal_vertex,
15708         morphtarget_pars_vertex: morphtarget_pars_vertex,
15709         morphtarget_vertex: morphtarget_vertex,
15710         normal_fragment_begin: normal_fragment_begin,
15711         normal_fragment_maps: normal_fragment_maps,
15712         normal_pars_fragment: normal_pars_fragment,
15713         normal_pars_vertex: normal_pars_vertex,
15714         normal_vertex: normal_vertex,
15715         normalmap_pars_fragment: normalmap_pars_fragment,
15716         clearcoat_normal_fragment_begin: clearcoat_normal_fragment_begin,
15717         clearcoat_normal_fragment_maps: clearcoat_normal_fragment_maps,
15718         clearcoat_pars_fragment: clearcoat_pars_fragment,
15719         output_fragment: output_fragment,
15720         packing: packing,
15721         premultiplied_alpha_fragment: premultiplied_alpha_fragment,
15722         project_vertex: project_vertex,
15723         dithering_fragment: dithering_fragment,
15724         dithering_pars_fragment: dithering_pars_fragment,
15725         roughnessmap_fragment: roughnessmap_fragment,
15726         roughnessmap_pars_fragment: roughnessmap_pars_fragment,
15727         shadowmap_pars_fragment: shadowmap_pars_fragment,
15728         shadowmap_pars_vertex: shadowmap_pars_vertex,
15729         shadowmap_vertex: shadowmap_vertex,
15730         shadowmask_pars_fragment: shadowmask_pars_fragment,
15731         skinbase_vertex: skinbase_vertex,
15732         skinning_pars_vertex: skinning_pars_vertex,
15733         skinning_vertex: skinning_vertex,
15734         skinnormal_vertex: skinnormal_vertex,
15735         specularmap_fragment: specularmap_fragment,
15736         specularmap_pars_fragment: specularmap_pars_fragment,
15737         tonemapping_fragment: tonemapping_fragment,
15738         tonemapping_pars_fragment: tonemapping_pars_fragment,
15739         transmission_fragment: transmission_fragment,
15740         transmission_pars_fragment: transmission_pars_fragment,
15741         uv_pars_fragment: uv_pars_fragment,
15742         uv_pars_vertex: uv_pars_vertex,
15743         uv_vertex: uv_vertex,
15744         uv2_pars_fragment: uv2_pars_fragment,
15745         uv2_pars_vertex: uv2_pars_vertex,
15746         uv2_vertex: uv2_vertex,
15747         worldpos_vertex: worldpos_vertex,
15748
15749         background_vert: vertex$g,
15750         background_frag: fragment$g,
15751         cube_vert: vertex$f,
15752         cube_frag: fragment$f,
15753         depth_vert: vertex$e,
15754         depth_frag: fragment$e,
15755         distanceRGBA_vert: vertex$d,
15756         distanceRGBA_frag: fragment$d,
15757         equirect_vert: vertex$c,
15758         equirect_frag: fragment$c,
15759         linedashed_vert: vertex$b,
15760         linedashed_frag: fragment$b,
15761         meshbasic_vert: vertex$a,
15762         meshbasic_frag: fragment$a,
15763         meshlambert_vert: vertex$9,
15764         meshlambert_frag: fragment$9,
15765         meshmatcap_vert: vertex$8,
15766         meshmatcap_frag: fragment$8,
15767         meshnormal_vert: vertex$7,
15768         meshnormal_frag: fragment$7,
15769         meshphong_vert: vertex$6,
15770         meshphong_frag: fragment$6,
15771         meshphysical_vert: vertex$5,
15772         meshphysical_frag: fragment$5,
15773         meshtoon_vert: vertex$4,
15774         meshtoon_frag: fragment$4,
15775         points_vert: vertex$3,
15776         points_frag: fragment$3,
15777         shadow_vert: vertex$2,
15778         shadow_frag: fragment$2,
15779         sprite_vert: vertex$1,
15780         sprite_frag: fragment$1
15781 };
15782
15783 /**
15784  * Uniforms library for shared webgl shaders
15785  */
15786
15787 const UniformsLib = {
15788
15789         common: {
15790
15791                 diffuse: { value: new Color( 0xffffff ) },
15792                 opacity: { value: 1.0 },
15793
15794                 map: { value: null },
15795                 uvTransform: { value: new Matrix3() },
15796                 uv2Transform: { value: new Matrix3() },
15797
15798                 alphaMap: { value: null },
15799                 alphaTest: { value: 0 }
15800
15801         },
15802
15803         specularmap: {
15804
15805                 specularMap: { value: null },
15806
15807         },
15808
15809         envmap: {
15810
15811                 envMap: { value: null },
15812                 flipEnvMap: { value: - 1 },
15813                 reflectivity: { value: 1.0 }, // basic, lambert, phong
15814                 ior: { value: 1.5 }, // standard, physical
15815                 refractionRatio: { value: 0.98 },
15816                 maxMipLevel: { value: 0 }
15817
15818         },
15819
15820         aomap: {
15821
15822                 aoMap: { value: null },
15823                 aoMapIntensity: { value: 1 }
15824
15825         },
15826
15827         lightmap: {
15828
15829                 lightMap: { value: null },
15830                 lightMapIntensity: { value: 1 }
15831
15832         },
15833
15834         emissivemap: {
15835
15836                 emissiveMap: { value: null }
15837
15838         },
15839
15840         bumpmap: {
15841
15842                 bumpMap: { value: null },
15843                 bumpScale: { value: 1 }
15844
15845         },
15846
15847         normalmap: {
15848
15849                 normalMap: { value: null },
15850                 normalScale: { value: new Vector2( 1, 1 ) }
15851
15852         },
15853
15854         displacementmap: {
15855
15856                 displacementMap: { value: null },
15857                 displacementScale: { value: 1 },
15858                 displacementBias: { value: 0 }
15859
15860         },
15861
15862         roughnessmap: {
15863
15864                 roughnessMap: { value: null }
15865
15866         },
15867
15868         metalnessmap: {
15869
15870                 metalnessMap: { value: null }
15871
15872         },
15873
15874         gradientmap: {
15875
15876                 gradientMap: { value: null }
15877
15878         },
15879
15880         fog: {
15881
15882                 fogDensity: { value: 0.00025 },
15883                 fogNear: { value: 1 },
15884                 fogFar: { value: 2000 },
15885                 fogColor: { value: new Color( 0xffffff ) }
15886
15887         },
15888
15889         lights: {
15890
15891                 ambientLightColor: { value: [] },
15892
15893                 lightProbe: { value: [] },
15894
15895                 directionalLights: { value: [], properties: {
15896                         direction: {},
15897                         color: {}
15898                 } },
15899
15900                 directionalLightShadows: { value: [], properties: {
15901                         shadowBias: {},
15902                         shadowNormalBias: {},
15903                         shadowRadius: {},
15904                         shadowMapSize: {}
15905                 } },
15906
15907                 directionalShadowMap: { value: [] },
15908                 directionalShadowMatrix: { value: [] },
15909
15910                 spotLights: { value: [], properties: {
15911                         color: {},
15912                         position: {},
15913                         direction: {},
15914                         distance: {},
15915                         coneCos: {},
15916                         penumbraCos: {},
15917                         decay: {}
15918                 } },
15919
15920                 spotLightShadows: { value: [], properties: {
15921                         shadowBias: {},
15922                         shadowNormalBias: {},
15923                         shadowRadius: {},
15924                         shadowMapSize: {}
15925                 } },
15926
15927                 spotShadowMap: { value: [] },
15928                 spotShadowMatrix: { value: [] },
15929
15930                 pointLights: { value: [], properties: {
15931                         color: {},
15932                         position: {},
15933                         decay: {},
15934                         distance: {}
15935                 } },
15936
15937                 pointLightShadows: { value: [], properties: {
15938                         shadowBias: {},
15939                         shadowNormalBias: {},
15940                         shadowRadius: {},
15941                         shadowMapSize: {},
15942                         shadowCameraNear: {},
15943                         shadowCameraFar: {}
15944                 } },
15945
15946                 pointShadowMap: { value: [] },
15947                 pointShadowMatrix: { value: [] },
15948
15949                 hemisphereLights: { value: [], properties: {
15950                         direction: {},
15951                         skyColor: {},
15952                         groundColor: {}
15953                 } },
15954
15955                 // TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src
15956                 rectAreaLights: { value: [], properties: {
15957                         color: {},
15958                         position: {},
15959                         width: {},
15960                         height: {}
15961                 } },
15962
15963                 ltc_1: { value: null },
15964                 ltc_2: { value: null }
15965
15966         },
15967
15968         points: {
15969
15970                 diffuse: { value: new Color( 0xffffff ) },
15971                 opacity: { value: 1.0 },
15972                 size: { value: 1.0 },
15973                 scale: { value: 1.0 },
15974                 map: { value: null },
15975                 alphaMap: { value: null },
15976                 alphaTest: { value: 0 },
15977                 uvTransform: { value: new Matrix3() }
15978
15979         },
15980
15981         sprite: {
15982
15983                 diffuse: { value: new Color( 0xffffff ) },
15984                 opacity: { value: 1.0 },
15985                 center: { value: new Vector2( 0.5, 0.5 ) },
15986                 rotation: { value: 0.0 },
15987                 map: { value: null },
15988                 alphaMap: { value: null },
15989                 alphaTest: { value: 0 },
15990                 uvTransform: { value: new Matrix3() }
15991
15992         }
15993
15994 };
15995
15996 const ShaderLib = {
15997
15998         basic: {
15999
16000                 uniforms: mergeUniforms( [
16001                         UniformsLib.common,
16002                         UniformsLib.specularmap,
16003                         UniformsLib.envmap,
16004                         UniformsLib.aomap,
16005                         UniformsLib.lightmap,
16006                         UniformsLib.fog
16007                 ] ),
16008
16009                 vertexShader: ShaderChunk.meshbasic_vert,
16010                 fragmentShader: ShaderChunk.meshbasic_frag
16011
16012         },
16013
16014         lambert: {
16015
16016                 uniforms: mergeUniforms( [
16017                         UniformsLib.common,
16018                         UniformsLib.specularmap,
16019                         UniformsLib.envmap,
16020                         UniformsLib.aomap,
16021                         UniformsLib.lightmap,
16022                         UniformsLib.emissivemap,
16023                         UniformsLib.fog,
16024                         UniformsLib.lights,
16025                         {
16026                                 emissive: { value: new Color( 0x000000 ) }
16027                         }
16028                 ] ),
16029
16030                 vertexShader: ShaderChunk.meshlambert_vert,
16031                 fragmentShader: ShaderChunk.meshlambert_frag
16032
16033         },
16034
16035         phong: {
16036
16037                 uniforms: mergeUniforms( [
16038                         UniformsLib.common,
16039                         UniformsLib.specularmap,
16040                         UniformsLib.envmap,
16041                         UniformsLib.aomap,
16042                         UniformsLib.lightmap,
16043                         UniformsLib.emissivemap,
16044                         UniformsLib.bumpmap,
16045                         UniformsLib.normalmap,
16046                         UniformsLib.displacementmap,
16047                         UniformsLib.fog,
16048                         UniformsLib.lights,
16049                         {
16050                                 emissive: { value: new Color( 0x000000 ) },
16051                                 specular: { value: new Color( 0x111111 ) },
16052                                 shininess: { value: 30 }
16053                         }
16054                 ] ),
16055
16056                 vertexShader: ShaderChunk.meshphong_vert,
16057                 fragmentShader: ShaderChunk.meshphong_frag
16058
16059         },
16060
16061         standard: {
16062
16063                 uniforms: mergeUniforms( [
16064                         UniformsLib.common,
16065                         UniformsLib.envmap,
16066                         UniformsLib.aomap,
16067                         UniformsLib.lightmap,
16068                         UniformsLib.emissivemap,
16069                         UniformsLib.bumpmap,
16070                         UniformsLib.normalmap,
16071                         UniformsLib.displacementmap,
16072                         UniformsLib.roughnessmap,
16073                         UniformsLib.metalnessmap,
16074                         UniformsLib.fog,
16075                         UniformsLib.lights,
16076                         {
16077                                 emissive: { value: new Color( 0x000000 ) },
16078                                 roughness: { value: 1.0 },
16079                                 metalness: { value: 0.0 },
16080                                 envMapIntensity: { value: 1 } // temporary
16081                         }
16082                 ] ),
16083
16084                 vertexShader: ShaderChunk.meshphysical_vert,
16085                 fragmentShader: ShaderChunk.meshphysical_frag
16086
16087         },
16088
16089         toon: {
16090
16091                 uniforms: mergeUniforms( [
16092                         UniformsLib.common,
16093                         UniformsLib.aomap,
16094                         UniformsLib.lightmap,
16095                         UniformsLib.emissivemap,
16096                         UniformsLib.bumpmap,
16097                         UniformsLib.normalmap,
16098                         UniformsLib.displacementmap,
16099                         UniformsLib.gradientmap,
16100                         UniformsLib.fog,
16101                         UniformsLib.lights,
16102                         {
16103                                 emissive: { value: new Color( 0x000000 ) }
16104                         }
16105                 ] ),
16106
16107                 vertexShader: ShaderChunk.meshtoon_vert,
16108                 fragmentShader: ShaderChunk.meshtoon_frag
16109
16110         },
16111
16112         matcap: {
16113
16114                 uniforms: mergeUniforms( [
16115                         UniformsLib.common,
16116                         UniformsLib.bumpmap,
16117                         UniformsLib.normalmap,
16118                         UniformsLib.displacementmap,
16119                         UniformsLib.fog,
16120                         {
16121                                 matcap: { value: null }
16122                         }
16123                 ] ),
16124
16125                 vertexShader: ShaderChunk.meshmatcap_vert,
16126                 fragmentShader: ShaderChunk.meshmatcap_frag
16127
16128         },
16129
16130         points: {
16131
16132                 uniforms: mergeUniforms( [
16133                         UniformsLib.points,
16134                         UniformsLib.fog
16135                 ] ),
16136
16137                 vertexShader: ShaderChunk.points_vert,
16138                 fragmentShader: ShaderChunk.points_frag
16139
16140         },
16141
16142         dashed: {
16143
16144                 uniforms: mergeUniforms( [
16145                         UniformsLib.common,
16146                         UniformsLib.fog,
16147                         {
16148                                 scale: { value: 1 },
16149                                 dashSize: { value: 1 },
16150                                 totalSize: { value: 2 }
16151                         }
16152                 ] ),
16153
16154                 vertexShader: ShaderChunk.linedashed_vert,
16155                 fragmentShader: ShaderChunk.linedashed_frag
16156
16157         },
16158
16159         depth: {
16160
16161                 uniforms: mergeUniforms( [
16162                         UniformsLib.common,
16163                         UniformsLib.displacementmap
16164                 ] ),
16165
16166                 vertexShader: ShaderChunk.depth_vert,
16167                 fragmentShader: ShaderChunk.depth_frag
16168
16169         },
16170
16171         normal: {
16172
16173                 uniforms: mergeUniforms( [
16174                         UniformsLib.common,
16175                         UniformsLib.bumpmap,
16176                         UniformsLib.normalmap,
16177                         UniformsLib.displacementmap,
16178                         {
16179                                 opacity: { value: 1.0 }
16180                         }
16181                 ] ),
16182
16183                 vertexShader: ShaderChunk.meshnormal_vert,
16184                 fragmentShader: ShaderChunk.meshnormal_frag
16185
16186         },
16187
16188         sprite: {
16189
16190                 uniforms: mergeUniforms( [
16191                         UniformsLib.sprite,
16192                         UniformsLib.fog
16193                 ] ),
16194
16195                 vertexShader: ShaderChunk.sprite_vert,
16196                 fragmentShader: ShaderChunk.sprite_frag
16197
16198         },
16199
16200         background: {
16201
16202                 uniforms: {
16203                         uvTransform: { value: new Matrix3() },
16204                         t2D: { value: null },
16205                 },
16206
16207                 vertexShader: ShaderChunk.background_vert,
16208                 fragmentShader: ShaderChunk.background_frag
16209
16210         },
16211         /* -------------------------------------------------------------------------
16212         //      Cube map shader
16213          ------------------------------------------------------------------------- */
16214
16215         cube: {
16216
16217                 uniforms: mergeUniforms( [
16218                         UniformsLib.envmap,
16219                         {
16220                                 opacity: { value: 1.0 }
16221                         }
16222                 ] ),
16223
16224                 vertexShader: ShaderChunk.cube_vert,
16225                 fragmentShader: ShaderChunk.cube_frag
16226
16227         },
16228
16229         equirect: {
16230
16231                 uniforms: {
16232                         tEquirect: { value: null },
16233                 },
16234
16235                 vertexShader: ShaderChunk.equirect_vert,
16236                 fragmentShader: ShaderChunk.equirect_frag
16237
16238         },
16239
16240         distanceRGBA: {
16241
16242                 uniforms: mergeUniforms( [
16243                         UniformsLib.common,
16244                         UniformsLib.displacementmap,
16245                         {
16246                                 referencePosition: { value: new Vector3() },
16247                                 nearDistance: { value: 1 },
16248                                 farDistance: { value: 1000 }
16249                         }
16250                 ] ),
16251
16252                 vertexShader: ShaderChunk.distanceRGBA_vert,
16253                 fragmentShader: ShaderChunk.distanceRGBA_frag
16254
16255         },
16256
16257         shadow: {
16258
16259                 uniforms: mergeUniforms( [
16260                         UniformsLib.lights,
16261                         UniformsLib.fog,
16262                         {
16263                                 color: { value: new Color( 0x00000 ) },
16264                                 opacity: { value: 1.0 }
16265                         },
16266                 ] ),
16267
16268                 vertexShader: ShaderChunk.shadow_vert,
16269                 fragmentShader: ShaderChunk.shadow_frag
16270
16271         }
16272
16273 };
16274
16275 ShaderLib.physical = {
16276
16277         uniforms: mergeUniforms( [
16278                 ShaderLib.standard.uniforms,
16279                 {
16280                         clearcoat: { value: 0 },
16281                         clearcoatMap: { value: null },
16282                         clearcoatRoughness: { value: 0 },
16283                         clearcoatRoughnessMap: { value: null },
16284                         clearcoatNormalScale: { value: new Vector2( 1, 1 ) },
16285                         clearcoatNormalMap: { value: null },
16286                         sheen: { value: 0 },
16287                         sheenColor: { value: new Color( 0x000000 ) },
16288                         sheenColorMap: { value: null },
16289                         sheenRoughness: { value: 0 },
16290                         sheenRoughnessMap: { value: null },
16291                         transmission: { value: 0 },
16292                         transmissionMap: { value: null },
16293                         transmissionSamplerSize: { value: new Vector2() },
16294                         transmissionSamplerMap: { value: null },
16295                         thickness: { value: 0 },
16296                         thicknessMap: { value: null },
16297                         attenuationDistance: { value: 0 },
16298                         attenuationColor: { value: new Color( 0x000000 ) },
16299                         specularIntensity: { value: 0 },
16300                         specularIntensityMap: { value: null },
16301                         specularColor: { value: new Color( 1, 1, 1 ) },
16302                         specularColorMap: { value: null },
16303                 }
16304         ] ),
16305
16306         vertexShader: ShaderChunk.meshphysical_vert,
16307         fragmentShader: ShaderChunk.meshphysical_frag
16308
16309 };
16310
16311 function WebGLBackground( renderer, cubemaps, state, objects, premultipliedAlpha ) {
16312
16313         const clearColor = new Color( 0x000000 );
16314         let clearAlpha = 0;
16315
16316         let planeMesh;
16317         let boxMesh;
16318
16319         let currentBackground = null;
16320         let currentBackgroundVersion = 0;
16321         let currentTonemapping = null;
16322
16323         function render( renderList, scene ) {
16324
16325                 let forceClear = false;
16326                 let background = scene.isScene === true ? scene.background : null;
16327
16328                 if ( background && background.isTexture ) {
16329
16330                         background = cubemaps.get( background );
16331
16332                 }
16333
16334                 // Ignore background in AR
16335                 // TODO: Reconsider this.
16336
16337                 const xr = renderer.xr;
16338                 const session = xr.getSession && xr.getSession();
16339
16340                 if ( session && session.environmentBlendMode === 'additive' ) {
16341
16342                         background = null;
16343
16344                 }
16345
16346                 if ( background === null ) {
16347
16348                         setClear( clearColor, clearAlpha );
16349
16350                 } else if ( background && background.isColor ) {
16351
16352                         setClear( background, 1 );
16353                         forceClear = true;
16354
16355                 }
16356
16357                 if ( renderer.autoClear || forceClear ) {
16358
16359                         renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );
16360
16361                 }
16362
16363                 if ( background && ( background.isCubeTexture || background.mapping === CubeUVReflectionMapping ) ) {
16364
16365                         if ( boxMesh === undefined ) {
16366
16367                                 boxMesh = new Mesh(
16368                                         new BoxGeometry( 1, 1, 1 ),
16369                                         new ShaderMaterial( {
16370                                                 name: 'BackgroundCubeMaterial',
16371                                                 uniforms: cloneUniforms( ShaderLib.cube.uniforms ),
16372                                                 vertexShader: ShaderLib.cube.vertexShader,
16373                                                 fragmentShader: ShaderLib.cube.fragmentShader,
16374                                                 side: BackSide,
16375                                                 depthTest: false,
16376                                                 depthWrite: false,
16377                                                 fog: false
16378                                         } )
16379                                 );
16380
16381                                 boxMesh.geometry.deleteAttribute( 'normal' );
16382                                 boxMesh.geometry.deleteAttribute( 'uv' );
16383
16384                                 boxMesh.onBeforeRender = function ( renderer, scene, camera ) {
16385
16386                                         this.matrixWorld.copyPosition( camera.matrixWorld );
16387
16388                                 };
16389
16390                                 // enable code injection for non-built-in material
16391                                 Object.defineProperty( boxMesh.material, 'envMap', {
16392
16393                                         get: function () {
16394
16395                                                 return this.uniforms.envMap.value;
16396
16397                                         }
16398
16399                                 } );
16400
16401                                 objects.update( boxMesh );
16402
16403                         }
16404
16405                         boxMesh.material.uniforms.envMap.value = background;
16406                         boxMesh.material.uniforms.flipEnvMap.value = ( background.isCubeTexture && background.isRenderTargetTexture === false ) ? - 1 : 1;
16407
16408                         if ( currentBackground !== background ||
16409                                 currentBackgroundVersion !== background.version ||
16410                                 currentTonemapping !== renderer.toneMapping ) {
16411
16412                                 boxMesh.material.needsUpdate = true;
16413
16414                                 currentBackground = background;
16415                                 currentBackgroundVersion = background.version;
16416                                 currentTonemapping = renderer.toneMapping;
16417
16418                         }
16419
16420                         // push to the pre-sorted opaque render list
16421                         renderList.unshift( boxMesh, boxMesh.geometry, boxMesh.material, 0, 0, null );
16422
16423                 } else if ( background && background.isTexture ) {
16424
16425                         if ( planeMesh === undefined ) {
16426
16427                                 planeMesh = new Mesh(
16428                                         new PlaneGeometry( 2, 2 ),
16429                                         new ShaderMaterial( {
16430                                                 name: 'BackgroundMaterial',
16431                                                 uniforms: cloneUniforms( ShaderLib.background.uniforms ),
16432                                                 vertexShader: ShaderLib.background.vertexShader,
16433                                                 fragmentShader: ShaderLib.background.fragmentShader,
16434                                                 side: FrontSide,
16435                                                 depthTest: false,
16436                                                 depthWrite: false,
16437                                                 fog: false
16438                                         } )
16439                                 );
16440
16441                                 planeMesh.geometry.deleteAttribute( 'normal' );
16442
16443                                 // enable code injection for non-built-in material
16444                                 Object.defineProperty( planeMesh.material, 'map', {
16445
16446                                         get: function () {
16447
16448                                                 return this.uniforms.t2D.value;
16449
16450                                         }
16451
16452                                 } );
16453
16454                                 objects.update( planeMesh );
16455
16456                         }
16457
16458                         planeMesh.material.uniforms.t2D.value = background;
16459
16460                         if ( background.matrixAutoUpdate === true ) {
16461
16462                                 background.updateMatrix();
16463
16464                         }
16465
16466                         planeMesh.material.uniforms.uvTransform.value.copy( background.matrix );
16467
16468                         if ( currentBackground !== background ||
16469                                 currentBackgroundVersion !== background.version ||
16470                                 currentTonemapping !== renderer.toneMapping ) {
16471
16472                                 planeMesh.material.needsUpdate = true;
16473
16474                                 currentBackground = background;
16475                                 currentBackgroundVersion = background.version;
16476                                 currentTonemapping = renderer.toneMapping;
16477
16478                         }
16479
16480
16481                         // push to the pre-sorted opaque render list
16482                         renderList.unshift( planeMesh, planeMesh.geometry, planeMesh.material, 0, 0, null );
16483
16484                 }
16485
16486         }
16487
16488         function setClear( color, alpha ) {
16489
16490                 state.buffers.color.setClear( color.r, color.g, color.b, alpha, premultipliedAlpha );
16491
16492         }
16493
16494         return {
16495
16496                 getClearColor: function () {
16497
16498                         return clearColor;
16499
16500                 },
16501                 setClearColor: function ( color, alpha = 1 ) {
16502
16503                         clearColor.set( color );
16504                         clearAlpha = alpha;
16505                         setClear( clearColor, clearAlpha );
16506
16507                 },
16508                 getClearAlpha: function () {
16509
16510                         return clearAlpha;
16511
16512                 },
16513                 setClearAlpha: function ( alpha ) {
16514
16515                         clearAlpha = alpha;
16516                         setClear( clearColor, clearAlpha );
16517
16518                 },
16519                 render: render
16520
16521         };
16522
16523 }
16524
16525 function WebGLBindingStates( gl, extensions, attributes, capabilities ) {
16526
16527         const maxVertexAttributes = gl.getParameter( 34921 );
16528
16529         const extension = capabilities.isWebGL2 ? null : extensions.get( 'OES_vertex_array_object' );
16530         const vaoAvailable = capabilities.isWebGL2 || extension !== null;
16531
16532         const bindingStates = {};
16533
16534         const defaultState = createBindingState( null );
16535         let currentState = defaultState;
16536
16537         function setup( object, material, program, geometry, index ) {
16538
16539                 let updateBuffers = false;
16540
16541                 if ( vaoAvailable ) {
16542
16543                         const state = getBindingState( geometry, program, material );
16544
16545                         if ( currentState !== state ) {
16546
16547                                 currentState = state;
16548                                 bindVertexArrayObject( currentState.object );
16549
16550                         }
16551
16552                         updateBuffers = needsUpdate( geometry, index );
16553
16554                         if ( updateBuffers ) saveCache( geometry, index );
16555
16556                 } else {
16557
16558                         const wireframe = ( material.wireframe === true );
16559
16560                         if ( currentState.geometry !== geometry.id ||
16561                                 currentState.program !== program.id ||
16562                                 currentState.wireframe !== wireframe ) {
16563
16564                                 currentState.geometry = geometry.id;
16565                                 currentState.program = program.id;
16566                                 currentState.wireframe = wireframe;
16567
16568                                 updateBuffers = true;
16569
16570                         }
16571
16572                 }
16573
16574                 if ( object.isInstancedMesh === true ) {
16575
16576                         updateBuffers = true;
16577
16578                 }
16579
16580                 if ( index !== null ) {
16581
16582                         attributes.update( index, 34963 );
16583
16584                 }
16585
16586                 if ( updateBuffers ) {
16587
16588                         setupVertexAttributes( object, material, program, geometry );
16589
16590                         if ( index !== null ) {
16591
16592                                 gl.bindBuffer( 34963, attributes.get( index ).buffer );
16593
16594                         }
16595
16596                 }
16597
16598         }
16599
16600         function createVertexArrayObject() {
16601
16602                 if ( capabilities.isWebGL2 ) return gl.createVertexArray();
16603
16604                 return extension.createVertexArrayOES();
16605
16606         }
16607
16608         function bindVertexArrayObject( vao ) {
16609
16610                 if ( capabilities.isWebGL2 ) return gl.bindVertexArray( vao );
16611
16612                 return extension.bindVertexArrayOES( vao );
16613
16614         }
16615
16616         function deleteVertexArrayObject( vao ) {
16617
16618                 if ( capabilities.isWebGL2 ) return gl.deleteVertexArray( vao );
16619
16620                 return extension.deleteVertexArrayOES( vao );
16621
16622         }
16623
16624         function getBindingState( geometry, program, material ) {
16625
16626                 const wireframe = ( material.wireframe === true );
16627
16628                 let programMap = bindingStates[ geometry.id ];
16629
16630                 if ( programMap === undefined ) {
16631
16632                         programMap = {};
16633                         bindingStates[ geometry.id ] = programMap;
16634
16635                 }
16636
16637                 let stateMap = programMap[ program.id ];
16638
16639                 if ( stateMap === undefined ) {
16640
16641                         stateMap = {};
16642                         programMap[ program.id ] = stateMap;
16643
16644                 }
16645
16646                 let state = stateMap[ wireframe ];
16647
16648                 if ( state === undefined ) {
16649
16650                         state = createBindingState( createVertexArrayObject() );
16651                         stateMap[ wireframe ] = state;
16652
16653                 }
16654
16655                 return state;
16656
16657         }
16658
16659         function createBindingState( vao ) {
16660
16661                 const newAttributes = [];
16662                 const enabledAttributes = [];
16663                 const attributeDivisors = [];
16664
16665                 for ( let i = 0; i < maxVertexAttributes; i ++ ) {
16666
16667                         newAttributes[ i ] = 0;
16668                         enabledAttributes[ i ] = 0;
16669                         attributeDivisors[ i ] = 0;
16670
16671                 }
16672
16673                 return {
16674
16675                         // for backward compatibility on non-VAO support browser
16676                         geometry: null,
16677                         program: null,
16678                         wireframe: false,
16679
16680                         newAttributes: newAttributes,
16681                         enabledAttributes: enabledAttributes,
16682                         attributeDivisors: attributeDivisors,
16683                         object: vao,
16684                         attributes: {},
16685                         index: null
16686
16687                 };
16688
16689         }
16690
16691         function needsUpdate( geometry, index ) {
16692
16693                 const cachedAttributes = currentState.attributes;
16694                 const geometryAttributes = geometry.attributes;
16695
16696                 let attributesNum = 0;
16697
16698                 for ( const key in geometryAttributes ) {
16699
16700                         const cachedAttribute = cachedAttributes[ key ];
16701                         const geometryAttribute = geometryAttributes[ key ];
16702
16703                         if ( cachedAttribute === undefined ) return true;
16704
16705                         if ( cachedAttribute.attribute !== geometryAttribute ) return true;
16706
16707                         if ( cachedAttribute.data !== geometryAttribute.data ) return true;
16708
16709                         attributesNum ++;
16710
16711                 }
16712
16713                 if ( currentState.attributesNum !== attributesNum ) return true;
16714
16715                 if ( currentState.index !== index ) return true;
16716
16717                 return false;
16718
16719         }
16720
16721         function saveCache( geometry, index ) {
16722
16723                 const cache = {};
16724                 const attributes = geometry.attributes;
16725                 let attributesNum = 0;
16726
16727                 for ( const key in attributes ) {
16728
16729                         const attribute = attributes[ key ];
16730
16731                         const data = {};
16732                         data.attribute = attribute;
16733
16734                         if ( attribute.data ) {
16735
16736                                 data.data = attribute.data;
16737
16738                         }
16739
16740                         cache[ key ] = data;
16741
16742                         attributesNum ++;
16743
16744                 }
16745
16746                 currentState.attributes = cache;
16747                 currentState.attributesNum = attributesNum;
16748
16749                 currentState.index = index;
16750
16751         }
16752
16753         function initAttributes() {
16754
16755                 const newAttributes = currentState.newAttributes;
16756
16757                 for ( let i = 0, il = newAttributes.length; i < il; i ++ ) {
16758
16759                         newAttributes[ i ] = 0;
16760
16761                 }
16762
16763         }
16764
16765         function enableAttribute( attribute ) {
16766
16767                 enableAttributeAndDivisor( attribute, 0 );
16768
16769         }
16770
16771         function enableAttributeAndDivisor( attribute, meshPerAttribute ) {
16772
16773                 const newAttributes = currentState.newAttributes;
16774                 const enabledAttributes = currentState.enabledAttributes;
16775                 const attributeDivisors = currentState.attributeDivisors;
16776
16777                 newAttributes[ attribute ] = 1;
16778
16779                 if ( enabledAttributes[ attribute ] === 0 ) {
16780
16781                         gl.enableVertexAttribArray( attribute );
16782                         enabledAttributes[ attribute ] = 1;
16783
16784                 }
16785
16786                 if ( attributeDivisors[ attribute ] !== meshPerAttribute ) {
16787
16788                         const extension = capabilities.isWebGL2 ? gl : extensions.get( 'ANGLE_instanced_arrays' );
16789
16790                         extension[ capabilities.isWebGL2 ? 'vertexAttribDivisor' : 'vertexAttribDivisorANGLE' ]( attribute, meshPerAttribute );
16791                         attributeDivisors[ attribute ] = meshPerAttribute;
16792
16793                 }
16794
16795         }
16796
16797         function disableUnusedAttributes() {
16798
16799                 const newAttributes = currentState.newAttributes;
16800                 const enabledAttributes = currentState.enabledAttributes;
16801
16802                 for ( let i = 0, il = enabledAttributes.length; i < il; i ++ ) {
16803
16804                         if ( enabledAttributes[ i ] !== newAttributes[ i ] ) {
16805
16806                                 gl.disableVertexAttribArray( i );
16807                                 enabledAttributes[ i ] = 0;
16808
16809                         }
16810
16811                 }
16812
16813         }
16814
16815         function vertexAttribPointer( index, size, type, normalized, stride, offset ) {
16816
16817                 if ( capabilities.isWebGL2 === true && ( type === 5124 || type === 5125 ) ) {
16818
16819                         gl.vertexAttribIPointer( index, size, type, stride, offset );
16820
16821                 } else {
16822
16823                         gl.vertexAttribPointer( index, size, type, normalized, stride, offset );
16824
16825                 }
16826
16827         }
16828
16829         function setupVertexAttributes( object, material, program, geometry ) {
16830
16831                 if ( capabilities.isWebGL2 === false && ( object.isInstancedMesh || geometry.isInstancedBufferGeometry ) ) {
16832
16833                         if ( extensions.get( 'ANGLE_instanced_arrays' ) === null ) return;
16834
16835                 }
16836
16837                 initAttributes();
16838
16839                 const geometryAttributes = geometry.attributes;
16840
16841                 const programAttributes = program.getAttributes();
16842
16843                 const materialDefaultAttributeValues = material.defaultAttributeValues;
16844
16845                 for ( const name in programAttributes ) {
16846
16847                         const programAttribute = programAttributes[ name ];
16848
16849                         if ( programAttribute.location >= 0 ) {
16850
16851                                 let geometryAttribute = geometryAttributes[ name ];
16852
16853                                 if ( geometryAttribute === undefined ) {
16854
16855                                         if ( name === 'instanceMatrix' && object.instanceMatrix ) geometryAttribute = object.instanceMatrix;
16856                                         if ( name === 'instanceColor' && object.instanceColor ) geometryAttribute = object.instanceColor;
16857
16858                                 }
16859
16860                                 if ( geometryAttribute !== undefined ) {
16861
16862                                         const normalized = geometryAttribute.normalized;
16863                                         const size = geometryAttribute.itemSize;
16864
16865                                         const attribute = attributes.get( geometryAttribute );
16866
16867                                         // TODO Attribute may not be available on context restore
16868
16869                                         if ( attribute === undefined ) continue;
16870
16871                                         const buffer = attribute.buffer;
16872                                         const type = attribute.type;
16873                                         const bytesPerElement = attribute.bytesPerElement;
16874
16875                                         if ( geometryAttribute.isInterleavedBufferAttribute ) {
16876
16877                                                 const data = geometryAttribute.data;
16878                                                 const stride = data.stride;
16879                                                 const offset = geometryAttribute.offset;
16880
16881                                                 if ( data && data.isInstancedInterleavedBuffer ) {
16882
16883                                                         for ( let i = 0; i < programAttribute.locationSize; i ++ ) {
16884
16885                                                                 enableAttributeAndDivisor( programAttribute.location + i, data.meshPerAttribute );
16886
16887                                                         }
16888
16889                                                         if ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) {
16890
16891                                                                 geometry._maxInstanceCount = data.meshPerAttribute * data.count;
16892
16893                                                         }
16894
16895                                                 } else {
16896
16897                                                         for ( let i = 0; i < programAttribute.locationSize; i ++ ) {
16898
16899                                                                 enableAttribute( programAttribute.location + i );
16900
16901                                                         }
16902
16903                                                 }
16904
16905                                                 gl.bindBuffer( 34962, buffer );
16906
16907                                                 for ( let i = 0; i < programAttribute.locationSize; i ++ ) {
16908
16909                                                         vertexAttribPointer(
16910                                                                 programAttribute.location + i,
16911                                                                 size / programAttribute.locationSize,
16912                                                                 type,
16913                                                                 normalized,
16914                                                                 stride * bytesPerElement,
16915                                                                 ( offset + ( size / programAttribute.locationSize ) * i ) * bytesPerElement
16916                                                         );
16917
16918                                                 }
16919
16920                                         } else {
16921
16922                                                 if ( geometryAttribute.isInstancedBufferAttribute ) {
16923
16924                                                         for ( let i = 0; i < programAttribute.locationSize; i ++ ) {
16925
16926                                                                 enableAttributeAndDivisor( programAttribute.location + i, geometryAttribute.meshPerAttribute );
16927
16928                                                         }
16929
16930                                                         if ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) {
16931
16932                                                                 geometry._maxInstanceCount = geometryAttribute.meshPerAttribute * geometryAttribute.count;
16933
16934                                                         }
16935
16936                                                 } else {
16937
16938                                                         for ( let i = 0; i < programAttribute.locationSize; i ++ ) {
16939
16940                                                                 enableAttribute( programAttribute.location + i );
16941
16942                                                         }
16943
16944                                                 }
16945
16946                                                 gl.bindBuffer( 34962, buffer );
16947
16948                                                 for ( let i = 0; i < programAttribute.locationSize; i ++ ) {
16949
16950                                                         vertexAttribPointer(
16951                                                                 programAttribute.location + i,
16952                                                                 size / programAttribute.locationSize,
16953                                                                 type,
16954                                                                 normalized,
16955                                                                 size * bytesPerElement,
16956                                                                 ( size / programAttribute.locationSize ) * i * bytesPerElement
16957                                                         );
16958
16959                                                 }
16960
16961                                         }
16962
16963                                 } else if ( materialDefaultAttributeValues !== undefined ) {
16964
16965                                         const value = materialDefaultAttributeValues[ name ];
16966
16967                                         if ( value !== undefined ) {
16968
16969                                                 switch ( value.length ) {
16970
16971                                                         case 2:
16972                                                                 gl.vertexAttrib2fv( programAttribute.location, value );
16973                                                                 break;
16974
16975                                                         case 3:
16976                                                                 gl.vertexAttrib3fv( programAttribute.location, value );
16977                                                                 break;
16978
16979                                                         case 4:
16980                                                                 gl.vertexAttrib4fv( programAttribute.location, value );
16981                                                                 break;
16982
16983                                                         default:
16984                                                                 gl.vertexAttrib1fv( programAttribute.location, value );
16985
16986                                                 }
16987
16988                                         }
16989
16990                                 }
16991
16992                         }
16993
16994                 }
16995
16996                 disableUnusedAttributes();
16997
16998         }
16999
17000         function dispose() {
17001
17002                 reset();
17003
17004                 for ( const geometryId in bindingStates ) {
17005
17006                         const programMap = bindingStates[ geometryId ];
17007
17008                         for ( const programId in programMap ) {
17009
17010                                 const stateMap = programMap[ programId ];
17011
17012                                 for ( const wireframe in stateMap ) {
17013
17014                                         deleteVertexArrayObject( stateMap[ wireframe ].object );
17015
17016                                         delete stateMap[ wireframe ];
17017
17018                                 }
17019
17020                                 delete programMap[ programId ];
17021
17022                         }
17023
17024                         delete bindingStates[ geometryId ];
17025
17026                 }
17027
17028         }
17029
17030         function releaseStatesOfGeometry( geometry ) {
17031
17032                 if ( bindingStates[ geometry.id ] === undefined ) return;
17033
17034                 const programMap = bindingStates[ geometry.id ];
17035
17036                 for ( const programId in programMap ) {
17037
17038                         const stateMap = programMap[ programId ];
17039
17040                         for ( const wireframe in stateMap ) {
17041
17042                                 deleteVertexArrayObject( stateMap[ wireframe ].object );
17043
17044                                 delete stateMap[ wireframe ];
17045
17046                         }
17047
17048                         delete programMap[ programId ];
17049
17050                 }
17051
17052                 delete bindingStates[ geometry.id ];
17053
17054         }
17055
17056         function releaseStatesOfProgram( program ) {
17057
17058                 for ( const geometryId in bindingStates ) {
17059
17060                         const programMap = bindingStates[ geometryId ];
17061
17062                         if ( programMap[ program.id ] === undefined ) continue;
17063
17064                         const stateMap = programMap[ program.id ];
17065
17066                         for ( const wireframe in stateMap ) {
17067
17068                                 deleteVertexArrayObject( stateMap[ wireframe ].object );
17069
17070                                 delete stateMap[ wireframe ];
17071
17072                         }
17073
17074                         delete programMap[ program.id ];
17075
17076                 }
17077
17078         }
17079
17080         function reset() {
17081
17082                 resetDefaultState();
17083
17084                 if ( currentState === defaultState ) return;
17085
17086                 currentState = defaultState;
17087                 bindVertexArrayObject( currentState.object );
17088
17089         }
17090
17091         // for backward-compatilibity
17092
17093         function resetDefaultState() {
17094
17095                 defaultState.geometry = null;
17096                 defaultState.program = null;
17097                 defaultState.wireframe = false;
17098
17099         }
17100
17101         return {
17102
17103                 setup: setup,
17104                 reset: reset,
17105                 resetDefaultState: resetDefaultState,
17106                 dispose: dispose,
17107                 releaseStatesOfGeometry: releaseStatesOfGeometry,
17108                 releaseStatesOfProgram: releaseStatesOfProgram,
17109
17110                 initAttributes: initAttributes,
17111                 enableAttribute: enableAttribute,
17112                 disableUnusedAttributes: disableUnusedAttributes
17113
17114         };
17115
17116 }
17117
17118 function WebGLBufferRenderer( gl, extensions, info, capabilities ) {
17119
17120         const isWebGL2 = capabilities.isWebGL2;
17121
17122         let mode;
17123
17124         function setMode( value ) {
17125
17126                 mode = value;
17127
17128         }
17129
17130         function render( start, count ) {
17131
17132                 gl.drawArrays( mode, start, count );
17133
17134                 info.update( count, mode, 1 );
17135
17136         }
17137
17138         function renderInstances( start, count, primcount ) {
17139
17140                 if ( primcount === 0 ) return;
17141
17142                 let extension, methodName;
17143
17144                 if ( isWebGL2 ) {
17145
17146                         extension = gl;
17147                         methodName = 'drawArraysInstanced';
17148
17149                 } else {
17150
17151                         extension = extensions.get( 'ANGLE_instanced_arrays' );
17152                         methodName = 'drawArraysInstancedANGLE';
17153
17154                         if ( extension === null ) {
17155
17156                                 console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
17157                                 return;
17158
17159                         }
17160
17161                 }
17162
17163                 extension[ methodName ]( mode, start, count, primcount );
17164
17165                 info.update( count, mode, primcount );
17166
17167         }
17168
17169         //
17170
17171         this.setMode = setMode;
17172         this.render = render;
17173         this.renderInstances = renderInstances;
17174
17175 }
17176
17177 function WebGLCapabilities( gl, extensions, parameters ) {
17178
17179         let maxAnisotropy;
17180
17181         function getMaxAnisotropy() {
17182
17183                 if ( maxAnisotropy !== undefined ) return maxAnisotropy;
17184
17185                 if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) {
17186
17187                         const extension = extensions.get( 'EXT_texture_filter_anisotropic' );
17188
17189                         maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT );
17190
17191                 } else {
17192
17193                         maxAnisotropy = 0;
17194
17195                 }
17196
17197                 return maxAnisotropy;
17198
17199         }
17200
17201         function getMaxPrecision( precision ) {
17202
17203                 if ( precision === 'highp' ) {
17204
17205                         if ( gl.getShaderPrecisionFormat( 35633, 36338 ).precision > 0 &&
17206                                 gl.getShaderPrecisionFormat( 35632, 36338 ).precision > 0 ) {
17207
17208                                 return 'highp';
17209
17210                         }
17211
17212                         precision = 'mediump';
17213
17214                 }
17215
17216                 if ( precision === 'mediump' ) {
17217
17218                         if ( gl.getShaderPrecisionFormat( 35633, 36337 ).precision > 0 &&
17219                                 gl.getShaderPrecisionFormat( 35632, 36337 ).precision > 0 ) {
17220
17221                                 return 'mediump';
17222
17223                         }
17224
17225                 }
17226
17227                 return 'lowp';
17228
17229         }
17230
17231         /* eslint-disable no-undef */
17232         const isWebGL2 = ( typeof WebGL2RenderingContext !== 'undefined' && gl instanceof WebGL2RenderingContext ) ||
17233                 ( typeof WebGL2ComputeRenderingContext !== 'undefined' && gl instanceof WebGL2ComputeRenderingContext );
17234         /* eslint-enable no-undef */
17235
17236         let precision = parameters.precision !== undefined ? parameters.precision : 'highp';
17237         const maxPrecision = getMaxPrecision( precision );
17238
17239         if ( maxPrecision !== precision ) {
17240
17241                 console.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' );
17242                 precision = maxPrecision;
17243
17244         }
17245
17246         const drawBuffers = isWebGL2 || extensions.has( 'WEBGL_draw_buffers' );
17247
17248         const logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true;
17249
17250         const maxTextures = gl.getParameter( 34930 );
17251         const maxVertexTextures = gl.getParameter( 35660 );
17252         const maxTextureSize = gl.getParameter( 3379 );
17253         const maxCubemapSize = gl.getParameter( 34076 );
17254
17255         const maxAttributes = gl.getParameter( 34921 );
17256         const maxVertexUniforms = gl.getParameter( 36347 );
17257         const maxVaryings = gl.getParameter( 36348 );
17258         const maxFragmentUniforms = gl.getParameter( 36349 );
17259
17260         const vertexTextures = maxVertexTextures > 0;
17261         const floatFragmentTextures = isWebGL2 || extensions.has( 'OES_texture_float' );
17262         const floatVertexTextures = vertexTextures && floatFragmentTextures;
17263
17264         const maxSamples = isWebGL2 ? gl.getParameter( 36183 ) : 0;
17265
17266         return {
17267
17268                 isWebGL2: isWebGL2,
17269
17270                 drawBuffers: drawBuffers,
17271
17272                 getMaxAnisotropy: getMaxAnisotropy,
17273                 getMaxPrecision: getMaxPrecision,
17274
17275                 precision: precision,
17276                 logarithmicDepthBuffer: logarithmicDepthBuffer,
17277
17278                 maxTextures: maxTextures,
17279                 maxVertexTextures: maxVertexTextures,
17280                 maxTextureSize: maxTextureSize,
17281                 maxCubemapSize: maxCubemapSize,
17282
17283                 maxAttributes: maxAttributes,
17284                 maxVertexUniforms: maxVertexUniforms,
17285                 maxVaryings: maxVaryings,
17286                 maxFragmentUniforms: maxFragmentUniforms,
17287
17288                 vertexTextures: vertexTextures,
17289                 floatFragmentTextures: floatFragmentTextures,
17290                 floatVertexTextures: floatVertexTextures,
17291
17292                 maxSamples: maxSamples
17293
17294         };
17295
17296 }
17297
17298 function WebGLClipping( properties ) {
17299
17300         const scope = this;
17301
17302         let globalState = null,
17303                 numGlobalPlanes = 0,
17304                 localClippingEnabled = false,
17305                 renderingShadows = false;
17306
17307         const plane = new Plane(),
17308                 viewNormalMatrix = new Matrix3(),
17309
17310                 uniform = { value: null, needsUpdate: false };
17311
17312         this.uniform = uniform;
17313         this.numPlanes = 0;
17314         this.numIntersection = 0;
17315
17316         this.init = function ( planes, enableLocalClipping, camera ) {
17317
17318                 const enabled =
17319                         planes.length !== 0 ||
17320                         enableLocalClipping ||
17321                         // enable state of previous frame - the clipping code has to
17322                         // run another frame in order to reset the state:
17323                         numGlobalPlanes !== 0 ||
17324                         localClippingEnabled;
17325
17326                 localClippingEnabled = enableLocalClipping;
17327
17328                 globalState = projectPlanes( planes, camera, 0 );
17329                 numGlobalPlanes = planes.length;
17330
17331                 return enabled;
17332
17333         };
17334
17335         this.beginShadows = function () {
17336
17337                 renderingShadows = true;
17338                 projectPlanes( null );
17339
17340         };
17341
17342         this.endShadows = function () {
17343
17344                 renderingShadows = false;
17345                 resetGlobalState();
17346
17347         };
17348
17349         this.setState = function ( material, camera, useCache ) {
17350
17351                 const planes = material.clippingPlanes,
17352                         clipIntersection = material.clipIntersection,
17353                         clipShadows = material.clipShadows;
17354
17355                 const materialProperties = properties.get( material );
17356
17357                 if ( ! localClippingEnabled || planes === null || planes.length === 0 || renderingShadows && ! clipShadows ) {
17358
17359                         // there's no local clipping
17360
17361                         if ( renderingShadows ) {
17362
17363                                 // there's no global clipping
17364
17365                                 projectPlanes( null );
17366
17367                         } else {
17368
17369                                 resetGlobalState();
17370
17371                         }
17372
17373                 } else {
17374
17375                         const nGlobal = renderingShadows ? 0 : numGlobalPlanes,
17376                                 lGlobal = nGlobal * 4;
17377
17378                         let dstArray = materialProperties.clippingState || null;
17379
17380                         uniform.value = dstArray; // ensure unique state
17381
17382                         dstArray = projectPlanes( planes, camera, lGlobal, useCache );
17383
17384                         for ( let i = 0; i !== lGlobal; ++ i ) {
17385
17386                                 dstArray[ i ] = globalState[ i ];
17387
17388                         }
17389
17390                         materialProperties.clippingState = dstArray;
17391                         this.numIntersection = clipIntersection ? this.numPlanes : 0;
17392                         this.numPlanes += nGlobal;
17393
17394                 }
17395
17396
17397         };
17398
17399         function resetGlobalState() {
17400
17401                 if ( uniform.value !== globalState ) {
17402
17403                         uniform.value = globalState;
17404                         uniform.needsUpdate = numGlobalPlanes > 0;
17405
17406                 }
17407
17408                 scope.numPlanes = numGlobalPlanes;
17409                 scope.numIntersection = 0;
17410
17411         }
17412
17413         function projectPlanes( planes, camera, dstOffset, skipTransform ) {
17414
17415                 const nPlanes = planes !== null ? planes.length : 0;
17416                 let dstArray = null;
17417
17418                 if ( nPlanes !== 0 ) {
17419
17420                         dstArray = uniform.value;
17421
17422                         if ( skipTransform !== true || dstArray === null ) {
17423
17424                                 const flatSize = dstOffset + nPlanes * 4,
17425                                         viewMatrix = camera.matrixWorldInverse;
17426
17427                                 viewNormalMatrix.getNormalMatrix( viewMatrix );
17428
17429                                 if ( dstArray === null || dstArray.length < flatSize ) {
17430
17431                                         dstArray = new Float32Array( flatSize );
17432
17433                                 }
17434
17435                                 for ( let i = 0, i4 = dstOffset; i !== nPlanes; ++ i, i4 += 4 ) {
17436
17437                                         plane.copy( planes[ i ] ).applyMatrix4( viewMatrix, viewNormalMatrix );
17438
17439                                         plane.normal.toArray( dstArray, i4 );
17440                                         dstArray[ i4 + 3 ] = plane.constant;
17441
17442                                 }
17443
17444                         }
17445
17446                         uniform.value = dstArray;
17447                         uniform.needsUpdate = true;
17448
17449                 }
17450
17451                 scope.numPlanes = nPlanes;
17452                 scope.numIntersection = 0;
17453
17454                 return dstArray;
17455
17456         }
17457
17458 }
17459
17460 function WebGLCubeMaps( renderer ) {
17461
17462         let cubemaps = new WeakMap();
17463
17464         function mapTextureMapping( texture, mapping ) {
17465
17466                 if ( mapping === EquirectangularReflectionMapping ) {
17467
17468                         texture.mapping = CubeReflectionMapping;
17469
17470                 } else if ( mapping === EquirectangularRefractionMapping ) {
17471
17472                         texture.mapping = CubeRefractionMapping;
17473
17474                 }
17475
17476                 return texture;
17477
17478         }
17479
17480         function get( texture ) {
17481
17482                 if ( texture && texture.isTexture && texture.isRenderTargetTexture === false ) {
17483
17484                         const mapping = texture.mapping;
17485
17486                         if ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ) {
17487
17488                                 if ( cubemaps.has( texture ) ) {
17489
17490                                         const cubemap = cubemaps.get( texture ).texture;
17491                                         return mapTextureMapping( cubemap, texture.mapping );
17492
17493                                 } else {
17494
17495                                         const image = texture.image;
17496
17497                                         if ( image && image.height > 0 ) {
17498
17499                                                 const currentRenderTarget = renderer.getRenderTarget();
17500
17501                                                 const renderTarget = new WebGLCubeRenderTarget( image.height / 2 );
17502                                                 renderTarget.fromEquirectangularTexture( renderer, texture );
17503                                                 cubemaps.set( texture, renderTarget );
17504
17505                                                 renderer.setRenderTarget( currentRenderTarget );
17506
17507                                                 texture.addEventListener( 'dispose', onTextureDispose );
17508
17509                                                 return mapTextureMapping( renderTarget.texture, texture.mapping );
17510
17511                                         } else {
17512
17513                                                 // image not yet ready. try the conversion next frame
17514
17515                                                 return null;
17516
17517                                         }
17518
17519                                 }
17520
17521                         }
17522
17523                 }
17524
17525                 return texture;
17526
17527         }
17528
17529         function onTextureDispose( event ) {
17530
17531                 const texture = event.target;
17532
17533                 texture.removeEventListener( 'dispose', onTextureDispose );
17534
17535                 const cubemap = cubemaps.get( texture );
17536
17537                 if ( cubemap !== undefined ) {
17538
17539                         cubemaps.delete( texture );
17540                         cubemap.dispose();
17541
17542                 }
17543
17544         }
17545
17546         function dispose() {
17547
17548                 cubemaps = new WeakMap();
17549
17550         }
17551
17552         return {
17553                 get: get,
17554                 dispose: dispose
17555         };
17556
17557 }
17558
17559 class OrthographicCamera extends Camera$1 {
17560
17561         constructor( left = - 1, right = 1, top = 1, bottom = - 1, near = 0.1, far = 2000 ) {
17562
17563                 super();
17564
17565                 this.type = 'OrthographicCamera';
17566
17567                 this.zoom = 1;
17568                 this.view = null;
17569
17570                 this.left = left;
17571                 this.right = right;
17572                 this.top = top;
17573                 this.bottom = bottom;
17574
17575                 this.near = near;
17576                 this.far = far;
17577
17578                 this.updateProjectionMatrix();
17579
17580         }
17581
17582         copy( source, recursive ) {
17583
17584                 super.copy( source, recursive );
17585
17586                 this.left = source.left;
17587                 this.right = source.right;
17588                 this.top = source.top;
17589                 this.bottom = source.bottom;
17590                 this.near = source.near;
17591                 this.far = source.far;
17592
17593                 this.zoom = source.zoom;
17594                 this.view = source.view === null ? null : Object.assign( {}, source.view );
17595
17596                 return this;
17597
17598         }
17599
17600         setViewOffset( fullWidth, fullHeight, x, y, width, height ) {
17601
17602                 if ( this.view === null ) {
17603
17604                         this.view = {
17605                                 enabled: true,
17606                                 fullWidth: 1,
17607                                 fullHeight: 1,
17608                                 offsetX: 0,
17609                                 offsetY: 0,
17610                                 width: 1,
17611                                 height: 1
17612                         };
17613
17614                 }
17615
17616                 this.view.enabled = true;
17617                 this.view.fullWidth = fullWidth;
17618                 this.view.fullHeight = fullHeight;
17619                 this.view.offsetX = x;
17620                 this.view.offsetY = y;
17621                 this.view.width = width;
17622                 this.view.height = height;
17623
17624                 this.updateProjectionMatrix();
17625
17626         }
17627
17628         clearViewOffset() {
17629
17630                 if ( this.view !== null ) {
17631
17632                         this.view.enabled = false;
17633
17634                 }
17635
17636                 this.updateProjectionMatrix();
17637
17638         }
17639
17640         updateProjectionMatrix() {
17641
17642                 const dx = ( this.right - this.left ) / ( 2 * this.zoom );
17643                 const dy = ( this.top - this.bottom ) / ( 2 * this.zoom );
17644                 const cx = ( this.right + this.left ) / 2;
17645                 const cy = ( this.top + this.bottom ) / 2;
17646
17647                 let left = cx - dx;
17648                 let right = cx + dx;
17649                 let top = cy + dy;
17650                 let bottom = cy - dy;
17651
17652                 if ( this.view !== null && this.view.enabled ) {
17653
17654                         const scaleW = ( this.right - this.left ) / this.view.fullWidth / this.zoom;
17655                         const scaleH = ( this.top - this.bottom ) / this.view.fullHeight / this.zoom;
17656
17657                         left += scaleW * this.view.offsetX;
17658                         right = left + scaleW * this.view.width;
17659                         top -= scaleH * this.view.offsetY;
17660                         bottom = top - scaleH * this.view.height;
17661
17662                 }
17663
17664                 this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far );
17665
17666                 this.projectionMatrixInverse.copy( this.projectionMatrix ).invert();
17667
17668         }
17669
17670         toJSON( meta ) {
17671
17672                 const data = super.toJSON( meta );
17673
17674                 data.object.zoom = this.zoom;
17675                 data.object.left = this.left;
17676                 data.object.right = this.right;
17677                 data.object.top = this.top;
17678                 data.object.bottom = this.bottom;
17679                 data.object.near = this.near;
17680                 data.object.far = this.far;
17681
17682                 if ( this.view !== null ) data.object.view = Object.assign( {}, this.view );
17683
17684                 return data;
17685
17686         }
17687
17688 }
17689
17690 OrthographicCamera.prototype.isOrthographicCamera = true;
17691
17692 class RawShaderMaterial extends ShaderMaterial {
17693
17694         constructor( parameters ) {
17695
17696                 super( parameters );
17697
17698                 this.type = 'RawShaderMaterial';
17699
17700         }
17701
17702 }
17703
17704 RawShaderMaterial.prototype.isRawShaderMaterial = true;
17705
17706 const LOD_MIN = 4;
17707 const LOD_MAX = 8;
17708 const SIZE_MAX = Math.pow( 2, LOD_MAX );
17709
17710 // The standard deviations (radians) associated with the extra mips. These are
17711 // chosen to approximate a Trowbridge-Reitz distribution function times the
17712 // geometric shadowing function. These sigma values squared must match the
17713 // variance #defines in cube_uv_reflection_fragment.glsl.js.
17714 const EXTRA_LOD_SIGMA = [ 0.125, 0.215, 0.35, 0.446, 0.526, 0.582 ];
17715
17716 const TOTAL_LODS = LOD_MAX - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length;
17717
17718 // The maximum length of the blur for loop. Smaller sigmas will use fewer
17719 // samples and exit early, but not recompile the shader.
17720 const MAX_SAMPLES = 20;
17721
17722 const ENCODINGS = {
17723         [ LinearEncoding ]: 0,
17724         [ sRGBEncoding ]: 1,
17725         [ RGBEEncoding ]: 2,
17726         [ RGBM7Encoding ]: 3,
17727         [ RGBM16Encoding ]: 4,
17728         [ RGBDEncoding ]: 5,
17729         [ GammaEncoding ]: 6
17730 };
17731
17732 const _flatCamera = /*@__PURE__*/ new OrthographicCamera();
17733 const { _lodPlanes, _sizeLods, _sigmas } = /*@__PURE__*/ _createPlanes();
17734 const _clearColor = /*@__PURE__*/ new Color();
17735 let _oldTarget = null;
17736
17737 // Golden Ratio
17738 const PHI = ( 1 + Math.sqrt( 5 ) ) / 2;
17739 const INV_PHI = 1 / PHI;
17740
17741 // Vertices of a dodecahedron (except the opposites, which represent the
17742 // same axis), used as axis directions evenly spread on a sphere.
17743 const _axisDirections = [
17744         /*@__PURE__*/ new Vector3( 1, 1, 1 ),
17745         /*@__PURE__*/ new Vector3( - 1, 1, 1 ),
17746         /*@__PURE__*/ new Vector3( 1, 1, - 1 ),
17747         /*@__PURE__*/ new Vector3( - 1, 1, - 1 ),
17748         /*@__PURE__*/ new Vector3( 0, PHI, INV_PHI ),
17749         /*@__PURE__*/ new Vector3( 0, PHI, - INV_PHI ),
17750         /*@__PURE__*/ new Vector3( INV_PHI, 0, PHI ),
17751         /*@__PURE__*/ new Vector3( - INV_PHI, 0, PHI ),
17752         /*@__PURE__*/ new Vector3( PHI, INV_PHI, 0 ),
17753         /*@__PURE__*/ new Vector3( - PHI, INV_PHI, 0 ) ];
17754
17755 /**
17756  * This class generates a Prefiltered, Mipmapped Radiance Environment Map
17757  * (PMREM) from a cubeMap environment texture. This allows different levels of
17758  * blur to be quickly accessed based on material roughness. It is packed into a
17759  * special CubeUV format that allows us to perform custom interpolation so that
17760  * we can support nonlinear formats such as RGBE. Unlike a traditional mipmap
17761  * chain, it only goes down to the LOD_MIN level (above), and then creates extra
17762  * even more filtered 'mips' at the same LOD_MIN resolution, associated with
17763  * higher roughness levels. In this way we maintain resolution to smoothly
17764  * interpolate diffuse lighting while limiting sampling computation.
17765  *
17766  * Paper: Fast, Accurate Image-Based Lighting
17767  * https://drive.google.com/file/d/15y8r_UpKlU9SvV4ILb0C3qCPecS8pvLz/view
17768 */
17769
17770 class PMREMGenerator {
17771
17772         constructor( renderer ) {
17773
17774                 this._renderer = renderer;
17775                 this._pingPongRenderTarget = null;
17776
17777                 this._blurMaterial = _getBlurShader( MAX_SAMPLES );
17778                 this._equirectShader = null;
17779                 this._cubemapShader = null;
17780
17781                 this._compileMaterial( this._blurMaterial );
17782
17783         }
17784
17785         /**
17786          * Generates a PMREM from a supplied Scene, which can be faster than using an
17787          * image if networking bandwidth is low. Optional sigma specifies a blur radius
17788          * in radians to be applied to the scene before PMREM generation. Optional near
17789          * and far planes ensure the scene is rendered in its entirety (the cubeCamera
17790          * is placed at the origin).
17791          */
17792         fromScene( scene, sigma = 0, near = 0.1, far = 100 ) {
17793
17794                 _oldTarget = this._renderer.getRenderTarget();
17795                 const cubeUVRenderTarget = this._allocateTargets();
17796
17797                 this._sceneToCubeUV( scene, near, far, cubeUVRenderTarget );
17798                 if ( sigma > 0 ) {
17799
17800                         this._blur( cubeUVRenderTarget, 0, 0, sigma );
17801
17802                 }
17803
17804                 this._applyPMREM( cubeUVRenderTarget );
17805                 this._cleanup( cubeUVRenderTarget );
17806
17807                 return cubeUVRenderTarget;
17808
17809         }
17810
17811         /**
17812          * Generates a PMREM from an equirectangular texture, which can be either LDR
17813          * (RGBFormat) or HDR (RGBEFormat). The ideal input image size is 1k (1024 x 512),
17814          * as this matches best with the 256 x 256 cubemap output.
17815          */
17816         fromEquirectangular( equirectangular ) {
17817
17818                 return this._fromTexture( equirectangular );
17819
17820         }
17821
17822         /**
17823          * Generates a PMREM from an cubemap texture, which can be either LDR
17824          * (RGBFormat) or HDR (RGBEFormat). The ideal input cube size is 256 x 256,
17825          * as this matches best with the 256 x 256 cubemap output.
17826          */
17827         fromCubemap( cubemap ) {
17828
17829                 return this._fromTexture( cubemap );
17830
17831         }
17832
17833         /**
17834          * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during
17835          * your texture's network fetch for increased concurrency.
17836          */
17837         compileCubemapShader() {
17838
17839                 if ( this._cubemapShader === null ) {
17840
17841                         this._cubemapShader = _getCubemapShader();
17842                         this._compileMaterial( this._cubemapShader );
17843
17844                 }
17845
17846         }
17847
17848         /**
17849          * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during
17850          * your texture's network fetch for increased concurrency.
17851          */
17852         compileEquirectangularShader() {
17853
17854                 if ( this._equirectShader === null ) {
17855
17856                         this._equirectShader = _getEquirectShader();
17857                         this._compileMaterial( this._equirectShader );
17858
17859                 }
17860
17861         }
17862
17863         /**
17864          * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class,
17865          * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on
17866          * one of them will cause any others to also become unusable.
17867          */
17868         dispose() {
17869
17870                 this._blurMaterial.dispose();
17871
17872                 if ( this._cubemapShader !== null ) this._cubemapShader.dispose();
17873                 if ( this._equirectShader !== null ) this._equirectShader.dispose();
17874
17875                 for ( let i = 0; i < _lodPlanes.length; i ++ ) {
17876
17877                         _lodPlanes[ i ].dispose();
17878
17879                 }
17880
17881         }
17882
17883         // private interface
17884
17885         _cleanup( outputTarget ) {
17886
17887                 this._pingPongRenderTarget.dispose();
17888                 this._renderer.setRenderTarget( _oldTarget );
17889                 outputTarget.scissorTest = false;
17890                 _setViewport( outputTarget, 0, 0, outputTarget.width, outputTarget.height );
17891
17892         }
17893
17894         _fromTexture( texture ) {
17895
17896                 _oldTarget = this._renderer.getRenderTarget();
17897                 const cubeUVRenderTarget = this._allocateTargets( texture );
17898                 this._textureToCubeUV( texture, cubeUVRenderTarget );
17899                 this._applyPMREM( cubeUVRenderTarget );
17900                 this._cleanup( cubeUVRenderTarget );
17901
17902                 return cubeUVRenderTarget;
17903
17904         }
17905
17906         _allocateTargets( texture ) { // warning: null texture is valid
17907
17908                 const params = {
17909                         magFilter: NearestFilter,
17910                         minFilter: NearestFilter,
17911                         generateMipmaps: false,
17912                         type: UnsignedByteType,
17913                         format: RGBEFormat,
17914                         encoding: _isLDR( texture ) ? texture.encoding : RGBEEncoding,
17915                         depthBuffer: false
17916                 };
17917
17918                 const cubeUVRenderTarget = _createRenderTarget( params );
17919                 cubeUVRenderTarget.depthBuffer = texture ? false : true;
17920                 this._pingPongRenderTarget = _createRenderTarget( params );
17921                 return cubeUVRenderTarget;
17922
17923         }
17924
17925         _compileMaterial( material ) {
17926
17927                 const tmpMesh = new Mesh( _lodPlanes[ 0 ], material );
17928                 this._renderer.compile( tmpMesh, _flatCamera );
17929
17930         }
17931
17932         _sceneToCubeUV( scene, near, far, cubeUVRenderTarget ) {
17933
17934                 const fov = 90;
17935                 const aspect = 1;
17936                 const cubeCamera = new PerspectiveCamera( fov, aspect, near, far );
17937                 const upSign = [ 1, - 1, 1, 1, 1, 1 ];
17938                 const forwardSign = [ 1, 1, 1, - 1, - 1, - 1 ];
17939                 const renderer = this._renderer;
17940
17941                 const originalAutoClear = renderer.autoClear;
17942                 const outputEncoding = renderer.outputEncoding;
17943                 const toneMapping = renderer.toneMapping;
17944                 renderer.getClearColor( _clearColor );
17945
17946                 renderer.toneMapping = NoToneMapping;
17947                 renderer.outputEncoding = LinearEncoding;
17948                 renderer.autoClear = false;
17949
17950                 const backgroundMaterial = new MeshBasicMaterial( {
17951                         name: 'PMREM.Background',
17952                         side: BackSide,
17953                         depthWrite: false,
17954                         depthTest: false,
17955                 } );
17956
17957                 const backgroundBox = new Mesh( new BoxGeometry(), backgroundMaterial );
17958
17959                 let useSolidColor = false;
17960                 const background = scene.background;
17961
17962                 if ( background ) {
17963
17964                         if ( background.isColor ) {
17965
17966                                 backgroundMaterial.color.copy( background );
17967                                 scene.background = null;
17968                                 useSolidColor = true;
17969
17970                         }
17971
17972                 } else {
17973
17974                         backgroundMaterial.color.copy( _clearColor );
17975                         useSolidColor = true;
17976
17977                 }
17978
17979                 for ( let i = 0; i < 6; i ++ ) {
17980
17981                         const col = i % 3;
17982                         if ( col == 0 ) {
17983
17984                                 cubeCamera.up.set( 0, upSign[ i ], 0 );
17985                                 cubeCamera.lookAt( forwardSign[ i ], 0, 0 );
17986
17987                         } else if ( col == 1 ) {
17988
17989                                 cubeCamera.up.set( 0, 0, upSign[ i ] );
17990                                 cubeCamera.lookAt( 0, forwardSign[ i ], 0 );
17991
17992                         } else {
17993
17994                                 cubeCamera.up.set( 0, upSign[ i ], 0 );
17995                                 cubeCamera.lookAt( 0, 0, forwardSign[ i ] );
17996
17997                         }
17998
17999                         _setViewport( cubeUVRenderTarget,
18000                                 col * SIZE_MAX, i > 2 ? SIZE_MAX : 0, SIZE_MAX, SIZE_MAX );
18001                         renderer.setRenderTarget( cubeUVRenderTarget );
18002
18003                         if ( useSolidColor ) {
18004
18005                                 renderer.render( backgroundBox, cubeCamera );
18006
18007                         }
18008
18009                         renderer.render( scene, cubeCamera );
18010
18011                 }
18012
18013                 backgroundBox.geometry.dispose();
18014                 backgroundBox.material.dispose();
18015
18016                 renderer.toneMapping = toneMapping;
18017                 renderer.outputEncoding = outputEncoding;
18018                 renderer.autoClear = originalAutoClear;
18019                 scene.background = background;
18020
18021         }
18022
18023         _setEncoding( uniform, texture ) {
18024
18025                 if ( this._renderer.capabilities.isWebGL2 === true && texture.format === RGBAFormat && texture.type === UnsignedByteType && texture.encoding === sRGBEncoding ) {
18026
18027                         uniform.value = ENCODINGS[ LinearEncoding ];
18028
18029                 } else {
18030
18031                         uniform.value = ENCODINGS[ texture.encoding ];
18032
18033                 }
18034
18035         }
18036
18037         _textureToCubeUV( texture, cubeUVRenderTarget ) {
18038
18039                 const renderer = this._renderer;
18040
18041                 const isCubeTexture = ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping );
18042
18043                 if ( isCubeTexture ) {
18044
18045                         if ( this._cubemapShader == null ) {
18046
18047                                 this._cubemapShader = _getCubemapShader();
18048
18049                         }
18050
18051                 } else {
18052
18053                         if ( this._equirectShader == null ) {
18054
18055                                 this._equirectShader = _getEquirectShader();
18056
18057                         }
18058
18059                 }
18060
18061                 const material = isCubeTexture ? this._cubemapShader : this._equirectShader;
18062                 const mesh = new Mesh( _lodPlanes[ 0 ], material );
18063
18064                 const uniforms = material.uniforms;
18065
18066                 uniforms[ 'envMap' ].value = texture;
18067
18068                 if ( ! isCubeTexture ) {
18069
18070                         uniforms[ 'texelSize' ].value.set( 1.0 / texture.image.width, 1.0 / texture.image.height );
18071
18072                 }
18073
18074                 this._setEncoding( uniforms[ 'inputEncoding' ], texture );
18075                 this._setEncoding( uniforms[ 'outputEncoding' ], cubeUVRenderTarget.texture );
18076
18077                 _setViewport( cubeUVRenderTarget, 0, 0, 3 * SIZE_MAX, 2 * SIZE_MAX );
18078
18079                 renderer.setRenderTarget( cubeUVRenderTarget );
18080                 renderer.render( mesh, _flatCamera );
18081
18082         }
18083
18084         _applyPMREM( cubeUVRenderTarget ) {
18085
18086                 const renderer = this._renderer;
18087                 const autoClear = renderer.autoClear;
18088                 renderer.autoClear = false;
18089
18090                 for ( let i = 1; i < TOTAL_LODS; i ++ ) {
18091
18092                         const sigma = Math.sqrt( _sigmas[ i ] * _sigmas[ i ] - _sigmas[ i - 1 ] * _sigmas[ i - 1 ] );
18093
18094                         const poleAxis = _axisDirections[ ( i - 1 ) % _axisDirections.length ];
18095
18096                         this._blur( cubeUVRenderTarget, i - 1, i, sigma, poleAxis );
18097
18098                 }
18099
18100                 renderer.autoClear = autoClear;
18101
18102         }
18103
18104         /**
18105          * This is a two-pass Gaussian blur for a cubemap. Normally this is done
18106          * vertically and horizontally, but this breaks down on a cube. Here we apply
18107          * the blur latitudinally (around the poles), and then longitudinally (towards
18108          * the poles) to approximate the orthogonally-separable blur. It is least
18109          * accurate at the poles, but still does a decent job.
18110          */
18111         _blur( cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis ) {
18112
18113                 const pingPongRenderTarget = this._pingPongRenderTarget;
18114
18115                 this._halfBlur(
18116                         cubeUVRenderTarget,
18117                         pingPongRenderTarget,
18118                         lodIn,
18119                         lodOut,
18120                         sigma,
18121                         'latitudinal',
18122                         poleAxis );
18123
18124                 this._halfBlur(
18125                         pingPongRenderTarget,
18126                         cubeUVRenderTarget,
18127                         lodOut,
18128                         lodOut,
18129                         sigma,
18130                         'longitudinal',
18131                         poleAxis );
18132
18133         }
18134
18135         _halfBlur( targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis ) {
18136
18137                 const renderer = this._renderer;
18138                 const blurMaterial = this._blurMaterial;
18139
18140                 if ( direction !== 'latitudinal' && direction !== 'longitudinal' ) {
18141
18142                         console.error(
18143                                 'blur direction must be either latitudinal or longitudinal!' );
18144
18145                 }
18146
18147                 // Number of standard deviations at which to cut off the discrete approximation.
18148                 const STANDARD_DEVIATIONS = 3;
18149
18150                 const blurMesh = new Mesh( _lodPlanes[ lodOut ], blurMaterial );
18151                 const blurUniforms = blurMaterial.uniforms;
18152
18153                 const pixels = _sizeLods[ lodIn ] - 1;
18154                 const radiansPerPixel = isFinite( sigmaRadians ) ? Math.PI / ( 2 * pixels ) : 2 * Math.PI / ( 2 * MAX_SAMPLES - 1 );
18155                 const sigmaPixels = sigmaRadians / radiansPerPixel;
18156                 const samples = isFinite( sigmaRadians ) ? 1 + Math.floor( STANDARD_DEVIATIONS * sigmaPixels ) : MAX_SAMPLES;
18157
18158                 if ( samples > MAX_SAMPLES ) {
18159
18160                         console.warn( `sigmaRadians, ${
18161                                 sigmaRadians}, is too large and will clip, as it requested ${
18162                                 samples} samples when the maximum is set to ${MAX_SAMPLES}` );
18163
18164                 }
18165
18166                 const weights = [];
18167                 let sum = 0;
18168
18169                 for ( let i = 0; i < MAX_SAMPLES; ++ i ) {
18170
18171                         const x = i / sigmaPixels;
18172                         const weight = Math.exp( - x * x / 2 );
18173                         weights.push( weight );
18174
18175                         if ( i == 0 ) {
18176
18177                                 sum += weight;
18178
18179                         } else if ( i < samples ) {
18180
18181                                 sum += 2 * weight;
18182
18183                         }
18184
18185                 }
18186
18187                 for ( let i = 0; i < weights.length; i ++ ) {
18188
18189                         weights[ i ] = weights[ i ] / sum;
18190
18191                 }
18192
18193                 blurUniforms[ 'envMap' ].value = targetIn.texture;
18194                 blurUniforms[ 'samples' ].value = samples;
18195                 blurUniforms[ 'weights' ].value = weights;
18196                 blurUniforms[ 'latitudinal' ].value = direction === 'latitudinal';
18197
18198                 if ( poleAxis ) {
18199
18200                         blurUniforms[ 'poleAxis' ].value = poleAxis;
18201
18202                 }
18203
18204                 blurUniforms[ 'dTheta' ].value = radiansPerPixel;
18205                 blurUniforms[ 'mipInt' ].value = LOD_MAX - lodIn;
18206
18207                 this._setEncoding( blurUniforms[ 'inputEncoding' ], targetIn.texture );
18208                 this._setEncoding( blurUniforms[ 'outputEncoding' ], targetIn.texture );
18209
18210                 const outputSize = _sizeLods[ lodOut ];
18211                 const x = 3 * Math.max( 0, SIZE_MAX - 2 * outputSize );
18212                 const y = ( lodOut === 0 ? 0 : 2 * SIZE_MAX ) + 2 * outputSize * ( lodOut > LOD_MAX - LOD_MIN ? lodOut - LOD_MAX + LOD_MIN : 0 );
18213
18214                 _setViewport( targetOut, x, y, 3 * outputSize, 2 * outputSize );
18215                 renderer.setRenderTarget( targetOut );
18216                 renderer.render( blurMesh, _flatCamera );
18217
18218         }
18219
18220 }
18221
18222 function _isLDR( texture ) {
18223
18224         if ( texture === undefined || texture.type !== UnsignedByteType ) return false;
18225
18226         return texture.encoding === LinearEncoding || texture.encoding === sRGBEncoding || texture.encoding === GammaEncoding;
18227
18228 }
18229
18230 function _createPlanes() {
18231
18232         const _lodPlanes = [];
18233         const _sizeLods = [];
18234         const _sigmas = [];
18235
18236         let lod = LOD_MAX;
18237
18238         for ( let i = 0; i < TOTAL_LODS; i ++ ) {
18239
18240                 const sizeLod = Math.pow( 2, lod );
18241                 _sizeLods.push( sizeLod );
18242                 let sigma = 1.0 / sizeLod;
18243
18244                 if ( i > LOD_MAX - LOD_MIN ) {
18245
18246                         sigma = EXTRA_LOD_SIGMA[ i - LOD_MAX + LOD_MIN - 1 ];
18247
18248                 } else if ( i == 0 ) {
18249
18250                         sigma = 0;
18251
18252                 }
18253
18254                 _sigmas.push( sigma );
18255
18256                 const texelSize = 1.0 / ( sizeLod - 1 );
18257                 const min = - texelSize / 2;
18258                 const max = 1 + texelSize / 2;
18259                 const uv1 = [ min, min, max, min, max, max, min, min, max, max, min, max ];
18260
18261                 const cubeFaces = 6;
18262                 const vertices = 6;
18263                 const positionSize = 3;
18264                 const uvSize = 2;
18265                 const faceIndexSize = 1;
18266
18267                 const position = new Float32Array( positionSize * vertices * cubeFaces );
18268                 const uv = new Float32Array( uvSize * vertices * cubeFaces );
18269                 const faceIndex = new Float32Array( faceIndexSize * vertices * cubeFaces );
18270
18271                 for ( let face = 0; face < cubeFaces; face ++ ) {
18272
18273                         const x = ( face % 3 ) * 2 / 3 - 1;
18274                         const y = face > 2 ? 0 : - 1;
18275                         const coordinates = [
18276                                 x, y, 0,
18277                                 x + 2 / 3, y, 0,
18278                                 x + 2 / 3, y + 1, 0,
18279                                 x, y, 0,
18280                                 x + 2 / 3, y + 1, 0,
18281                                 x, y + 1, 0
18282                         ];
18283                         position.set( coordinates, positionSize * vertices * face );
18284                         uv.set( uv1, uvSize * vertices * face );
18285                         const fill = [ face, face, face, face, face, face ];
18286                         faceIndex.set( fill, faceIndexSize * vertices * face );
18287
18288                 }
18289
18290                 const planes = new BufferGeometry();
18291                 planes.setAttribute( 'position', new BufferAttribute( position, positionSize ) );
18292                 planes.setAttribute( 'uv', new BufferAttribute( uv, uvSize ) );
18293                 planes.setAttribute( 'faceIndex', new BufferAttribute( faceIndex, faceIndexSize ) );
18294                 _lodPlanes.push( planes );
18295
18296                 if ( lod > LOD_MIN ) {
18297
18298                         lod --;
18299
18300                 }
18301
18302         }
18303
18304         return { _lodPlanes, _sizeLods, _sigmas };
18305
18306 }
18307
18308 function _createRenderTarget( params ) {
18309
18310         const cubeUVRenderTarget = new WebGLRenderTarget( 3 * SIZE_MAX, 3 * SIZE_MAX, params );
18311         cubeUVRenderTarget.texture.mapping = CubeUVReflectionMapping;
18312         cubeUVRenderTarget.texture.name = 'PMREM.cubeUv';
18313         cubeUVRenderTarget.scissorTest = true;
18314         return cubeUVRenderTarget;
18315
18316 }
18317
18318 function _setViewport( target, x, y, width, height ) {
18319
18320         target.viewport.set( x, y, width, height );
18321         target.scissor.set( x, y, width, height );
18322
18323 }
18324
18325 function _getBlurShader( maxSamples ) {
18326
18327         const weights = new Float32Array( maxSamples );
18328         const poleAxis = new Vector3( 0, 1, 0 );
18329         const shaderMaterial = new RawShaderMaterial( {
18330
18331                 name: 'SphericalGaussianBlur',
18332
18333                 defines: { 'n': maxSamples },
18334
18335                 uniforms: {
18336                         'envMap': { value: null },
18337                         'samples': { value: 1 },
18338                         'weights': { value: weights },
18339                         'latitudinal': { value: false },
18340                         'dTheta': { value: 0 },
18341                         'mipInt': { value: 0 },
18342                         'poleAxis': { value: poleAxis },
18343                         'inputEncoding': { value: ENCODINGS[ LinearEncoding ] },
18344                         'outputEncoding': { value: ENCODINGS[ LinearEncoding ] }
18345                 },
18346
18347                 vertexShader: _getCommonVertexShader(),
18348
18349                 fragmentShader: /* glsl */`
18350
18351                         precision mediump float;
18352                         precision mediump int;
18353
18354                         varying vec3 vOutputDirection;
18355
18356                         uniform sampler2D envMap;
18357                         uniform int samples;
18358                         uniform float weights[ n ];
18359                         uniform bool latitudinal;
18360                         uniform float dTheta;
18361                         uniform float mipInt;
18362                         uniform vec3 poleAxis;
18363
18364                         ${ _getEncodings() }
18365
18366                         #define ENVMAP_TYPE_CUBE_UV
18367                         #include <cube_uv_reflection_fragment>
18368
18369                         vec3 getSample( float theta, vec3 axis ) {
18370
18371                                 float cosTheta = cos( theta );
18372                                 // Rodrigues' axis-angle rotation
18373                                 vec3 sampleDirection = vOutputDirection * cosTheta
18374                                         + cross( axis, vOutputDirection ) * sin( theta )
18375                                         + axis * dot( axis, vOutputDirection ) * ( 1.0 - cosTheta );
18376
18377                                 return bilinearCubeUV( envMap, sampleDirection, mipInt );
18378
18379                         }
18380
18381                         void main() {
18382
18383                                 vec3 axis = latitudinal ? poleAxis : cross( poleAxis, vOutputDirection );
18384
18385                                 if ( all( equal( axis, vec3( 0.0 ) ) ) ) {
18386
18387                                         axis = vec3( vOutputDirection.z, 0.0, - vOutputDirection.x );
18388
18389                                 }
18390
18391                                 axis = normalize( axis );
18392
18393                                 gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );
18394                                 gl_FragColor.rgb += weights[ 0 ] * getSample( 0.0, axis );
18395
18396                                 for ( int i = 1; i < n; i++ ) {
18397
18398                                         if ( i >= samples ) {
18399
18400                                                 break;
18401
18402                                         }
18403
18404                                         float theta = dTheta * float( i );
18405                                         gl_FragColor.rgb += weights[ i ] * getSample( -1.0 * theta, axis );
18406                                         gl_FragColor.rgb += weights[ i ] * getSample( theta, axis );
18407
18408                                 }
18409
18410                                 gl_FragColor = linearToOutputTexel( gl_FragColor );
18411
18412                         }
18413                 `,
18414
18415                 blending: NoBlending,
18416                 depthTest: false,
18417                 depthWrite: false
18418
18419         } );
18420
18421         return shaderMaterial;
18422
18423 }
18424
18425 function _getEquirectShader() {
18426
18427         const texelSize = new Vector2( 1, 1 );
18428         const shaderMaterial = new RawShaderMaterial( {
18429
18430                 name: 'EquirectangularToCubeUV',
18431
18432                 uniforms: {
18433                         'envMap': { value: null },
18434                         'texelSize': { value: texelSize },
18435                         'inputEncoding': { value: ENCODINGS[ LinearEncoding ] },
18436                         'outputEncoding': { value: ENCODINGS[ LinearEncoding ] }
18437                 },
18438
18439                 vertexShader: _getCommonVertexShader(),
18440
18441                 fragmentShader: /* glsl */`
18442
18443                         precision mediump float;
18444                         precision mediump int;
18445
18446                         varying vec3 vOutputDirection;
18447
18448                         uniform sampler2D envMap;
18449                         uniform vec2 texelSize;
18450
18451                         ${ _getEncodings() }
18452
18453                         #include <common>
18454
18455                         void main() {
18456
18457                                 gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );
18458
18459                                 vec3 outputDirection = normalize( vOutputDirection );
18460                                 vec2 uv = equirectUv( outputDirection );
18461
18462                                 vec2 f = fract( uv / texelSize - 0.5 );
18463                                 uv -= f * texelSize;
18464                                 vec3 tl = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;
18465                                 uv.x += texelSize.x;
18466                                 vec3 tr = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;
18467                                 uv.y += texelSize.y;
18468                                 vec3 br = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;
18469                                 uv.x -= texelSize.x;
18470                                 vec3 bl = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;
18471
18472                                 vec3 tm = mix( tl, tr, f.x );
18473                                 vec3 bm = mix( bl, br, f.x );
18474                                 gl_FragColor.rgb = mix( tm, bm, f.y );
18475
18476                                 gl_FragColor = linearToOutputTexel( gl_FragColor );
18477
18478                         }
18479                 `,
18480
18481                 blending: NoBlending,
18482                 depthTest: false,
18483                 depthWrite: false
18484
18485         } );
18486
18487         return shaderMaterial;
18488
18489 }
18490
18491 function _getCubemapShader() {
18492
18493         const shaderMaterial = new RawShaderMaterial( {
18494
18495                 name: 'CubemapToCubeUV',
18496
18497                 uniforms: {
18498                         'envMap': { value: null },
18499                         'inputEncoding': { value: ENCODINGS[ LinearEncoding ] },
18500                         'outputEncoding': { value: ENCODINGS[ LinearEncoding ] }
18501                 },
18502
18503                 vertexShader: _getCommonVertexShader(),
18504
18505                 fragmentShader: /* glsl */`
18506
18507                         precision mediump float;
18508                         precision mediump int;
18509
18510                         varying vec3 vOutputDirection;
18511
18512                         uniform samplerCube envMap;
18513
18514                         ${ _getEncodings() }
18515
18516                         void main() {
18517
18518                                 gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );
18519                                 gl_FragColor.rgb = envMapTexelToLinear( textureCube( envMap, vec3( - vOutputDirection.x, vOutputDirection.yz ) ) ).rgb;
18520                                 gl_FragColor = linearToOutputTexel( gl_FragColor );
18521
18522                         }
18523                 `,
18524
18525                 blending: NoBlending,
18526                 depthTest: false,
18527                 depthWrite: false
18528
18529         } );
18530
18531         return shaderMaterial;
18532
18533 }
18534
18535 function _getCommonVertexShader() {
18536
18537         return /* glsl */`
18538
18539                 precision mediump float;
18540                 precision mediump int;
18541
18542                 attribute vec3 position;
18543                 attribute vec2 uv;
18544                 attribute float faceIndex;
18545
18546                 varying vec3 vOutputDirection;
18547
18548                 // RH coordinate system; PMREM face-indexing convention
18549                 vec3 getDirection( vec2 uv, float face ) {
18550
18551                         uv = 2.0 * uv - 1.0;
18552
18553                         vec3 direction = vec3( uv, 1.0 );
18554
18555                         if ( face == 0.0 ) {
18556
18557                                 direction = direction.zyx; // ( 1, v, u ) pos x
18558
18559                         } else if ( face == 1.0 ) {
18560
18561                                 direction = direction.xzy;
18562                                 direction.xz *= -1.0; // ( -u, 1, -v ) pos y
18563
18564                         } else if ( face == 2.0 ) {
18565
18566                                 direction.x *= -1.0; // ( -u, v, 1 ) pos z
18567
18568                         } else if ( face == 3.0 ) {
18569
18570                                 direction = direction.zyx;
18571                                 direction.xz *= -1.0; // ( -1, v, -u ) neg x
18572
18573                         } else if ( face == 4.0 ) {
18574
18575                                 direction = direction.xzy;
18576                                 direction.xy *= -1.0; // ( -u, -1, v ) neg y
18577
18578                         } else if ( face == 5.0 ) {
18579
18580                                 direction.z *= -1.0; // ( u, v, -1 ) neg z
18581
18582                         }
18583
18584                         return direction;
18585
18586                 }
18587
18588                 void main() {
18589
18590                         vOutputDirection = getDirection( uv, faceIndex );
18591                         gl_Position = vec4( position, 1.0 );
18592
18593                 }
18594         `;
18595
18596 }
18597
18598 function _getEncodings() {
18599
18600         return /* glsl */`
18601
18602                 uniform int inputEncoding;
18603                 uniform int outputEncoding;
18604
18605                 #include <encodings_pars_fragment>
18606
18607                 vec4 inputTexelToLinear( vec4 value ) {
18608
18609                         if ( inputEncoding == 0 ) {
18610
18611                                 return value;
18612
18613                         } else if ( inputEncoding == 1 ) {
18614
18615                                 return sRGBToLinear( value );
18616
18617                         } else if ( inputEncoding == 2 ) {
18618
18619                                 return RGBEToLinear( value );
18620
18621                         } else if ( inputEncoding == 3 ) {
18622
18623                                 return RGBMToLinear( value, 7.0 );
18624
18625                         } else if ( inputEncoding == 4 ) {
18626
18627                                 return RGBMToLinear( value, 16.0 );
18628
18629                         } else if ( inputEncoding == 5 ) {
18630
18631                                 return RGBDToLinear( value, 256.0 );
18632
18633                         } else {
18634
18635                                 return GammaToLinear( value, 2.2 );
18636
18637                         }
18638
18639                 }
18640
18641                 vec4 linearToOutputTexel( vec4 value ) {
18642
18643                         if ( outputEncoding == 0 ) {
18644
18645                                 return value;
18646
18647                         } else if ( outputEncoding == 1 ) {
18648
18649                                 return LinearTosRGB( value );
18650
18651                         } else if ( outputEncoding == 2 ) {
18652
18653                                 return LinearToRGBE( value );
18654
18655                         } else if ( outputEncoding == 3 ) {
18656
18657                                 return LinearToRGBM( value, 7.0 );
18658
18659                         } else if ( outputEncoding == 4 ) {
18660
18661                                 return LinearToRGBM( value, 16.0 );
18662
18663                         } else if ( outputEncoding == 5 ) {
18664
18665                                 return LinearToRGBD( value, 256.0 );
18666
18667                         } else {
18668
18669                                 return LinearToGamma( value, 2.2 );
18670
18671                         }
18672
18673                 }
18674
18675                 vec4 envMapTexelToLinear( vec4 color ) {
18676
18677                         return inputTexelToLinear( color );
18678
18679                 }
18680         `;
18681
18682 }
18683
18684 function WebGLCubeUVMaps( renderer ) {
18685
18686         let cubeUVmaps = new WeakMap();
18687
18688         let pmremGenerator = null;
18689
18690         function get( texture ) {
18691
18692                 if ( texture && texture.isTexture && texture.isRenderTargetTexture === false ) {
18693
18694                         const mapping = texture.mapping;
18695
18696                         const isEquirectMap = ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping );
18697                         const isCubeMap = ( mapping === CubeReflectionMapping || mapping === CubeRefractionMapping );
18698
18699                         if ( isEquirectMap || isCubeMap ) {
18700
18701                                 // equirect/cube map to cubeUV conversion
18702
18703                                 if ( cubeUVmaps.has( texture ) ) {
18704
18705                                         return cubeUVmaps.get( texture ).texture;
18706
18707                                 } else {
18708
18709                                         const image = texture.image;
18710
18711                                         if ( ( isEquirectMap && image && image.height > 0 ) || ( isCubeMap && image && isCubeTextureComplete( image ) ) ) {
18712
18713                                                 const currentRenderTarget = renderer.getRenderTarget();
18714
18715                                                 if ( pmremGenerator === null ) pmremGenerator = new PMREMGenerator( renderer );
18716
18717                                                 const renderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular( texture ) : pmremGenerator.fromCubemap( texture );
18718                                                 cubeUVmaps.set( texture, renderTarget );
18719
18720                                                 renderer.setRenderTarget( currentRenderTarget );
18721
18722                                                 texture.addEventListener( 'dispose', onTextureDispose );
18723
18724                                                 return renderTarget.texture;
18725
18726                                         } else {
18727
18728                                                 // image not yet ready. try the conversion next frame
18729
18730                                                 return null;
18731
18732                                         }
18733
18734                                 }
18735
18736                         }
18737
18738                 }
18739
18740                 return texture;
18741
18742         }
18743
18744         function isCubeTextureComplete( image ) {
18745
18746                 let count = 0;
18747                 const length = 6;
18748
18749                 for ( let i = 0; i < length; i ++ ) {
18750
18751                         if ( image[ i ] !== undefined ) count ++;
18752
18753                 }
18754
18755                 return count === length;
18756
18757
18758         }
18759
18760         function onTextureDispose( event ) {
18761
18762                 const texture = event.target;
18763
18764                 texture.removeEventListener( 'dispose', onTextureDispose );
18765
18766                 const cubemapUV = cubeUVmaps.get( texture );
18767
18768                 if ( cubemapUV !== undefined ) {
18769
18770                         cubeUVmaps.delete( texture );
18771                         cubemapUV.dispose();
18772
18773                 }
18774
18775         }
18776
18777         function dispose() {
18778
18779                 cubeUVmaps = new WeakMap();
18780
18781                 if ( pmremGenerator !== null ) {
18782
18783                         pmremGenerator.dispose();
18784                         pmremGenerator = null;
18785
18786                 }
18787
18788         }
18789
18790         return {
18791                 get: get,
18792                 dispose: dispose
18793         };
18794
18795 }
18796
18797 function WebGLExtensions( gl ) {
18798
18799         const extensions = {};
18800
18801         function getExtension( name ) {
18802
18803                 if ( extensions[ name ] !== undefined ) {
18804
18805                         return extensions[ name ];
18806
18807                 }
18808
18809                 let extension;
18810
18811                 switch ( name ) {
18812
18813                         case 'WEBGL_depth_texture':
18814                                 extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' );
18815                                 break;
18816
18817                         case 'EXT_texture_filter_anisotropic':
18818                                 extension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );
18819                                 break;
18820
18821                         case 'WEBGL_compressed_texture_s3tc':
18822                                 extension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );
18823                                 break;
18824
18825                         case 'WEBGL_compressed_texture_pvrtc':
18826                                 extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' );
18827                                 break;
18828
18829                         default:
18830                                 extension = gl.getExtension( name );
18831
18832                 }
18833
18834                 extensions[ name ] = extension;
18835
18836                 return extension;
18837
18838         }
18839
18840         return {
18841
18842                 has: function ( name ) {
18843
18844                         return getExtension( name ) !== null;
18845
18846                 },
18847
18848                 init: function ( capabilities ) {
18849
18850                         if ( capabilities.isWebGL2 ) {
18851
18852                                 getExtension( 'EXT_color_buffer_float' );
18853
18854                         } else {
18855
18856                                 getExtension( 'WEBGL_depth_texture' );
18857                                 getExtension( 'OES_texture_float' );
18858                                 getExtension( 'OES_texture_half_float' );
18859                                 getExtension( 'OES_texture_half_float_linear' );
18860                                 getExtension( 'OES_standard_derivatives' );
18861                                 getExtension( 'OES_element_index_uint' );
18862                                 getExtension( 'OES_vertex_array_object' );
18863                                 getExtension( 'ANGLE_instanced_arrays' );
18864
18865                         }
18866
18867                         getExtension( 'OES_texture_float_linear' );
18868                         getExtension( 'EXT_color_buffer_half_float' );
18869
18870                 },
18871
18872                 get: function ( name ) {
18873
18874                         const extension = getExtension( name );
18875
18876                         if ( extension === null ) {
18877
18878                                 console.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' );
18879
18880                         }
18881
18882                         return extension;
18883
18884                 }
18885
18886         };
18887
18888 }
18889
18890 function WebGLGeometries( gl, attributes, info, bindingStates ) {
18891
18892         const geometries = {};
18893         const wireframeAttributes = new WeakMap();
18894
18895         function onGeometryDispose( event ) {
18896
18897                 const geometry = event.target;
18898
18899                 if ( geometry.index !== null ) {
18900
18901                         attributes.remove( geometry.index );
18902
18903                 }
18904
18905                 for ( const name in geometry.attributes ) {
18906
18907                         attributes.remove( geometry.attributes[ name ] );
18908
18909                 }
18910
18911                 geometry.removeEventListener( 'dispose', onGeometryDispose );
18912
18913                 delete geometries[ geometry.id ];
18914
18915                 const attribute = wireframeAttributes.get( geometry );
18916
18917                 if ( attribute ) {
18918
18919                         attributes.remove( attribute );
18920                         wireframeAttributes.delete( geometry );
18921
18922                 }
18923
18924                 bindingStates.releaseStatesOfGeometry( geometry );
18925
18926                 if ( geometry.isInstancedBufferGeometry === true ) {
18927
18928                         delete geometry._maxInstanceCount;
18929
18930                 }
18931
18932                 //
18933
18934                 info.memory.geometries --;
18935
18936         }
18937
18938         function get( object, geometry ) {
18939
18940                 if ( geometries[ geometry.id ] === true ) return geometry;
18941
18942                 geometry.addEventListener( 'dispose', onGeometryDispose );
18943
18944                 geometries[ geometry.id ] = true;
18945
18946                 info.memory.geometries ++;
18947
18948                 return geometry;
18949
18950         }
18951
18952         function update( geometry ) {
18953
18954                 const geometryAttributes = geometry.attributes;
18955
18956                 // Updating index buffer in VAO now. See WebGLBindingStates.
18957
18958                 for ( const name in geometryAttributes ) {
18959
18960                         attributes.update( geometryAttributes[ name ], 34962 );
18961
18962                 }
18963
18964                 // morph targets
18965
18966                 const morphAttributes = geometry.morphAttributes;
18967
18968                 for ( const name in morphAttributes ) {
18969
18970                         const array = morphAttributes[ name ];
18971
18972                         for ( let i = 0, l = array.length; i < l; i ++ ) {
18973
18974                                 attributes.update( array[ i ], 34962 );
18975
18976                         }
18977
18978                 }
18979
18980         }
18981
18982         function updateWireframeAttribute( geometry ) {
18983
18984                 const indices = [];
18985
18986                 const geometryIndex = geometry.index;
18987                 const geometryPosition = geometry.attributes.position;
18988                 let version = 0;
18989
18990                 if ( geometryIndex !== null ) {
18991
18992                         const array = geometryIndex.array;
18993                         version = geometryIndex.version;
18994
18995                         for ( let i = 0, l = array.length; i < l; i += 3 ) {
18996
18997                                 const a = array[ i + 0 ];
18998                                 const b = array[ i + 1 ];
18999                                 const c = array[ i + 2 ];
19000
19001                                 indices.push( a, b, b, c, c, a );
19002
19003                         }
19004
19005                 } else {
19006
19007                         const array = geometryPosition.array;
19008                         version = geometryPosition.version;
19009
19010                         for ( let i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) {
19011
19012                                 const a = i + 0;
19013                                 const b = i + 1;
19014                                 const c = i + 2;
19015
19016                                 indices.push( a, b, b, c, c, a );
19017
19018                         }
19019
19020                 }
19021
19022                 const attribute = new ( arrayMax( indices ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 );
19023                 attribute.version = version;
19024
19025                 // Updating index buffer in VAO now. See WebGLBindingStates
19026
19027                 //
19028
19029                 const previousAttribute = wireframeAttributes.get( geometry );
19030
19031                 if ( previousAttribute ) attributes.remove( previousAttribute );
19032
19033                 //
19034
19035                 wireframeAttributes.set( geometry, attribute );
19036
19037         }
19038
19039         function getWireframeAttribute( geometry ) {
19040
19041                 const currentAttribute = wireframeAttributes.get( geometry );
19042
19043                 if ( currentAttribute ) {
19044
19045                         const geometryIndex = geometry.index;
19046
19047                         if ( geometryIndex !== null ) {
19048
19049                                 // if the attribute is obsolete, create a new one
19050
19051                                 if ( currentAttribute.version < geometryIndex.version ) {
19052
19053                                         updateWireframeAttribute( geometry );
19054
19055                                 }
19056
19057                         }
19058
19059                 } else {
19060
19061                         updateWireframeAttribute( geometry );
19062
19063                 }
19064
19065                 return wireframeAttributes.get( geometry );
19066
19067         }
19068
19069         return {
19070
19071                 get: get,
19072                 update: update,
19073
19074                 getWireframeAttribute: getWireframeAttribute
19075
19076         };
19077
19078 }
19079
19080 function WebGLIndexedBufferRenderer( gl, extensions, info, capabilities ) {
19081
19082         const isWebGL2 = capabilities.isWebGL2;
19083
19084         let mode;
19085
19086         function setMode( value ) {
19087
19088                 mode = value;
19089
19090         }
19091
19092         let type, bytesPerElement;
19093
19094         function setIndex( value ) {
19095
19096                 type = value.type;
19097                 bytesPerElement = value.bytesPerElement;
19098
19099         }
19100
19101         function render( start, count ) {
19102
19103                 gl.drawElements( mode, count, type, start * bytesPerElement );
19104
19105                 info.update( count, mode, 1 );
19106
19107         }
19108
19109         function renderInstances( start, count, primcount ) {
19110
19111                 if ( primcount === 0 ) return;
19112
19113                 let extension, methodName;
19114
19115                 if ( isWebGL2 ) {
19116
19117                         extension = gl;
19118                         methodName = 'drawElementsInstanced';
19119
19120                 } else {
19121
19122                         extension = extensions.get( 'ANGLE_instanced_arrays' );
19123                         methodName = 'drawElementsInstancedANGLE';
19124
19125                         if ( extension === null ) {
19126
19127                                 console.error( 'THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
19128                                 return;
19129
19130                         }
19131
19132                 }
19133
19134                 extension[ methodName ]( mode, count, type, start * bytesPerElement, primcount );
19135
19136                 info.update( count, mode, primcount );
19137
19138         }
19139
19140         //
19141
19142         this.setMode = setMode;
19143         this.setIndex = setIndex;
19144         this.render = render;
19145         this.renderInstances = renderInstances;
19146
19147 }
19148
19149 function WebGLInfo( gl ) {
19150
19151         const memory = {
19152                 geometries: 0,
19153                 textures: 0
19154         };
19155
19156         const render = {
19157                 frame: 0,
19158                 calls: 0,
19159                 triangles: 0,
19160                 points: 0,
19161                 lines: 0
19162         };
19163
19164         function update( count, mode, instanceCount ) {
19165
19166                 render.calls ++;
19167
19168                 switch ( mode ) {
19169
19170                         case 4:
19171                                 render.triangles += instanceCount * ( count / 3 );
19172                                 break;
19173
19174                         case 1:
19175                                 render.lines += instanceCount * ( count / 2 );
19176                                 break;
19177
19178                         case 3:
19179                                 render.lines += instanceCount * ( count - 1 );
19180                                 break;
19181
19182                         case 2:
19183                                 render.lines += instanceCount * count;
19184                                 break;
19185
19186                         case 0:
19187                                 render.points += instanceCount * count;
19188                                 break;
19189
19190                         default:
19191                                 console.error( 'THREE.WebGLInfo: Unknown draw mode:', mode );
19192                                 break;
19193
19194                 }
19195
19196         }
19197
19198         function reset() {
19199
19200                 render.frame ++;
19201                 render.calls = 0;
19202                 render.triangles = 0;
19203                 render.points = 0;
19204                 render.lines = 0;
19205
19206         }
19207
19208         return {
19209                 memory: memory,
19210                 render: render,
19211                 programs: null,
19212                 autoReset: true,
19213                 reset: reset,
19214                 update: update
19215         };
19216
19217 }
19218
19219 class DataTexture2DArray extends Texture {
19220
19221         constructor( data = null, width = 1, height = 1, depth = 1 ) {
19222
19223                 super( null );
19224
19225                 this.image = { data, width, height, depth };
19226
19227                 this.magFilter = NearestFilter;
19228                 this.minFilter = NearestFilter;
19229
19230                 this.wrapR = ClampToEdgeWrapping;
19231
19232                 this.generateMipmaps = false;
19233                 this.flipY = false;
19234                 this.unpackAlignment = 1;
19235
19236                 this.needsUpdate = true;
19237
19238         }
19239
19240 }
19241
19242 DataTexture2DArray.prototype.isDataTexture2DArray = true;
19243
19244 function numericalSort( a, b ) {
19245
19246         return a[ 0 ] - b[ 0 ];
19247
19248 }
19249
19250 function absNumericalSort( a, b ) {
19251
19252         return Math.abs( b[ 1 ] ) - Math.abs( a[ 1 ] );
19253
19254 }
19255
19256 function denormalize( morph, attribute ) {
19257
19258         let denominator = 1;
19259         const array = attribute.isInterleavedBufferAttribute ? attribute.data.array : attribute.array;
19260
19261         if ( array instanceof Int8Array ) denominator = 127;
19262         else if ( array instanceof Int16Array ) denominator = 32767;
19263         else if ( array instanceof Int32Array ) denominator = 2147483647;
19264         else console.error( 'THREE.WebGLMorphtargets: Unsupported morph attribute data type: ', array );
19265
19266         morph.divideScalar( denominator );
19267
19268 }
19269
19270 function WebGLMorphtargets( gl, capabilities, textures ) {
19271
19272         const influencesList = {};
19273         const morphInfluences = new Float32Array( 8 );
19274         const morphTextures = new WeakMap();
19275         const morph = new Vector3();
19276
19277         const workInfluences = [];
19278
19279         for ( let i = 0; i < 8; i ++ ) {
19280
19281                 workInfluences[ i ] = [ i, 0 ];
19282
19283         }
19284
19285         function update( object, geometry, material, program ) {
19286
19287                 const objectInfluences = object.morphTargetInfluences;
19288
19289                 if ( capabilities.isWebGL2 === true ) {
19290
19291                         // instead of using attributes, the WebGL 2 code path encodes morph targets
19292                         // into an array of data textures. Each layer represents a single morph target.
19293
19294                         const numberOfMorphTargets = geometry.morphAttributes.position.length;
19295
19296                         let entry = morphTextures.get( geometry );
19297
19298                         if ( entry === undefined || entry.count !== numberOfMorphTargets ) {
19299
19300                                 if ( entry !== undefined ) entry.texture.dispose();
19301
19302                                 const hasMorphNormals = geometry.morphAttributes.normal !== undefined;
19303
19304                                 const morphTargets = geometry.morphAttributes.position;
19305                                 const morphNormals = geometry.morphAttributes.normal || [];
19306
19307                                 const numberOfVertices = geometry.attributes.position.count;
19308                                 const numberOfVertexData = ( hasMorphNormals === true ) ? 2 : 1; // (v,n) vs. (v)
19309
19310                                 let width = numberOfVertices * numberOfVertexData;
19311                                 let height = 1;
19312
19313                                 if ( width > capabilities.maxTextureSize ) {
19314
19315                                         height = Math.ceil( width / capabilities.maxTextureSize );
19316                                         width = capabilities.maxTextureSize;
19317
19318                                 }
19319
19320                                 const buffer = new Float32Array( width * height * 4 * numberOfMorphTargets );
19321
19322                                 const texture = new DataTexture2DArray( buffer, width, height, numberOfMorphTargets );
19323                                 texture.format = RGBAFormat; // using RGBA since RGB might be emulated (and is thus slower)
19324                                 texture.type = FloatType;
19325
19326                                 // fill buffer
19327
19328                                 const vertexDataStride = numberOfVertexData * 4;
19329
19330                                 for ( let i = 0; i < numberOfMorphTargets; i ++ ) {
19331
19332                                         const morphTarget = morphTargets[ i ];
19333                                         const morphNormal = morphNormals[ i ];
19334
19335                                         const offset = width * height * 4 * i;
19336
19337                                         for ( let j = 0; j < morphTarget.count; j ++ ) {
19338
19339                                                 morph.fromBufferAttribute( morphTarget, j );
19340
19341                                                 if ( morphTarget.normalized === true ) denormalize( morph, morphTarget );
19342
19343                                                 const stride = j * vertexDataStride;
19344
19345                                                 buffer[ offset + stride + 0 ] = morph.x;
19346                                                 buffer[ offset + stride + 1 ] = morph.y;
19347                                                 buffer[ offset + stride + 2 ] = morph.z;
19348                                                 buffer[ offset + stride + 3 ] = 0;
19349
19350                                                 if ( hasMorphNormals === true ) {
19351
19352                                                         morph.fromBufferAttribute( morphNormal, j );
19353
19354                                                         if ( morphNormal.normalized === true ) denormalize( morph, morphNormal );
19355
19356                                                         buffer[ offset + stride + 4 ] = morph.x;
19357                                                         buffer[ offset + stride + 5 ] = morph.y;
19358                                                         buffer[ offset + stride + 6 ] = morph.z;
19359                                                         buffer[ offset + stride + 7 ] = 0;
19360
19361                                                 }
19362
19363                                         }
19364
19365                                 }
19366
19367                                 entry = {
19368                                         count: numberOfMorphTargets,
19369                                         texture: texture,
19370                                         size: new Vector2( width, height )
19371                                 };
19372
19373                                 morphTextures.set( geometry, entry );
19374
19375                         }
19376
19377                         //
19378
19379                         let morphInfluencesSum = 0;
19380
19381                         for ( let i = 0; i < objectInfluences.length; i ++ ) {
19382
19383                                 morphInfluencesSum += objectInfluences[ i ];
19384
19385                         }
19386
19387                         const morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum;
19388
19389                         program.getUniforms().setValue( gl, 'morphTargetBaseInfluence', morphBaseInfluence );
19390                         program.getUniforms().setValue( gl, 'morphTargetInfluences', objectInfluences );
19391
19392                         program.getUniforms().setValue( gl, 'morphTargetsTexture', entry.texture, textures );
19393                         program.getUniforms().setValue( gl, 'morphTargetsTextureSize', entry.size );
19394
19395
19396                 } else {
19397
19398                         // When object doesn't have morph target influences defined, we treat it as a 0-length array
19399                         // This is important to make sure we set up morphTargetBaseInfluence / morphTargetInfluences
19400
19401                         const length = objectInfluences === undefined ? 0 : objectInfluences.length;
19402
19403                         let influences = influencesList[ geometry.id ];
19404
19405                         if ( influences === undefined || influences.length !== length ) {
19406
19407                                 // initialise list
19408
19409                                 influences = [];
19410
19411                                 for ( let i = 0; i < length; i ++ ) {
19412
19413                                         influences[ i ] = [ i, 0 ];
19414
19415                                 }
19416
19417                                 influencesList[ geometry.id ] = influences;
19418
19419                         }
19420
19421                         // Collect influences
19422
19423                         for ( let i = 0; i < length; i ++ ) {
19424
19425                                 const influence = influences[ i ];
19426
19427                                 influence[ 0 ] = i;
19428                                 influence[ 1 ] = objectInfluences[ i ];
19429
19430                         }
19431
19432                         influences.sort( absNumericalSort );
19433
19434                         for ( let i = 0; i < 8; i ++ ) {
19435
19436                                 if ( i < length && influences[ i ][ 1 ] ) {
19437
19438                                         workInfluences[ i ][ 0 ] = influences[ i ][ 0 ];
19439                                         workInfluences[ i ][ 1 ] = influences[ i ][ 1 ];
19440
19441                                 } else {
19442
19443                                         workInfluences[ i ][ 0 ] = Number.MAX_SAFE_INTEGER;
19444                                         workInfluences[ i ][ 1 ] = 0;
19445
19446                                 }
19447
19448                         }
19449
19450                         workInfluences.sort( numericalSort );
19451
19452                         const morphTargets = geometry.morphAttributes.position;
19453                         const morphNormals = geometry.morphAttributes.normal;
19454
19455                         let morphInfluencesSum = 0;
19456
19457                         for ( let i = 0; i < 8; i ++ ) {
19458
19459                                 const influence = workInfluences[ i ];
19460                                 const index = influence[ 0 ];
19461                                 const value = influence[ 1 ];
19462
19463                                 if ( index !== Number.MAX_SAFE_INTEGER && value ) {
19464
19465                                         if ( morphTargets && geometry.getAttribute( 'morphTarget' + i ) !== morphTargets[ index ] ) {
19466
19467                                                 geometry.setAttribute( 'morphTarget' + i, morphTargets[ index ] );
19468
19469                                         }
19470
19471                                         if ( morphNormals && geometry.getAttribute( 'morphNormal' + i ) !== morphNormals[ index ] ) {
19472
19473                                                 geometry.setAttribute( 'morphNormal' + i, morphNormals[ index ] );
19474
19475                                         }
19476
19477                                         morphInfluences[ i ] = value;
19478                                         morphInfluencesSum += value;
19479
19480                                 } else {
19481
19482                                         if ( morphTargets && geometry.hasAttribute( 'morphTarget' + i ) === true ) {
19483
19484                                                 geometry.deleteAttribute( 'morphTarget' + i );
19485
19486                                         }
19487
19488                                         if ( morphNormals && geometry.hasAttribute( 'morphNormal' + i ) === true ) {
19489
19490                                                 geometry.deleteAttribute( 'morphNormal' + i );
19491
19492                                         }
19493
19494                                         morphInfluences[ i ] = 0;
19495
19496                                 }
19497
19498                         }
19499
19500                         // GLSL shader uses formula baseinfluence * base + sum(target * influence)
19501                         // This allows us to switch between absolute morphs and relative morphs without changing shader code
19502                         // When baseinfluence = 1 - sum(influence), the above is equivalent to sum((target - base) * influence)
19503                         const morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum;
19504
19505                         program.getUniforms().setValue( gl, 'morphTargetBaseInfluence', morphBaseInfluence );
19506                         program.getUniforms().setValue( gl, 'morphTargetInfluences', morphInfluences );
19507
19508                 }
19509
19510         }
19511
19512         return {
19513
19514                 update: update
19515
19516         };
19517
19518 }
19519
19520 function WebGLObjects( gl, geometries, attributes, info ) {
19521
19522         let updateMap = new WeakMap();
19523
19524         function update( object ) {
19525
19526                 const frame = info.render.frame;
19527
19528                 const geometry = object.geometry;
19529                 const buffergeometry = geometries.get( object, geometry );
19530
19531                 // Update once per frame
19532
19533                 if ( updateMap.get( buffergeometry ) !== frame ) {
19534
19535                         geometries.update( buffergeometry );
19536
19537                         updateMap.set( buffergeometry, frame );
19538
19539                 }
19540
19541                 if ( object.isInstancedMesh ) {
19542
19543                         if ( object.hasEventListener( 'dispose', onInstancedMeshDispose ) === false ) {
19544
19545                                 object.addEventListener( 'dispose', onInstancedMeshDispose );
19546
19547                         }
19548
19549                         attributes.update( object.instanceMatrix, 34962 );
19550
19551                         if ( object.instanceColor !== null ) {
19552
19553                                 attributes.update( object.instanceColor, 34962 );
19554
19555                         }
19556
19557                 }
19558
19559                 return buffergeometry;
19560
19561         }
19562
19563         function dispose() {
19564
19565                 updateMap = new WeakMap();
19566
19567         }
19568
19569         function onInstancedMeshDispose( event ) {
19570
19571                 const instancedMesh = event.target;
19572
19573                 instancedMesh.removeEventListener( 'dispose', onInstancedMeshDispose );
19574
19575                 attributes.remove( instancedMesh.instanceMatrix );
19576
19577                 if ( instancedMesh.instanceColor !== null ) attributes.remove( instancedMesh.instanceColor );
19578
19579         }
19580
19581         return {
19582
19583                 update: update,
19584                 dispose: dispose
19585
19586         };
19587
19588 }
19589
19590 class DataTexture3D extends Texture {
19591
19592         constructor( data = null, width = 1, height = 1, depth = 1 ) {
19593
19594                 // We're going to add .setXXX() methods for setting properties later.
19595                 // Users can still set in DataTexture3D directly.
19596                 //
19597                 //      const texture = new THREE.DataTexture3D( data, width, height, depth );
19598                 //      texture.anisotropy = 16;
19599                 //
19600                 // See #14839
19601
19602                 super( null );
19603
19604                 this.image = { data, width, height, depth };
19605
19606                 this.magFilter = NearestFilter;
19607                 this.minFilter = NearestFilter;
19608
19609                 this.wrapR = ClampToEdgeWrapping;
19610
19611                 this.generateMipmaps = false;
19612                 this.flipY = false;
19613                 this.unpackAlignment = 1;
19614
19615                 this.needsUpdate = true;
19616
19617         }
19618
19619 }
19620
19621 DataTexture3D.prototype.isDataTexture3D = true;
19622
19623 /**
19624  * Uniforms of a program.
19625  * Those form a tree structure with a special top-level container for the root,
19626  * which you get by calling 'new WebGLUniforms( gl, program )'.
19627  *
19628  *
19629  * Properties of inner nodes including the top-level container:
19630  *
19631  * .seq - array of nested uniforms
19632  * .map - nested uniforms by name
19633  *
19634  *
19635  * Methods of all nodes except the top-level container:
19636  *
19637  * .setValue( gl, value, [textures] )
19638  *
19639  *              uploads a uniform value(s)
19640  *      the 'textures' parameter is needed for sampler uniforms
19641  *
19642  *
19643  * Static methods of the top-level container (textures factorizations):
19644  *
19645  * .upload( gl, seq, values, textures )
19646  *
19647  *              sets uniforms in 'seq' to 'values[id].value'
19648  *
19649  * .seqWithValue( seq, values ) : filteredSeq
19650  *
19651  *              filters 'seq' entries with corresponding entry in values
19652  *
19653  *
19654  * Methods of the top-level container (textures factorizations):
19655  *
19656  * .setValue( gl, name, value, textures )
19657  *
19658  *              sets uniform with  name 'name' to 'value'
19659  *
19660  * .setOptional( gl, obj, prop )
19661  *
19662  *              like .set for an optional property of the object
19663  *
19664  */
19665
19666 const emptyTexture = new Texture();
19667 const emptyTexture2dArray = new DataTexture2DArray();
19668 const emptyTexture3d = new DataTexture3D();
19669 const emptyCubeTexture = new CubeTexture();
19670
19671 // --- Utilities ---
19672
19673 // Array Caches (provide typed arrays for temporary by size)
19674
19675 const arrayCacheF32 = [];
19676 const arrayCacheI32 = [];
19677
19678 // Float32Array caches used for uploading Matrix uniforms
19679
19680 const mat4array = new Float32Array( 16 );
19681 const mat3array = new Float32Array( 9 );
19682 const mat2array = new Float32Array( 4 );
19683
19684 // Flattening for arrays of vectors and matrices
19685
19686 function flatten( array, nBlocks, blockSize ) {
19687
19688         const firstElem = array[ 0 ];
19689
19690         if ( firstElem <= 0 || firstElem > 0 ) return array;
19691         // unoptimized: ! isNaN( firstElem )
19692         // see http://jacksondunstan.com/articles/983
19693
19694         const n = nBlocks * blockSize;
19695         let r = arrayCacheF32[ n ];
19696
19697         if ( r === undefined ) {
19698
19699                 r = new Float32Array( n );
19700                 arrayCacheF32[ n ] = r;
19701
19702         }
19703
19704         if ( nBlocks !== 0 ) {
19705
19706                 firstElem.toArray( r, 0 );
19707
19708                 for ( let i = 1, offset = 0; i !== nBlocks; ++ i ) {
19709
19710                         offset += blockSize;
19711                         array[ i ].toArray( r, offset );
19712
19713                 }
19714
19715         }
19716
19717         return r;
19718
19719 }
19720
19721 function arraysEqual( a, b ) {
19722
19723         if ( a.length !== b.length ) return false;
19724
19725         for ( let i = 0, l = a.length; i < l; i ++ ) {
19726
19727                 if ( a[ i ] !== b[ i ] ) return false;
19728
19729         }
19730
19731         return true;
19732
19733 }
19734
19735 function copyArray( a, b ) {
19736
19737         for ( let i = 0, l = b.length; i < l; i ++ ) {
19738
19739                 a[ i ] = b[ i ];
19740
19741         }
19742
19743 }
19744
19745 // Texture unit allocation
19746
19747 function allocTexUnits( textures, n ) {
19748
19749         let r = arrayCacheI32[ n ];
19750
19751         if ( r === undefined ) {
19752
19753                 r = new Int32Array( n );
19754                 arrayCacheI32[ n ] = r;
19755
19756         }
19757
19758         for ( let i = 0; i !== n; ++ i ) {
19759
19760                 r[ i ] = textures.allocateTextureUnit();
19761
19762         }
19763
19764         return r;
19765
19766 }
19767
19768 // --- Setters ---
19769
19770 // Note: Defining these methods externally, because they come in a bunch
19771 // and this way their names minify.
19772
19773 // Single scalar
19774
19775 function setValueV1f( gl, v ) {
19776
19777         const cache = this.cache;
19778
19779         if ( cache[ 0 ] === v ) return;
19780
19781         gl.uniform1f( this.addr, v );
19782
19783         cache[ 0 ] = v;
19784
19785 }
19786
19787 // Single float vector (from flat array or THREE.VectorN)
19788
19789 function setValueV2f( gl, v ) {
19790
19791         const cache = this.cache;
19792
19793         if ( v.x !== undefined ) {
19794
19795                 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) {
19796
19797                         gl.uniform2f( this.addr, v.x, v.y );
19798
19799                         cache[ 0 ] = v.x;
19800                         cache[ 1 ] = v.y;
19801
19802                 }
19803
19804         } else {
19805
19806                 if ( arraysEqual( cache, v ) ) return;
19807
19808                 gl.uniform2fv( this.addr, v );
19809
19810                 copyArray( cache, v );
19811
19812         }
19813
19814 }
19815
19816 function setValueV3f( gl, v ) {
19817
19818         const cache = this.cache;
19819
19820         if ( v.x !== undefined ) {
19821
19822                 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) {
19823
19824                         gl.uniform3f( this.addr, v.x, v.y, v.z );
19825
19826                         cache[ 0 ] = v.x;
19827                         cache[ 1 ] = v.y;
19828                         cache[ 2 ] = v.z;
19829
19830                 }
19831
19832         } else if ( v.r !== undefined ) {
19833
19834                 if ( cache[ 0 ] !== v.r || cache[ 1 ] !== v.g || cache[ 2 ] !== v.b ) {
19835
19836                         gl.uniform3f( this.addr, v.r, v.g, v.b );
19837
19838                         cache[ 0 ] = v.r;
19839                         cache[ 1 ] = v.g;
19840                         cache[ 2 ] = v.b;
19841
19842                 }
19843
19844         } else {
19845
19846                 if ( arraysEqual( cache, v ) ) return;
19847
19848                 gl.uniform3fv( this.addr, v );
19849
19850                 copyArray( cache, v );
19851
19852         }
19853
19854 }
19855
19856 function setValueV4f( gl, v ) {
19857
19858         const cache = this.cache;
19859
19860         if ( v.x !== undefined ) {
19861
19862                 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) {
19863
19864                         gl.uniform4f( this.addr, v.x, v.y, v.z, v.w );
19865
19866                         cache[ 0 ] = v.x;
19867                         cache[ 1 ] = v.y;
19868                         cache[ 2 ] = v.z;
19869                         cache[ 3 ] = v.w;
19870
19871                 }
19872
19873         } else {
19874
19875                 if ( arraysEqual( cache, v ) ) return;
19876
19877                 gl.uniform4fv( this.addr, v );
19878
19879                 copyArray( cache, v );
19880
19881         }
19882
19883 }
19884
19885 // Single matrix (from flat array or THREE.MatrixN)
19886
19887 function setValueM2( gl, v ) {
19888
19889         const cache = this.cache;
19890         const elements = v.elements;
19891
19892         if ( elements === undefined ) {
19893
19894                 if ( arraysEqual( cache, v ) ) return;
19895
19896                 gl.uniformMatrix2fv( this.addr, false, v );
19897
19898                 copyArray( cache, v );
19899
19900         } else {
19901
19902                 if ( arraysEqual( cache, elements ) ) return;
19903
19904                 mat2array.set( elements );
19905
19906                 gl.uniformMatrix2fv( this.addr, false, mat2array );
19907
19908                 copyArray( cache, elements );
19909
19910         }
19911
19912 }
19913
19914 function setValueM3( gl, v ) {
19915
19916         const cache = this.cache;
19917         const elements = v.elements;
19918
19919         if ( elements === undefined ) {
19920
19921                 if ( arraysEqual( cache, v ) ) return;
19922
19923                 gl.uniformMatrix3fv( this.addr, false, v );
19924
19925                 copyArray( cache, v );
19926
19927         } else {
19928
19929                 if ( arraysEqual( cache, elements ) ) return;
19930
19931                 mat3array.set( elements );
19932
19933                 gl.uniformMatrix3fv( this.addr, false, mat3array );
19934
19935                 copyArray( cache, elements );
19936
19937         }
19938
19939 }
19940
19941 function setValueM4( gl, v ) {
19942
19943         const cache = this.cache;
19944         const elements = v.elements;
19945
19946         if ( elements === undefined ) {
19947
19948                 if ( arraysEqual( cache, v ) ) return;
19949
19950                 gl.uniformMatrix4fv( this.addr, false, v );
19951
19952                 copyArray( cache, v );
19953
19954         } else {
19955
19956                 if ( arraysEqual( cache, elements ) ) return;
19957
19958                 mat4array.set( elements );
19959
19960                 gl.uniformMatrix4fv( this.addr, false, mat4array );
19961
19962                 copyArray( cache, elements );
19963
19964         }
19965
19966 }
19967
19968 // Single integer / boolean
19969
19970 function setValueV1i( gl, v ) {
19971
19972         const cache = this.cache;
19973
19974         if ( cache[ 0 ] === v ) return;
19975
19976         gl.uniform1i( this.addr, v );
19977
19978         cache[ 0 ] = v;
19979
19980 }
19981
19982 // Single integer / boolean vector (from flat array)
19983
19984 function setValueV2i( gl, v ) {
19985
19986         const cache = this.cache;
19987
19988         if ( arraysEqual( cache, v ) ) return;
19989
19990         gl.uniform2iv( this.addr, v );
19991
19992         copyArray( cache, v );
19993
19994 }
19995
19996 function setValueV3i( gl, v ) {
19997
19998         const cache = this.cache;
19999
20000         if ( arraysEqual( cache, v ) ) return;
20001
20002         gl.uniform3iv( this.addr, v );
20003
20004         copyArray( cache, v );
20005
20006 }
20007
20008 function setValueV4i( gl, v ) {
20009
20010         const cache = this.cache;
20011
20012         if ( arraysEqual( cache, v ) ) return;
20013
20014         gl.uniform4iv( this.addr, v );
20015
20016         copyArray( cache, v );
20017
20018 }
20019
20020 // Single unsigned integer
20021
20022 function setValueV1ui( gl, v ) {
20023
20024         const cache = this.cache;
20025
20026         if ( cache[ 0 ] === v ) return;
20027
20028         gl.uniform1ui( this.addr, v );
20029
20030         cache[ 0 ] = v;
20031
20032 }
20033
20034 // Single unsigned integer vector (from flat array)
20035
20036 function setValueV2ui( gl, v ) {
20037
20038         const cache = this.cache;
20039
20040         if ( arraysEqual( cache, v ) ) return;
20041
20042         gl.uniform2uiv( this.addr, v );
20043
20044         copyArray( cache, v );
20045
20046 }
20047
20048 function setValueV3ui( gl, v ) {
20049
20050         const cache = this.cache;
20051
20052         if ( arraysEqual( cache, v ) ) return;
20053
20054         gl.uniform3uiv( this.addr, v );
20055
20056         copyArray( cache, v );
20057
20058 }
20059
20060 function setValueV4ui( gl, v ) {
20061
20062         const cache = this.cache;
20063
20064         if ( arraysEqual( cache, v ) ) return;
20065
20066         gl.uniform4uiv( this.addr, v );
20067
20068         copyArray( cache, v );
20069
20070 }
20071
20072
20073 // Single texture (2D / Cube)
20074
20075 function setValueT1( gl, v, textures ) {
20076
20077         const cache = this.cache;
20078         const unit = textures.allocateTextureUnit();
20079
20080         if ( cache[ 0 ] !== unit ) {
20081
20082                 gl.uniform1i( this.addr, unit );
20083                 cache[ 0 ] = unit;
20084
20085         }
20086
20087         textures.safeSetTexture2D( v || emptyTexture, unit );
20088
20089 }
20090
20091 function setValueT3D1( gl, v, textures ) {
20092
20093         const cache = this.cache;
20094         const unit = textures.allocateTextureUnit();
20095
20096         if ( cache[ 0 ] !== unit ) {
20097
20098                 gl.uniform1i( this.addr, unit );
20099                 cache[ 0 ] = unit;
20100
20101         }
20102
20103         textures.setTexture3D( v || emptyTexture3d, unit );
20104
20105 }
20106
20107 function setValueT6( gl, v, textures ) {
20108
20109         const cache = this.cache;
20110         const unit = textures.allocateTextureUnit();
20111
20112         if ( cache[ 0 ] !== unit ) {
20113
20114                 gl.uniform1i( this.addr, unit );
20115                 cache[ 0 ] = unit;
20116
20117         }
20118
20119         textures.safeSetTextureCube( v || emptyCubeTexture, unit );
20120
20121 }
20122
20123 function setValueT2DArray1( gl, v, textures ) {
20124
20125         const cache = this.cache;
20126         const unit = textures.allocateTextureUnit();
20127
20128         if ( cache[ 0 ] !== unit ) {
20129
20130                 gl.uniform1i( this.addr, unit );
20131                 cache[ 0 ] = unit;
20132
20133         }
20134
20135         textures.setTexture2DArray( v || emptyTexture2dArray, unit );
20136
20137 }
20138
20139 // Helper to pick the right setter for the singular case
20140
20141 function getSingularSetter( type ) {
20142
20143         switch ( type ) {
20144
20145                 case 0x1406: return setValueV1f; // FLOAT
20146                 case 0x8b50: return setValueV2f; // _VEC2
20147                 case 0x8b51: return setValueV3f; // _VEC3
20148                 case 0x8b52: return setValueV4f; // _VEC4
20149
20150                 case 0x8b5a: return setValueM2; // _MAT2
20151                 case 0x8b5b: return setValueM3; // _MAT3
20152                 case 0x8b5c: return setValueM4; // _MAT4
20153
20154                 case 0x1404: case 0x8b56: return setValueV1i; // INT, BOOL
20155                 case 0x8b53: case 0x8b57: return setValueV2i; // _VEC2
20156                 case 0x8b54: case 0x8b58: return setValueV3i; // _VEC3
20157                 case 0x8b55: case 0x8b59: return setValueV4i; // _VEC4
20158
20159                 case 0x1405: return setValueV1ui; // UINT
20160                 case 0x8dc6: return setValueV2ui; // _VEC2
20161                 case 0x8dc7: return setValueV3ui; // _VEC3
20162                 case 0x8dc8: return setValueV4ui; // _VEC4
20163
20164                 case 0x8b5e: // SAMPLER_2D
20165                 case 0x8d66: // SAMPLER_EXTERNAL_OES
20166                 case 0x8dca: // INT_SAMPLER_2D
20167                 case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D
20168                 case 0x8b62: // SAMPLER_2D_SHADOW
20169                         return setValueT1;
20170
20171                 case 0x8b5f: // SAMPLER_3D
20172                 case 0x8dcb: // INT_SAMPLER_3D
20173                 case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D
20174                         return setValueT3D1;
20175
20176                 case 0x8b60: // SAMPLER_CUBE
20177                 case 0x8dcc: // INT_SAMPLER_CUBE
20178                 case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE
20179                 case 0x8dc5: // SAMPLER_CUBE_SHADOW
20180                         return setValueT6;
20181
20182                 case 0x8dc1: // SAMPLER_2D_ARRAY
20183                 case 0x8dcf: // INT_SAMPLER_2D_ARRAY
20184                 case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY
20185                 case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW
20186                         return setValueT2DArray1;
20187
20188         }
20189
20190 }
20191
20192
20193 // Array of scalars
20194
20195 function setValueV1fArray( gl, v ) {
20196
20197         gl.uniform1fv( this.addr, v );
20198
20199 }
20200
20201 // Array of vectors (from flat array or array of THREE.VectorN)
20202
20203 function setValueV2fArray( gl, v ) {
20204
20205         const data = flatten( v, this.size, 2 );
20206
20207         gl.uniform2fv( this.addr, data );
20208
20209 }
20210
20211 function setValueV3fArray( gl, v ) {
20212
20213         const data = flatten( v, this.size, 3 );
20214
20215         gl.uniform3fv( this.addr, data );
20216
20217 }
20218
20219 function setValueV4fArray( gl, v ) {
20220
20221         const data = flatten( v, this.size, 4 );
20222
20223         gl.uniform4fv( this.addr, data );
20224
20225 }
20226
20227 // Array of matrices (from flat array or array of THREE.MatrixN)
20228
20229 function setValueM2Array( gl, v ) {
20230
20231         const data = flatten( v, this.size, 4 );
20232
20233         gl.uniformMatrix2fv( this.addr, false, data );
20234
20235 }
20236
20237 function setValueM3Array( gl, v ) {
20238
20239         const data = flatten( v, this.size, 9 );
20240
20241         gl.uniformMatrix3fv( this.addr, false, data );
20242
20243 }
20244
20245 function setValueM4Array( gl, v ) {
20246
20247         const data = flatten( v, this.size, 16 );
20248
20249         gl.uniformMatrix4fv( this.addr, false, data );
20250
20251 }
20252
20253 // Array of integer / boolean
20254
20255 function setValueV1iArray( gl, v ) {
20256
20257         gl.uniform1iv( this.addr, v );
20258
20259 }
20260
20261 // Array of integer / boolean vectors (from flat array)
20262
20263 function setValueV2iArray( gl, v ) {
20264
20265         gl.uniform2iv( this.addr, v );
20266
20267 }
20268
20269 function setValueV3iArray( gl, v ) {
20270
20271         gl.uniform3iv( this.addr, v );
20272
20273 }
20274
20275 function setValueV4iArray( gl, v ) {
20276
20277         gl.uniform4iv( this.addr, v );
20278
20279 }
20280
20281 // Array of unsigned integer
20282
20283 function setValueV1uiArray( gl, v ) {
20284
20285         gl.uniform1uiv( this.addr, v );
20286
20287 }
20288
20289 // Array of unsigned integer vectors (from flat array)
20290
20291 function setValueV2uiArray( gl, v ) {
20292
20293         gl.uniform2uiv( this.addr, v );
20294
20295 }
20296
20297 function setValueV3uiArray( gl, v ) {
20298
20299         gl.uniform3uiv( this.addr, v );
20300
20301 }
20302
20303 function setValueV4uiArray( gl, v ) {
20304
20305         gl.uniform4uiv( this.addr, v );
20306
20307 }
20308
20309
20310 // Array of textures (2D / Cube)
20311
20312 function setValueT1Array( gl, v, textures ) {
20313
20314         const n = v.length;
20315
20316         const units = allocTexUnits( textures, n );
20317
20318         gl.uniform1iv( this.addr, units );
20319
20320         for ( let i = 0; i !== n; ++ i ) {
20321
20322                 textures.safeSetTexture2D( v[ i ] || emptyTexture, units[ i ] );
20323
20324         }
20325
20326 }
20327
20328 function setValueT6Array( gl, v, textures ) {
20329
20330         const n = v.length;
20331
20332         const units = allocTexUnits( textures, n );
20333
20334         gl.uniform1iv( this.addr, units );
20335
20336         for ( let i = 0; i !== n; ++ i ) {
20337
20338                 textures.safeSetTextureCube( v[ i ] || emptyCubeTexture, units[ i ] );
20339
20340         }
20341
20342 }
20343
20344 // Helper to pick the right setter for a pure (bottom-level) array
20345
20346 function getPureArraySetter( type ) {
20347
20348         switch ( type ) {
20349
20350                 case 0x1406: return setValueV1fArray; // FLOAT
20351                 case 0x8b50: return setValueV2fArray; // _VEC2
20352                 case 0x8b51: return setValueV3fArray; // _VEC3
20353                 case 0x8b52: return setValueV4fArray; // _VEC4
20354
20355                 case 0x8b5a: return setValueM2Array; // _MAT2
20356                 case 0x8b5b: return setValueM3Array; // _MAT3
20357                 case 0x8b5c: return setValueM4Array; // _MAT4
20358
20359                 case 0x1404: case 0x8b56: return setValueV1iArray; // INT, BOOL
20360                 case 0x8b53: case 0x8b57: return setValueV2iArray; // _VEC2
20361                 case 0x8b54: case 0x8b58: return setValueV3iArray; // _VEC3
20362                 case 0x8b55: case 0x8b59: return setValueV4iArray; // _VEC4
20363
20364                 case 0x1405: return setValueV1uiArray; // UINT
20365                 case 0x8dc6: return setValueV2uiArray; // _VEC2
20366                 case 0x8dc7: return setValueV3uiArray; // _VEC3
20367                 case 0x8dc8: return setValueV4uiArray; // _VEC4
20368
20369                 case 0x8b5e: // SAMPLER_2D
20370                 case 0x8d66: // SAMPLER_EXTERNAL_OES
20371                 case 0x8dca: // INT_SAMPLER_2D
20372                 case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D
20373                 case 0x8b62: // SAMPLER_2D_SHADOW
20374                         return setValueT1Array;
20375
20376                 case 0x8b60: // SAMPLER_CUBE
20377                 case 0x8dcc: // INT_SAMPLER_CUBE
20378                 case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE
20379                 case 0x8dc5: // SAMPLER_CUBE_SHADOW
20380                         return setValueT6Array;
20381
20382         }
20383
20384 }
20385
20386 // --- Uniform Classes ---
20387
20388 function SingleUniform( id, activeInfo, addr ) {
20389
20390         this.id = id;
20391         this.addr = addr;
20392         this.cache = [];
20393         this.setValue = getSingularSetter( activeInfo.type );
20394
20395         // this.path = activeInfo.name; // DEBUG
20396
20397 }
20398
20399 function PureArrayUniform( id, activeInfo, addr ) {
20400
20401         this.id = id;
20402         this.addr = addr;
20403         this.cache = [];
20404         this.size = activeInfo.size;
20405         this.setValue = getPureArraySetter( activeInfo.type );
20406
20407         // this.path = activeInfo.name; // DEBUG
20408
20409 }
20410
20411 PureArrayUniform.prototype.updateCache = function ( data ) {
20412
20413         const cache = this.cache;
20414
20415         if ( data instanceof Float32Array && cache.length !== data.length ) {
20416
20417                 this.cache = new Float32Array( data.length );
20418
20419         }
20420
20421         copyArray( cache, data );
20422
20423 };
20424
20425 function StructuredUniform( id ) {
20426
20427         this.id = id;
20428
20429         this.seq = [];
20430         this.map = {};
20431
20432 }
20433
20434 StructuredUniform.prototype.setValue = function ( gl, value, textures ) {
20435
20436         const seq = this.seq;
20437
20438         for ( let i = 0, n = seq.length; i !== n; ++ i ) {
20439
20440                 const u = seq[ i ];
20441                 u.setValue( gl, value[ u.id ], textures );
20442
20443         }
20444
20445 };
20446
20447 // --- Top-level ---
20448
20449 // Parser - builds up the property tree from the path strings
20450
20451 const RePathPart = /(\w+)(\])?(\[|\.)?/g;
20452
20453 // extracts
20454 //      - the identifier (member name or array index)
20455 //  - followed by an optional right bracket (found when array index)
20456 //  - followed by an optional left bracket or dot (type of subscript)
20457 //
20458 // Note: These portions can be read in a non-overlapping fashion and
20459 // allow straightforward parsing of the hierarchy that WebGL encodes
20460 // in the uniform names.
20461
20462 function addUniform( container, uniformObject ) {
20463
20464         container.seq.push( uniformObject );
20465         container.map[ uniformObject.id ] = uniformObject;
20466
20467 }
20468
20469 function parseUniform( activeInfo, addr, container ) {
20470
20471         const path = activeInfo.name,
20472                 pathLength = path.length;
20473
20474         // reset RegExp object, because of the early exit of a previous run
20475         RePathPart.lastIndex = 0;
20476
20477         while ( true ) {
20478
20479                 const match = RePathPart.exec( path ),
20480                         matchEnd = RePathPart.lastIndex;
20481
20482                 let id = match[ 1 ];
20483                 const idIsIndex = match[ 2 ] === ']',
20484                         subscript = match[ 3 ];
20485
20486                 if ( idIsIndex ) id = id | 0; // convert to integer
20487
20488                 if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) {
20489
20490                         // bare name or "pure" bottom-level array "[0]" suffix
20491
20492                         addUniform( container, subscript === undefined ?
20493                                 new SingleUniform( id, activeInfo, addr ) :
20494                                 new PureArrayUniform( id, activeInfo, addr ) );
20495
20496                         break;
20497
20498                 } else {
20499
20500                         // step into inner node / create it in case it doesn't exist
20501
20502                         const map = container.map;
20503                         let next = map[ id ];
20504
20505                         if ( next === undefined ) {
20506
20507                                 next = new StructuredUniform( id );
20508                                 addUniform( container, next );
20509
20510                         }
20511
20512                         container = next;
20513
20514                 }
20515
20516         }
20517
20518 }
20519
20520 // Root Container
20521
20522 function WebGLUniforms( gl, program ) {
20523
20524         this.seq = [];
20525         this.map = {};
20526
20527         const n = gl.getProgramParameter( program, 35718 );
20528
20529         for ( let i = 0; i < n; ++ i ) {
20530
20531                 const info = gl.getActiveUniform( program, i ),
20532                         addr = gl.getUniformLocation( program, info.name );
20533
20534                 parseUniform( info, addr, this );
20535
20536         }
20537
20538 }
20539
20540 WebGLUniforms.prototype.setValue = function ( gl, name, value, textures ) {
20541
20542         const u = this.map[ name ];
20543
20544         if ( u !== undefined ) u.setValue( gl, value, textures );
20545
20546 };
20547
20548 WebGLUniforms.prototype.setOptional = function ( gl, object, name ) {
20549
20550         const v = object[ name ];
20551
20552         if ( v !== undefined ) this.setValue( gl, name, v );
20553
20554 };
20555
20556
20557 // Static interface
20558
20559 WebGLUniforms.upload = function ( gl, seq, values, textures ) {
20560
20561         for ( let i = 0, n = seq.length; i !== n; ++ i ) {
20562
20563                 const u = seq[ i ],
20564                         v = values[ u.id ];
20565
20566                 if ( v.needsUpdate !== false ) {
20567
20568                         // note: always updating when .needsUpdate is undefined
20569                         u.setValue( gl, v.value, textures );
20570
20571                 }
20572
20573         }
20574
20575 };
20576
20577 WebGLUniforms.seqWithValue = function ( seq, values ) {
20578
20579         const r = [];
20580
20581         for ( let i = 0, n = seq.length; i !== n; ++ i ) {
20582
20583                 const u = seq[ i ];
20584                 if ( u.id in values ) r.push( u );
20585
20586         }
20587
20588         return r;
20589
20590 };
20591
20592 function WebGLShader( gl, type, string ) {
20593
20594         const shader = gl.createShader( type );
20595
20596         gl.shaderSource( shader, string );
20597         gl.compileShader( shader );
20598
20599         return shader;
20600
20601 }
20602
20603 let programIdCount = 0;
20604
20605 function addLineNumbers( string ) {
20606
20607         const lines = string.split( '\n' );
20608
20609         for ( let i = 0; i < lines.length; i ++ ) {
20610
20611                 lines[ i ] = ( i + 1 ) + ': ' + lines[ i ];
20612
20613         }
20614
20615         return lines.join( '\n' );
20616
20617 }
20618
20619 function getEncodingComponents( encoding ) {
20620
20621         switch ( encoding ) {
20622
20623                 case LinearEncoding:
20624                         return [ 'Linear', '( value )' ];
20625                 case sRGBEncoding:
20626                         return [ 'sRGB', '( value )' ];
20627                 case RGBEEncoding:
20628                         return [ 'RGBE', '( value )' ];
20629                 case RGBM7Encoding:
20630                         return [ 'RGBM', '( value, 7.0 )' ];
20631                 case RGBM16Encoding:
20632                         return [ 'RGBM', '( value, 16.0 )' ];
20633                 case RGBDEncoding:
20634                         return [ 'RGBD', '( value, 256.0 )' ];
20635                 case GammaEncoding:
20636                         return [ 'Gamma', '( value, float( GAMMA_FACTOR ) )' ];
20637                 case LogLuvEncoding:
20638                         return [ 'LogLuv', '( value )' ];
20639                 default:
20640                         console.warn( 'THREE.WebGLProgram: Unsupported encoding:', encoding );
20641                         return [ 'Linear', '( value )' ];
20642
20643         }
20644
20645 }
20646
20647 function getShaderErrors( gl, shader, type ) {
20648
20649         const status = gl.getShaderParameter( shader, 35713 );
20650         const errors = gl.getShaderInfoLog( shader ).trim();
20651
20652         if ( status && errors === '' ) return '';
20653
20654         // --enable-privileged-webgl-extension
20655         // console.log( '**' + type + '**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) );
20656
20657         return type.toUpperCase() + '\n\n' + errors + '\n\n' + addLineNumbers( gl.getShaderSource( shader ) );
20658
20659 }
20660
20661 function getTexelDecodingFunction( functionName, encoding ) {
20662
20663         const components = getEncodingComponents( encoding );
20664         return 'vec4 ' + functionName + '( vec4 value ) { return ' + components[ 0 ] + 'ToLinear' + components[ 1 ] + '; }';
20665
20666 }
20667
20668 function getTexelEncodingFunction( functionName, encoding ) {
20669
20670         const components = getEncodingComponents( encoding );
20671         return 'vec4 ' + functionName + '( vec4 value ) { return LinearTo' + components[ 0 ] + components[ 1 ] + '; }';
20672
20673 }
20674
20675 function getToneMappingFunction( functionName, toneMapping ) {
20676
20677         let toneMappingName;
20678
20679         switch ( toneMapping ) {
20680
20681                 case LinearToneMapping:
20682                         toneMappingName = 'Linear';
20683                         break;
20684
20685                 case ReinhardToneMapping:
20686                         toneMappingName = 'Reinhard';
20687                         break;
20688
20689                 case CineonToneMapping:
20690                         toneMappingName = 'OptimizedCineon';
20691                         break;
20692
20693                 case ACESFilmicToneMapping:
20694                         toneMappingName = 'ACESFilmic';
20695                         break;
20696
20697                 case CustomToneMapping:
20698                         toneMappingName = 'Custom';
20699                         break;
20700
20701                 default:
20702                         console.warn( 'THREE.WebGLProgram: Unsupported toneMapping:', toneMapping );
20703                         toneMappingName = 'Linear';
20704
20705         }
20706
20707         return 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName + 'ToneMapping( color ); }';
20708
20709 }
20710
20711 function generateExtensions( parameters ) {
20712
20713         const chunks = [
20714                 ( parameters.extensionDerivatives || parameters.envMapCubeUV || parameters.bumpMap || parameters.tangentSpaceNormalMap || parameters.clearcoatNormalMap || parameters.flatShading || parameters.shaderID === 'physical' ) ? '#extension GL_OES_standard_derivatives : enable' : '',
20715                 ( parameters.extensionFragDepth || parameters.logarithmicDepthBuffer ) && parameters.rendererExtensionFragDepth ? '#extension GL_EXT_frag_depth : enable' : '',
20716                 ( parameters.extensionDrawBuffers && parameters.rendererExtensionDrawBuffers ) ? '#extension GL_EXT_draw_buffers : require' : '',
20717                 ( parameters.extensionShaderTextureLOD || parameters.envMap || parameters.transmission ) && parameters.rendererExtensionShaderTextureLod ? '#extension GL_EXT_shader_texture_lod : enable' : ''
20718         ];
20719
20720         return chunks.filter( filterEmptyLine ).join( '\n' );
20721
20722 }
20723
20724 function generateDefines( defines ) {
20725
20726         const chunks = [];
20727
20728         for ( const name in defines ) {
20729
20730                 const value = defines[ name ];
20731
20732                 if ( value === false ) continue;
20733
20734                 chunks.push( '#define ' + name + ' ' + value );
20735
20736         }
20737
20738         return chunks.join( '\n' );
20739
20740 }
20741
20742 function fetchAttributeLocations( gl, program ) {
20743
20744         const attributes = {};
20745
20746         const n = gl.getProgramParameter( program, 35721 );
20747
20748         for ( let i = 0; i < n; i ++ ) {
20749
20750                 const info = gl.getActiveAttrib( program, i );
20751                 const name = info.name;
20752
20753                 let locationSize = 1;
20754                 if ( info.type === 35674 ) locationSize = 2;
20755                 if ( info.type === 35675 ) locationSize = 3;
20756                 if ( info.type === 35676 ) locationSize = 4;
20757
20758                 // console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i );
20759
20760                 attributes[ name ] = {
20761                         type: info.type,
20762                         location: gl.getAttribLocation( program, name ),
20763                         locationSize: locationSize
20764                 };
20765
20766         }
20767
20768         return attributes;
20769
20770 }
20771
20772 function filterEmptyLine( string ) {
20773
20774         return string !== '';
20775
20776 }
20777
20778 function replaceLightNums( string, parameters ) {
20779
20780         return string
20781                 .replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights )
20782                 .replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights )
20783                 .replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights )
20784                 .replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights )
20785                 .replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights )
20786                 .replace( /NUM_DIR_LIGHT_SHADOWS/g, parameters.numDirLightShadows )
20787                 .replace( /NUM_SPOT_LIGHT_SHADOWS/g, parameters.numSpotLightShadows )
20788                 .replace( /NUM_POINT_LIGHT_SHADOWS/g, parameters.numPointLightShadows );
20789
20790 }
20791
20792 function replaceClippingPlaneNums( string, parameters ) {
20793
20794         return string
20795                 .replace( /NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes )
20796                 .replace( /UNION_CLIPPING_PLANES/g, ( parameters.numClippingPlanes - parameters.numClipIntersection ) );
20797
20798 }
20799
20800 // Resolve Includes
20801
20802 const includePattern = /^[ \t]*#include +<([\w\d./]+)>/gm;
20803
20804 function resolveIncludes( string ) {
20805
20806         return string.replace( includePattern, includeReplacer );
20807
20808 }
20809
20810 function includeReplacer( match, include ) {
20811
20812         const string = ShaderChunk[ include ];
20813
20814         if ( string === undefined ) {
20815
20816                 throw new Error( 'Can not resolve #include <' + include + '>' );
20817
20818         }
20819
20820         return resolveIncludes( string );
20821
20822 }
20823
20824 // Unroll Loops
20825
20826 const deprecatedUnrollLoopPattern = /#pragma unroll_loop[\s]+?for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g;
20827 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;
20828
20829 function unrollLoops( string ) {
20830
20831         return string
20832                 .replace( unrollLoopPattern, loopReplacer )
20833                 .replace( deprecatedUnrollLoopPattern, deprecatedLoopReplacer );
20834
20835 }
20836
20837 function deprecatedLoopReplacer( match, start, end, snippet ) {
20838
20839         console.warn( 'WebGLProgram: #pragma unroll_loop shader syntax is deprecated. Please use #pragma unroll_loop_start syntax instead.' );
20840         return loopReplacer( match, start, end, snippet );
20841
20842 }
20843
20844 function loopReplacer( match, start, end, snippet ) {
20845
20846         let string = '';
20847
20848         for ( let i = parseInt( start ); i < parseInt( end ); i ++ ) {
20849
20850                 string += snippet
20851                         .replace( /\[\s*i\s*\]/g, '[ ' + i + ' ]' )
20852                         .replace( /UNROLLED_LOOP_INDEX/g, i );
20853
20854         }
20855
20856         return string;
20857
20858 }
20859
20860 //
20861
20862 function generatePrecision( parameters ) {
20863
20864         let precisionstring = 'precision ' + parameters.precision + ' float;\nprecision ' + parameters.precision + ' int;';
20865
20866         if ( parameters.precision === 'highp' ) {
20867
20868                 precisionstring += '\n#define HIGH_PRECISION';
20869
20870         } else if ( parameters.precision === 'mediump' ) {
20871
20872                 precisionstring += '\n#define MEDIUM_PRECISION';
20873
20874         } else if ( parameters.precision === 'lowp' ) {
20875
20876                 precisionstring += '\n#define LOW_PRECISION';
20877
20878         }
20879
20880         return precisionstring;
20881
20882 }
20883
20884 function generateShadowMapTypeDefine( parameters ) {
20885
20886         let shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC';
20887
20888         if ( parameters.shadowMapType === PCFShadowMap ) {
20889
20890                 shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF';
20891
20892         } else if ( parameters.shadowMapType === PCFSoftShadowMap ) {
20893
20894                 shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT';
20895
20896         } else if ( parameters.shadowMapType === VSMShadowMap ) {
20897
20898                 shadowMapTypeDefine = 'SHADOWMAP_TYPE_VSM';
20899
20900         }
20901
20902         return shadowMapTypeDefine;
20903
20904 }
20905
20906 function generateEnvMapTypeDefine( parameters ) {
20907
20908         let envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
20909
20910         if ( parameters.envMap ) {
20911
20912                 switch ( parameters.envMapMode ) {
20913
20914                         case CubeReflectionMapping:
20915                         case CubeRefractionMapping:
20916                                 envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
20917                                 break;
20918
20919                         case CubeUVReflectionMapping:
20920                         case CubeUVRefractionMapping:
20921                                 envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV';
20922                                 break;
20923
20924                 }
20925
20926         }
20927
20928         return envMapTypeDefine;
20929
20930 }
20931
20932 function generateEnvMapModeDefine( parameters ) {
20933
20934         let envMapModeDefine = 'ENVMAP_MODE_REFLECTION';
20935
20936         if ( parameters.envMap ) {
20937
20938                 switch ( parameters.envMapMode ) {
20939
20940                         case CubeRefractionMapping:
20941                         case CubeUVRefractionMapping:
20942
20943                                 envMapModeDefine = 'ENVMAP_MODE_REFRACTION';
20944                                 break;
20945
20946                 }
20947
20948         }
20949
20950         return envMapModeDefine;
20951
20952 }
20953
20954 function generateEnvMapBlendingDefine( parameters ) {
20955
20956         let envMapBlendingDefine = 'ENVMAP_BLENDING_NONE';
20957
20958         if ( parameters.envMap ) {
20959
20960                 switch ( parameters.combine ) {
20961
20962                         case MultiplyOperation:
20963                                 envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';
20964                                 break;
20965
20966                         case MixOperation:
20967                                 envMapBlendingDefine = 'ENVMAP_BLENDING_MIX';
20968                                 break;
20969
20970                         case AddOperation:
20971                                 envMapBlendingDefine = 'ENVMAP_BLENDING_ADD';
20972                                 break;
20973
20974                 }
20975
20976         }
20977
20978         return envMapBlendingDefine;
20979
20980 }
20981
20982 function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
20983
20984         // TODO Send this event to Three.js DevTools
20985         // console.log( 'WebGLProgram', cacheKey );
20986
20987         const gl = renderer.getContext();
20988
20989         const defines = parameters.defines;
20990
20991         let vertexShader = parameters.vertexShader;
20992         let fragmentShader = parameters.fragmentShader;
20993
20994         const shadowMapTypeDefine = generateShadowMapTypeDefine( parameters );
20995         const envMapTypeDefine = generateEnvMapTypeDefine( parameters );
20996         const envMapModeDefine = generateEnvMapModeDefine( parameters );
20997         const envMapBlendingDefine = generateEnvMapBlendingDefine( parameters );
20998
20999
21000         const gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0;
21001
21002         const customExtensions = parameters.isWebGL2 ? '' : generateExtensions( parameters );
21003
21004         const customDefines = generateDefines( defines );
21005
21006         const program = gl.createProgram();
21007
21008         let prefixVertex, prefixFragment;
21009         let versionString = parameters.glslVersion ? '#version ' + parameters.glslVersion + '\n' : '';
21010
21011         if ( parameters.isRawShaderMaterial ) {
21012
21013                 prefixVertex = [
21014
21015                         customDefines
21016
21017                 ].filter( filterEmptyLine ).join( '\n' );
21018
21019                 if ( prefixVertex.length > 0 ) {
21020
21021                         prefixVertex += '\n';
21022
21023                 }
21024
21025                 prefixFragment = [
21026
21027                         customExtensions,
21028                         customDefines
21029
21030                 ].filter( filterEmptyLine ).join( '\n' );
21031
21032                 if ( prefixFragment.length > 0 ) {
21033
21034                         prefixFragment += '\n';
21035
21036                 }
21037
21038         } else {
21039
21040                 prefixVertex = [
21041
21042                         generatePrecision( parameters ),
21043
21044                         '#define SHADER_NAME ' + parameters.shaderName,
21045
21046                         customDefines,
21047
21048                         parameters.instancing ? '#define USE_INSTANCING' : '',
21049                         parameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '',
21050
21051                         parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '',
21052
21053                         '#define GAMMA_FACTOR ' + gammaFactorDefine,
21054
21055                         '#define MAX_BONES ' + parameters.maxBones,
21056                         ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '',
21057                         ( parameters.useFog && parameters.fogExp2 ) ? '#define FOG_EXP2' : '',
21058
21059                         parameters.map ? '#define USE_MAP' : '',
21060                         parameters.envMap ? '#define USE_ENVMAP' : '',
21061                         parameters.envMap ? '#define ' + envMapModeDefine : '',
21062                         parameters.lightMap ? '#define USE_LIGHTMAP' : '',
21063                         parameters.aoMap ? '#define USE_AOMAP' : '',
21064                         parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
21065                         parameters.bumpMap ? '#define USE_BUMPMAP' : '',
21066                         parameters.normalMap ? '#define USE_NORMALMAP' : '',
21067                         ( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '',
21068                         ( parameters.normalMap && parameters.tangentSpaceNormalMap ) ? '#define TANGENTSPACE_NORMALMAP' : '',
21069
21070                         parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '',
21071                         parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '',
21072                         parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',
21073
21074                         parameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '',
21075
21076                         parameters.specularMap ? '#define USE_SPECULARMAP' : '',
21077                         parameters.specularIntensityMap ? '#define USE_SPECULARINTENSITYMAP' : '',
21078                         parameters.specularColorMap ? '#define USE_SPECULARCOLORMAP' : '',
21079
21080                         parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
21081                         parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
21082                         parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
21083
21084                         parameters.transmission ? '#define USE_TRANSMISSION' : '',
21085                         parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '',
21086                         parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '',
21087
21088                         parameters.sheenColorMap ? '#define USE_SHEENCOLORMAP' : '',
21089                         parameters.sheenRoughnessMap ? '#define USE_SHEENROUGHNESSMAP' : '',
21090
21091                         parameters.vertexTangents ? '#define USE_TANGENT' : '',
21092                         parameters.vertexColors ? '#define USE_COLOR' : '',
21093                         parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '',
21094                         parameters.vertexUvs ? '#define USE_UV' : '',
21095                         parameters.uvsVertexOnly ? '#define UVS_VERTEX_ONLY' : '',
21096
21097                         parameters.flatShading ? '#define FLAT_SHADED' : '',
21098
21099                         parameters.skinning ? '#define USE_SKINNING' : '',
21100                         parameters.useVertexTexture ? '#define BONE_TEXTURE' : '',
21101
21102                         parameters.morphTargets ? '#define USE_MORPHTARGETS' : '',
21103                         parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '',
21104                         ( parameters.morphTargets && parameters.isWebGL2 ) ? '#define MORPHTARGETS_TEXTURE' : '',
21105                         ( parameters.morphTargets && parameters.isWebGL2 ) ? '#define MORPHTARGETS_COUNT ' + parameters.morphTargetsCount : '',
21106                         parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
21107                         parameters.flipSided ? '#define FLIP_SIDED' : '',
21108
21109                         parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
21110                         parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
21111
21112                         parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '',
21113
21114                         parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
21115                         ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
21116
21117                         'uniform mat4 modelMatrix;',
21118                         'uniform mat4 modelViewMatrix;',
21119                         'uniform mat4 projectionMatrix;',
21120                         'uniform mat4 viewMatrix;',
21121                         'uniform mat3 normalMatrix;',
21122                         'uniform vec3 cameraPosition;',
21123                         'uniform bool isOrthographic;',
21124
21125                         '#ifdef USE_INSTANCING',
21126
21127                         '       attribute mat4 instanceMatrix;',
21128
21129                         '#endif',
21130
21131                         '#ifdef USE_INSTANCING_COLOR',
21132
21133                         '       attribute vec3 instanceColor;',
21134
21135                         '#endif',
21136
21137                         'attribute vec3 position;',
21138                         'attribute vec3 normal;',
21139                         'attribute vec2 uv;',
21140
21141                         '#ifdef USE_TANGENT',
21142
21143                         '       attribute vec4 tangent;',
21144
21145                         '#endif',
21146
21147                         '#if defined( USE_COLOR_ALPHA )',
21148
21149                         '       attribute vec4 color;',
21150
21151                         '#elif defined( USE_COLOR )',
21152
21153                         '       attribute vec3 color;',
21154
21155                         '#endif',
21156
21157                         '#if ( defined( USE_MORPHTARGETS ) && ! defined( MORPHTARGETS_TEXTURE ) )',
21158
21159                         '       attribute vec3 morphTarget0;',
21160                         '       attribute vec3 morphTarget1;',
21161                         '       attribute vec3 morphTarget2;',
21162                         '       attribute vec3 morphTarget3;',
21163
21164                         '       #ifdef USE_MORPHNORMALS',
21165
21166                         '               attribute vec3 morphNormal0;',
21167                         '               attribute vec3 morphNormal1;',
21168                         '               attribute vec3 morphNormal2;',
21169                         '               attribute vec3 morphNormal3;',
21170
21171                         '       #else',
21172
21173                         '               attribute vec3 morphTarget4;',
21174                         '               attribute vec3 morphTarget5;',
21175                         '               attribute vec3 morphTarget6;',
21176                         '               attribute vec3 morphTarget7;',
21177
21178                         '       #endif',
21179
21180                         '#endif',
21181
21182                         '#ifdef USE_SKINNING',
21183
21184                         '       attribute vec4 skinIndex;',
21185                         '       attribute vec4 skinWeight;',
21186
21187                         '#endif',
21188
21189                         '\n'
21190
21191                 ].filter( filterEmptyLine ).join( '\n' );
21192
21193                 prefixFragment = [
21194
21195                         customExtensions,
21196
21197                         generatePrecision( parameters ),
21198
21199                         '#define SHADER_NAME ' + parameters.shaderName,
21200
21201                         customDefines,
21202
21203                         '#define GAMMA_FACTOR ' + gammaFactorDefine,
21204
21205                         ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '',
21206                         ( parameters.useFog && parameters.fogExp2 ) ? '#define FOG_EXP2' : '',
21207
21208                         parameters.map ? '#define USE_MAP' : '',
21209                         parameters.matcap ? '#define USE_MATCAP' : '',
21210                         parameters.envMap ? '#define USE_ENVMAP' : '',
21211                         parameters.envMap ? '#define ' + envMapTypeDefine : '',
21212                         parameters.envMap ? '#define ' + envMapModeDefine : '',
21213                         parameters.envMap ? '#define ' + envMapBlendingDefine : '',
21214                         parameters.lightMap ? '#define USE_LIGHTMAP' : '',
21215                         parameters.aoMap ? '#define USE_AOMAP' : '',
21216                         parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
21217                         parameters.bumpMap ? '#define USE_BUMPMAP' : '',
21218                         parameters.normalMap ? '#define USE_NORMALMAP' : '',
21219                         ( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '',
21220                         ( parameters.normalMap && parameters.tangentSpaceNormalMap ) ? '#define TANGENTSPACE_NORMALMAP' : '',
21221
21222                         parameters.clearcoat ? '#define USE_CLEARCOAT' : '',
21223                         parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '',
21224                         parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '',
21225                         parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',
21226
21227                         parameters.specularMap ? '#define USE_SPECULARMAP' : '',
21228                         parameters.specularIntensityMap ? '#define USE_SPECULARINTENSITYMAP' : '',
21229                         parameters.specularColorMap ? '#define USE_SPECULARCOLORMAP' : '',
21230                         parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
21231                         parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
21232
21233                         parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
21234                         parameters.alphaTest ? '#define USE_ALPHATEST' : '',
21235
21236                         parameters.sheen ? '#define USE_SHEEN' : '',
21237                         parameters.sheenColorMap ? '#define USE_SHEENCOLORMAP' : '',
21238                         parameters.sheenRoughnessMap ? '#define USE_SHEENROUGHNESSMAP' : '',
21239
21240                         parameters.transmission ? '#define USE_TRANSMISSION' : '',
21241                         parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '',
21242                         parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '',
21243
21244                         parameters.vertexTangents ? '#define USE_TANGENT' : '',
21245                         parameters.vertexColors || parameters.instancingColor ? '#define USE_COLOR' : '',
21246                         parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '',
21247                         parameters.vertexUvs ? '#define USE_UV' : '',
21248                         parameters.uvsVertexOnly ? '#define UVS_VERTEX_ONLY' : '',
21249
21250                         parameters.gradientMap ? '#define USE_GRADIENTMAP' : '',
21251
21252                         parameters.flatShading ? '#define FLAT_SHADED' : '',
21253
21254                         parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
21255                         parameters.flipSided ? '#define FLIP_SIDED' : '',
21256
21257                         parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
21258                         parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
21259
21260                         parameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '',
21261
21262                         parameters.physicallyCorrectLights ? '#define PHYSICALLY_CORRECT_LIGHTS' : '',
21263
21264                         parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
21265                         ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
21266
21267                         ( ( parameters.extensionShaderTextureLOD || parameters.envMap ) && parameters.rendererExtensionShaderTextureLod ) ? '#define TEXTURE_LOD_EXT' : '',
21268
21269                         'uniform mat4 viewMatrix;',
21270                         'uniform vec3 cameraPosition;',
21271                         'uniform bool isOrthographic;',
21272
21273                         ( parameters.toneMapping !== NoToneMapping ) ? '#define TONE_MAPPING' : '',
21274                         ( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below
21275                         ( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( 'toneMapping', parameters.toneMapping ) : '',
21276
21277                         parameters.dithering ? '#define DITHERING' : '',
21278                         parameters.format === RGBFormat ? '#define OPAQUE' : '',
21279
21280                         ShaderChunk[ 'encodings_pars_fragment' ], // this code is required here because it is used by the various encoding/decoding function defined below
21281                         parameters.map ? getTexelDecodingFunction( 'mapTexelToLinear', parameters.mapEncoding ) : '',
21282                         parameters.matcap ? getTexelDecodingFunction( 'matcapTexelToLinear', parameters.matcapEncoding ) : '',
21283                         parameters.envMap ? getTexelDecodingFunction( 'envMapTexelToLinear', parameters.envMapEncoding ) : '',
21284                         parameters.emissiveMap ? getTexelDecodingFunction( 'emissiveMapTexelToLinear', parameters.emissiveMapEncoding ) : '',
21285                         parameters.specularColorMap ? getTexelDecodingFunction( 'specularColorMapTexelToLinear', parameters.specularColorMapEncoding ) : '',
21286                         parameters.sheenColorMap ? getTexelDecodingFunction( 'sheenColorMapTexelToLinear', parameters.sheenColorMapEncoding ) : '',
21287                         parameters.lightMap ? getTexelDecodingFunction( 'lightMapTexelToLinear', parameters.lightMapEncoding ) : '',
21288                         getTexelEncodingFunction( 'linearToOutputTexel', parameters.outputEncoding ),
21289
21290                         parameters.depthPacking ? '#define DEPTH_PACKING ' + parameters.depthPacking : '',
21291
21292                         '\n'
21293
21294                 ].filter( filterEmptyLine ).join( '\n' );
21295
21296         }
21297
21298         vertexShader = resolveIncludes( vertexShader );
21299         vertexShader = replaceLightNums( vertexShader, parameters );
21300         vertexShader = replaceClippingPlaneNums( vertexShader, parameters );
21301
21302         fragmentShader = resolveIncludes( fragmentShader );
21303         fragmentShader = replaceLightNums( fragmentShader, parameters );
21304         fragmentShader = replaceClippingPlaneNums( fragmentShader, parameters );
21305
21306         vertexShader = unrollLoops( vertexShader );
21307         fragmentShader = unrollLoops( fragmentShader );
21308
21309         if ( parameters.isWebGL2 && parameters.isRawShaderMaterial !== true ) {
21310
21311                 // GLSL 3.0 conversion for built-in materials and ShaderMaterial
21312
21313                 versionString = '#version 300 es\n';
21314
21315                 prefixVertex = [
21316                         'precision mediump sampler2DArray;',
21317                         '#define attribute in',
21318                         '#define varying out',
21319                         '#define texture2D texture'
21320                 ].join( '\n' ) + '\n' + prefixVertex;
21321
21322                 prefixFragment = [
21323                         '#define varying in',
21324                         ( parameters.glslVersion === GLSL3 ) ? '' : 'out highp vec4 pc_fragColor;',
21325                         ( parameters.glslVersion === GLSL3 ) ? '' : '#define gl_FragColor pc_fragColor',
21326                         '#define gl_FragDepthEXT gl_FragDepth',
21327                         '#define texture2D texture',
21328                         '#define textureCube texture',
21329                         '#define texture2DProj textureProj',
21330                         '#define texture2DLodEXT textureLod',
21331                         '#define texture2DProjLodEXT textureProjLod',
21332                         '#define textureCubeLodEXT textureLod',
21333                         '#define texture2DGradEXT textureGrad',
21334                         '#define texture2DProjGradEXT textureProjGrad',
21335                         '#define textureCubeGradEXT textureGrad'
21336                 ].join( '\n' ) + '\n' + prefixFragment;
21337
21338         }
21339
21340         const vertexGlsl = versionString + prefixVertex + vertexShader;
21341         const fragmentGlsl = versionString + prefixFragment + fragmentShader;
21342
21343         // console.log( '*VERTEX*', vertexGlsl );
21344         // console.log( '*FRAGMENT*', fragmentGlsl );
21345
21346         const glVertexShader = WebGLShader( gl, 35633, vertexGlsl );
21347         const glFragmentShader = WebGLShader( gl, 35632, fragmentGlsl );
21348
21349         gl.attachShader( program, glVertexShader );
21350         gl.attachShader( program, glFragmentShader );
21351
21352         // Force a particular attribute to index 0.
21353
21354         if ( parameters.index0AttributeName !== undefined ) {
21355
21356                 gl.bindAttribLocation( program, 0, parameters.index0AttributeName );
21357
21358         } else if ( parameters.morphTargets === true ) {
21359
21360                 // programs with morphTargets displace position out of attribute 0
21361                 gl.bindAttribLocation( program, 0, 'position' );
21362
21363         }
21364
21365         gl.linkProgram( program );
21366
21367         // check for link errors
21368         if ( renderer.debug.checkShaderErrors ) {
21369
21370                 const programLog = gl.getProgramInfoLog( program ).trim();
21371                 const vertexLog = gl.getShaderInfoLog( glVertexShader ).trim();
21372                 const fragmentLog = gl.getShaderInfoLog( glFragmentShader ).trim();
21373
21374                 let runnable = true;
21375                 let haveDiagnostics = true;
21376
21377                 if ( gl.getProgramParameter( program, 35714 ) === false ) {
21378
21379                         runnable = false;
21380
21381                         const vertexErrors = getShaderErrors( gl, glVertexShader, 'vertex' );
21382                         const fragmentErrors = getShaderErrors( gl, glFragmentShader, 'fragment' );
21383
21384                         console.error(
21385                                 'THREE.WebGLProgram: Shader Error ' + gl.getError() + ' - ' +
21386                                 'VALIDATE_STATUS ' + gl.getProgramParameter( program, 35715 ) + '\n\n' +
21387                                 'Program Info Log: ' + programLog + '\n' +
21388                                 vertexErrors + '\n' +
21389                                 fragmentErrors
21390                         );
21391
21392                 } else if ( programLog !== '' ) {
21393
21394                         console.warn( 'THREE.WebGLProgram: Program Info Log:', programLog );
21395
21396                 } else if ( vertexLog === '' || fragmentLog === '' ) {
21397
21398                         haveDiagnostics = false;
21399
21400                 }
21401
21402                 if ( haveDiagnostics ) {
21403
21404                         this.diagnostics = {
21405
21406                                 runnable: runnable,
21407
21408                                 programLog: programLog,
21409
21410                                 vertexShader: {
21411
21412                                         log: vertexLog,
21413                                         prefix: prefixVertex
21414
21415                                 },
21416
21417                                 fragmentShader: {
21418
21419                                         log: fragmentLog,
21420                                         prefix: prefixFragment
21421
21422                                 }
21423
21424                         };
21425
21426                 }
21427
21428         }
21429
21430         // Clean up
21431
21432         // Crashes in iOS9 and iOS10. #18402
21433         // gl.detachShader( program, glVertexShader );
21434         // gl.detachShader( program, glFragmentShader );
21435
21436         gl.deleteShader( glVertexShader );
21437         gl.deleteShader( glFragmentShader );
21438
21439         // set up caching for uniform locations
21440
21441         let cachedUniforms;
21442
21443         this.getUniforms = function () {
21444
21445                 if ( cachedUniforms === undefined ) {
21446
21447                         cachedUniforms = new WebGLUniforms( gl, program );
21448
21449                 }
21450
21451                 return cachedUniforms;
21452
21453         };
21454
21455         // set up caching for attribute locations
21456
21457         let cachedAttributes;
21458
21459         this.getAttributes = function () {
21460
21461                 if ( cachedAttributes === undefined ) {
21462
21463                         cachedAttributes = fetchAttributeLocations( gl, program );
21464
21465                 }
21466
21467                 return cachedAttributes;
21468
21469         };
21470
21471         // free resource
21472
21473         this.destroy = function () {
21474
21475                 bindingStates.releaseStatesOfProgram( this );
21476
21477                 gl.deleteProgram( program );
21478                 this.program = undefined;
21479
21480         };
21481
21482         //
21483
21484         this.name = parameters.shaderName;
21485         this.id = programIdCount ++;
21486         this.cacheKey = cacheKey;
21487         this.usedTimes = 1;
21488         this.program = program;
21489         this.vertexShader = glVertexShader;
21490         this.fragmentShader = glFragmentShader;
21491
21492         return this;
21493
21494 }
21495
21496 function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping ) {
21497
21498         const programs = [];
21499
21500         const isWebGL2 = capabilities.isWebGL2;
21501         const logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer;
21502         const floatVertexTextures = capabilities.floatVertexTextures;
21503         const maxVertexUniforms = capabilities.maxVertexUniforms;
21504         const vertexTextures = capabilities.vertexTextures;
21505
21506         let precision = capabilities.precision;
21507
21508         const shaderIDs = {
21509                 MeshDepthMaterial: 'depth',
21510                 MeshDistanceMaterial: 'distanceRGBA',
21511                 MeshNormalMaterial: 'normal',
21512                 MeshBasicMaterial: 'basic',
21513                 MeshLambertMaterial: 'lambert',
21514                 MeshPhongMaterial: 'phong',
21515                 MeshToonMaterial: 'toon',
21516                 MeshStandardMaterial: 'physical',
21517                 MeshPhysicalMaterial: 'physical',
21518                 MeshMatcapMaterial: 'matcap',
21519                 LineBasicMaterial: 'basic',
21520                 LineDashedMaterial: 'dashed',
21521                 PointsMaterial: 'points',
21522                 ShadowMaterial: 'shadow',
21523                 SpriteMaterial: 'sprite'
21524         };
21525
21526         const parameterNames = [
21527                 'precision', 'isWebGL2', 'supportsVertexTextures', 'outputEncoding', 'instancing', 'instancingColor',
21528                 'map', 'mapEncoding', 'matcap', 'matcapEncoding', 'envMap', 'envMapMode', 'envMapEncoding', 'envMapCubeUV',
21529                 'lightMap', 'lightMapEncoding', 'aoMap', 'emissiveMap', 'emissiveMapEncoding', 'bumpMap', 'normalMap',
21530                 'objectSpaceNormalMap', 'tangentSpaceNormalMap',
21531                 'clearcoat', 'clearcoatMap', 'clearcoatRoughnessMap', 'clearcoatNormalMap',
21532                 'displacementMap', 'specularMap', , 'roughnessMap', 'metalnessMap', 'gradientMap',
21533                 'alphaMap', 'alphaTest', 'combine', 'vertexColors', 'vertexAlphas', 'vertexTangents', 'vertexUvs', 'uvsVertexOnly', 'fog', 'useFog', 'fogExp2',
21534                 'flatShading', 'sizeAttenuation', 'logarithmicDepthBuffer', 'skinning',
21535                 'maxBones', 'useVertexTexture', 'morphTargets', 'morphNormals', 'morphTargetsCount', 'premultipliedAlpha',
21536                 'numDirLights', 'numPointLights', 'numSpotLights', 'numHemiLights', 'numRectAreaLights',
21537                 'numDirLightShadows', 'numPointLightShadows', 'numSpotLightShadows',
21538                 'shadowMapEnabled', 'shadowMapType', 'toneMapping', 'physicallyCorrectLights',
21539                 'doubleSided', 'flipSided', 'numClippingPlanes', 'numClipIntersection', 'depthPacking', 'dithering', 'format',
21540                 'specularIntensityMap', 'specularColorMap', 'specularColorMapEncoding',
21541                 'transmission', 'transmissionMap', 'thicknessMap',
21542                 'sheen', 'sheenColorMap', 'sheenColorMapEncoding', 'sheenRoughnessMap'
21543         ];
21544
21545         function getMaxBones( object ) {
21546
21547                 const skeleton = object.skeleton;
21548                 const bones = skeleton.bones;
21549
21550                 if ( floatVertexTextures ) {
21551
21552                         return 1024;
21553
21554                 } else {
21555
21556                         // default for when object is not specified
21557                         // ( for example when prebuilding shader to be used with multiple objects )
21558                         //
21559                         //  - leave some extra space for other uniforms
21560                         //  - limit here is ANGLE's 254 max uniform vectors
21561                         //    (up to 54 should be safe)
21562
21563                         const nVertexUniforms = maxVertexUniforms;
21564                         const nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 );
21565
21566                         const maxBones = Math.min( nVertexMatrices, bones.length );
21567
21568                         if ( maxBones < bones.length ) {
21569
21570                                 console.warn( 'THREE.WebGLRenderer: Skeleton has ' + bones.length + ' bones. This GPU supports ' + maxBones + '.' );
21571                                 return 0;
21572
21573                         }
21574
21575                         return maxBones;
21576
21577                 }
21578
21579         }
21580
21581         function getTextureEncodingFromMap( map ) {
21582
21583                 let encoding;
21584
21585                 if ( map && map.isTexture ) {
21586
21587                         encoding = map.encoding;
21588
21589                 } else if ( map && map.isWebGLRenderTarget ) {
21590
21591                         console.warn( 'THREE.WebGLPrograms.getTextureEncodingFromMap: don\'t use render targets as textures. Use their .texture property instead.' );
21592                         encoding = map.texture.encoding;
21593
21594                 } else {
21595
21596                         encoding = LinearEncoding;
21597
21598                 }
21599
21600                 if ( isWebGL2 && map && map.isTexture && map.format === RGBAFormat && map.type === UnsignedByteType && map.encoding === sRGBEncoding ) {
21601
21602                         encoding = LinearEncoding; // disable inline decode for sRGB textures in WebGL 2
21603
21604                 }
21605
21606                 return encoding;
21607
21608         }
21609
21610         function getParameters( material, lights, shadows, scene, object ) {
21611
21612                 const fog = scene.fog;
21613                 const environment = material.isMeshStandardMaterial ? scene.environment : null;
21614
21615                 const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment );
21616
21617                 const shaderID = shaderIDs[ material.type ];
21618
21619                 // heuristics to create shader parameters according to lights in the scene
21620                 // (not to blow over maxLights budget)
21621
21622                 const maxBones = object.isSkinnedMesh ? getMaxBones( object ) : 0;
21623
21624                 if ( material.precision !== null ) {
21625
21626                         precision = capabilities.getMaxPrecision( material.precision );
21627
21628                         if ( precision !== material.precision ) {
21629
21630                                 console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' );
21631
21632                         }
21633
21634                 }
21635
21636                 let vertexShader, fragmentShader;
21637
21638                 if ( shaderID ) {
21639
21640                         const shader = ShaderLib[ shaderID ];
21641
21642                         vertexShader = shader.vertexShader;
21643                         fragmentShader = shader.fragmentShader;
21644
21645                 } else {
21646
21647                         vertexShader = material.vertexShader;
21648                         fragmentShader = material.fragmentShader;
21649
21650                 }
21651
21652                 const currentRenderTarget = renderer.getRenderTarget();
21653
21654                 const useAlphaTest = material.alphaTest > 0;
21655                 const useClearcoat = material.clearcoat > 0;
21656
21657                 const parameters = {
21658
21659                         isWebGL2: isWebGL2,
21660
21661                         shaderID: shaderID,
21662                         shaderName: material.type,
21663
21664                         vertexShader: vertexShader,
21665                         fragmentShader: fragmentShader,
21666                         defines: material.defines,
21667
21668                         isRawShaderMaterial: material.isRawShaderMaterial === true,
21669                         glslVersion: material.glslVersion,
21670
21671                         precision: precision,
21672
21673                         instancing: object.isInstancedMesh === true,
21674                         instancingColor: object.isInstancedMesh === true && object.instanceColor !== null,
21675
21676                         supportsVertexTextures: vertexTextures,
21677                         outputEncoding: ( currentRenderTarget !== null ) ? getTextureEncodingFromMap( currentRenderTarget.texture ) : renderer.outputEncoding,
21678                         map: !! material.map,
21679                         mapEncoding: getTextureEncodingFromMap( material.map ),
21680                         matcap: !! material.matcap,
21681                         matcapEncoding: getTextureEncodingFromMap( material.matcap ),
21682                         envMap: !! envMap,
21683                         envMapMode: envMap && envMap.mapping,
21684                         envMapEncoding: getTextureEncodingFromMap( envMap ),
21685                         envMapCubeUV: ( !! envMap ) && ( ( envMap.mapping === CubeUVReflectionMapping ) || ( envMap.mapping === CubeUVRefractionMapping ) ),
21686                         lightMap: !! material.lightMap,
21687                         lightMapEncoding: getTextureEncodingFromMap( material.lightMap ),
21688                         aoMap: !! material.aoMap,
21689                         emissiveMap: !! material.emissiveMap,
21690                         emissiveMapEncoding: getTextureEncodingFromMap( material.emissiveMap ),
21691                         bumpMap: !! material.bumpMap,
21692                         normalMap: !! material.normalMap,
21693                         objectSpaceNormalMap: material.normalMapType === ObjectSpaceNormalMap,
21694                         tangentSpaceNormalMap: material.normalMapType === TangentSpaceNormalMap,
21695
21696                         clearcoat: useClearcoat,
21697                         clearcoatMap: useClearcoat && !! material.clearcoatMap,
21698                         clearcoatRoughnessMap: useClearcoat && !! material.clearcoatRoughnessMap,
21699                         clearcoatNormalMap: useClearcoat && !! material.clearcoatNormalMap,
21700
21701                         displacementMap: !! material.displacementMap,
21702                         roughnessMap: !! material.roughnessMap,
21703                         metalnessMap: !! material.metalnessMap,
21704                         specularMap: !! material.specularMap,
21705                         specularIntensityMap: !! material.specularIntensityMap,
21706                         specularColorMap: !! material.specularColorMap,
21707                         specularColorMapEncoding: getTextureEncodingFromMap( material.specularColorMap ),
21708
21709                         alphaMap: !! material.alphaMap,
21710                         alphaTest: useAlphaTest,
21711
21712                         gradientMap: !! material.gradientMap,
21713
21714                         sheen: material.sheen > 0,
21715                         sheenColorMap: !! material.sheenColorMap,
21716                         sheenColorMapEncoding: getTextureEncodingFromMap( material.sheenColorMap ),
21717                         sheenRoughnessMap: !! material.sheenRoughnessMap,
21718
21719                         transmission: material.transmission > 0,
21720                         transmissionMap: !! material.transmissionMap,
21721                         thicknessMap: !! material.thicknessMap,
21722
21723                         combine: material.combine,
21724
21725                         vertexTangents: ( !! material.normalMap && !! object.geometry && !! object.geometry.attributes.tangent ),
21726                         vertexColors: material.vertexColors,
21727                         vertexAlphas: material.vertexColors === true && !! object.geometry && !! object.geometry.attributes.color && object.geometry.attributes.color.itemSize === 4,
21728                         vertexUvs: !! material.map || !! material.bumpMap || !! material.normalMap || !! material.specularMap || !! material.alphaMap || !! material.emissiveMap || !! material.roughnessMap || !! material.metalnessMap || !! material.clearcoatMap || !! material.clearcoatRoughnessMap || !! material.clearcoatNormalMap || !! material.displacementMap || !! material.transmissionMap || !! material.thicknessMap || !! material.specularIntensityMap || !! material.specularColorMap || !! material.sheenColorMap || material.sheenRoughnessMap,
21729                         uvsVertexOnly: ! ( !! material.map || !! material.bumpMap || !! material.normalMap || !! material.specularMap || !! material.alphaMap || !! material.emissiveMap || !! material.roughnessMap || !! material.metalnessMap || !! material.clearcoatNormalMap || material.transmission > 0 || !! material.transmissionMap || !! material.thicknessMap || !! material.specularIntensityMap || !! material.specularColorMap || !! material.sheen > 0 || !! material.sheenColorMap || !! material.sheenRoughnessMap ) && !! material.displacementMap,
21730
21731                         fog: !! fog,
21732                         useFog: material.fog,
21733                         fogExp2: ( fog && fog.isFogExp2 ),
21734
21735                         flatShading: !! material.flatShading,
21736
21737                         sizeAttenuation: material.sizeAttenuation,
21738                         logarithmicDepthBuffer: logarithmicDepthBuffer,
21739
21740                         skinning: object.isSkinnedMesh === true && maxBones > 0,
21741                         maxBones: maxBones,
21742                         useVertexTexture: floatVertexTextures,
21743
21744                         morphTargets: !! object.geometry && !! object.geometry.morphAttributes.position,
21745                         morphNormals: !! object.geometry && !! object.geometry.morphAttributes.normal,
21746                         morphTargetsCount: ( !! object.geometry && !! object.geometry.morphAttributes.position ) ? object.geometry.morphAttributes.position.length : 0,
21747
21748                         numDirLights: lights.directional.length,
21749                         numPointLights: lights.point.length,
21750                         numSpotLights: lights.spot.length,
21751                         numRectAreaLights: lights.rectArea.length,
21752                         numHemiLights: lights.hemi.length,
21753
21754                         numDirLightShadows: lights.directionalShadowMap.length,
21755                         numPointLightShadows: lights.pointShadowMap.length,
21756                         numSpotLightShadows: lights.spotShadowMap.length,
21757
21758                         numClippingPlanes: clipping.numPlanes,
21759                         numClipIntersection: clipping.numIntersection,
21760
21761                         format: material.format,
21762                         dithering: material.dithering,
21763
21764                         shadowMapEnabled: renderer.shadowMap.enabled && shadows.length > 0,
21765                         shadowMapType: renderer.shadowMap.type,
21766
21767                         toneMapping: material.toneMapped ? renderer.toneMapping : NoToneMapping,
21768                         physicallyCorrectLights: renderer.physicallyCorrectLights,
21769
21770                         premultipliedAlpha: material.premultipliedAlpha,
21771
21772                         doubleSided: material.side === DoubleSide,
21773                         flipSided: material.side === BackSide,
21774
21775                         depthPacking: ( material.depthPacking !== undefined ) ? material.depthPacking : false,
21776
21777                         index0AttributeName: material.index0AttributeName,
21778
21779                         extensionDerivatives: material.extensions && material.extensions.derivatives,
21780                         extensionFragDepth: material.extensions && material.extensions.fragDepth,
21781                         extensionDrawBuffers: material.extensions && material.extensions.drawBuffers,
21782                         extensionShaderTextureLOD: material.extensions && material.extensions.shaderTextureLOD,
21783
21784                         rendererExtensionFragDepth: isWebGL2 || extensions.has( 'EXT_frag_depth' ),
21785                         rendererExtensionDrawBuffers: isWebGL2 || extensions.has( 'WEBGL_draw_buffers' ),
21786                         rendererExtensionShaderTextureLod: isWebGL2 || extensions.has( 'EXT_shader_texture_lod' ),
21787
21788                         customProgramCacheKey: material.customProgramCacheKey()
21789
21790                 };
21791
21792                 return parameters;
21793
21794         }
21795
21796         function getProgramCacheKey( parameters ) {
21797
21798                 const array = [];
21799
21800                 if ( parameters.shaderID ) {
21801
21802                         array.push( parameters.shaderID );
21803
21804                 } else {
21805
21806                         array.push( hashString( parameters.fragmentShader ) );
21807                         array.push( hashString( parameters.vertexShader ) );
21808
21809                 }
21810
21811                 if ( parameters.defines !== undefined ) {
21812
21813                         for ( const name in parameters.defines ) {
21814
21815                                 array.push( name );
21816                                 array.push( parameters.defines[ name ] );
21817
21818                         }
21819
21820                 }
21821
21822                 if ( parameters.isRawShaderMaterial === false ) {
21823
21824                         for ( let i = 0; i < parameterNames.length; i ++ ) {
21825
21826                                 array.push( parameters[ parameterNames[ i ] ] );
21827
21828                         }
21829
21830                         array.push( renderer.outputEncoding );
21831                         array.push( renderer.gammaFactor );
21832
21833                 }
21834
21835                 array.push( parameters.customProgramCacheKey );
21836
21837                 return array.join();
21838
21839         }
21840
21841         function getUniforms( material ) {
21842
21843                 const shaderID = shaderIDs[ material.type ];
21844                 let uniforms;
21845
21846                 if ( shaderID ) {
21847
21848                         const shader = ShaderLib[ shaderID ];
21849                         uniforms = UniformsUtils.clone( shader.uniforms );
21850
21851                 } else {
21852
21853                         uniforms = material.uniforms;
21854
21855                 }
21856
21857                 return uniforms;
21858
21859         }
21860
21861         function acquireProgram( parameters, cacheKey ) {
21862
21863                 let program;
21864
21865                 // Check if code has been already compiled
21866                 for ( let p = 0, pl = programs.length; p < pl; p ++ ) {
21867
21868                         const preexistingProgram = programs[ p ];
21869
21870                         if ( preexistingProgram.cacheKey === cacheKey ) {
21871
21872                                 program = preexistingProgram;
21873                                 ++ program.usedTimes;
21874
21875                                 break;
21876
21877                         }
21878
21879                 }
21880
21881                 if ( program === undefined ) {
21882
21883                         program = new WebGLProgram( renderer, cacheKey, parameters, bindingStates );
21884                         programs.push( program );
21885
21886                 }
21887
21888                 return program;
21889
21890         }
21891
21892         function releaseProgram( program ) {
21893
21894                 if ( -- program.usedTimes === 0 ) {
21895
21896                         // Remove from unordered set
21897                         const i = programs.indexOf( program );
21898                         programs[ i ] = programs[ programs.length - 1 ];
21899                         programs.pop();
21900
21901                         // Free WebGL resources
21902                         program.destroy();
21903
21904                 }
21905
21906         }
21907
21908         return {
21909                 getParameters: getParameters,
21910                 getProgramCacheKey: getProgramCacheKey,
21911                 getUniforms: getUniforms,
21912                 acquireProgram: acquireProgram,
21913                 releaseProgram: releaseProgram,
21914                 // Exposed for resource monitoring & error feedback via renderer.info:
21915                 programs: programs
21916         };
21917
21918 }
21919
21920 function WebGLProperties() {
21921
21922         let properties = new WeakMap();
21923
21924         function get( object ) {
21925
21926                 let map = properties.get( object );
21927
21928                 if ( map === undefined ) {
21929
21930                         map = {};
21931                         properties.set( object, map );
21932
21933                 }
21934
21935                 return map;
21936
21937         }
21938
21939         function remove( object ) {
21940
21941                 properties.delete( object );
21942
21943         }
21944
21945         function update( object, key, value ) {
21946
21947                 properties.get( object )[ key ] = value;
21948
21949         }
21950
21951         function dispose() {
21952
21953                 properties = new WeakMap();
21954
21955         }
21956
21957         return {
21958                 get: get,
21959                 remove: remove,
21960                 update: update,
21961                 dispose: dispose
21962         };
21963
21964 }
21965
21966 function painterSortStable( a, b ) {
21967
21968         if ( a.groupOrder !== b.groupOrder ) {
21969
21970                 return a.groupOrder - b.groupOrder;
21971
21972         } else if ( a.renderOrder !== b.renderOrder ) {
21973
21974                 return a.renderOrder - b.renderOrder;
21975
21976         } else if ( a.program !== b.program ) {
21977
21978                 return a.program.id - b.program.id;
21979
21980         } else if ( a.material.id !== b.material.id ) {
21981
21982                 return a.material.id - b.material.id;
21983
21984         } else if ( a.z !== b.z ) {
21985
21986                 return a.z - b.z;
21987
21988         } else {
21989
21990                 return a.id - b.id;
21991
21992         }
21993
21994 }
21995
21996 function reversePainterSortStable( a, b ) {
21997
21998         if ( a.groupOrder !== b.groupOrder ) {
21999
22000                 return a.groupOrder - b.groupOrder;
22001
22002         } else if ( a.renderOrder !== b.renderOrder ) {
22003
22004                 return a.renderOrder - b.renderOrder;
22005
22006         } else if ( a.z !== b.z ) {
22007
22008                 return b.z - a.z;
22009
22010         } else {
22011
22012                 return a.id - b.id;
22013
22014         }
22015
22016 }
22017
22018
22019 function WebGLRenderList( properties ) {
22020
22021         const renderItems = [];
22022         let renderItemsIndex = 0;
22023
22024         const opaque = [];
22025         const transmissive = [];
22026         const transparent = [];
22027
22028         const defaultProgram = { id: - 1 };
22029
22030         function init() {
22031
22032                 renderItemsIndex = 0;
22033
22034                 opaque.length = 0;
22035                 transmissive.length = 0;
22036                 transparent.length = 0;
22037
22038         }
22039
22040         function getNextRenderItem( object, geometry, material, groupOrder, z, group ) {
22041
22042                 let renderItem = renderItems[ renderItemsIndex ];
22043                 const materialProperties = properties.get( material );
22044
22045                 if ( renderItem === undefined ) {
22046
22047                         renderItem = {
22048                                 id: object.id,
22049                                 object: object,
22050                                 geometry: geometry,
22051                                 material: material,
22052                                 program: materialProperties.program || defaultProgram,
22053                                 groupOrder: groupOrder,
22054                                 renderOrder: object.renderOrder,
22055                                 z: z,
22056                                 group: group
22057                         };
22058
22059                         renderItems[ renderItemsIndex ] = renderItem;
22060
22061                 } else {
22062
22063                         renderItem.id = object.id;
22064                         renderItem.object = object;
22065                         renderItem.geometry = geometry;
22066                         renderItem.material = material;
22067                         renderItem.program = materialProperties.program || defaultProgram;
22068                         renderItem.groupOrder = groupOrder;
22069                         renderItem.renderOrder = object.renderOrder;
22070                         renderItem.z = z;
22071                         renderItem.group = group;
22072
22073                 }
22074
22075                 renderItemsIndex ++;
22076
22077                 return renderItem;
22078
22079         }
22080
22081         function push( object, geometry, material, groupOrder, z, group ) {
22082
22083                 const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group );
22084
22085                 if ( material.transmission > 0.0 ) {
22086
22087                         transmissive.push( renderItem );
22088
22089                 } else if ( material.transparent === true ) {
22090
22091                         transparent.push( renderItem );
22092
22093                 } else {
22094
22095                         opaque.push( renderItem );
22096
22097                 }
22098
22099         }
22100
22101         function unshift( object, geometry, material, groupOrder, z, group ) {
22102
22103                 const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group );
22104
22105                 if ( material.transmission > 0.0 ) {
22106
22107                         transmissive.unshift( renderItem );
22108
22109                 } else if ( material.transparent === true ) {
22110
22111                         transparent.unshift( renderItem );
22112
22113                 } else {
22114
22115                         opaque.unshift( renderItem );
22116
22117                 }
22118
22119         }
22120
22121         function sort( customOpaqueSort, customTransparentSort ) {
22122
22123                 if ( opaque.length > 1 ) opaque.sort( customOpaqueSort || painterSortStable );
22124                 if ( transmissive.length > 1 ) transmissive.sort( customTransparentSort || reversePainterSortStable );
22125                 if ( transparent.length > 1 ) transparent.sort( customTransparentSort || reversePainterSortStable );
22126
22127         }
22128
22129         function finish() {
22130
22131                 // Clear references from inactive renderItems in the list
22132
22133                 for ( let i = renderItemsIndex, il = renderItems.length; i < il; i ++ ) {
22134
22135                         const renderItem = renderItems[ i ];
22136
22137                         if ( renderItem.id === null ) break;
22138
22139                         renderItem.id = null;
22140                         renderItem.object = null;
22141                         renderItem.geometry = null;
22142                         renderItem.material = null;
22143                         renderItem.program = null;
22144                         renderItem.group = null;
22145
22146                 }
22147
22148         }
22149
22150         return {
22151
22152                 opaque: opaque,
22153                 transmissive: transmissive,
22154                 transparent: transparent,
22155
22156                 init: init,
22157                 push: push,
22158                 unshift: unshift,
22159                 finish: finish,
22160
22161                 sort: sort
22162         };
22163
22164 }
22165
22166 function WebGLRenderLists( properties ) {
22167
22168         let lists = new WeakMap();
22169
22170         function get( scene, renderCallDepth ) {
22171
22172                 let list;
22173
22174                 if ( lists.has( scene ) === false ) {
22175
22176                         list = new WebGLRenderList( properties );
22177                         lists.set( scene, [ list ] );
22178
22179                 } else {
22180
22181                         if ( renderCallDepth >= lists.get( scene ).length ) {
22182
22183                                 list = new WebGLRenderList( properties );
22184                                 lists.get( scene ).push( list );
22185
22186                         } else {
22187
22188                                 list = lists.get( scene )[ renderCallDepth ];
22189
22190                         }
22191
22192                 }
22193
22194                 return list;
22195
22196         }
22197
22198         function dispose() {
22199
22200                 lists = new WeakMap();
22201
22202         }
22203
22204         return {
22205                 get: get,
22206                 dispose: dispose
22207         };
22208
22209 }
22210
22211 function UniformsCache() {
22212
22213         const lights = {};
22214
22215         return {
22216
22217                 get: function ( light ) {
22218
22219                         if ( lights[ light.id ] !== undefined ) {
22220
22221                                 return lights[ light.id ];
22222
22223                         }
22224
22225                         let uniforms;
22226
22227                         switch ( light.type ) {
22228
22229                                 case 'DirectionalLight':
22230                                         uniforms = {
22231                                                 direction: new Vector3(),
22232                                                 color: new Color()
22233                                         };
22234                                         break;
22235
22236                                 case 'SpotLight':
22237                                         uniforms = {
22238                                                 position: new Vector3(),
22239                                                 direction: new Vector3(),
22240                                                 color: new Color(),
22241                                                 distance: 0,
22242                                                 coneCos: 0,
22243                                                 penumbraCos: 0,
22244                                                 decay: 0
22245                                         };
22246                                         break;
22247
22248                                 case 'PointLight':
22249                                         uniforms = {
22250                                                 position: new Vector3(),
22251                                                 color: new Color(),
22252                                                 distance: 0,
22253                                                 decay: 0
22254                                         };
22255                                         break;
22256
22257                                 case 'HemisphereLight':
22258                                         uniforms = {
22259                                                 direction: new Vector3(),
22260                                                 skyColor: new Color(),
22261                                                 groundColor: new Color()
22262                                         };
22263                                         break;
22264
22265                                 case 'RectAreaLight':
22266                                         uniforms = {
22267                                                 color: new Color(),
22268                                                 position: new Vector3(),
22269                                                 halfWidth: new Vector3(),
22270                                                 halfHeight: new Vector3()
22271                                         };
22272                                         break;
22273
22274                         }
22275
22276                         lights[ light.id ] = uniforms;
22277
22278                         return uniforms;
22279
22280                 }
22281
22282         };
22283
22284 }
22285
22286 function ShadowUniformsCache() {
22287
22288         const lights = {};
22289
22290         return {
22291
22292                 get: function ( light ) {
22293
22294                         if ( lights[ light.id ] !== undefined ) {
22295
22296                                 return lights[ light.id ];
22297
22298                         }
22299
22300                         let uniforms;
22301
22302                         switch ( light.type ) {
22303
22304                                 case 'DirectionalLight':
22305                                         uniforms = {
22306                                                 shadowBias: 0,
22307                                                 shadowNormalBias: 0,
22308                                                 shadowRadius: 1,
22309                                                 shadowMapSize: new Vector2()
22310                                         };
22311                                         break;
22312
22313                                 case 'SpotLight':
22314                                         uniforms = {
22315                                                 shadowBias: 0,
22316                                                 shadowNormalBias: 0,
22317                                                 shadowRadius: 1,
22318                                                 shadowMapSize: new Vector2()
22319                                         };
22320                                         break;
22321
22322                                 case 'PointLight':
22323                                         uniforms = {
22324                                                 shadowBias: 0,
22325                                                 shadowNormalBias: 0,
22326                                                 shadowRadius: 1,
22327                                                 shadowMapSize: new Vector2(),
22328                                                 shadowCameraNear: 1,
22329                                                 shadowCameraFar: 1000
22330                                         };
22331                                         break;
22332
22333                                 // TODO (abelnation): set RectAreaLight shadow uniforms
22334
22335                         }
22336
22337                         lights[ light.id ] = uniforms;
22338
22339                         return uniforms;
22340
22341                 }
22342
22343         };
22344
22345 }
22346
22347
22348
22349 let nextVersion = 0;
22350
22351 function shadowCastingLightsFirst( lightA, lightB ) {
22352
22353         return ( lightB.castShadow ? 1 : 0 ) - ( lightA.castShadow ? 1 : 0 );
22354
22355 }
22356
22357 function WebGLLights( extensions, capabilities ) {
22358
22359         const cache = new UniformsCache();
22360
22361         const shadowCache = ShadowUniformsCache();
22362
22363         const state = {
22364
22365                 version: 0,
22366
22367                 hash: {
22368                         directionalLength: - 1,
22369                         pointLength: - 1,
22370                         spotLength: - 1,
22371                         rectAreaLength: - 1,
22372                         hemiLength: - 1,
22373
22374                         numDirectionalShadows: - 1,
22375                         numPointShadows: - 1,
22376                         numSpotShadows: - 1
22377                 },
22378
22379                 ambient: [ 0, 0, 0 ],
22380                 probe: [],
22381                 directional: [],
22382                 directionalShadow: [],
22383                 directionalShadowMap: [],
22384                 directionalShadowMatrix: [],
22385                 spot: [],
22386                 spotShadow: [],
22387                 spotShadowMap: [],
22388                 spotShadowMatrix: [],
22389                 rectArea: [],
22390                 rectAreaLTC1: null,
22391                 rectAreaLTC2: null,
22392                 point: [],
22393                 pointShadow: [],
22394                 pointShadowMap: [],
22395                 pointShadowMatrix: [],
22396                 hemi: []
22397
22398         };
22399
22400         for ( let i = 0; i < 9; i ++ ) state.probe.push( new Vector3() );
22401
22402         const vector3 = new Vector3();
22403         const matrix4 = new Matrix4();
22404         const matrix42 = new Matrix4();
22405
22406         function setup( lights, physicallyCorrectLights ) {
22407
22408                 let r = 0, g = 0, b = 0;
22409
22410                 for ( let i = 0; i < 9; i ++ ) state.probe[ i ].set( 0, 0, 0 );
22411
22412                 let directionalLength = 0;
22413                 let pointLength = 0;
22414                 let spotLength = 0;
22415                 let rectAreaLength = 0;
22416                 let hemiLength = 0;
22417
22418                 let numDirectionalShadows = 0;
22419                 let numPointShadows = 0;
22420                 let numSpotShadows = 0;
22421
22422                 lights.sort( shadowCastingLightsFirst );
22423
22424                 // artist-friendly light intensity scaling factor
22425                 const scaleFactor = ( physicallyCorrectLights !== true ) ? Math.PI : 1;
22426
22427                 for ( let i = 0, l = lights.length; i < l; i ++ ) {
22428
22429                         const light = lights[ i ];
22430
22431                         const color = light.color;
22432                         const intensity = light.intensity;
22433                         const distance = light.distance;
22434
22435                         const shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null;
22436
22437                         if ( light.isAmbientLight ) {
22438
22439                                 r += color.r * intensity * scaleFactor;
22440                                 g += color.g * intensity * scaleFactor;
22441                                 b += color.b * intensity * scaleFactor;
22442
22443                         } else if ( light.isLightProbe ) {
22444
22445                                 for ( let j = 0; j < 9; j ++ ) {
22446
22447                                         state.probe[ j ].addScaledVector( light.sh.coefficients[ j ], intensity );
22448
22449                                 }
22450
22451                         } else if ( light.isDirectionalLight ) {
22452
22453                                 const uniforms = cache.get( light );
22454
22455                                 uniforms.color.copy( light.color ).multiplyScalar( light.intensity * scaleFactor );
22456
22457                                 if ( light.castShadow ) {
22458
22459                                         const shadow = light.shadow;
22460
22461                                         const shadowUniforms = shadowCache.get( light );
22462
22463                                         shadowUniforms.shadowBias = shadow.bias;
22464                                         shadowUniforms.shadowNormalBias = shadow.normalBias;
22465                                         shadowUniforms.shadowRadius = shadow.radius;
22466                                         shadowUniforms.shadowMapSize = shadow.mapSize;
22467
22468                                         state.directionalShadow[ directionalLength ] = shadowUniforms;
22469                                         state.directionalShadowMap[ directionalLength ] = shadowMap;
22470                                         state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix;
22471
22472                                         numDirectionalShadows ++;
22473
22474                                 }
22475
22476                                 state.directional[ directionalLength ] = uniforms;
22477
22478                                 directionalLength ++;
22479
22480                         } else if ( light.isSpotLight ) {
22481
22482                                 const uniforms = cache.get( light );
22483
22484                                 uniforms.position.setFromMatrixPosition( light.matrixWorld );
22485
22486                                 uniforms.color.copy( color ).multiplyScalar( intensity * scaleFactor );
22487                                 uniforms.distance = distance;
22488
22489                                 uniforms.coneCos = Math.cos( light.angle );
22490                                 uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) );
22491                                 uniforms.decay = light.decay;
22492
22493                                 if ( light.castShadow ) {
22494
22495                                         const shadow = light.shadow;
22496
22497                                         const shadowUniforms = shadowCache.get( light );
22498
22499                                         shadowUniforms.shadowBias = shadow.bias;
22500                                         shadowUniforms.shadowNormalBias = shadow.normalBias;
22501                                         shadowUniforms.shadowRadius = shadow.radius;
22502                                         shadowUniforms.shadowMapSize = shadow.mapSize;
22503
22504                                         state.spotShadow[ spotLength ] = shadowUniforms;
22505                                         state.spotShadowMap[ spotLength ] = shadowMap;
22506                                         state.spotShadowMatrix[ spotLength ] = light.shadow.matrix;
22507
22508                                         numSpotShadows ++;
22509
22510                                 }
22511
22512                                 state.spot[ spotLength ] = uniforms;
22513
22514                                 spotLength ++;
22515
22516                         } else if ( light.isRectAreaLight ) {
22517
22518                                 const uniforms = cache.get( light );
22519
22520                                 // (a) intensity is the total visible light emitted
22521                                 //uniforms.color.copy( color ).multiplyScalar( intensity / ( light.width * light.height * Math.PI ) );
22522
22523                                 // (b) intensity is the brightness of the light
22524                                 uniforms.color.copy( color ).multiplyScalar( intensity );
22525
22526                                 uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );
22527                                 uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );
22528
22529                                 state.rectArea[ rectAreaLength ] = uniforms;
22530
22531                                 rectAreaLength ++;
22532
22533                         } else if ( light.isPointLight ) {
22534
22535                                 const uniforms = cache.get( light );
22536
22537                                 uniforms.color.copy( light.color ).multiplyScalar( light.intensity * scaleFactor );
22538                                 uniforms.distance = light.distance;
22539                                 uniforms.decay = light.decay;
22540
22541                                 if ( light.castShadow ) {
22542
22543                                         const shadow = light.shadow;
22544
22545                                         const shadowUniforms = shadowCache.get( light );
22546
22547                                         shadowUniforms.shadowBias = shadow.bias;
22548                                         shadowUniforms.shadowNormalBias = shadow.normalBias;
22549                                         shadowUniforms.shadowRadius = shadow.radius;
22550                                         shadowUniforms.shadowMapSize = shadow.mapSize;
22551                                         shadowUniforms.shadowCameraNear = shadow.camera.near;
22552                                         shadowUniforms.shadowCameraFar = shadow.camera.far;
22553
22554                                         state.pointShadow[ pointLength ] = shadowUniforms;
22555                                         state.pointShadowMap[ pointLength ] = shadowMap;
22556                                         state.pointShadowMatrix[ pointLength ] = light.shadow.matrix;
22557
22558                                         numPointShadows ++;
22559
22560                                 }
22561
22562                                 state.point[ pointLength ] = uniforms;
22563
22564                                 pointLength ++;
22565
22566                         } else if ( light.isHemisphereLight ) {
22567
22568                                 const uniforms = cache.get( light );
22569
22570                                 uniforms.skyColor.copy( light.color ).multiplyScalar( intensity * scaleFactor );
22571                                 uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity * scaleFactor );
22572
22573                                 state.hemi[ hemiLength ] = uniforms;
22574
22575                                 hemiLength ++;
22576
22577                         }
22578
22579                 }
22580
22581                 if ( rectAreaLength > 0 ) {
22582
22583                         if ( capabilities.isWebGL2 ) {
22584
22585                                 // WebGL 2
22586
22587                                 state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1;
22588                                 state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2;
22589
22590                         } else {
22591
22592                                 // WebGL 1
22593
22594                                 if ( extensions.has( 'OES_texture_float_linear' ) === true ) {
22595
22596                                         state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1;
22597                                         state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2;
22598
22599                                 } else if ( extensions.has( 'OES_texture_half_float_linear' ) === true ) {
22600
22601                                         state.rectAreaLTC1 = UniformsLib.LTC_HALF_1;
22602                                         state.rectAreaLTC2 = UniformsLib.LTC_HALF_2;
22603
22604                                 } else {
22605
22606                                         console.error( 'THREE.WebGLRenderer: Unable to use RectAreaLight. Missing WebGL extensions.' );
22607
22608                                 }
22609
22610                         }
22611
22612                 }
22613
22614                 state.ambient[ 0 ] = r;
22615                 state.ambient[ 1 ] = g;
22616                 state.ambient[ 2 ] = b;
22617
22618                 const hash = state.hash;
22619
22620                 if ( hash.directionalLength !== directionalLength ||
22621                         hash.pointLength !== pointLength ||
22622                         hash.spotLength !== spotLength ||
22623                         hash.rectAreaLength !== rectAreaLength ||
22624                         hash.hemiLength !== hemiLength ||
22625                         hash.numDirectionalShadows !== numDirectionalShadows ||
22626                         hash.numPointShadows !== numPointShadows ||
22627                         hash.numSpotShadows !== numSpotShadows ) {
22628
22629                         state.directional.length = directionalLength;
22630                         state.spot.length = spotLength;
22631                         state.rectArea.length = rectAreaLength;
22632                         state.point.length = pointLength;
22633                         state.hemi.length = hemiLength;
22634
22635                         state.directionalShadow.length = numDirectionalShadows;
22636                         state.directionalShadowMap.length = numDirectionalShadows;
22637                         state.pointShadow.length = numPointShadows;
22638                         state.pointShadowMap.length = numPointShadows;
22639                         state.spotShadow.length = numSpotShadows;
22640                         state.spotShadowMap.length = numSpotShadows;
22641                         state.directionalShadowMatrix.length = numDirectionalShadows;
22642                         state.pointShadowMatrix.length = numPointShadows;
22643                         state.spotShadowMatrix.length = numSpotShadows;
22644
22645                         hash.directionalLength = directionalLength;
22646                         hash.pointLength = pointLength;
22647                         hash.spotLength = spotLength;
22648                         hash.rectAreaLength = rectAreaLength;
22649                         hash.hemiLength = hemiLength;
22650
22651                         hash.numDirectionalShadows = numDirectionalShadows;
22652                         hash.numPointShadows = numPointShadows;
22653                         hash.numSpotShadows = numSpotShadows;
22654
22655                         state.version = nextVersion ++;
22656
22657                 }
22658
22659         }
22660
22661         function setupView( lights, camera ) {
22662
22663                 let directionalLength = 0;
22664                 let pointLength = 0;
22665                 let spotLength = 0;
22666                 let rectAreaLength = 0;
22667                 let hemiLength = 0;
22668
22669                 const viewMatrix = camera.matrixWorldInverse;
22670
22671                 for ( let i = 0, l = lights.length; i < l; i ++ ) {
22672
22673                         const light = lights[ i ];
22674
22675                         if ( light.isDirectionalLight ) {
22676
22677                                 const uniforms = state.directional[ directionalLength ];
22678
22679                                 uniforms.direction.setFromMatrixPosition( light.matrixWorld );
22680                                 vector3.setFromMatrixPosition( light.target.matrixWorld );
22681                                 uniforms.direction.sub( vector3 );
22682                                 uniforms.direction.transformDirection( viewMatrix );
22683
22684                                 directionalLength ++;
22685
22686                         } else if ( light.isSpotLight ) {
22687
22688                                 const uniforms = state.spot[ spotLength ];
22689
22690                                 uniforms.position.setFromMatrixPosition( light.matrixWorld );
22691                                 uniforms.position.applyMatrix4( viewMatrix );
22692
22693                                 uniforms.direction.setFromMatrixPosition( light.matrixWorld );
22694                                 vector3.setFromMatrixPosition( light.target.matrixWorld );
22695                                 uniforms.direction.sub( vector3 );
22696                                 uniforms.direction.transformDirection( viewMatrix );
22697
22698                                 spotLength ++;
22699
22700                         } else if ( light.isRectAreaLight ) {
22701
22702                                 const uniforms = state.rectArea[ rectAreaLength ];
22703
22704                                 uniforms.position.setFromMatrixPosition( light.matrixWorld );
22705                                 uniforms.position.applyMatrix4( viewMatrix );
22706
22707                                 // extract local rotation of light to derive width/height half vectors
22708                                 matrix42.identity();
22709                                 matrix4.copy( light.matrixWorld );
22710                                 matrix4.premultiply( viewMatrix );
22711                                 matrix42.extractRotation( matrix4 );
22712
22713                                 uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );
22714                                 uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );
22715
22716                                 uniforms.halfWidth.applyMatrix4( matrix42 );
22717                                 uniforms.halfHeight.applyMatrix4( matrix42 );
22718
22719                                 rectAreaLength ++;
22720
22721                         } else if ( light.isPointLight ) {
22722
22723                                 const uniforms = state.point[ pointLength ];
22724
22725                                 uniforms.position.setFromMatrixPosition( light.matrixWorld );
22726                                 uniforms.position.applyMatrix4( viewMatrix );
22727
22728                                 pointLength ++;
22729
22730                         } else if ( light.isHemisphereLight ) {
22731
22732                                 const uniforms = state.hemi[ hemiLength ];
22733
22734                                 uniforms.direction.setFromMatrixPosition( light.matrixWorld );
22735                                 uniforms.direction.transformDirection( viewMatrix );
22736                                 uniforms.direction.normalize();
22737
22738                                 hemiLength ++;
22739
22740                         }
22741
22742                 }
22743
22744         }
22745
22746         return {
22747                 setup: setup,
22748                 setupView: setupView,
22749                 state: state
22750         };
22751
22752 }
22753
22754 function WebGLRenderState( extensions, capabilities ) {
22755
22756         const lights = new WebGLLights( extensions, capabilities );
22757
22758         const lightsArray = [];
22759         const shadowsArray = [];
22760
22761         function init() {
22762
22763                 lightsArray.length = 0;
22764                 shadowsArray.length = 0;
22765
22766         }
22767
22768         function pushLight( light ) {
22769
22770                 lightsArray.push( light );
22771
22772         }
22773
22774         function pushShadow( shadowLight ) {
22775
22776                 shadowsArray.push( shadowLight );
22777
22778         }
22779
22780         function setupLights( physicallyCorrectLights ) {
22781
22782                 lights.setup( lightsArray, physicallyCorrectLights );
22783
22784         }
22785
22786         function setupLightsView( camera ) {
22787
22788                 lights.setupView( lightsArray, camera );
22789
22790         }
22791
22792         const state = {
22793                 lightsArray: lightsArray,
22794                 shadowsArray: shadowsArray,
22795
22796                 lights: lights
22797         };
22798
22799         return {
22800                 init: init,
22801                 state: state,
22802                 setupLights: setupLights,
22803                 setupLightsView: setupLightsView,
22804
22805                 pushLight: pushLight,
22806                 pushShadow: pushShadow
22807         };
22808
22809 }
22810
22811 function WebGLRenderStates( extensions, capabilities ) {
22812
22813         let renderStates = new WeakMap();
22814
22815         function get( scene, renderCallDepth = 0 ) {
22816
22817                 let renderState;
22818
22819                 if ( renderStates.has( scene ) === false ) {
22820
22821                         renderState = new WebGLRenderState( extensions, capabilities );
22822                         renderStates.set( scene, [ renderState ] );
22823
22824                 } else {
22825
22826                         if ( renderCallDepth >= renderStates.get( scene ).length ) {
22827
22828                                 renderState = new WebGLRenderState( extensions, capabilities );
22829                                 renderStates.get( scene ).push( renderState );
22830
22831                         } else {
22832
22833                                 renderState = renderStates.get( scene )[ renderCallDepth ];
22834
22835                         }
22836
22837                 }
22838
22839                 return renderState;
22840
22841         }
22842
22843         function dispose() {
22844
22845                 renderStates = new WeakMap();
22846
22847         }
22848
22849         return {
22850                 get: get,
22851                 dispose: dispose
22852         };
22853
22854 }
22855
22856 /**
22857  * parameters = {
22858  *
22859  *  opacity: <float>,
22860  *
22861  *  map: new THREE.Texture( <Image> ),
22862  *
22863  *  alphaMap: new THREE.Texture( <Image> ),
22864  *
22865  *  displacementMap: new THREE.Texture( <Image> ),
22866  *  displacementScale: <float>,
22867  *  displacementBias: <float>,
22868  *
22869  *  wireframe: <boolean>,
22870  *  wireframeLinewidth: <float>
22871  * }
22872  */
22873
22874 class MeshDepthMaterial extends Material {
22875
22876         constructor( parameters ) {
22877
22878                 super();
22879
22880                 this.type = 'MeshDepthMaterial';
22881
22882                 this.depthPacking = BasicDepthPacking;
22883
22884                 this.map = null;
22885
22886                 this.alphaMap = null;
22887
22888                 this.displacementMap = null;
22889                 this.displacementScale = 1;
22890                 this.displacementBias = 0;
22891
22892                 this.wireframe = false;
22893                 this.wireframeLinewidth = 1;
22894
22895                 this.fog = false;
22896
22897                 this.setValues( parameters );
22898
22899         }
22900
22901         copy( source ) {
22902
22903                 super.copy( source );
22904
22905                 this.depthPacking = source.depthPacking;
22906
22907                 this.map = source.map;
22908
22909                 this.alphaMap = source.alphaMap;
22910
22911                 this.displacementMap = source.displacementMap;
22912                 this.displacementScale = source.displacementScale;
22913                 this.displacementBias = source.displacementBias;
22914
22915                 this.wireframe = source.wireframe;
22916                 this.wireframeLinewidth = source.wireframeLinewidth;
22917
22918                 return this;
22919
22920         }
22921
22922 }
22923
22924 MeshDepthMaterial.prototype.isMeshDepthMaterial = true;
22925
22926 /**
22927  * parameters = {
22928  *
22929  *  referencePosition: <float>,
22930  *  nearDistance: <float>,
22931  *  farDistance: <float>,
22932  *
22933  *  map: new THREE.Texture( <Image> ),
22934  *
22935  *  alphaMap: new THREE.Texture( <Image> ),
22936  *
22937  *  displacementMap: new THREE.Texture( <Image> ),
22938  *  displacementScale: <float>,
22939  *  displacementBias: <float>
22940  *
22941  * }
22942  */
22943
22944 class MeshDistanceMaterial extends Material {
22945
22946         constructor( parameters ) {
22947
22948                 super();
22949
22950                 this.type = 'MeshDistanceMaterial';
22951
22952                 this.referencePosition = new Vector3();
22953                 this.nearDistance = 1;
22954                 this.farDistance = 1000;
22955
22956                 this.map = null;
22957
22958                 this.alphaMap = null;
22959
22960                 this.displacementMap = null;
22961                 this.displacementScale = 1;
22962                 this.displacementBias = 0;
22963
22964                 this.fog = false;
22965
22966                 this.setValues( parameters );
22967
22968         }
22969
22970         copy( source ) {
22971
22972                 super.copy( source );
22973
22974                 this.referencePosition.copy( source.referencePosition );
22975                 this.nearDistance = source.nearDistance;
22976                 this.farDistance = source.farDistance;
22977
22978                 this.map = source.map;
22979
22980                 this.alphaMap = source.alphaMap;
22981
22982                 this.displacementMap = source.displacementMap;
22983                 this.displacementScale = source.displacementScale;
22984                 this.displacementBias = source.displacementBias;
22985
22986                 return this;
22987
22988         }
22989
22990 }
22991
22992 MeshDistanceMaterial.prototype.isMeshDistanceMaterial = true;
22993
22994 const vertex = "void main() {\n\tgl_Position = vec4( position, 1.0 );\n}";
22995
22996 const fragment = "uniform sampler2D shadow_pass;\nuniform vec2 resolution;\nuniform float radius;\n#include <packing>\nvoid main() {\n\tconst float samples = float( VSM_SAMPLES );\n\tfloat mean = 0.0;\n\tfloat squared_mean = 0.0;\n\tfloat uvStride = samples <= 1.0 ? 0.0 : 2.0 / ( samples - 1.0 );\n\tfloat uvStart = samples <= 1.0 ? 0.0 : - 1.0;\n\tfor ( float i = 0.0; i < samples; i ++ ) {\n\t\tfloat uvOffset = uvStart + i * uvStride;\n\t\t#ifdef HORIZONTAL_PASS\n\t\t\tvec2 distribution = unpackRGBATo2Half( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( uvOffset, 0.0 ) * radius ) / resolution ) );\n\t\t\tmean += distribution.x;\n\t\t\tsquared_mean += distribution.y * distribution.y + distribution.x * distribution.x;\n\t\t#else\n\t\t\tfloat depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( 0.0, uvOffset ) * radius ) / resolution ) );\n\t\t\tmean += depth;\n\t\t\tsquared_mean += depth * depth;\n\t\t#endif\n\t}\n\tmean = mean / samples;\n\tsquared_mean = squared_mean / samples;\n\tfloat std_dev = sqrt( squared_mean - mean * mean );\n\tgl_FragColor = pack2HalfToRGBA( vec2( mean, std_dev ) );\n}";
22997
22998 function WebGLShadowMap( _renderer, _objects, _capabilities ) {
22999
23000         let _frustum = new Frustum();
23001
23002         const _shadowMapSize = new Vector2(),
23003                 _viewportSize = new Vector2(),
23004
23005                 _viewport = new Vector4(),
23006
23007                 _depthMaterial = new MeshDepthMaterial( { depthPacking: RGBADepthPacking } ),
23008                 _distanceMaterial = new MeshDistanceMaterial(),
23009
23010                 _materialCache = {},
23011
23012                 _maxTextureSize = _capabilities.maxTextureSize;
23013
23014         const shadowSide = { 0: BackSide, 1: FrontSide, 2: DoubleSide };
23015
23016         const shadowMaterialVertical = new ShaderMaterial( {
23017                 defines: {
23018                         VSM_SAMPLES: 8
23019                 },
23020                 uniforms: {
23021                         shadow_pass: { value: null },
23022                         resolution: { value: new Vector2() },
23023                         radius: { value: 4.0 }
23024                 },
23025
23026                 vertexShader: vertex,
23027                 fragmentShader: fragment
23028
23029         } );
23030
23031         const shadowMaterialHorizontal = shadowMaterialVertical.clone();
23032         shadowMaterialHorizontal.defines.HORIZONTAL_PASS = 1;
23033
23034         const fullScreenTri = new BufferGeometry();
23035         fullScreenTri.setAttribute(
23036                 'position',
23037                 new BufferAttribute(
23038                         new Float32Array( [ - 1, - 1, 0.5, 3, - 1, 0.5, - 1, 3, 0.5 ] ),
23039                         3
23040                 )
23041         );
23042
23043         const fullScreenMesh = new Mesh( fullScreenTri, shadowMaterialVertical );
23044
23045         const scope = this;
23046
23047         this.enabled = false;
23048
23049         this.autoUpdate = true;
23050         this.needsUpdate = false;
23051
23052         this.type = PCFShadowMap;
23053
23054         this.render = function ( lights, scene, camera ) {
23055
23056                 if ( scope.enabled === false ) return;
23057                 if ( scope.autoUpdate === false && scope.needsUpdate === false ) return;
23058
23059                 if ( lights.length === 0 ) return;
23060
23061                 const currentRenderTarget = _renderer.getRenderTarget();
23062                 const activeCubeFace = _renderer.getActiveCubeFace();
23063                 const activeMipmapLevel = _renderer.getActiveMipmapLevel();
23064
23065                 const _state = _renderer.state;
23066
23067                 // Set GL state for depth map.
23068                 _state.setBlending( NoBlending );
23069                 _state.buffers.color.setClear( 1, 1, 1, 1 );
23070                 _state.buffers.depth.setTest( true );
23071                 _state.setScissorTest( false );
23072
23073                 // render depth map
23074
23075                 for ( let i = 0, il = lights.length; i < il; i ++ ) {
23076
23077                         const light = lights[ i ];
23078                         const shadow = light.shadow;
23079
23080                         if ( shadow === undefined ) {
23081
23082                                 console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' );
23083                                 continue;
23084
23085                         }
23086
23087                         if ( shadow.autoUpdate === false && shadow.needsUpdate === false ) continue;
23088
23089                         _shadowMapSize.copy( shadow.mapSize );
23090
23091                         const shadowFrameExtents = shadow.getFrameExtents();
23092
23093                         _shadowMapSize.multiply( shadowFrameExtents );
23094
23095                         _viewportSize.copy( shadow.mapSize );
23096
23097                         if ( _shadowMapSize.x > _maxTextureSize || _shadowMapSize.y > _maxTextureSize ) {
23098
23099                                 if ( _shadowMapSize.x > _maxTextureSize ) {
23100
23101                                         _viewportSize.x = Math.floor( _maxTextureSize / shadowFrameExtents.x );
23102                                         _shadowMapSize.x = _viewportSize.x * shadowFrameExtents.x;
23103                                         shadow.mapSize.x = _viewportSize.x;
23104
23105                                 }
23106
23107                                 if ( _shadowMapSize.y > _maxTextureSize ) {
23108
23109                                         _viewportSize.y = Math.floor( _maxTextureSize / shadowFrameExtents.y );
23110                                         _shadowMapSize.y = _viewportSize.y * shadowFrameExtents.y;
23111                                         shadow.mapSize.y = _viewportSize.y;
23112
23113                                 }
23114
23115                         }
23116
23117                         if ( shadow.map === null && ! shadow.isPointLightShadow && this.type === VSMShadowMap ) {
23118
23119                                 const pars = { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat };
23120
23121                                 shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars );
23122                                 shadow.map.texture.name = light.name + '.shadowMap';
23123
23124                                 shadow.mapPass = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars );
23125
23126                                 shadow.camera.updateProjectionMatrix();
23127
23128                         }
23129
23130                         if ( shadow.map === null ) {
23131
23132                                 const pars = { minFilter: NearestFilter, magFilter: NearestFilter, format: RGBAFormat };
23133
23134                                 shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars );
23135                                 shadow.map.texture.name = light.name + '.shadowMap';
23136
23137                                 shadow.camera.updateProjectionMatrix();
23138
23139                         }
23140
23141                         _renderer.setRenderTarget( shadow.map );
23142                         _renderer.clear();
23143
23144                         const viewportCount = shadow.getViewportCount();
23145
23146                         for ( let vp = 0; vp < viewportCount; vp ++ ) {
23147
23148                                 const viewport = shadow.getViewport( vp );
23149
23150                                 _viewport.set(
23151                                         _viewportSize.x * viewport.x,
23152                                         _viewportSize.y * viewport.y,
23153                                         _viewportSize.x * viewport.z,
23154                                         _viewportSize.y * viewport.w
23155                                 );
23156
23157                                 _state.viewport( _viewport );
23158
23159                                 shadow.updateMatrices( light, vp );
23160
23161                                 _frustum = shadow.getFrustum();
23162
23163                                 renderObject( scene, camera, shadow.camera, light, this.type );
23164
23165                         }
23166
23167                         // do blur pass for VSM
23168
23169                         if ( ! shadow.isPointLightShadow && this.type === VSMShadowMap ) {
23170
23171                                 VSMPass( shadow, camera );
23172
23173                         }
23174
23175                         shadow.needsUpdate = false;
23176
23177                 }
23178
23179                 scope.needsUpdate = false;
23180
23181                 _renderer.setRenderTarget( currentRenderTarget, activeCubeFace, activeMipmapLevel );
23182
23183         };
23184
23185         function VSMPass( shadow, camera ) {
23186
23187                 const geometry = _objects.update( fullScreenMesh );
23188
23189                 if ( shadowMaterialVertical.defines.VSM_SAMPLES !== shadow.blurSamples ) {
23190
23191                         shadowMaterialVertical.defines.VSM_SAMPLES = shadow.blurSamples;
23192                         shadowMaterialHorizontal.defines.VSM_SAMPLES = shadow.blurSamples;
23193
23194                         shadowMaterialVertical.needsUpdate = true;
23195                         shadowMaterialHorizontal.needsUpdate = true;
23196
23197                 }
23198
23199                 // vertical pass
23200
23201                 shadowMaterialVertical.uniforms.shadow_pass.value = shadow.map.texture;
23202                 shadowMaterialVertical.uniforms.resolution.value = shadow.mapSize;
23203                 shadowMaterialVertical.uniforms.radius.value = shadow.radius;
23204                 _renderer.setRenderTarget( shadow.mapPass );
23205                 _renderer.clear();
23206                 _renderer.renderBufferDirect( camera, null, geometry, shadowMaterialVertical, fullScreenMesh, null );
23207
23208                 // horizontal pass
23209
23210                 shadowMaterialHorizontal.uniforms.shadow_pass.value = shadow.mapPass.texture;
23211                 shadowMaterialHorizontal.uniforms.resolution.value = shadow.mapSize;
23212                 shadowMaterialHorizontal.uniforms.radius.value = shadow.radius;
23213                 _renderer.setRenderTarget( shadow.map );
23214                 _renderer.clear();
23215                 _renderer.renderBufferDirect( camera, null, geometry, shadowMaterialHorizontal, fullScreenMesh, null );
23216
23217         }
23218
23219         function getDepthMaterial( object, geometry, material, light, shadowCameraNear, shadowCameraFar, type ) {
23220
23221                 let result = null;
23222
23223                 const customMaterial = ( light.isPointLight === true ) ? object.customDistanceMaterial : object.customDepthMaterial;
23224
23225                 if ( customMaterial !== undefined ) {
23226
23227                         result = customMaterial;
23228
23229                 } else {
23230
23231                         result = ( light.isPointLight === true ) ? _distanceMaterial : _depthMaterial;
23232
23233                 }
23234
23235                 if ( ( _renderer.localClippingEnabled && material.clipShadows === true && material.clippingPlanes.length !== 0 ) ||
23236                         ( material.displacementMap && material.displacementScale !== 0 ) ||
23237                         ( material.alphaMap && material.alphaTest > 0 ) ) {
23238
23239                         // in this case we need a unique material instance reflecting the
23240                         // appropriate state
23241
23242                         const keyA = result.uuid, keyB = material.uuid;
23243
23244                         let materialsForVariant = _materialCache[ keyA ];
23245
23246                         if ( materialsForVariant === undefined ) {
23247
23248                                 materialsForVariant = {};
23249                                 _materialCache[ keyA ] = materialsForVariant;
23250
23251                         }
23252
23253                         let cachedMaterial = materialsForVariant[ keyB ];
23254
23255                         if ( cachedMaterial === undefined ) {
23256
23257                                 cachedMaterial = result.clone();
23258                                 materialsForVariant[ keyB ] = cachedMaterial;
23259
23260                         }
23261
23262                         result = cachedMaterial;
23263
23264                 }
23265
23266                 result.visible = material.visible;
23267                 result.wireframe = material.wireframe;
23268
23269                 if ( type === VSMShadowMap ) {
23270
23271                         result.side = ( material.shadowSide !== null ) ? material.shadowSide : material.side;
23272
23273                 } else {
23274
23275                         result.side = ( material.shadowSide !== null ) ? material.shadowSide : shadowSide[ material.side ];
23276
23277                 }
23278
23279                 result.alphaMap = material.alphaMap;
23280                 result.alphaTest = material.alphaTest;
23281
23282                 result.clipShadows = material.clipShadows;
23283                 result.clippingPlanes = material.clippingPlanes;
23284                 result.clipIntersection = material.clipIntersection;
23285
23286                 result.displacementMap = material.displacementMap;
23287                 result.displacementScale = material.displacementScale;
23288                 result.displacementBias = material.displacementBias;
23289
23290                 result.wireframeLinewidth = material.wireframeLinewidth;
23291                 result.linewidth = material.linewidth;
23292
23293                 if ( light.isPointLight === true && result.isMeshDistanceMaterial === true ) {
23294
23295                         result.referencePosition.setFromMatrixPosition( light.matrixWorld );
23296                         result.nearDistance = shadowCameraNear;
23297                         result.farDistance = shadowCameraFar;
23298
23299                 }
23300
23301                 return result;
23302
23303         }
23304
23305         function renderObject( object, camera, shadowCamera, light, type ) {
23306
23307                 if ( object.visible === false ) return;
23308
23309                 const visible = object.layers.test( camera.layers );
23310
23311                 if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) {
23312
23313                         if ( ( object.castShadow || ( object.receiveShadow && type === VSMShadowMap ) ) && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) {
23314
23315                                 object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );
23316
23317                                 const geometry = _objects.update( object );
23318                                 const material = object.material;
23319
23320                                 if ( Array.isArray( material ) ) {
23321
23322                                         const groups = geometry.groups;
23323
23324                                         for ( let k = 0, kl = groups.length; k < kl; k ++ ) {
23325
23326                                                 const group = groups[ k ];
23327                                                 const groupMaterial = material[ group.materialIndex ];
23328
23329                                                 if ( groupMaterial && groupMaterial.visible ) {
23330
23331                                                         const depthMaterial = getDepthMaterial( object, geometry, groupMaterial, light, shadowCamera.near, shadowCamera.far, type );
23332
23333                                                         _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group );
23334
23335                                                 }
23336
23337                                         }
23338
23339                                 } else if ( material.visible ) {
23340
23341                                         const depthMaterial = getDepthMaterial( object, geometry, material, light, shadowCamera.near, shadowCamera.far, type );
23342
23343                                         _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null );
23344
23345                                 }
23346
23347                         }
23348
23349                 }
23350
23351                 const children = object.children;
23352
23353                 for ( let i = 0, l = children.length; i < l; i ++ ) {
23354
23355                         renderObject( children[ i ], camera, shadowCamera, light, type );
23356
23357                 }
23358
23359         }
23360
23361 }
23362
23363 function WebGLState( gl, extensions, capabilities ) {
23364
23365         const isWebGL2 = capabilities.isWebGL2;
23366
23367         function ColorBuffer() {
23368
23369                 let locked = false;
23370
23371                 const color = new Vector4();
23372                 let currentColorMask = null;
23373                 const currentColorClear = new Vector4( 0, 0, 0, 0 );
23374
23375                 return {
23376
23377                         setMask: function ( colorMask ) {
23378
23379                                 if ( currentColorMask !== colorMask && ! locked ) {
23380
23381                                         gl.colorMask( colorMask, colorMask, colorMask, colorMask );
23382                                         currentColorMask = colorMask;
23383
23384                                 }
23385
23386                         },
23387
23388                         setLocked: function ( lock ) {
23389
23390                                 locked = lock;
23391
23392                         },
23393
23394                         setClear: function ( r, g, b, a, premultipliedAlpha ) {
23395
23396                                 if ( premultipliedAlpha === true ) {
23397
23398                                         r *= a; g *= a; b *= a;
23399
23400                                 }
23401
23402                                 color.set( r, g, b, a );
23403
23404                                 if ( currentColorClear.equals( color ) === false ) {
23405
23406                                         gl.clearColor( r, g, b, a );
23407                                         currentColorClear.copy( color );
23408
23409                                 }
23410
23411                         },
23412
23413                         reset: function () {
23414
23415                                 locked = false;
23416
23417                                 currentColorMask = null;
23418                                 currentColorClear.set( - 1, 0, 0, 0 ); // set to invalid state
23419
23420                         }
23421
23422                 };
23423
23424         }
23425
23426         function DepthBuffer() {
23427
23428                 let locked = false;
23429
23430                 let currentDepthMask = null;
23431                 let currentDepthFunc = null;
23432                 let currentDepthClear = null;
23433
23434                 return {
23435
23436                         setTest: function ( depthTest ) {
23437
23438                                 if ( depthTest ) {
23439
23440                                         enable( 2929 );
23441
23442                                 } else {
23443
23444                                         disable( 2929 );
23445
23446                                 }
23447
23448                         },
23449
23450                         setMask: function ( depthMask ) {
23451
23452                                 if ( currentDepthMask !== depthMask && ! locked ) {
23453
23454                                         gl.depthMask( depthMask );
23455                                         currentDepthMask = depthMask;
23456
23457                                 }
23458
23459                         },
23460
23461                         setFunc: function ( depthFunc ) {
23462
23463                                 if ( currentDepthFunc !== depthFunc ) {
23464
23465                                         if ( depthFunc ) {
23466
23467                                                 switch ( depthFunc ) {
23468
23469                                                         case NeverDepth:
23470
23471                                                                 gl.depthFunc( 512 );
23472                                                                 break;
23473
23474                                                         case AlwaysDepth:
23475
23476                                                                 gl.depthFunc( 519 );
23477                                                                 break;
23478
23479                                                         case LessDepth:
23480
23481                                                                 gl.depthFunc( 513 );
23482                                                                 break;
23483
23484                                                         case LessEqualDepth:
23485
23486                                                                 gl.depthFunc( 515 );
23487                                                                 break;
23488
23489                                                         case EqualDepth:
23490
23491                                                                 gl.depthFunc( 514 );
23492                                                                 break;
23493
23494                                                         case GreaterEqualDepth:
23495
23496                                                                 gl.depthFunc( 518 );
23497                                                                 break;
23498
23499                                                         case GreaterDepth:
23500
23501                                                                 gl.depthFunc( 516 );
23502                                                                 break;
23503
23504                                                         case NotEqualDepth:
23505
23506                                                                 gl.depthFunc( 517 );
23507                                                                 break;
23508
23509                                                         default:
23510
23511                                                                 gl.depthFunc( 515 );
23512
23513                                                 }
23514
23515                                         } else {
23516
23517                                                 gl.depthFunc( 515 );
23518
23519                                         }
23520
23521                                         currentDepthFunc = depthFunc;
23522
23523                                 }
23524
23525                         },
23526
23527                         setLocked: function ( lock ) {
23528
23529                                 locked = lock;
23530
23531                         },
23532
23533                         setClear: function ( depth ) {
23534
23535                                 if ( currentDepthClear !== depth ) {
23536
23537                                         gl.clearDepth( depth );
23538                                         currentDepthClear = depth;
23539
23540                                 }
23541
23542                         },
23543
23544                         reset: function () {
23545
23546                                 locked = false;
23547
23548                                 currentDepthMask = null;
23549                                 currentDepthFunc = null;
23550                                 currentDepthClear = null;
23551
23552                         }
23553
23554                 };
23555
23556         }
23557
23558         function StencilBuffer() {
23559
23560                 let locked = false;
23561
23562                 let currentStencilMask = null;
23563                 let currentStencilFunc = null;
23564                 let currentStencilRef = null;
23565                 let currentStencilFuncMask = null;
23566                 let currentStencilFail = null;
23567                 let currentStencilZFail = null;
23568                 let currentStencilZPass = null;
23569                 let currentStencilClear = null;
23570
23571                 return {
23572
23573                         setTest: function ( stencilTest ) {
23574
23575                                 if ( ! locked ) {
23576
23577                                         if ( stencilTest ) {
23578
23579                                                 enable( 2960 );
23580
23581                                         } else {
23582
23583                                                 disable( 2960 );
23584
23585                                         }
23586
23587                                 }
23588
23589                         },
23590
23591                         setMask: function ( stencilMask ) {
23592
23593                                 if ( currentStencilMask !== stencilMask && ! locked ) {
23594
23595                                         gl.stencilMask( stencilMask );
23596                                         currentStencilMask = stencilMask;
23597
23598                                 }
23599
23600                         },
23601
23602                         setFunc: function ( stencilFunc, stencilRef, stencilMask ) {
23603
23604                                 if ( currentStencilFunc !== stencilFunc ||
23605                                      currentStencilRef !== stencilRef ||
23606                                      currentStencilFuncMask !== stencilMask ) {
23607
23608                                         gl.stencilFunc( stencilFunc, stencilRef, stencilMask );
23609
23610                                         currentStencilFunc = stencilFunc;
23611                                         currentStencilRef = stencilRef;
23612                                         currentStencilFuncMask = stencilMask;
23613
23614                                 }
23615
23616                         },
23617
23618                         setOp: function ( stencilFail, stencilZFail, stencilZPass ) {
23619
23620                                 if ( currentStencilFail !== stencilFail ||
23621                                      currentStencilZFail !== stencilZFail ||
23622                                      currentStencilZPass !== stencilZPass ) {
23623
23624                                         gl.stencilOp( stencilFail, stencilZFail, stencilZPass );
23625
23626                                         currentStencilFail = stencilFail;
23627                                         currentStencilZFail = stencilZFail;
23628                                         currentStencilZPass = stencilZPass;
23629
23630                                 }
23631
23632                         },
23633
23634                         setLocked: function ( lock ) {
23635
23636                                 locked = lock;
23637
23638                         },
23639
23640                         setClear: function ( stencil ) {
23641
23642                                 if ( currentStencilClear !== stencil ) {
23643
23644                                         gl.clearStencil( stencil );
23645                                         currentStencilClear = stencil;
23646
23647                                 }
23648
23649                         },
23650
23651                         reset: function () {
23652
23653                                 locked = false;
23654
23655                                 currentStencilMask = null;
23656                                 currentStencilFunc = null;
23657                                 currentStencilRef = null;
23658                                 currentStencilFuncMask = null;
23659                                 currentStencilFail = null;
23660                                 currentStencilZFail = null;
23661                                 currentStencilZPass = null;
23662                                 currentStencilClear = null;
23663
23664                         }
23665
23666                 };
23667
23668         }
23669
23670         //
23671
23672         const colorBuffer = new ColorBuffer();
23673         const depthBuffer = new DepthBuffer();
23674         const stencilBuffer = new StencilBuffer();
23675
23676         let enabledCapabilities = {};
23677
23678         let xrFramebuffer = null;
23679         let currentBoundFramebuffers = {};
23680
23681         let currentProgram = null;
23682
23683         let currentBlendingEnabled = false;
23684         let currentBlending = null;
23685         let currentBlendEquation = null;
23686         let currentBlendSrc = null;
23687         let currentBlendDst = null;
23688         let currentBlendEquationAlpha = null;
23689         let currentBlendSrcAlpha = null;
23690         let currentBlendDstAlpha = null;
23691         let currentPremultipledAlpha = false;
23692
23693         let currentFlipSided = null;
23694         let currentCullFace = null;
23695
23696         let currentLineWidth = null;
23697
23698         let currentPolygonOffsetFactor = null;
23699         let currentPolygonOffsetUnits = null;
23700
23701         const maxTextures = gl.getParameter( 35661 );
23702
23703         let lineWidthAvailable = false;
23704         let version = 0;
23705         const glVersion = gl.getParameter( 7938 );
23706
23707         if ( glVersion.indexOf( 'WebGL' ) !== - 1 ) {
23708
23709                 version = parseFloat( /^WebGL (\d)/.exec( glVersion )[ 1 ] );
23710                 lineWidthAvailable = ( version >= 1.0 );
23711
23712         } else if ( glVersion.indexOf( 'OpenGL ES' ) !== - 1 ) {
23713
23714                 version = parseFloat( /^OpenGL ES (\d)/.exec( glVersion )[ 1 ] );
23715                 lineWidthAvailable = ( version >= 2.0 );
23716
23717         }
23718
23719         let currentTextureSlot = null;
23720         let currentBoundTextures = {};
23721
23722         const scissorParam = gl.getParameter( 3088 );
23723         const viewportParam = gl.getParameter( 2978 );
23724
23725         const currentScissor = new Vector4().fromArray( scissorParam );
23726         const currentViewport = new Vector4().fromArray( viewportParam );
23727
23728         function createTexture( type, target, count ) {
23729
23730                 const data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4.
23731                 const texture = gl.createTexture();
23732
23733                 gl.bindTexture( type, texture );
23734                 gl.texParameteri( type, 10241, 9728 );
23735                 gl.texParameteri( type, 10240, 9728 );
23736
23737                 for ( let i = 0; i < count; i ++ ) {
23738
23739                         gl.texImage2D( target + i, 0, 6408, 1, 1, 0, 6408, 5121, data );
23740
23741                 }
23742
23743                 return texture;
23744
23745         }
23746
23747         const emptyTextures = {};
23748         emptyTextures[ 3553 ] = createTexture( 3553, 3553, 1 );
23749         emptyTextures[ 34067 ] = createTexture( 34067, 34069, 6 );
23750
23751         // init
23752
23753         colorBuffer.setClear( 0, 0, 0, 1 );
23754         depthBuffer.setClear( 1 );
23755         stencilBuffer.setClear( 0 );
23756
23757         enable( 2929 );
23758         depthBuffer.setFunc( LessEqualDepth );
23759
23760         setFlipSided( false );
23761         setCullFace( CullFaceBack );
23762         enable( 2884 );
23763
23764         setBlending( NoBlending );
23765
23766         //
23767
23768         function enable( id ) {
23769
23770                 if ( enabledCapabilities[ id ] !== true ) {
23771
23772                         gl.enable( id );
23773                         enabledCapabilities[ id ] = true;
23774
23775                 }
23776
23777         }
23778
23779         function disable( id ) {
23780
23781                 if ( enabledCapabilities[ id ] !== false ) {
23782
23783                         gl.disable( id );
23784                         enabledCapabilities[ id ] = false;
23785
23786                 }
23787
23788         }
23789
23790         function bindXRFramebuffer( framebuffer ) {
23791
23792                 if ( framebuffer !== xrFramebuffer ) {
23793
23794                         gl.bindFramebuffer( 36160, framebuffer );
23795
23796                         xrFramebuffer = framebuffer;
23797
23798                 }
23799
23800         }
23801
23802         function bindFramebuffer( target, framebuffer ) {
23803
23804                 if ( framebuffer === null && xrFramebuffer !== null ) framebuffer = xrFramebuffer; // use active XR framebuffer if available
23805
23806                 if ( currentBoundFramebuffers[ target ] !== framebuffer ) {
23807
23808                         gl.bindFramebuffer( target, framebuffer );
23809
23810                         currentBoundFramebuffers[ target ] = framebuffer;
23811
23812                         if ( isWebGL2 ) {
23813
23814                                 // 36009 is equivalent to 36160
23815
23816                                 if ( target === 36009 ) {
23817
23818                                         currentBoundFramebuffers[ 36160 ] = framebuffer;
23819
23820                                 }
23821
23822                                 if ( target === 36160 ) {
23823
23824                                         currentBoundFramebuffers[ 36009 ] = framebuffer;
23825
23826                                 }
23827
23828                         }
23829
23830                         return true;
23831
23832                 }
23833
23834                 return false;
23835
23836         }
23837
23838         function useProgram( program ) {
23839
23840                 if ( currentProgram !== program ) {
23841
23842                         gl.useProgram( program );
23843
23844                         currentProgram = program;
23845
23846                         return true;
23847
23848                 }
23849
23850                 return false;
23851
23852         }
23853
23854         const equationToGL = {
23855                 [ AddEquation ]: 32774,
23856                 [ SubtractEquation ]: 32778,
23857                 [ ReverseSubtractEquation ]: 32779
23858         };
23859
23860         if ( isWebGL2 ) {
23861
23862                 equationToGL[ MinEquation ] = 32775;
23863                 equationToGL[ MaxEquation ] = 32776;
23864
23865         } else {
23866
23867                 const extension = extensions.get( 'EXT_blend_minmax' );
23868
23869                 if ( extension !== null ) {
23870
23871                         equationToGL[ MinEquation ] = extension.MIN_EXT;
23872                         equationToGL[ MaxEquation ] = extension.MAX_EXT;
23873
23874                 }
23875
23876         }
23877
23878         const factorToGL = {
23879                 [ ZeroFactor ]: 0,
23880                 [ OneFactor ]: 1,
23881                 [ SrcColorFactor ]: 768,
23882                 [ SrcAlphaFactor ]: 770,
23883                 [ SrcAlphaSaturateFactor ]: 776,
23884                 [ DstColorFactor ]: 774,
23885                 [ DstAlphaFactor ]: 772,
23886                 [ OneMinusSrcColorFactor ]: 769,
23887                 [ OneMinusSrcAlphaFactor ]: 771,
23888                 [ OneMinusDstColorFactor ]: 775,
23889                 [ OneMinusDstAlphaFactor ]: 773
23890         };
23891
23892         function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) {
23893
23894                 if ( blending === NoBlending ) {
23895
23896                         if ( currentBlendingEnabled === true ) {
23897
23898                                 disable( 3042 );
23899                                 currentBlendingEnabled = false;
23900
23901                         }
23902
23903                         return;
23904
23905                 }
23906
23907                 if ( currentBlendingEnabled === false ) {
23908
23909                         enable( 3042 );
23910                         currentBlendingEnabled = true;
23911
23912                 }
23913
23914                 if ( blending !== CustomBlending ) {
23915
23916                         if ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) {
23917
23918                                 if ( currentBlendEquation !== AddEquation || currentBlendEquationAlpha !== AddEquation ) {
23919
23920                                         gl.blendEquation( 32774 );
23921
23922                                         currentBlendEquation = AddEquation;
23923                                         currentBlendEquationAlpha = AddEquation;
23924
23925                                 }
23926
23927                                 if ( premultipliedAlpha ) {
23928
23929                                         switch ( blending ) {
23930
23931                                                 case NormalBlending:
23932                                                         gl.blendFuncSeparate( 1, 771, 1, 771 );
23933                                                         break;
23934
23935                                                 case AdditiveBlending:
23936                                                         gl.blendFunc( 1, 1 );
23937                                                         break;
23938
23939                                                 case SubtractiveBlending:
23940                                                         gl.blendFuncSeparate( 0, 0, 769, 771 );
23941                                                         break;
23942
23943                                                 case MultiplyBlending:
23944                                                         gl.blendFuncSeparate( 0, 768, 0, 770 );
23945                                                         break;
23946
23947                                                 default:
23948                                                         console.error( 'THREE.WebGLState: Invalid blending: ', blending );
23949                                                         break;
23950
23951                                         }
23952
23953                                 } else {
23954
23955                                         switch ( blending ) {
23956
23957                                                 case NormalBlending:
23958                                                         gl.blendFuncSeparate( 770, 771, 1, 771 );
23959                                                         break;
23960
23961                                                 case AdditiveBlending:
23962                                                         gl.blendFunc( 770, 1 );
23963                                                         break;
23964
23965                                                 case SubtractiveBlending:
23966                                                         gl.blendFunc( 0, 769 );
23967                                                         break;
23968
23969                                                 case MultiplyBlending:
23970                                                         gl.blendFunc( 0, 768 );
23971                                                         break;
23972
23973                                                 default:
23974                                                         console.error( 'THREE.WebGLState: Invalid blending: ', blending );
23975                                                         break;
23976
23977                                         }
23978
23979                                 }
23980
23981                                 currentBlendSrc = null;
23982                                 currentBlendDst = null;
23983                                 currentBlendSrcAlpha = null;
23984                                 currentBlendDstAlpha = null;
23985
23986                                 currentBlending = blending;
23987                                 currentPremultipledAlpha = premultipliedAlpha;
23988
23989                         }
23990
23991                         return;
23992
23993                 }
23994
23995                 // custom blending
23996
23997                 blendEquationAlpha = blendEquationAlpha || blendEquation;
23998                 blendSrcAlpha = blendSrcAlpha || blendSrc;
23999                 blendDstAlpha = blendDstAlpha || blendDst;
24000
24001                 if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) {
24002
24003                         gl.blendEquationSeparate( equationToGL[ blendEquation ], equationToGL[ blendEquationAlpha ] );
24004
24005                         currentBlendEquation = blendEquation;
24006                         currentBlendEquationAlpha = blendEquationAlpha;
24007
24008                 }
24009
24010                 if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) {
24011
24012                         gl.blendFuncSeparate( factorToGL[ blendSrc ], factorToGL[ blendDst ], factorToGL[ blendSrcAlpha ], factorToGL[ blendDstAlpha ] );
24013
24014                         currentBlendSrc = blendSrc;
24015                         currentBlendDst = blendDst;
24016                         currentBlendSrcAlpha = blendSrcAlpha;
24017                         currentBlendDstAlpha = blendDstAlpha;
24018
24019                 }
24020
24021                 currentBlending = blending;
24022                 currentPremultipledAlpha = null;
24023
24024         }
24025
24026         function setMaterial( material, frontFaceCW ) {
24027
24028                 material.side === DoubleSide
24029                         ? disable( 2884 )
24030                         : enable( 2884 );
24031
24032                 let flipSided = ( material.side === BackSide );
24033                 if ( frontFaceCW ) flipSided = ! flipSided;
24034
24035                 setFlipSided( flipSided );
24036
24037                 ( material.blending === NormalBlending && material.transparent === false )
24038                         ? setBlending( NoBlending )
24039                         : setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha );
24040
24041                 depthBuffer.setFunc( material.depthFunc );
24042                 depthBuffer.setTest( material.depthTest );
24043                 depthBuffer.setMask( material.depthWrite );
24044                 colorBuffer.setMask( material.colorWrite );
24045
24046                 const stencilWrite = material.stencilWrite;
24047                 stencilBuffer.setTest( stencilWrite );
24048                 if ( stencilWrite ) {
24049
24050                         stencilBuffer.setMask( material.stencilWriteMask );
24051                         stencilBuffer.setFunc( material.stencilFunc, material.stencilRef, material.stencilFuncMask );
24052                         stencilBuffer.setOp( material.stencilFail, material.stencilZFail, material.stencilZPass );
24053
24054                 }
24055
24056                 setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
24057
24058                 material.alphaToCoverage === true
24059                         ? enable( 32926 )
24060                         : disable( 32926 );
24061
24062         }
24063
24064         //
24065
24066         function setFlipSided( flipSided ) {
24067
24068                 if ( currentFlipSided !== flipSided ) {
24069
24070                         if ( flipSided ) {
24071
24072                                 gl.frontFace( 2304 );
24073
24074                         } else {
24075
24076                                 gl.frontFace( 2305 );
24077
24078                         }
24079
24080                         currentFlipSided = flipSided;
24081
24082                 }
24083
24084         }
24085
24086         function setCullFace( cullFace ) {
24087
24088                 if ( cullFace !== CullFaceNone ) {
24089
24090                         enable( 2884 );
24091
24092                         if ( cullFace !== currentCullFace ) {
24093
24094                                 if ( cullFace === CullFaceBack ) {
24095
24096                                         gl.cullFace( 1029 );
24097
24098                                 } else if ( cullFace === CullFaceFront ) {
24099
24100                                         gl.cullFace( 1028 );
24101
24102                                 } else {
24103
24104                                         gl.cullFace( 1032 );
24105
24106                                 }
24107
24108                         }
24109
24110                 } else {
24111
24112                         disable( 2884 );
24113
24114                 }
24115
24116                 currentCullFace = cullFace;
24117
24118         }
24119
24120         function setLineWidth( width ) {
24121
24122                 if ( width !== currentLineWidth ) {
24123
24124                         if ( lineWidthAvailable ) gl.lineWidth( width );
24125
24126                         currentLineWidth = width;
24127
24128                 }
24129
24130         }
24131
24132         function setPolygonOffset( polygonOffset, factor, units ) {
24133
24134                 if ( polygonOffset ) {
24135
24136                         enable( 32823 );
24137
24138                         if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) {
24139
24140                                 gl.polygonOffset( factor, units );
24141
24142                                 currentPolygonOffsetFactor = factor;
24143                                 currentPolygonOffsetUnits = units;
24144
24145                         }
24146
24147                 } else {
24148
24149                         disable( 32823 );
24150
24151                 }
24152
24153         }
24154
24155         function setScissorTest( scissorTest ) {
24156
24157                 if ( scissorTest ) {
24158
24159                         enable( 3089 );
24160
24161                 } else {
24162
24163                         disable( 3089 );
24164
24165                 }
24166
24167         }
24168
24169         // texture
24170
24171         function activeTexture( webglSlot ) {
24172
24173                 if ( webglSlot === undefined ) webglSlot = 33984 + maxTextures - 1;
24174
24175                 if ( currentTextureSlot !== webglSlot ) {
24176
24177                         gl.activeTexture( webglSlot );
24178                         currentTextureSlot = webglSlot;
24179
24180                 }
24181
24182         }
24183
24184         function bindTexture( webglType, webglTexture ) {
24185
24186                 if ( currentTextureSlot === null ) {
24187
24188                         activeTexture();
24189
24190                 }
24191
24192                 let boundTexture = currentBoundTextures[ currentTextureSlot ];
24193
24194                 if ( boundTexture === undefined ) {
24195
24196                         boundTexture = { type: undefined, texture: undefined };
24197                         currentBoundTextures[ currentTextureSlot ] = boundTexture;
24198
24199                 }
24200
24201                 if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) {
24202
24203                         gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] );
24204
24205                         boundTexture.type = webglType;
24206                         boundTexture.texture = webglTexture;
24207
24208                 }
24209
24210         }
24211
24212         function unbindTexture() {
24213
24214                 const boundTexture = currentBoundTextures[ currentTextureSlot ];
24215
24216                 if ( boundTexture !== undefined && boundTexture.type !== undefined ) {
24217
24218                         gl.bindTexture( boundTexture.type, null );
24219
24220                         boundTexture.type = undefined;
24221                         boundTexture.texture = undefined;
24222
24223                 }
24224
24225         }
24226
24227         function compressedTexImage2D() {
24228
24229                 try {
24230
24231                         gl.compressedTexImage2D.apply( gl, arguments );
24232
24233                 } catch ( error ) {
24234
24235                         console.error( 'THREE.WebGLState:', error );
24236
24237                 }
24238
24239         }
24240
24241         function texImage2D() {
24242
24243                 try {
24244
24245                         gl.texImage2D.apply( gl, arguments );
24246
24247                 } catch ( error ) {
24248
24249                         console.error( 'THREE.WebGLState:', error );
24250
24251                 }
24252
24253         }
24254
24255         function texImage3D() {
24256
24257                 try {
24258
24259                         gl.texImage3D.apply( gl, arguments );
24260
24261                 } catch ( error ) {
24262
24263                         console.error( 'THREE.WebGLState:', error );
24264
24265                 }
24266
24267         }
24268
24269         //
24270
24271         function scissor( scissor ) {
24272
24273                 if ( currentScissor.equals( scissor ) === false ) {
24274
24275                         gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w );
24276                         currentScissor.copy( scissor );
24277
24278                 }
24279
24280         }
24281
24282         function viewport( viewport ) {
24283
24284                 if ( currentViewport.equals( viewport ) === false ) {
24285
24286                         gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w );
24287                         currentViewport.copy( viewport );
24288
24289                 }
24290
24291         }
24292
24293         //
24294
24295         function reset() {
24296
24297                 // reset state
24298
24299                 gl.disable( 3042 );
24300                 gl.disable( 2884 );
24301                 gl.disable( 2929 );
24302                 gl.disable( 32823 );
24303                 gl.disable( 3089 );
24304                 gl.disable( 2960 );
24305                 gl.disable( 32926 );
24306
24307                 gl.blendEquation( 32774 );
24308                 gl.blendFunc( 1, 0 );
24309                 gl.blendFuncSeparate( 1, 0, 1, 0 );
24310
24311                 gl.colorMask( true, true, true, true );
24312                 gl.clearColor( 0, 0, 0, 0 );
24313
24314                 gl.depthMask( true );
24315                 gl.depthFunc( 513 );
24316                 gl.clearDepth( 1 );
24317
24318                 gl.stencilMask( 0xffffffff );
24319                 gl.stencilFunc( 519, 0, 0xffffffff );
24320                 gl.stencilOp( 7680, 7680, 7680 );
24321                 gl.clearStencil( 0 );
24322
24323                 gl.cullFace( 1029 );
24324                 gl.frontFace( 2305 );
24325
24326                 gl.polygonOffset( 0, 0 );
24327
24328                 gl.activeTexture( 33984 );
24329
24330                 gl.bindFramebuffer( 36160, null );
24331
24332                 if ( isWebGL2 === true ) {
24333
24334                         gl.bindFramebuffer( 36009, null );
24335                         gl.bindFramebuffer( 36008, null );
24336
24337                 }
24338
24339                 gl.useProgram( null );
24340
24341                 gl.lineWidth( 1 );
24342
24343                 gl.scissor( 0, 0, gl.canvas.width, gl.canvas.height );
24344                 gl.viewport( 0, 0, gl.canvas.width, gl.canvas.height );
24345
24346                 // reset internals
24347
24348                 enabledCapabilities = {};
24349
24350                 currentTextureSlot = null;
24351                 currentBoundTextures = {};
24352
24353                 xrFramebuffer = null;
24354                 currentBoundFramebuffers = {};
24355
24356                 currentProgram = null;
24357
24358                 currentBlendingEnabled = false;
24359                 currentBlending = null;
24360                 currentBlendEquation = null;
24361                 currentBlendSrc = null;
24362                 currentBlendDst = null;
24363                 currentBlendEquationAlpha = null;
24364                 currentBlendSrcAlpha = null;
24365                 currentBlendDstAlpha = null;
24366                 currentPremultipledAlpha = false;
24367
24368                 currentFlipSided = null;
24369                 currentCullFace = null;
24370
24371                 currentLineWidth = null;
24372
24373                 currentPolygonOffsetFactor = null;
24374                 currentPolygonOffsetUnits = null;
24375
24376                 currentScissor.set( 0, 0, gl.canvas.width, gl.canvas.height );
24377                 currentViewport.set( 0, 0, gl.canvas.width, gl.canvas.height );
24378
24379                 colorBuffer.reset();
24380                 depthBuffer.reset();
24381                 stencilBuffer.reset();
24382
24383         }
24384
24385         return {
24386
24387                 buffers: {
24388                         color: colorBuffer,
24389                         depth: depthBuffer,
24390                         stencil: stencilBuffer
24391                 },
24392
24393                 enable: enable,
24394                 disable: disable,
24395
24396                 bindFramebuffer: bindFramebuffer,
24397                 bindXRFramebuffer: bindXRFramebuffer,
24398
24399                 useProgram: useProgram,
24400
24401                 setBlending: setBlending,
24402                 setMaterial: setMaterial,
24403
24404                 setFlipSided: setFlipSided,
24405                 setCullFace: setCullFace,
24406
24407                 setLineWidth: setLineWidth,
24408                 setPolygonOffset: setPolygonOffset,
24409
24410                 setScissorTest: setScissorTest,
24411
24412                 activeTexture: activeTexture,
24413                 bindTexture: bindTexture,
24414                 unbindTexture: unbindTexture,
24415                 compressedTexImage2D: compressedTexImage2D,
24416                 texImage2D: texImage2D,
24417                 texImage3D: texImage3D,
24418
24419                 scissor: scissor,
24420                 viewport: viewport,
24421
24422                 reset: reset
24423
24424         };
24425
24426 }
24427
24428 function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) {
24429
24430         const isWebGL2 = capabilities.isWebGL2;
24431         const maxTextures = capabilities.maxTextures;
24432         const maxCubemapSize = capabilities.maxCubemapSize;
24433         const maxTextureSize = capabilities.maxTextureSize;
24434         const maxSamples = capabilities.maxSamples;
24435
24436         const _videoTextures = new WeakMap();
24437         let _canvas;
24438
24439         // cordova iOS (as of 5.0) still uses UIWebView, which provides OffscreenCanvas,
24440         // also OffscreenCanvas.getContext("webgl"), but not OffscreenCanvas.getContext("2d")!
24441         // Some implementations may only implement OffscreenCanvas partially (e.g. lacking 2d).
24442
24443         let useOffscreenCanvas = false;
24444
24445         try {
24446
24447                 useOffscreenCanvas = typeof OffscreenCanvas !== 'undefined'
24448                         && ( new OffscreenCanvas( 1, 1 ).getContext( '2d' ) ) !== null;
24449
24450         } catch ( err ) {
24451
24452                 // Ignore any errors
24453
24454         }
24455
24456         function createCanvas( width, height ) {
24457
24458                 // Use OffscreenCanvas when available. Specially needed in web workers
24459
24460                 return useOffscreenCanvas ?
24461                         new OffscreenCanvas( width, height ) : createElementNS( 'canvas' );
24462
24463         }
24464
24465         function resizeImage( image, needsPowerOfTwo, needsNewCanvas, maxSize ) {
24466
24467                 let scale = 1;
24468
24469                 // handle case if texture exceeds max size
24470
24471                 if ( image.width > maxSize || image.height > maxSize ) {
24472
24473                         scale = maxSize / Math.max( image.width, image.height );
24474
24475                 }
24476
24477                 // only perform resize if necessary
24478
24479                 if ( scale < 1 || needsPowerOfTwo === true ) {
24480
24481                         // only perform resize for certain image types
24482
24483                         if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||
24484                                 ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||
24485                                 ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) {
24486
24487                                 const floor = needsPowerOfTwo ? floorPowerOfTwo : Math.floor;
24488
24489                                 const width = floor( scale * image.width );
24490                                 const height = floor( scale * image.height );
24491
24492                                 if ( _canvas === undefined ) _canvas = createCanvas( width, height );
24493
24494                                 // cube textures can't reuse the same canvas
24495
24496                                 const canvas = needsNewCanvas ? createCanvas( width, height ) : _canvas;
24497
24498                                 canvas.width = width;
24499                                 canvas.height = height;
24500
24501                                 const context = canvas.getContext( '2d' );
24502                                 context.drawImage( image, 0, 0, width, height );
24503
24504                                 console.warn( 'THREE.WebGLRenderer: Texture has been resized from (' + image.width + 'x' + image.height + ') to (' + width + 'x' + height + ').' );
24505
24506                                 return canvas;
24507
24508                         } else {
24509
24510                                 if ( 'data' in image ) {
24511
24512                                         console.warn( 'THREE.WebGLRenderer: Image in DataTexture is too big (' + image.width + 'x' + image.height + ').' );
24513
24514                                 }
24515
24516                                 return image;
24517
24518                         }
24519
24520                 }
24521
24522                 return image;
24523
24524         }
24525
24526         function isPowerOfTwo$1( image ) {
24527
24528                 return isPowerOfTwo( image.width ) && isPowerOfTwo( image.height );
24529
24530         }
24531
24532         function textureNeedsPowerOfTwo( texture ) {
24533
24534                 if ( isWebGL2 ) return false;
24535
24536                 return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) ||
24537                         ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter );
24538
24539         }
24540
24541         function textureNeedsGenerateMipmaps( texture, supportsMips ) {
24542
24543                 return texture.generateMipmaps && supportsMips &&
24544                         texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter;
24545
24546         }
24547
24548         function generateMipmap( target, texture, width, height, depth = 1 ) {
24549
24550                 _gl.generateMipmap( target );
24551
24552                 const textureProperties = properties.get( texture );
24553
24554                 textureProperties.__maxMipLevel = Math.log2( Math.max( width, height, depth ) );
24555
24556         }
24557
24558         function getInternalFormat( internalFormatName, glFormat, glType, encoding ) {
24559
24560                 if ( isWebGL2 === false ) return glFormat;
24561
24562                 if ( internalFormatName !== null ) {
24563
24564                         if ( _gl[ internalFormatName ] !== undefined ) return _gl[ internalFormatName ];
24565
24566                         console.warn( 'THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format \'' + internalFormatName + '\'' );
24567
24568                 }
24569
24570                 let internalFormat = glFormat;
24571
24572                 if ( glFormat === 6403 ) {
24573
24574                         if ( glType === 5126 ) internalFormat = 33326;
24575                         if ( glType === 5131 ) internalFormat = 33325;
24576                         if ( glType === 5121 ) internalFormat = 33321;
24577
24578                 }
24579
24580                 if ( glFormat === 6407 ) {
24581
24582                         if ( glType === 5126 ) internalFormat = 34837;
24583                         if ( glType === 5131 ) internalFormat = 34843;
24584                         if ( glType === 5121 ) internalFormat = 32849;
24585
24586                 }
24587
24588                 if ( glFormat === 6408 ) {
24589
24590                         if ( glType === 5126 ) internalFormat = 34836;
24591                         if ( glType === 5131 ) internalFormat = 34842;
24592                         if ( glType === 5121 ) internalFormat = ( encoding === sRGBEncoding ) ? 35907 : 32856;
24593
24594                 }
24595
24596                 if ( internalFormat === 33325 || internalFormat === 33326 ||
24597                         internalFormat === 34842 || internalFormat === 34836 ) {
24598
24599                         extensions.get( 'EXT_color_buffer_float' );
24600
24601                 }
24602
24603                 return internalFormat;
24604
24605         }
24606
24607         // Fallback filters for non-power-of-2 textures
24608
24609         function filterFallback( f ) {
24610
24611                 if ( f === NearestFilter || f === NearestMipmapNearestFilter || f === NearestMipmapLinearFilter ) {
24612
24613                         return 9728;
24614
24615                 }
24616
24617                 return 9729;
24618
24619         }
24620
24621         //
24622
24623         function onTextureDispose( event ) {
24624
24625                 const texture = event.target;
24626
24627                 texture.removeEventListener( 'dispose', onTextureDispose );
24628
24629                 deallocateTexture( texture );
24630
24631                 if ( texture.isVideoTexture ) {
24632
24633                         _videoTextures.delete( texture );
24634
24635                 }
24636
24637                 info.memory.textures --;
24638
24639         }
24640
24641         function onRenderTargetDispose( event ) {
24642
24643                 const renderTarget = event.target;
24644
24645                 renderTarget.removeEventListener( 'dispose', onRenderTargetDispose );
24646
24647                 deallocateRenderTarget( renderTarget );
24648
24649         }
24650
24651         //
24652
24653         function deallocateTexture( texture ) {
24654
24655                 const textureProperties = properties.get( texture );
24656
24657                 if ( textureProperties.__webglInit === undefined ) return;
24658
24659                 _gl.deleteTexture( textureProperties.__webglTexture );
24660
24661                 properties.remove( texture );
24662
24663         }
24664
24665         function deallocateRenderTarget( renderTarget ) {
24666
24667                 const texture = renderTarget.texture;
24668
24669                 const renderTargetProperties = properties.get( renderTarget );
24670                 const textureProperties = properties.get( texture );
24671
24672                 if ( ! renderTarget ) return;
24673
24674                 if ( textureProperties.__webglTexture !== undefined ) {
24675
24676                         _gl.deleteTexture( textureProperties.__webglTexture );
24677
24678                         info.memory.textures --;
24679
24680                 }
24681
24682                 if ( renderTarget.depthTexture ) {
24683
24684                         renderTarget.depthTexture.dispose();
24685
24686                 }
24687
24688                 if ( renderTarget.isWebGLCubeRenderTarget ) {
24689
24690                         for ( let i = 0; i < 6; i ++ ) {
24691
24692                                 _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] );
24693                                 if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] );
24694
24695                         }
24696
24697                 } else {
24698
24699                         _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer );
24700                         if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer );
24701                         if ( renderTargetProperties.__webglMultisampledFramebuffer ) _gl.deleteFramebuffer( renderTargetProperties.__webglMultisampledFramebuffer );
24702                         if ( renderTargetProperties.__webglColorRenderbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglColorRenderbuffer );
24703                         if ( renderTargetProperties.__webglDepthRenderbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthRenderbuffer );
24704
24705                 }
24706
24707                 if ( renderTarget.isWebGLMultipleRenderTargets ) {
24708
24709                         for ( let i = 0, il = texture.length; i < il; i ++ ) {
24710
24711                                 const attachmentProperties = properties.get( texture[ i ] );
24712
24713                                 if ( attachmentProperties.__webglTexture ) {
24714
24715                                         _gl.deleteTexture( attachmentProperties.__webglTexture );
24716
24717                                         info.memory.textures --;
24718
24719                                 }
24720
24721                                 properties.remove( texture[ i ] );
24722
24723                         }
24724
24725                 }
24726
24727                 properties.remove( texture );
24728                 properties.remove( renderTarget );
24729
24730         }
24731
24732         //
24733
24734         let textureUnits = 0;
24735
24736         function resetTextureUnits() {
24737
24738                 textureUnits = 0;
24739
24740         }
24741
24742         function allocateTextureUnit() {
24743
24744                 const textureUnit = textureUnits;
24745
24746                 if ( textureUnit >= maxTextures ) {
24747
24748                         console.warn( 'THREE.WebGLTextures: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + maxTextures );
24749
24750                 }
24751
24752                 textureUnits += 1;
24753
24754                 return textureUnit;
24755
24756         }
24757
24758         //
24759
24760         function setTexture2D( texture, slot ) {
24761
24762                 const textureProperties = properties.get( texture );
24763
24764                 if ( texture.isVideoTexture ) updateVideoTexture( texture );
24765
24766                 if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
24767
24768                         const image = texture.image;
24769
24770                         if ( image === undefined ) {
24771
24772                                 console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is undefined' );
24773
24774                         } else if ( image.complete === false ) {
24775
24776                                 console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete' );
24777
24778                         } else {
24779
24780                                 uploadTexture( textureProperties, texture, slot );
24781                                 return;
24782
24783                         }
24784
24785                 }
24786
24787                 state.activeTexture( 33984 + slot );
24788                 state.bindTexture( 3553, textureProperties.__webglTexture );
24789
24790         }
24791
24792         function setTexture2DArray( texture, slot ) {
24793
24794                 const textureProperties = properties.get( texture );
24795
24796                 if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
24797
24798                         uploadTexture( textureProperties, texture, slot );
24799                         return;
24800
24801                 }
24802
24803                 state.activeTexture( 33984 + slot );
24804                 state.bindTexture( 35866, textureProperties.__webglTexture );
24805
24806         }
24807
24808         function setTexture3D( texture, slot ) {
24809
24810                 const textureProperties = properties.get( texture );
24811
24812                 if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
24813
24814                         uploadTexture( textureProperties, texture, slot );
24815                         return;
24816
24817                 }
24818
24819                 state.activeTexture( 33984 + slot );
24820                 state.bindTexture( 32879, textureProperties.__webglTexture );
24821
24822         }
24823
24824         function setTextureCube( texture, slot ) {
24825
24826                 const textureProperties = properties.get( texture );
24827
24828                 if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
24829
24830                         uploadCubeTexture( textureProperties, texture, slot );
24831                         return;
24832
24833                 }
24834
24835                 state.activeTexture( 33984 + slot );
24836                 state.bindTexture( 34067, textureProperties.__webglTexture );
24837
24838         }
24839
24840         const wrappingToGL = {
24841                 [ RepeatWrapping ]: 10497,
24842                 [ ClampToEdgeWrapping ]: 33071,
24843                 [ MirroredRepeatWrapping ]: 33648
24844         };
24845
24846         const filterToGL = {
24847                 [ NearestFilter ]: 9728,
24848                 [ NearestMipmapNearestFilter ]: 9984,
24849                 [ NearestMipmapLinearFilter ]: 9986,
24850
24851                 [ LinearFilter ]: 9729,
24852                 [ LinearMipmapNearestFilter ]: 9985,
24853                 [ LinearMipmapLinearFilter ]: 9987
24854         };
24855
24856         function setTextureParameters( textureType, texture, supportsMips ) {
24857
24858                 if ( supportsMips ) {
24859
24860                         _gl.texParameteri( textureType, 10242, wrappingToGL[ texture.wrapS ] );
24861                         _gl.texParameteri( textureType, 10243, wrappingToGL[ texture.wrapT ] );
24862
24863                         if ( textureType === 32879 || textureType === 35866 ) {
24864
24865                                 _gl.texParameteri( textureType, 32882, wrappingToGL[ texture.wrapR ] );
24866
24867                         }
24868
24869                         _gl.texParameteri( textureType, 10240, filterToGL[ texture.magFilter ] );
24870                         _gl.texParameteri( textureType, 10241, filterToGL[ texture.minFilter ] );
24871
24872                 } else {
24873
24874                         _gl.texParameteri( textureType, 10242, 33071 );
24875                         _gl.texParameteri( textureType, 10243, 33071 );
24876
24877                         if ( textureType === 32879 || textureType === 35866 ) {
24878
24879                                 _gl.texParameteri( textureType, 32882, 33071 );
24880
24881                         }
24882
24883                         if ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) {
24884
24885                                 console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.' );
24886
24887                         }
24888
24889                         _gl.texParameteri( textureType, 10240, filterFallback( texture.magFilter ) );
24890                         _gl.texParameteri( textureType, 10241, filterFallback( texture.minFilter ) );
24891
24892                         if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) {
24893
24894                                 console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.' );
24895
24896                         }
24897
24898                 }
24899
24900                 if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) {
24901
24902                         const extension = extensions.get( 'EXT_texture_filter_anisotropic' );
24903
24904                         if ( texture.type === FloatType && extensions.has( 'OES_texture_float_linear' ) === false ) return; // verify extension for WebGL 1 and WebGL 2
24905                         if ( isWebGL2 === false && ( texture.type === HalfFloatType && extensions.has( 'OES_texture_half_float_linear' ) === false ) ) return; // verify extension for WebGL 1 only
24906
24907                         if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) {
24908
24909                                 _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) );
24910                                 properties.get( texture ).__currentAnisotropy = texture.anisotropy;
24911
24912                         }
24913
24914                 }
24915
24916         }
24917
24918         function initTexture( textureProperties, texture ) {
24919
24920                 if ( textureProperties.__webglInit === undefined ) {
24921
24922                         textureProperties.__webglInit = true;
24923
24924                         texture.addEventListener( 'dispose', onTextureDispose );
24925
24926                         textureProperties.__webglTexture = _gl.createTexture();
24927
24928                         info.memory.textures ++;
24929
24930                 }
24931
24932         }
24933
24934         function uploadTexture( textureProperties, texture, slot ) {
24935
24936                 let textureType = 3553;
24937
24938                 if ( texture.isDataTexture2DArray ) textureType = 35866;
24939                 if ( texture.isDataTexture3D ) textureType = 32879;
24940
24941                 initTexture( textureProperties, texture );
24942
24943                 state.activeTexture( 33984 + slot );
24944                 state.bindTexture( textureType, textureProperties.__webglTexture );
24945
24946                 _gl.pixelStorei( 37440, texture.flipY );
24947                 _gl.pixelStorei( 37441, texture.premultiplyAlpha );
24948                 _gl.pixelStorei( 3317, texture.unpackAlignment );
24949                 _gl.pixelStorei( 37443, 0 );
24950
24951                 const needsPowerOfTwo = textureNeedsPowerOfTwo( texture ) && isPowerOfTwo$1( texture.image ) === false;
24952                 const image = resizeImage( texture.image, needsPowerOfTwo, false, maxTextureSize );
24953
24954                 const supportsMips = isPowerOfTwo$1( image ) || isWebGL2,
24955                         glFormat = utils.convert( texture.format );
24956
24957                 let glType = utils.convert( texture.type ),
24958                         glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding );
24959
24960                 setTextureParameters( textureType, texture, supportsMips );
24961
24962                 let mipmap;
24963                 const mipmaps = texture.mipmaps;
24964
24965                 if ( texture.isDepthTexture ) {
24966
24967                         // populate depth texture with dummy data
24968
24969                         glInternalFormat = 6402;
24970
24971                         if ( isWebGL2 ) {
24972
24973                                 if ( texture.type === FloatType ) {
24974
24975                                         glInternalFormat = 36012;
24976
24977                                 } else if ( texture.type === UnsignedIntType ) {
24978
24979                                         glInternalFormat = 33190;
24980
24981                                 } else if ( texture.type === UnsignedInt248Type ) {
24982
24983                                         glInternalFormat = 35056;
24984
24985                                 } else {
24986
24987                                         glInternalFormat = 33189; // WebGL2 requires sized internalformat for glTexImage2D
24988
24989                                 }
24990
24991                         } else {
24992
24993                                 if ( texture.type === FloatType ) {
24994
24995                                         console.error( 'WebGLRenderer: Floating point depth texture requires WebGL2.' );
24996
24997                                 }
24998
24999                         }
25000
25001                         // validation checks for WebGL 1
25002
25003                         if ( texture.format === DepthFormat && glInternalFormat === 6402 ) {
25004
25005                                 // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
25006                                 // DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT
25007                                 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
25008                                 if ( texture.type !== UnsignedShortType && texture.type !== UnsignedIntType ) {
25009
25010                                         console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' );
25011
25012                                         texture.type = UnsignedShortType;
25013                                         glType = utils.convert( texture.type );
25014
25015                                 }
25016
25017                         }
25018
25019                         if ( texture.format === DepthStencilFormat && glInternalFormat === 6402 ) {
25020
25021                                 // Depth stencil textures need the DEPTH_STENCIL internal format
25022                                 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
25023                                 glInternalFormat = 34041;
25024
25025                                 // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
25026                                 // DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL.
25027                                 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
25028                                 if ( texture.type !== UnsignedInt248Type ) {
25029
25030                                         console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' );
25031
25032                                         texture.type = UnsignedInt248Type;
25033                                         glType = utils.convert( texture.type );
25034
25035                                 }
25036
25037                         }
25038
25039                         //
25040
25041                         state.texImage2D( 3553, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null );
25042
25043                 } else if ( texture.isDataTexture ) {
25044
25045                         // use manually created mipmaps if available
25046                         // if there are no manual mipmaps
25047                         // set 0 level mipmap and then use GL to generate other mipmap levels
25048
25049                         if ( mipmaps.length > 0 && supportsMips ) {
25050
25051                                 for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
25052
25053                                         mipmap = mipmaps[ i ];
25054                                         state.texImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
25055
25056                                 }
25057
25058                                 texture.generateMipmaps = false;
25059                                 textureProperties.__maxMipLevel = mipmaps.length - 1;
25060
25061                         } else {
25062
25063                                 state.texImage2D( 3553, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data );
25064                                 textureProperties.__maxMipLevel = 0;
25065
25066                         }
25067
25068                 } else if ( texture.isCompressedTexture ) {
25069
25070                         for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
25071
25072                                 mipmap = mipmaps[ i ];
25073
25074                                 if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) {
25075
25076                                         if ( glFormat !== null ) {
25077
25078                                                 state.compressedTexImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );
25079
25080                                         } else {
25081
25082                                                 console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' );
25083
25084                                         }
25085
25086                                 } else {
25087
25088                                         state.texImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
25089
25090                                 }
25091
25092                         }
25093
25094                         textureProperties.__maxMipLevel = mipmaps.length - 1;
25095
25096                 } else if ( texture.isDataTexture2DArray ) {
25097
25098                         state.texImage3D( 35866, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data );
25099                         textureProperties.__maxMipLevel = 0;
25100
25101                 } else if ( texture.isDataTexture3D ) {
25102
25103                         state.texImage3D( 32879, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data );
25104                         textureProperties.__maxMipLevel = 0;
25105
25106                 } else {
25107
25108                         // regular Texture (image, video, canvas)
25109
25110                         // use manually created mipmaps if available
25111                         // if there are no manual mipmaps
25112                         // set 0 level mipmap and then use GL to generate other mipmap levels
25113
25114                         if ( mipmaps.length > 0 && supportsMips ) {
25115
25116                                 for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
25117
25118                                         mipmap = mipmaps[ i ];
25119                                         state.texImage2D( 3553, i, glInternalFormat, glFormat, glType, mipmap );
25120
25121                                 }
25122
25123                                 texture.generateMipmaps = false;
25124                                 textureProperties.__maxMipLevel = mipmaps.length - 1;
25125
25126                         } else {
25127
25128                                 state.texImage2D( 3553, 0, glInternalFormat, glFormat, glType, image );
25129                                 textureProperties.__maxMipLevel = 0;
25130
25131                         }
25132
25133                 }
25134
25135                 if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
25136
25137                         generateMipmap( textureType, texture, image.width, image.height );
25138
25139                 }
25140
25141                 textureProperties.__version = texture.version;
25142
25143                 if ( texture.onUpdate ) texture.onUpdate( texture );
25144
25145         }
25146
25147         function uploadCubeTexture( textureProperties, texture, slot ) {
25148
25149                 if ( texture.image.length !== 6 ) return;
25150
25151                 initTexture( textureProperties, texture );
25152
25153                 state.activeTexture( 33984 + slot );
25154                 state.bindTexture( 34067, textureProperties.__webglTexture );
25155
25156                 _gl.pixelStorei( 37440, texture.flipY );
25157                 _gl.pixelStorei( 37441, texture.premultiplyAlpha );
25158                 _gl.pixelStorei( 3317, texture.unpackAlignment );
25159                 _gl.pixelStorei( 37443, 0 );
25160
25161                 const isCompressed = ( texture && ( texture.isCompressedTexture || texture.image[ 0 ].isCompressedTexture ) );
25162                 const isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture );
25163
25164                 const cubeImage = [];
25165
25166                 for ( let i = 0; i < 6; i ++ ) {
25167
25168                         if ( ! isCompressed && ! isDataTexture ) {
25169
25170                                 cubeImage[ i ] = resizeImage( texture.image[ i ], false, true, maxCubemapSize );
25171
25172                         } else {
25173
25174                                 cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ];
25175
25176                         }
25177
25178                 }
25179
25180                 const image = cubeImage[ 0 ],
25181                         supportsMips = isPowerOfTwo$1( image ) || isWebGL2,
25182                         glFormat = utils.convert( texture.format ),
25183                         glType = utils.convert( texture.type ),
25184                         glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding );
25185
25186                 setTextureParameters( 34067, texture, supportsMips );
25187
25188                 let mipmaps;
25189
25190                 if ( isCompressed ) {
25191
25192                         for ( let i = 0; i < 6; i ++ ) {
25193
25194                                 mipmaps = cubeImage[ i ].mipmaps;
25195
25196                                 for ( let j = 0; j < mipmaps.length; j ++ ) {
25197
25198                                         const mipmap = mipmaps[ j ];
25199
25200                                         if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) {
25201
25202                                                 if ( glFormat !== null ) {
25203
25204                                                         state.compressedTexImage2D( 34069 + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );
25205
25206                                                 } else {
25207
25208                                                         console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()' );
25209
25210                                                 }
25211
25212                                         } else {
25213
25214                                                 state.texImage2D( 34069 + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
25215
25216                                         }
25217
25218                                 }
25219
25220                         }
25221
25222                         textureProperties.__maxMipLevel = mipmaps.length - 1;
25223
25224                 } else {
25225
25226                         mipmaps = texture.mipmaps;
25227
25228                         for ( let i = 0; i < 6; i ++ ) {
25229
25230                                 if ( isDataTexture ) {
25231
25232                                         state.texImage2D( 34069 + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data );
25233
25234                                         for ( let j = 0; j < mipmaps.length; j ++ ) {
25235
25236                                                 const mipmap = mipmaps[ j ];
25237                                                 const mipmapImage = mipmap.image[ i ].image;
25238
25239                                                 state.texImage2D( 34069 + i, j + 1, glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType, mipmapImage.data );
25240
25241                                         }
25242
25243                                 } else {
25244
25245                                         state.texImage2D( 34069 + i, 0, glInternalFormat, glFormat, glType, cubeImage[ i ] );
25246
25247                                         for ( let j = 0; j < mipmaps.length; j ++ ) {
25248
25249                                                 const mipmap = mipmaps[ j ];
25250
25251                                                 state.texImage2D( 34069 + i, j + 1, glInternalFormat, glFormat, glType, mipmap.image[ i ] );
25252
25253                                         }
25254
25255                                 }
25256
25257                         }
25258
25259                         textureProperties.__maxMipLevel = mipmaps.length;
25260
25261                 }
25262
25263                 if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
25264
25265                         // We assume images for cube map have the same size.
25266                         generateMipmap( 34067, texture, image.width, image.height );
25267
25268                 }
25269
25270                 textureProperties.__version = texture.version;
25271
25272                 if ( texture.onUpdate ) texture.onUpdate( texture );
25273
25274         }
25275
25276         // Render targets
25277
25278         // Setup storage for target texture and bind it to correct framebuffer
25279         function setupFrameBufferTexture( framebuffer, renderTarget, texture, attachment, textureTarget ) {
25280
25281                 const glFormat = utils.convert( texture.format );
25282                 const glType = utils.convert( texture.type );
25283                 const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding );
25284
25285                 if ( textureTarget === 32879 || textureTarget === 35866 ) {
25286
25287                         state.texImage3D( textureTarget, 0, glInternalFormat, renderTarget.width, renderTarget.height, renderTarget.depth, 0, glFormat, glType, null );
25288
25289                 } else {
25290
25291                         state.texImage2D( textureTarget, 0, glInternalFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
25292
25293                 }
25294
25295                 state.bindFramebuffer( 36160, framebuffer );
25296                 _gl.framebufferTexture2D( 36160, attachment, textureTarget, properties.get( texture ).__webglTexture, 0 );
25297                 state.bindFramebuffer( 36160, null );
25298
25299         }
25300
25301         // Setup storage for internal depth/stencil buffers and bind to correct framebuffer
25302         function setupRenderBufferStorage( renderbuffer, renderTarget, isMultisample ) {
25303
25304                 _gl.bindRenderbuffer( 36161, renderbuffer );
25305
25306                 if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
25307
25308                         let glInternalFormat = 33189;
25309
25310                         if ( isMultisample ) {
25311
25312                                 const depthTexture = renderTarget.depthTexture;
25313
25314                                 if ( depthTexture && depthTexture.isDepthTexture ) {
25315
25316                                         if ( depthTexture.type === FloatType ) {
25317
25318                                                 glInternalFormat = 36012;
25319
25320                                         } else if ( depthTexture.type === UnsignedIntType ) {
25321
25322                                                 glInternalFormat = 33190;
25323
25324                                         }
25325
25326                                 }
25327
25328                                 const samples = getRenderTargetSamples( renderTarget );
25329
25330                                 _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height );
25331
25332                         } else {
25333
25334                                 _gl.renderbufferStorage( 36161, glInternalFormat, renderTarget.width, renderTarget.height );
25335
25336                         }
25337
25338                         _gl.framebufferRenderbuffer( 36160, 36096, 36161, renderbuffer );
25339
25340                 } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
25341
25342                         if ( isMultisample ) {
25343
25344                                 const samples = getRenderTargetSamples( renderTarget );
25345
25346                                 _gl.renderbufferStorageMultisample( 36161, samples, 35056, renderTarget.width, renderTarget.height );
25347
25348                         } else {
25349
25350                                 _gl.renderbufferStorage( 36161, 34041, renderTarget.width, renderTarget.height );
25351
25352                         }
25353
25354
25355                         _gl.framebufferRenderbuffer( 36160, 33306, 36161, renderbuffer );
25356
25357                 } else {
25358
25359                         // Use the first texture for MRT so far
25360                         const texture = renderTarget.isWebGLMultipleRenderTargets === true ? renderTarget.texture[ 0 ] : renderTarget.texture;
25361
25362                         const glFormat = utils.convert( texture.format );
25363                         const glType = utils.convert( texture.type );
25364                         const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding );
25365
25366                         if ( isMultisample ) {
25367
25368                                 const samples = getRenderTargetSamples( renderTarget );
25369
25370                                 _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height );
25371
25372                         } else {
25373
25374                                 _gl.renderbufferStorage( 36161, glInternalFormat, renderTarget.width, renderTarget.height );
25375
25376                         }
25377
25378                 }
25379
25380                 _gl.bindRenderbuffer( 36161, null );
25381
25382         }
25383
25384         // Setup resources for a Depth Texture for a FBO (needs an extension)
25385         function setupDepthTexture( framebuffer, renderTarget ) {
25386
25387                 const isCube = ( renderTarget && renderTarget.isWebGLCubeRenderTarget );
25388                 if ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' );
25389
25390                 state.bindFramebuffer( 36160, framebuffer );
25391
25392                 if ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) {
25393
25394                         throw new Error( 'renderTarget.depthTexture must be an instance of THREE.DepthTexture' );
25395
25396                 }
25397
25398                 // upload an empty depth texture with framebuffer size
25399                 if ( ! properties.get( renderTarget.depthTexture ).__webglTexture ||
25400                                 renderTarget.depthTexture.image.width !== renderTarget.width ||
25401                                 renderTarget.depthTexture.image.height !== renderTarget.height ) {
25402
25403                         renderTarget.depthTexture.image.width = renderTarget.width;
25404                         renderTarget.depthTexture.image.height = renderTarget.height;
25405                         renderTarget.depthTexture.needsUpdate = true;
25406
25407                 }
25408
25409                 setTexture2D( renderTarget.depthTexture, 0 );
25410
25411                 const webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture;
25412
25413                 if ( renderTarget.depthTexture.format === DepthFormat ) {
25414
25415                         _gl.framebufferTexture2D( 36160, 36096, 3553, webglDepthTexture, 0 );
25416
25417                 } else if ( renderTarget.depthTexture.format === DepthStencilFormat ) {
25418
25419                         _gl.framebufferTexture2D( 36160, 33306, 3553, webglDepthTexture, 0 );
25420
25421                 } else {
25422
25423                         throw new Error( 'Unknown depthTexture format' );
25424
25425                 }
25426
25427         }
25428
25429         // Setup GL resources for a non-texture depth buffer
25430         function setupDepthRenderbuffer( renderTarget ) {
25431
25432                 const renderTargetProperties = properties.get( renderTarget );
25433
25434                 const isCube = ( renderTarget.isWebGLCubeRenderTarget === true );
25435
25436                 if ( renderTarget.depthTexture ) {
25437
25438                         if ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' );
25439
25440                         setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget );
25441
25442                 } else {
25443
25444                         if ( isCube ) {
25445
25446                                 renderTargetProperties.__webglDepthbuffer = [];
25447
25448                                 for ( let i = 0; i < 6; i ++ ) {
25449
25450                                         state.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer[ i ] );
25451                                         renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer();
25452                                         setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget, false );
25453
25454                                 }
25455
25456                         } else {
25457
25458                                 state.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer );
25459                                 renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer();
25460                                 setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget, false );
25461
25462                         }
25463
25464                 }
25465
25466                 state.bindFramebuffer( 36160, null );
25467
25468         }
25469
25470         // Set up GL resources for the render target
25471         function setupRenderTarget( renderTarget ) {
25472
25473                 const texture = renderTarget.texture;
25474
25475                 const renderTargetProperties = properties.get( renderTarget );
25476                 const textureProperties = properties.get( texture );
25477
25478                 renderTarget.addEventListener( 'dispose', onRenderTargetDispose );
25479
25480                 if ( renderTarget.isWebGLMultipleRenderTargets !== true ) {
25481
25482                         textureProperties.__webglTexture = _gl.createTexture();
25483                         textureProperties.__version = texture.version;
25484                         info.memory.textures ++;
25485
25486                 }
25487
25488                 const isCube = ( renderTarget.isWebGLCubeRenderTarget === true );
25489                 const isMultipleRenderTargets = ( renderTarget.isWebGLMultipleRenderTargets === true );
25490                 const isMultisample = ( renderTarget.isWebGLMultisampleRenderTarget === true );
25491                 const isRenderTarget3D = texture.isDataTexture3D || texture.isDataTexture2DArray;
25492                 const supportsMips = isPowerOfTwo$1( renderTarget ) || isWebGL2;
25493
25494                 // Handles WebGL2 RGBFormat fallback - #18858
25495
25496                 if ( isWebGL2 && texture.format === RGBFormat && ( texture.type === FloatType || texture.type === HalfFloatType ) ) {
25497
25498                         texture.format = RGBAFormat;
25499
25500                         console.warn( 'THREE.WebGLRenderer: Rendering to textures with RGB format is not supported. Using RGBA format instead.' );
25501
25502                 }
25503
25504                 // Setup framebuffer
25505
25506                 if ( isCube ) {
25507
25508                         renderTargetProperties.__webglFramebuffer = [];
25509
25510                         for ( let i = 0; i < 6; i ++ ) {
25511
25512                                 renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer();
25513
25514                         }
25515
25516                 } else {
25517
25518                         renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer();
25519
25520                         if ( isMultipleRenderTargets ) {
25521
25522                                 if ( capabilities.drawBuffers ) {
25523
25524                                         const textures = renderTarget.texture;
25525
25526                                         for ( let i = 0, il = textures.length; i < il; i ++ ) {
25527
25528                                                 const attachmentProperties = properties.get( textures[ i ] );
25529
25530                                                 if ( attachmentProperties.__webglTexture === undefined ) {
25531
25532                                                         attachmentProperties.__webglTexture = _gl.createTexture();
25533
25534                                                         info.memory.textures ++;
25535
25536                                                 }
25537
25538                                         }
25539
25540                                 } else {
25541
25542                                         console.warn( 'THREE.WebGLRenderer: WebGLMultipleRenderTargets can only be used with WebGL2 or WEBGL_draw_buffers extension.' );
25543
25544                                 }
25545
25546                         } else if ( isMultisample ) {
25547
25548                                 if ( isWebGL2 ) {
25549
25550                                         renderTargetProperties.__webglMultisampledFramebuffer = _gl.createFramebuffer();
25551                                         renderTargetProperties.__webglColorRenderbuffer = _gl.createRenderbuffer();
25552
25553                                         _gl.bindRenderbuffer( 36161, renderTargetProperties.__webglColorRenderbuffer );
25554
25555                                         const glFormat = utils.convert( texture.format );
25556                                         const glType = utils.convert( texture.type );
25557                                         const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding );
25558                                         const samples = getRenderTargetSamples( renderTarget );
25559                                         _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height );
25560
25561                                         state.bindFramebuffer( 36160, renderTargetProperties.__webglMultisampledFramebuffer );
25562                                         _gl.framebufferRenderbuffer( 36160, 36064, 36161, renderTargetProperties.__webglColorRenderbuffer );
25563                                         _gl.bindRenderbuffer( 36161, null );
25564
25565                                         if ( renderTarget.depthBuffer ) {
25566
25567                                                 renderTargetProperties.__webglDepthRenderbuffer = _gl.createRenderbuffer();
25568                                                 setupRenderBufferStorage( renderTargetProperties.__webglDepthRenderbuffer, renderTarget, true );
25569
25570                                         }
25571
25572                                         state.bindFramebuffer( 36160, null );
25573
25574
25575                                 } else {
25576
25577                                         console.warn( 'THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2.' );
25578
25579                                 }
25580
25581                         }
25582
25583                 }
25584
25585                 // Setup color buffer
25586
25587                 if ( isCube ) {
25588
25589                         state.bindTexture( 34067, textureProperties.__webglTexture );
25590                         setTextureParameters( 34067, texture, supportsMips );
25591
25592                         for ( let i = 0; i < 6; i ++ ) {
25593
25594                                 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, texture, 36064, 34069 + i );
25595
25596                         }
25597
25598                         if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
25599
25600                                 generateMipmap( 34067, texture, renderTarget.width, renderTarget.height );
25601
25602                         }
25603
25604                         state.unbindTexture();
25605
25606                 } else if ( isMultipleRenderTargets ) {
25607
25608                         const textures = renderTarget.texture;
25609
25610                         for ( let i = 0, il = textures.length; i < il; i ++ ) {
25611
25612                                 const attachment = textures[ i ];
25613                                 const attachmentProperties = properties.get( attachment );
25614
25615                                 state.bindTexture( 3553, attachmentProperties.__webglTexture );
25616                                 setTextureParameters( 3553, attachment, supportsMips );
25617                                 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, attachment, 36064 + i, 3553 );
25618
25619                                 if ( textureNeedsGenerateMipmaps( attachment, supportsMips ) ) {
25620
25621                                         generateMipmap( 3553, attachment, renderTarget.width, renderTarget.height );
25622
25623                                 }
25624
25625                         }
25626
25627                         state.unbindTexture();
25628
25629                 } else {
25630
25631                         let glTextureType = 3553;
25632
25633                         if ( isRenderTarget3D ) {
25634
25635                                 // Render targets containing layers, i.e: Texture 3D and 2d arrays
25636
25637                                 if ( isWebGL2 ) {
25638
25639                                         const isTexture3D = texture.isDataTexture3D;
25640                                         glTextureType = isTexture3D ? 32879 : 35866;
25641
25642                                 } else {
25643
25644                                         console.warn( 'THREE.DataTexture3D and THREE.DataTexture2DArray only supported with WebGL2.' );
25645
25646                                 }
25647
25648                         }
25649
25650                         state.bindTexture( glTextureType, textureProperties.__webglTexture );
25651                         setTextureParameters( glTextureType, texture, supportsMips );
25652                         setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, texture, 36064, glTextureType );
25653
25654                         if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
25655
25656                                 generateMipmap( glTextureType, texture, renderTarget.width, renderTarget.height, renderTarget.depth );
25657
25658                         }
25659
25660                         state.unbindTexture();
25661
25662                 }
25663
25664                 // Setup depth and stencil buffers
25665
25666                 if ( renderTarget.depthBuffer ) {
25667
25668                         setupDepthRenderbuffer( renderTarget );
25669
25670                 }
25671
25672         }
25673
25674         function updateRenderTargetMipmap( renderTarget ) {
25675
25676                 const supportsMips = isPowerOfTwo$1( renderTarget ) || isWebGL2;
25677
25678                 const textures = renderTarget.isWebGLMultipleRenderTargets === true ? renderTarget.texture : [ renderTarget.texture ];
25679
25680                 for ( let i = 0, il = textures.length; i < il; i ++ ) {
25681
25682                         const texture = textures[ i ];
25683
25684                         if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
25685
25686                                 const target = renderTarget.isWebGLCubeRenderTarget ? 34067 : 3553;
25687                                 const webglTexture = properties.get( texture ).__webglTexture;
25688
25689                                 state.bindTexture( target, webglTexture );
25690                                 generateMipmap( target, texture, renderTarget.width, renderTarget.height );
25691                                 state.unbindTexture();
25692
25693                         }
25694
25695                 }
25696
25697         }
25698
25699         function updateMultisampleRenderTarget( renderTarget ) {
25700
25701                 if ( renderTarget.isWebGLMultisampleRenderTarget ) {
25702
25703                         if ( isWebGL2 ) {
25704
25705                                 const width = renderTarget.width;
25706                                 const height = renderTarget.height;
25707                                 let mask = 16384;
25708
25709                                 if ( renderTarget.depthBuffer ) mask |= 256;
25710                                 if ( renderTarget.stencilBuffer ) mask |= 1024;
25711
25712                                 const renderTargetProperties = properties.get( renderTarget );
25713
25714                                 state.bindFramebuffer( 36008, renderTargetProperties.__webglMultisampledFramebuffer );
25715                                 state.bindFramebuffer( 36009, renderTargetProperties.__webglFramebuffer );
25716
25717                                 _gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, 9728 );
25718
25719                                 state.bindFramebuffer( 36008, null );
25720                                 state.bindFramebuffer( 36009, renderTargetProperties.__webglMultisampledFramebuffer );
25721
25722                         } else {
25723
25724                                 console.warn( 'THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2.' );
25725
25726                         }
25727
25728                 }
25729
25730         }
25731
25732         function getRenderTargetSamples( renderTarget ) {
25733
25734                 return ( isWebGL2 && renderTarget.isWebGLMultisampleRenderTarget ) ?
25735                         Math.min( maxSamples, renderTarget.samples ) : 0;
25736
25737         }
25738
25739         function updateVideoTexture( texture ) {
25740
25741                 const frame = info.render.frame;
25742
25743                 // Check the last frame we updated the VideoTexture
25744
25745                 if ( _videoTextures.get( texture ) !== frame ) {
25746
25747                         _videoTextures.set( texture, frame );
25748                         texture.update();
25749
25750                 }
25751
25752         }
25753
25754         // backwards compatibility
25755
25756         let warnedTexture2D = false;
25757         let warnedTextureCube = false;
25758
25759         function safeSetTexture2D( texture, slot ) {
25760
25761                 if ( texture && texture.isWebGLRenderTarget ) {
25762
25763                         if ( warnedTexture2D === false ) {
25764
25765                                 console.warn( 'THREE.WebGLTextures.safeSetTexture2D: don\'t use render targets as textures. Use their .texture property instead.' );
25766                                 warnedTexture2D = true;
25767
25768                         }
25769
25770                         texture = texture.texture;
25771
25772                 }
25773
25774                 setTexture2D( texture, slot );
25775
25776         }
25777
25778         function safeSetTextureCube( texture, slot ) {
25779
25780                 if ( texture && texture.isWebGLCubeRenderTarget ) {
25781
25782                         if ( warnedTextureCube === false ) {
25783
25784                                 console.warn( 'THREE.WebGLTextures.safeSetTextureCube: don\'t use cube render targets as textures. Use their .texture property instead.' );
25785                                 warnedTextureCube = true;
25786
25787                         }
25788
25789                         texture = texture.texture;
25790
25791                 }
25792
25793
25794                 setTextureCube( texture, slot );
25795
25796         }
25797
25798         //
25799
25800         this.allocateTextureUnit = allocateTextureUnit;
25801         this.resetTextureUnits = resetTextureUnits;
25802
25803         this.setTexture2D = setTexture2D;
25804         this.setTexture2DArray = setTexture2DArray;
25805         this.setTexture3D = setTexture3D;
25806         this.setTextureCube = setTextureCube;
25807         this.setupRenderTarget = setupRenderTarget;
25808         this.updateRenderTargetMipmap = updateRenderTargetMipmap;
25809         this.updateMultisampleRenderTarget = updateMultisampleRenderTarget;
25810
25811         this.safeSetTexture2D = safeSetTexture2D;
25812         this.safeSetTextureCube = safeSetTextureCube;
25813
25814 }
25815
25816 function WebGLUtils( gl, extensions, capabilities ) {
25817
25818         const isWebGL2 = capabilities.isWebGL2;
25819
25820         function convert( p ) {
25821
25822                 let extension;
25823
25824                 if ( p === UnsignedByteType ) return 5121;
25825                 if ( p === UnsignedShort4444Type ) return 32819;
25826                 if ( p === UnsignedShort5551Type ) return 32820;
25827                 if ( p === UnsignedShort565Type ) return 33635;
25828
25829                 if ( p === ByteType ) return 5120;
25830                 if ( p === ShortType ) return 5122;
25831                 if ( p === UnsignedShortType ) return 5123;
25832                 if ( p === IntType ) return 5124;
25833                 if ( p === UnsignedIntType ) return 5125;
25834                 if ( p === FloatType ) return 5126;
25835
25836                 if ( p === HalfFloatType ) {
25837
25838                         if ( isWebGL2 ) return 5131;
25839
25840                         extension = extensions.get( 'OES_texture_half_float' );
25841
25842                         if ( extension !== null ) {
25843
25844                                 return extension.HALF_FLOAT_OES;
25845
25846                         } else {
25847
25848                                 return null;
25849
25850                         }
25851
25852                 }
25853
25854                 if ( p === AlphaFormat ) return 6406;
25855                 if ( p === RGBFormat ) return 6407;
25856                 if ( p === RGBAFormat ) return 6408;
25857                 if ( p === LuminanceFormat ) return 6409;
25858                 if ( p === LuminanceAlphaFormat ) return 6410;
25859                 if ( p === DepthFormat ) return 6402;
25860                 if ( p === DepthStencilFormat ) return 34041;
25861                 if ( p === RedFormat ) return 6403;
25862
25863                 // WebGL2 formats.
25864
25865                 if ( p === RedIntegerFormat ) return 36244;
25866                 if ( p === RGFormat ) return 33319;
25867                 if ( p === RGIntegerFormat ) return 33320;
25868                 if ( p === RGBIntegerFormat ) return 36248;
25869                 if ( p === RGBAIntegerFormat ) return 36249;
25870
25871                 if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format ||
25872                         p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) {
25873
25874                         extension = extensions.get( 'WEBGL_compressed_texture_s3tc' );
25875
25876                         if ( extension !== null ) {
25877
25878                                 if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;
25879                                 if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;
25880                                 if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;
25881                                 if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;
25882
25883                         } else {
25884
25885                                 return null;
25886
25887                         }
25888
25889                 }
25890
25891                 if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format ||
25892                         p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) {
25893
25894                         extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' );
25895
25896                         if ( extension !== null ) {
25897
25898                                 if ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
25899                                 if ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
25900                                 if ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
25901                                 if ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
25902
25903                         } else {
25904
25905                                 return null;
25906
25907                         }
25908
25909                 }
25910
25911                 if ( p === RGB_ETC1_Format ) {
25912
25913                         extension = extensions.get( 'WEBGL_compressed_texture_etc1' );
25914
25915                         if ( extension !== null ) {
25916
25917                                 return extension.COMPRESSED_RGB_ETC1_WEBGL;
25918
25919                         } else {
25920
25921                                 return null;
25922
25923                         }
25924
25925                 }
25926
25927                 if ( p === RGB_ETC2_Format || p === RGBA_ETC2_EAC_Format ) {
25928
25929                         extension = extensions.get( 'WEBGL_compressed_texture_etc' );
25930
25931                         if ( extension !== null ) {
25932
25933                                 if ( p === RGB_ETC2_Format ) return extension.COMPRESSED_RGB8_ETC2;
25934                                 if ( p === RGBA_ETC2_EAC_Format ) return extension.COMPRESSED_RGBA8_ETC2_EAC;
25935
25936                         }
25937
25938                 }
25939
25940                 if ( p === RGBA_ASTC_4x4_Format || p === RGBA_ASTC_5x4_Format || p === RGBA_ASTC_5x5_Format ||
25941                         p === RGBA_ASTC_6x5_Format || p === RGBA_ASTC_6x6_Format || p === RGBA_ASTC_8x5_Format ||
25942                         p === RGBA_ASTC_8x6_Format || p === RGBA_ASTC_8x8_Format || p === RGBA_ASTC_10x5_Format ||
25943                         p === RGBA_ASTC_10x6_Format || p === RGBA_ASTC_10x8_Format || p === RGBA_ASTC_10x10_Format ||
25944                         p === RGBA_ASTC_12x10_Format || p === RGBA_ASTC_12x12_Format ||
25945                         p === SRGB8_ALPHA8_ASTC_4x4_Format || p === SRGB8_ALPHA8_ASTC_5x4_Format || p === SRGB8_ALPHA8_ASTC_5x5_Format ||
25946                         p === SRGB8_ALPHA8_ASTC_6x5_Format || p === SRGB8_ALPHA8_ASTC_6x6_Format || p === SRGB8_ALPHA8_ASTC_8x5_Format ||
25947                         p === SRGB8_ALPHA8_ASTC_8x6_Format || p === SRGB8_ALPHA8_ASTC_8x8_Format || p === SRGB8_ALPHA8_ASTC_10x5_Format ||
25948                         p === SRGB8_ALPHA8_ASTC_10x6_Format || p === SRGB8_ALPHA8_ASTC_10x8_Format || p === SRGB8_ALPHA8_ASTC_10x10_Format ||
25949                         p === SRGB8_ALPHA8_ASTC_12x10_Format || p === SRGB8_ALPHA8_ASTC_12x12_Format ) {
25950
25951                         extension = extensions.get( 'WEBGL_compressed_texture_astc' );
25952
25953                         if ( extension !== null ) {
25954
25955                                 // TODO Complete?
25956
25957                                 return p;
25958
25959                         } else {
25960
25961                                 return null;
25962
25963                         }
25964
25965                 }
25966
25967                 if ( p === RGBA_BPTC_Format ) {
25968
25969                         extension = extensions.get( 'EXT_texture_compression_bptc' );
25970
25971                         if ( extension !== null ) {
25972
25973                                 // TODO Complete?
25974
25975                                 return p;
25976
25977                         } else {
25978
25979                                 return null;
25980
25981                         }
25982
25983                 }
25984
25985                 if ( p === UnsignedInt248Type ) {
25986
25987                         if ( isWebGL2 ) return 34042;
25988
25989                         extension = extensions.get( 'WEBGL_depth_texture' );
25990
25991                         if ( extension !== null ) {
25992
25993                                 return extension.UNSIGNED_INT_24_8_WEBGL;
25994
25995                         } else {
25996
25997                                 return null;
25998
25999                         }
26000
26001                 }
26002
26003         }
26004
26005         return { convert: convert };
26006
26007 }
26008
26009 class ArrayCamera extends PerspectiveCamera {
26010
26011         constructor( array = [] ) {
26012
26013                 super();
26014
26015                 this.cameras = array;
26016
26017         }
26018
26019 }
26020
26021 ArrayCamera.prototype.isArrayCamera = true;
26022
26023 class Group extends Object3D {
26024
26025         constructor() {
26026
26027                 super();
26028
26029                 this.type = 'Group';
26030
26031         }
26032
26033 }
26034
26035 Group.prototype.isGroup = true;
26036
26037 const _moveEvent = { type: 'move' };
26038
26039 class WebXRController {
26040
26041         constructor() {
26042
26043                 this._targetRay = null;
26044                 this._grip = null;
26045                 this._hand = null;
26046
26047         }
26048
26049         getHandSpace() {
26050
26051                 if ( this._hand === null ) {
26052
26053                         this._hand = new Group();
26054                         this._hand.matrixAutoUpdate = false;
26055                         this._hand.visible = false;
26056
26057                         this._hand.joints = {};
26058                         this._hand.inputState = { pinching: false };
26059
26060                 }
26061
26062                 return this._hand;
26063
26064         }
26065
26066         getTargetRaySpace() {
26067
26068                 if ( this._targetRay === null ) {
26069
26070                         this._targetRay = new Group();
26071                         this._targetRay.matrixAutoUpdate = false;
26072                         this._targetRay.visible = false;
26073                         this._targetRay.hasLinearVelocity = false;
26074                         this._targetRay.linearVelocity = new Vector3();
26075                         this._targetRay.hasAngularVelocity = false;
26076                         this._targetRay.angularVelocity = new Vector3();
26077
26078                 }
26079
26080                 return this._targetRay;
26081
26082         }
26083
26084         getGripSpace() {
26085
26086                 if ( this._grip === null ) {
26087
26088                         this._grip = new Group();
26089                         this._grip.matrixAutoUpdate = false;
26090                         this._grip.visible = false;
26091                         this._grip.hasLinearVelocity = false;
26092                         this._grip.linearVelocity = new Vector3();
26093                         this._grip.hasAngularVelocity = false;
26094                         this._grip.angularVelocity = new Vector3();
26095
26096                 }
26097
26098                 return this._grip;
26099
26100         }
26101
26102         dispatchEvent( event ) {
26103
26104                 if ( this._targetRay !== null ) {
26105
26106                         this._targetRay.dispatchEvent( event );
26107
26108                 }
26109
26110                 if ( this._grip !== null ) {
26111
26112                         this._grip.dispatchEvent( event );
26113
26114                 }
26115
26116                 if ( this._hand !== null ) {
26117
26118                         this._hand.dispatchEvent( event );
26119
26120                 }
26121
26122                 return this;
26123
26124         }
26125
26126         disconnect( inputSource ) {
26127
26128                 this.dispatchEvent( { type: 'disconnected', data: inputSource } );
26129
26130                 if ( this._targetRay !== null ) {
26131
26132                         this._targetRay.visible = false;
26133
26134                 }
26135
26136                 if ( this._grip !== null ) {
26137
26138                         this._grip.visible = false;
26139
26140                 }
26141
26142                 if ( this._hand !== null ) {
26143
26144                         this._hand.visible = false;
26145
26146                 }
26147
26148                 return this;
26149
26150         }
26151
26152         update( inputSource, frame, referenceSpace ) {
26153
26154                 let inputPose = null;
26155                 let gripPose = null;
26156                 let handPose = null;
26157
26158                 const targetRay = this._targetRay;
26159                 const grip = this._grip;
26160                 const hand = this._hand;
26161
26162                 if ( inputSource && frame.session.visibilityState !== 'visible-blurred' ) {
26163
26164                         if ( targetRay !== null ) {
26165
26166                                 inputPose = frame.getPose( inputSource.targetRaySpace, referenceSpace );
26167
26168                                 if ( inputPose !== null ) {
26169
26170                                         targetRay.matrix.fromArray( inputPose.transform.matrix );
26171                                         targetRay.matrix.decompose( targetRay.position, targetRay.rotation, targetRay.scale );
26172
26173                                         if ( inputPose.linearVelocity ) {
26174
26175                                                 targetRay.hasLinearVelocity = true;
26176                                                 targetRay.linearVelocity.copy( inputPose.linearVelocity );
26177
26178                                         } else {
26179
26180                                                 targetRay.hasLinearVelocity = false;
26181
26182                                         }
26183
26184                                         if ( inputPose.angularVelocity ) {
26185
26186                                                 targetRay.hasAngularVelocity = true;
26187                                                 targetRay.angularVelocity.copy( inputPose.angularVelocity );
26188
26189                                         } else {
26190
26191                                                 targetRay.hasAngularVelocity = false;
26192
26193                                         }
26194
26195                                         this.dispatchEvent( _moveEvent );
26196
26197                                 }
26198
26199                         }
26200
26201                         if ( hand && inputSource.hand ) {
26202
26203                                 handPose = true;
26204
26205                                 for ( const inputjoint of inputSource.hand.values() ) {
26206
26207                                         // Update the joints groups with the XRJoint poses
26208                                         const jointPose = frame.getJointPose( inputjoint, referenceSpace );
26209
26210                                         if ( hand.joints[ inputjoint.jointName ] === undefined ) {
26211
26212                                                 // The transform of this joint will be updated with the joint pose on each frame
26213                                                 const joint = new Group();
26214                                                 joint.matrixAutoUpdate = false;
26215                                                 joint.visible = false;
26216                                                 hand.joints[ inputjoint.jointName ] = joint;
26217                                                 // ??
26218                                                 hand.add( joint );
26219
26220                                         }
26221
26222                                         const joint = hand.joints[ inputjoint.jointName ];
26223
26224                                         if ( jointPose !== null ) {
26225
26226                                                 joint.matrix.fromArray( jointPose.transform.matrix );
26227                                                 joint.matrix.decompose( joint.position, joint.rotation, joint.scale );
26228                                                 joint.jointRadius = jointPose.radius;
26229
26230                                         }
26231
26232                                         joint.visible = jointPose !== null;
26233
26234                                 }
26235
26236                                 // Custom events
26237
26238                                 // Check pinchz
26239                                 const indexTip = hand.joints[ 'index-finger-tip' ];
26240                                 const thumbTip = hand.joints[ 'thumb-tip' ];
26241                                 const distance = indexTip.position.distanceTo( thumbTip.position );
26242
26243                                 const distanceToPinch = 0.02;
26244                                 const threshold = 0.005;
26245
26246                                 if ( hand.inputState.pinching && distance > distanceToPinch + threshold ) {
26247
26248                                         hand.inputState.pinching = false;
26249                                         this.dispatchEvent( {
26250                                                 type: 'pinchend',
26251                                                 handedness: inputSource.handedness,
26252                                                 target: this
26253                                         } );
26254
26255                                 } else if ( ! hand.inputState.pinching && distance <= distanceToPinch - threshold ) {
26256
26257                                         hand.inputState.pinching = true;
26258                                         this.dispatchEvent( {
26259                                                 type: 'pinchstart',
26260                                                 handedness: inputSource.handedness,
26261                                                 target: this
26262                                         } );
26263
26264                                 }
26265
26266                         } else {
26267
26268                                 if ( grip !== null && inputSource.gripSpace ) {
26269
26270                                         gripPose = frame.getPose( inputSource.gripSpace, referenceSpace );
26271
26272                                         if ( gripPose !== null ) {
26273
26274                                                 grip.matrix.fromArray( gripPose.transform.matrix );
26275                                                 grip.matrix.decompose( grip.position, grip.rotation, grip.scale );
26276
26277                                                 if ( gripPose.linearVelocity ) {
26278
26279                                                         grip.hasLinearVelocity = true;
26280                                                         grip.linearVelocity.copy( gripPose.linearVelocity );
26281
26282                                                 } else {
26283
26284                                                         grip.hasLinearVelocity = false;
26285
26286                                                 }
26287
26288                                                 if ( gripPose.angularVelocity ) {
26289
26290                                                         grip.hasAngularVelocity = true;
26291                                                         grip.angularVelocity.copy( gripPose.angularVelocity );
26292
26293                                                 } else {
26294
26295                                                         grip.hasAngularVelocity = false;
26296
26297                                                 }
26298
26299                                         }
26300
26301                                 }
26302
26303                         }
26304
26305                 }
26306
26307                 if ( targetRay !== null ) {
26308
26309                         targetRay.visible = ( inputPose !== null );
26310
26311                 }
26312
26313                 if ( grip !== null ) {
26314
26315                         grip.visible = ( gripPose !== null );
26316
26317                 }
26318
26319                 if ( hand !== null ) {
26320
26321                         hand.visible = ( handPose !== null );
26322
26323                 }
26324
26325                 return this;
26326
26327         }
26328
26329 }
26330
26331 class WebXRManager extends EventDispatcher {
26332
26333         constructor( renderer, gl ) {
26334
26335                 super();
26336
26337                 const scope = this;
26338                 const state = renderer.state;
26339
26340                 let session = null;
26341                 let framebufferScaleFactor = 1.0;
26342
26343                 let referenceSpace = null;
26344                 let referenceSpaceType = 'local-floor';
26345
26346                 let pose = null;
26347                 let glBinding = null;
26348                 let glFramebuffer = null;
26349                 let glProjLayer = null;
26350                 let glBaseLayer = null;
26351                 let isMultisample = false;
26352                 let glMultisampledFramebuffer = null;
26353                 let glColorRenderbuffer = null;
26354                 let glDepthRenderbuffer = null;
26355                 let xrFrame = null;
26356                 let depthStyle = null;
26357                 let clearStyle = null;
26358
26359                 const controllers = [];
26360                 const inputSourcesMap = new Map();
26361
26362                 //
26363
26364                 const cameraL = new PerspectiveCamera();
26365                 cameraL.layers.enable( 1 );
26366                 cameraL.viewport = new Vector4();
26367
26368                 const cameraR = new PerspectiveCamera();
26369                 cameraR.layers.enable( 2 );
26370                 cameraR.viewport = new Vector4();
26371
26372                 const cameras = [ cameraL, cameraR ];
26373
26374                 const cameraVR = new ArrayCamera();
26375                 cameraVR.layers.enable( 1 );
26376                 cameraVR.layers.enable( 2 );
26377
26378                 let _currentDepthNear = null;
26379                 let _currentDepthFar = null;
26380
26381                 //
26382
26383                 this.cameraAutoUpdate = true;
26384                 this.enabled = false;
26385
26386                 this.isPresenting = false;
26387
26388                 this.getController = function ( index ) {
26389
26390                         let controller = controllers[ index ];
26391
26392                         if ( controller === undefined ) {
26393
26394                                 controller = new WebXRController();
26395                                 controllers[ index ] = controller;
26396
26397                         }
26398
26399                         return controller.getTargetRaySpace();
26400
26401                 };
26402
26403                 this.getControllerGrip = function ( index ) {
26404
26405                         let controller = controllers[ index ];
26406
26407                         if ( controller === undefined ) {
26408
26409                                 controller = new WebXRController();
26410                                 controllers[ index ] = controller;
26411
26412                         }
26413
26414                         return controller.getGripSpace();
26415
26416                 };
26417
26418                 this.getHand = function ( index ) {
26419
26420                         let controller = controllers[ index ];
26421
26422                         if ( controller === undefined ) {
26423
26424                                 controller = new WebXRController();
26425                                 controllers[ index ] = controller;
26426
26427                         }
26428
26429                         return controller.getHandSpace();
26430
26431                 };
26432
26433                 //
26434
26435                 function onSessionEvent( event ) {
26436
26437                         const controller = inputSourcesMap.get( event.inputSource );
26438
26439                         if ( controller ) {
26440
26441                                 controller.dispatchEvent( { type: event.type, data: event.inputSource } );
26442
26443                         }
26444
26445                 }
26446
26447                 function onSessionEnd() {
26448
26449                         inputSourcesMap.forEach( function ( controller, inputSource ) {
26450
26451                                 controller.disconnect( inputSource );
26452
26453                         } );
26454
26455                         inputSourcesMap.clear();
26456
26457                         _currentDepthNear = null;
26458                         _currentDepthFar = null;
26459
26460                         // restore framebuffer/rendering state
26461
26462                         state.bindXRFramebuffer( null );
26463                         renderer.setRenderTarget( renderer.getRenderTarget() );
26464
26465                         if ( glFramebuffer ) gl.deleteFramebuffer( glFramebuffer );
26466                         if ( glMultisampledFramebuffer ) gl.deleteFramebuffer( glMultisampledFramebuffer );
26467                         if ( glColorRenderbuffer ) gl.deleteRenderbuffer( glColorRenderbuffer );
26468                         if ( glDepthRenderbuffer ) gl.deleteRenderbuffer( glDepthRenderbuffer );
26469                         glFramebuffer = null;
26470                         glMultisampledFramebuffer = null;
26471                         glColorRenderbuffer = null;
26472                         glDepthRenderbuffer = null;
26473                         glBaseLayer = null;
26474                         glProjLayer = null;
26475                         glBinding = null;
26476                         session = null;
26477
26478                         //
26479
26480                         animation.stop();
26481
26482                         scope.isPresenting = false;
26483
26484                         scope.dispatchEvent( { type: 'sessionend' } );
26485
26486                 }
26487
26488                 this.setFramebufferScaleFactor = function ( value ) {
26489
26490                         framebufferScaleFactor = value;
26491
26492                         if ( scope.isPresenting === true ) {
26493
26494                                 console.warn( 'THREE.WebXRManager: Cannot change framebuffer scale while presenting.' );
26495
26496                         }
26497
26498                 };
26499
26500                 this.setReferenceSpaceType = function ( value ) {
26501
26502                         referenceSpaceType = value;
26503
26504                         if ( scope.isPresenting === true ) {
26505
26506                                 console.warn( 'THREE.WebXRManager: Cannot change reference space type while presenting.' );
26507
26508                         }
26509
26510                 };
26511
26512                 this.getReferenceSpace = function () {
26513
26514                         return referenceSpace;
26515
26516                 };
26517
26518                 this.getBaseLayer = function () {
26519
26520                         return glProjLayer !== null ? glProjLayer : glBaseLayer;
26521
26522                 };
26523
26524                 this.getBinding = function () {
26525
26526                         return glBinding;
26527
26528                 };
26529
26530                 this.getFrame = function () {
26531
26532                         return xrFrame;
26533
26534                 };
26535
26536                 this.getSession = function () {
26537
26538                         return session;
26539
26540                 };
26541
26542                 this.setSession = async function ( value ) {
26543
26544                         session = value;
26545
26546                         if ( session !== null ) {
26547
26548                                 session.addEventListener( 'select', onSessionEvent );
26549                                 session.addEventListener( 'selectstart', onSessionEvent );
26550                                 session.addEventListener( 'selectend', onSessionEvent );
26551                                 session.addEventListener( 'squeeze', onSessionEvent );
26552                                 session.addEventListener( 'squeezestart', onSessionEvent );
26553                                 session.addEventListener( 'squeezeend', onSessionEvent );
26554                                 session.addEventListener( 'end', onSessionEnd );
26555                                 session.addEventListener( 'inputsourceschange', onInputSourcesChange );
26556
26557                                 const attributes = gl.getContextAttributes();
26558
26559                                 if ( attributes.xrCompatible !== true ) {
26560
26561                                         await gl.makeXRCompatible();
26562
26563                                 }
26564
26565                                 if ( session.renderState.layers === undefined ) {
26566
26567                                         const layerInit = {
26568                                                 antialias: attributes.antialias,
26569                                                 alpha: attributes.alpha,
26570                                                 depth: attributes.depth,
26571                                                 stencil: attributes.stencil,
26572                                                 framebufferScaleFactor: framebufferScaleFactor
26573                                         };
26574
26575                                         glBaseLayer = new XRWebGLLayer( session, gl, layerInit );
26576
26577                                         session.updateRenderState( { baseLayer: glBaseLayer } );
26578
26579                                 } else if ( gl instanceof WebGLRenderingContext ) {
26580
26581                                         // Use old style webgl layer because we can't use MSAA
26582                                         // WebGL2 support.
26583
26584                                         const layerInit = {
26585                                                 antialias: true,
26586                                                 alpha: attributes.alpha,
26587                                                 depth: attributes.depth,
26588                                                 stencil: attributes.stencil,
26589                                                 framebufferScaleFactor: framebufferScaleFactor
26590                                         };
26591
26592                                         glBaseLayer = new XRWebGLLayer( session, gl, layerInit );
26593
26594                                         session.updateRenderState( { layers: [ glBaseLayer ] } );
26595
26596                                 } else {
26597
26598                                         isMultisample = attributes.antialias;
26599                                         let depthFormat = null;
26600
26601
26602                                         if ( attributes.depth ) {
26603
26604                                                 clearStyle = 256;
26605
26606                                                 if ( attributes.stencil ) clearStyle |= 1024;
26607
26608                                                 depthStyle = attributes.stencil ? 33306 : 36096;
26609                                                 depthFormat = attributes.stencil ? 35056 : 33190;
26610
26611                                         }
26612
26613                                         const projectionlayerInit = {
26614                                                 colorFormat: attributes.alpha ? 32856 : 32849,
26615                                                 depthFormat: depthFormat,
26616                                                 scaleFactor: framebufferScaleFactor
26617                                         };
26618
26619                                         glBinding = new XRWebGLBinding( session, gl );
26620
26621                                         glProjLayer = glBinding.createProjectionLayer( projectionlayerInit );
26622
26623                                         glFramebuffer = gl.createFramebuffer();
26624
26625                                         session.updateRenderState( { layers: [ glProjLayer ] } );
26626
26627                                         if ( isMultisample ) {
26628
26629                                                 glMultisampledFramebuffer = gl.createFramebuffer();
26630                                                 glColorRenderbuffer = gl.createRenderbuffer();
26631                                                 gl.bindRenderbuffer( 36161, glColorRenderbuffer );
26632                                                 gl.renderbufferStorageMultisample(
26633                                                         36161,
26634                                                         4,
26635                                                         32856,
26636                                                         glProjLayer.textureWidth,
26637                                                         glProjLayer.textureHeight );
26638                                                 state.bindFramebuffer( 36160, glMultisampledFramebuffer );
26639                                                 gl.framebufferRenderbuffer( 36160, 36064, 36161, glColorRenderbuffer );
26640                                                 gl.bindRenderbuffer( 36161, null );
26641
26642                                                 if ( depthFormat !== null ) {
26643
26644                                                         glDepthRenderbuffer = gl.createRenderbuffer();
26645                                                         gl.bindRenderbuffer( 36161, glDepthRenderbuffer );
26646                                                         gl.renderbufferStorageMultisample( 36161, 4, depthFormat, glProjLayer.textureWidth, glProjLayer.textureHeight );
26647                                                         gl.framebufferRenderbuffer( 36160, depthStyle, 36161, glDepthRenderbuffer );
26648                                                         gl.bindRenderbuffer( 36161, null );
26649
26650                                                 }
26651
26652                                                 state.bindFramebuffer( 36160, null );
26653
26654                                         }
26655
26656                                 }
26657
26658                                 referenceSpace = await session.requestReferenceSpace( referenceSpaceType );
26659
26660                                 animation.setContext( session );
26661                                 animation.start();
26662
26663                                 scope.isPresenting = true;
26664
26665                                 scope.dispatchEvent( { type: 'sessionstart' } );
26666
26667                         }
26668
26669                 };
26670
26671                 function onInputSourcesChange( event ) {
26672
26673                         const inputSources = session.inputSources;
26674
26675                         // Assign inputSources to available controllers
26676
26677                         for ( let i = 0; i < controllers.length; i ++ ) {
26678
26679                                 inputSourcesMap.set( inputSources[ i ], controllers[ i ] );
26680
26681                         }
26682
26683                         // Notify disconnected
26684
26685                         for ( let i = 0; i < event.removed.length; i ++ ) {
26686
26687                                 const inputSource = event.removed[ i ];
26688                                 const controller = inputSourcesMap.get( inputSource );
26689
26690                                 if ( controller ) {
26691
26692                                         controller.dispatchEvent( { type: 'disconnected', data: inputSource } );
26693                                         inputSourcesMap.delete( inputSource );
26694
26695                                 }
26696
26697                         }
26698
26699                         // Notify connected
26700
26701                         for ( let i = 0; i < event.added.length; i ++ ) {
26702
26703                                 const inputSource = event.added[ i ];
26704                                 const controller = inputSourcesMap.get( inputSource );
26705
26706                                 if ( controller ) {
26707
26708                                         controller.dispatchEvent( { type: 'connected', data: inputSource } );
26709
26710                                 }
26711
26712                         }
26713
26714                 }
26715
26716                 //
26717
26718                 const cameraLPos = new Vector3();
26719                 const cameraRPos = new Vector3();
26720
26721                 /**
26722                  * Assumes 2 cameras that are parallel and share an X-axis, and that
26723                  * the cameras' projection and world matrices have already been set.
26724                  * And that near and far planes are identical for both cameras.
26725                  * Visualization of this technique: https://computergraphics.stackexchange.com/a/4765
26726                  */
26727                 function setProjectionFromUnion( camera, cameraL, cameraR ) {
26728
26729                         cameraLPos.setFromMatrixPosition( cameraL.matrixWorld );
26730                         cameraRPos.setFromMatrixPosition( cameraR.matrixWorld );
26731
26732                         const ipd = cameraLPos.distanceTo( cameraRPos );
26733
26734                         const projL = cameraL.projectionMatrix.elements;
26735                         const projR = cameraR.projectionMatrix.elements;
26736
26737                         // VR systems will have identical far and near planes, and
26738                         // most likely identical top and bottom frustum extents.
26739                         // Use the left camera for these values.
26740                         const near = projL[ 14 ] / ( projL[ 10 ] - 1 );
26741                         const far = projL[ 14 ] / ( projL[ 10 ] + 1 );
26742                         const topFov = ( projL[ 9 ] + 1 ) / projL[ 5 ];
26743                         const bottomFov = ( projL[ 9 ] - 1 ) / projL[ 5 ];
26744
26745                         const leftFov = ( projL[ 8 ] - 1 ) / projL[ 0 ];
26746                         const rightFov = ( projR[ 8 ] + 1 ) / projR[ 0 ];
26747                         const left = near * leftFov;
26748                         const right = near * rightFov;
26749
26750                         // Calculate the new camera's position offset from the
26751                         // left camera. xOffset should be roughly half `ipd`.
26752                         const zOffset = ipd / ( - leftFov + rightFov );
26753                         const xOffset = zOffset * - leftFov;
26754
26755                         // TODO: Better way to apply this offset?
26756                         cameraL.matrixWorld.decompose( camera.position, camera.quaternion, camera.scale );
26757                         camera.translateX( xOffset );
26758                         camera.translateZ( zOffset );
26759                         camera.matrixWorld.compose( camera.position, camera.quaternion, camera.scale );
26760                         camera.matrixWorldInverse.copy( camera.matrixWorld ).invert();
26761
26762                         // Find the union of the frustum values of the cameras and scale
26763                         // the values so that the near plane's position does not change in world space,
26764                         // although must now be relative to the new union camera.
26765                         const near2 = near + zOffset;
26766                         const far2 = far + zOffset;
26767                         const left2 = left - xOffset;
26768                         const right2 = right + ( ipd - xOffset );
26769                         const top2 = topFov * far / far2 * near2;
26770                         const bottom2 = bottomFov * far / far2 * near2;
26771
26772                         camera.projectionMatrix.makePerspective( left2, right2, top2, bottom2, near2, far2 );
26773
26774                 }
26775
26776                 function updateCamera( camera, parent ) {
26777
26778                         if ( parent === null ) {
26779
26780                                 camera.matrixWorld.copy( camera.matrix );
26781
26782                         } else {
26783
26784                                 camera.matrixWorld.multiplyMatrices( parent.matrixWorld, camera.matrix );
26785
26786                         }
26787
26788                         camera.matrixWorldInverse.copy( camera.matrixWorld ).invert();
26789
26790                 }
26791
26792                 this.updateCamera = function ( camera ) {
26793
26794                         if ( session === null ) return;
26795
26796                         cameraVR.near = cameraR.near = cameraL.near = camera.near;
26797                         cameraVR.far = cameraR.far = cameraL.far = camera.far;
26798
26799                         if ( _currentDepthNear !== cameraVR.near || _currentDepthFar !== cameraVR.far ) {
26800
26801                                 // Note that the new renderState won't apply until the next frame. See #18320
26802
26803                                 session.updateRenderState( {
26804                                         depthNear: cameraVR.near,
26805                                         depthFar: cameraVR.far
26806                                 } );
26807
26808                                 _currentDepthNear = cameraVR.near;
26809                                 _currentDepthFar = cameraVR.far;
26810
26811                         }
26812
26813                         const parent = camera.parent;
26814                         const cameras = cameraVR.cameras;
26815
26816                         updateCamera( cameraVR, parent );
26817
26818                         for ( let i = 0; i < cameras.length; i ++ ) {
26819
26820                                 updateCamera( cameras[ i ], parent );
26821
26822                         }
26823
26824                         cameraVR.matrixWorld.decompose( cameraVR.position, cameraVR.quaternion, cameraVR.scale );
26825
26826                         // update user camera and its children
26827
26828                         camera.position.copy( cameraVR.position );
26829                         camera.quaternion.copy( cameraVR.quaternion );
26830                         camera.scale.copy( cameraVR.scale );
26831                         camera.matrix.copy( cameraVR.matrix );
26832                         camera.matrixWorld.copy( cameraVR.matrixWorld );
26833
26834                         const children = camera.children;
26835
26836                         for ( let i = 0, l = children.length; i < l; i ++ ) {
26837
26838                                 children[ i ].updateMatrixWorld( true );
26839
26840                         }
26841
26842                         // update projection matrix for proper view frustum culling
26843
26844                         if ( cameras.length === 2 ) {
26845
26846                                 setProjectionFromUnion( cameraVR, cameraL, cameraR );
26847
26848                         } else {
26849
26850                                 // assume single camera setup (AR)
26851
26852                                 cameraVR.projectionMatrix.copy( cameraL.projectionMatrix );
26853
26854                         }
26855
26856                 };
26857
26858                 this.getCamera = function () {
26859
26860                         return cameraVR;
26861
26862                 };
26863
26864                 this.getFoveation = function () {
26865
26866                         if ( glProjLayer !== null ) {
26867
26868                                 return glProjLayer.fixedFoveation;
26869
26870                         }
26871
26872                         if ( glBaseLayer !== null ) {
26873
26874                                 return glBaseLayer.fixedFoveation;
26875
26876                         }
26877
26878                         return undefined;
26879
26880                 };
26881
26882                 this.setFoveation = function ( foveation ) {
26883
26884                         // 0 = no foveation = full resolution
26885                         // 1 = maximum foveation = the edges render at lower resolution
26886
26887                         if ( glProjLayer !== null ) {
26888
26889                                 glProjLayer.fixedFoveation = foveation;
26890
26891                         }
26892
26893                         if ( glBaseLayer !== null && glBaseLayer.fixedFoveation !== undefined ) {
26894
26895                                 glBaseLayer.fixedFoveation = foveation;
26896
26897                         }
26898
26899                 };
26900
26901                 // Animation Loop
26902
26903                 let onAnimationFrameCallback = null;
26904
26905                 function onAnimationFrame( time, frame ) {
26906
26907                         pose = frame.getViewerPose( referenceSpace );
26908                         xrFrame = frame;
26909
26910                         if ( pose !== null ) {
26911
26912                                 const views = pose.views;
26913
26914                                 if ( glBaseLayer !== null ) {
26915
26916                                         state.bindXRFramebuffer( glBaseLayer.framebuffer );
26917
26918                                 }
26919
26920                                 let cameraVRNeedsUpdate = false;
26921
26922                                 // check if it's necessary to rebuild cameraVR's camera list
26923
26924                                 if ( views.length !== cameraVR.cameras.length ) {
26925
26926                                         cameraVR.cameras.length = 0;
26927
26928                                         cameraVRNeedsUpdate = true;
26929
26930                                 }
26931
26932                                 for ( let i = 0; i < views.length; i ++ ) {
26933
26934                                         const view = views[ i ];
26935
26936                                         let viewport = null;
26937
26938                                         if ( glBaseLayer !== null ) {
26939
26940                                                 viewport = glBaseLayer.getViewport( view );
26941
26942                                         } else {
26943
26944                                                 const glSubImage = glBinding.getViewSubImage( glProjLayer, view );
26945
26946                                                 state.bindXRFramebuffer( glFramebuffer );
26947
26948                                                 if ( glSubImage.depthStencilTexture !== undefined ) {
26949
26950                                                         gl.framebufferTexture2D( 36160, depthStyle, 3553, glSubImage.depthStencilTexture, 0 );
26951
26952                                                 }
26953
26954                                                 gl.framebufferTexture2D( 36160, 36064, 3553, glSubImage.colorTexture, 0 );
26955
26956                                                 viewport = glSubImage.viewport;
26957
26958                                         }
26959
26960                                         const camera = cameras[ i ];
26961
26962                                         camera.matrix.fromArray( view.transform.matrix );
26963                                         camera.projectionMatrix.fromArray( view.projectionMatrix );
26964                                         camera.viewport.set( viewport.x, viewport.y, viewport.width, viewport.height );
26965
26966                                         if ( i === 0 ) {
26967
26968                                                 cameraVR.matrix.copy( camera.matrix );
26969
26970                                         }
26971
26972                                         if ( cameraVRNeedsUpdate === true ) {
26973
26974                                                 cameraVR.cameras.push( camera );
26975
26976                                         }
26977
26978                                 }
26979
26980                                 if ( isMultisample ) {
26981
26982                                         state.bindXRFramebuffer( glMultisampledFramebuffer );
26983
26984                                         if ( clearStyle !== null ) gl.clear( clearStyle );
26985
26986                                 }
26987
26988                         }
26989
26990                         //
26991
26992                         const inputSources = session.inputSources;
26993
26994                         for ( let i = 0; i < controllers.length; i ++ ) {
26995
26996                                 const controller = controllers[ i ];
26997                                 const inputSource = inputSources[ i ];
26998
26999                                 controller.update( inputSource, frame, referenceSpace );
27000
27001                         }
27002
27003                         if ( onAnimationFrameCallback ) onAnimationFrameCallback( time, frame );
27004
27005                         if ( isMultisample ) {
27006
27007                                 const width = glProjLayer.textureWidth;
27008                                 const height = glProjLayer.textureHeight;
27009
27010                                 state.bindFramebuffer( 36008, glMultisampledFramebuffer );
27011                                 state.bindFramebuffer( 36009, glFramebuffer );
27012                                 // Invalidate the depth here to avoid flush of the depth data to main memory.
27013                                 gl.invalidateFramebuffer( 36008, [ depthStyle ] );
27014                                 gl.invalidateFramebuffer( 36009, [ depthStyle ] );
27015                                 gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, 16384, 9728 );
27016                                 // Invalidate the MSAA buffer because it's not needed anymore.
27017                                 gl.invalidateFramebuffer( 36008, [ 36064 ] );
27018                                 state.bindFramebuffer( 36008, null );
27019                                 state.bindFramebuffer( 36009, null );
27020
27021                                 state.bindFramebuffer( 36160, glMultisampledFramebuffer );
27022
27023                         }
27024
27025                         xrFrame = null;
27026
27027                 }
27028
27029                 const animation = new WebGLAnimation();
27030
27031                 animation.setAnimationLoop( onAnimationFrame );
27032
27033                 this.setAnimationLoop = function ( callback ) {
27034
27035                         onAnimationFrameCallback = callback;
27036
27037                 };
27038
27039                 this.dispose = function () {};
27040
27041         }
27042
27043 }
27044
27045 function WebGLMaterials( properties ) {
27046
27047         function refreshFogUniforms( uniforms, fog ) {
27048
27049                 uniforms.fogColor.value.copy( fog.color );
27050
27051                 if ( fog.isFog ) {
27052
27053                         uniforms.fogNear.value = fog.near;
27054                         uniforms.fogFar.value = fog.far;
27055
27056                 } else if ( fog.isFogExp2 ) {
27057
27058                         uniforms.fogDensity.value = fog.density;
27059
27060                 }
27061
27062         }
27063
27064         function refreshMaterialUniforms( uniforms, material, pixelRatio, height, transmissionRenderTarget ) {
27065
27066                 if ( material.isMeshBasicMaterial ) {
27067
27068                         refreshUniformsCommon( uniforms, material );
27069
27070                 } else if ( material.isMeshLambertMaterial ) {
27071
27072                         refreshUniformsCommon( uniforms, material );
27073                         refreshUniformsLambert( uniforms, material );
27074
27075                 } else if ( material.isMeshToonMaterial ) {
27076
27077                         refreshUniformsCommon( uniforms, material );
27078                         refreshUniformsToon( uniforms, material );
27079
27080                 } else if ( material.isMeshPhongMaterial ) {
27081
27082                         refreshUniformsCommon( uniforms, material );
27083                         refreshUniformsPhong( uniforms, material );
27084
27085                 } else if ( material.isMeshStandardMaterial ) {
27086
27087                         refreshUniformsCommon( uniforms, material );
27088
27089                         if ( material.isMeshPhysicalMaterial ) {
27090
27091                                 refreshUniformsPhysical( uniforms, material, transmissionRenderTarget );
27092
27093                         } else {
27094
27095                                 refreshUniformsStandard( uniforms, material );
27096
27097                         }
27098
27099                 } else if ( material.isMeshMatcapMaterial ) {
27100
27101                         refreshUniformsCommon( uniforms, material );
27102                         refreshUniformsMatcap( uniforms, material );
27103
27104                 } else if ( material.isMeshDepthMaterial ) {
27105
27106                         refreshUniformsCommon( uniforms, material );
27107                         refreshUniformsDepth( uniforms, material );
27108
27109                 } else if ( material.isMeshDistanceMaterial ) {
27110
27111                         refreshUniformsCommon( uniforms, material );
27112                         refreshUniformsDistance( uniforms, material );
27113
27114                 } else if ( material.isMeshNormalMaterial ) {
27115
27116                         refreshUniformsCommon( uniforms, material );
27117                         refreshUniformsNormal( uniforms, material );
27118
27119                 } else if ( material.isLineBasicMaterial ) {
27120
27121                         refreshUniformsLine( uniforms, material );
27122
27123                         if ( material.isLineDashedMaterial ) {
27124
27125                                 refreshUniformsDash( uniforms, material );
27126
27127                         }
27128
27129                 } else if ( material.isPointsMaterial ) {
27130
27131                         refreshUniformsPoints( uniforms, material, pixelRatio, height );
27132
27133                 } else if ( material.isSpriteMaterial ) {
27134
27135                         refreshUniformsSprites( uniforms, material );
27136
27137                 } else if ( material.isShadowMaterial ) {
27138
27139                         uniforms.color.value.copy( material.color );
27140                         uniforms.opacity.value = material.opacity;
27141
27142                 } else if ( material.isShaderMaterial ) {
27143
27144                         material.uniformsNeedUpdate = false; // #15581
27145
27146                 }
27147
27148         }
27149
27150         function refreshUniformsCommon( uniforms, material ) {
27151
27152                 uniforms.opacity.value = material.opacity;
27153
27154                 if ( material.color ) {
27155
27156                         uniforms.diffuse.value.copy( material.color );
27157
27158                 }
27159
27160                 if ( material.emissive ) {
27161
27162                         uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity );
27163
27164                 }
27165
27166                 if ( material.map ) {
27167
27168                         uniforms.map.value = material.map;
27169
27170                 }
27171
27172                 if ( material.alphaMap ) {
27173
27174                         uniforms.alphaMap.value = material.alphaMap;
27175
27176                 }
27177
27178                 if ( material.specularMap ) {
27179
27180                         uniforms.specularMap.value = material.specularMap;
27181
27182                 }
27183
27184                 if ( material.alphaTest > 0 ) {
27185
27186                         uniforms.alphaTest.value = material.alphaTest;
27187
27188                 }
27189
27190                 const envMap = properties.get( material ).envMap;
27191
27192                 if ( envMap ) {
27193
27194                         uniforms.envMap.value = envMap;
27195
27196                         uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? - 1 : 1;
27197
27198                         uniforms.reflectivity.value = material.reflectivity;
27199                         uniforms.ior.value = material.ior;
27200                         uniforms.refractionRatio.value = material.refractionRatio;
27201
27202                         const maxMipLevel = properties.get( envMap ).__maxMipLevel;
27203
27204                         if ( maxMipLevel !== undefined ) {
27205
27206                                 uniforms.maxMipLevel.value = maxMipLevel;
27207
27208                         }
27209
27210                 }
27211
27212                 if ( material.lightMap ) {
27213
27214                         uniforms.lightMap.value = material.lightMap;
27215                         uniforms.lightMapIntensity.value = material.lightMapIntensity;
27216
27217                 }
27218
27219                 if ( material.aoMap ) {
27220
27221                         uniforms.aoMap.value = material.aoMap;
27222                         uniforms.aoMapIntensity.value = material.aoMapIntensity;
27223
27224                 }
27225
27226                 // uv repeat and offset setting priorities
27227                 // 1. color map
27228                 // 2. specular map
27229                 // 3. displacementMap map
27230                 // 4. normal map
27231                 // 5. bump map
27232                 // 6. roughnessMap map
27233                 // 7. metalnessMap map
27234                 // 8. alphaMap map
27235                 // 9. emissiveMap map
27236                 // 10. clearcoat map
27237                 // 11. clearcoat normal map
27238                 // 12. clearcoat roughnessMap map
27239                 // 13. specular intensity map
27240                 // 14. specular tint map
27241                 // 15. transmission map
27242                 // 16. thickness map
27243
27244                 let uvScaleMap;
27245
27246                 if ( material.map ) {
27247
27248                         uvScaleMap = material.map;
27249
27250                 } else if ( material.specularMap ) {
27251
27252                         uvScaleMap = material.specularMap;
27253
27254                 } else if ( material.displacementMap ) {
27255
27256                         uvScaleMap = material.displacementMap;
27257
27258                 } else if ( material.normalMap ) {
27259
27260                         uvScaleMap = material.normalMap;
27261
27262                 } else if ( material.bumpMap ) {
27263
27264                         uvScaleMap = material.bumpMap;
27265
27266                 } else if ( material.roughnessMap ) {
27267
27268                         uvScaleMap = material.roughnessMap;
27269
27270                 } else if ( material.metalnessMap ) {
27271
27272                         uvScaleMap = material.metalnessMap;
27273
27274                 } else if ( material.alphaMap ) {
27275
27276                         uvScaleMap = material.alphaMap;
27277
27278                 } else if ( material.emissiveMap ) {
27279
27280                         uvScaleMap = material.emissiveMap;
27281
27282                 } else if ( material.clearcoatMap ) {
27283
27284                         uvScaleMap = material.clearcoatMap;
27285
27286                 } else if ( material.clearcoatNormalMap ) {
27287
27288                         uvScaleMap = material.clearcoatNormalMap;
27289
27290                 } else if ( material.clearcoatRoughnessMap ) {
27291
27292                         uvScaleMap = material.clearcoatRoughnessMap;
27293
27294                 } else if ( material.specularIntensityMap ) {
27295
27296                         uvScaleMap = material.specularIntensityMap;
27297
27298                 } else if ( material.specularColorMap ) {
27299
27300                         uvScaleMap = material.specularColorMap;
27301
27302                 } else if ( material.transmissionMap ) {
27303
27304                         uvScaleMap = material.transmissionMap;
27305
27306                 } else if ( material.thicknessMap ) {
27307
27308                         uvScaleMap = material.thicknessMap;
27309
27310                 } else if ( material.sheenColorMap ) {
27311
27312                         uvScaleMap = material.sheenColorMap;
27313
27314                 } else if ( material.sheenRoughnessMap ) {
27315
27316                         uvScaleMap = material.sheenRoughnessMap;
27317
27318                 }
27319
27320                 if ( uvScaleMap !== undefined ) {
27321
27322                         // backwards compatibility
27323                         if ( uvScaleMap.isWebGLRenderTarget ) {
27324
27325                                 uvScaleMap = uvScaleMap.texture;
27326
27327                         }
27328
27329                         if ( uvScaleMap.matrixAutoUpdate === true ) {
27330
27331                                 uvScaleMap.updateMatrix();
27332
27333                         }
27334
27335                         uniforms.uvTransform.value.copy( uvScaleMap.matrix );
27336
27337                 }
27338
27339                 // uv repeat and offset setting priorities for uv2
27340                 // 1. ao map
27341                 // 2. light map
27342
27343                 let uv2ScaleMap;
27344
27345                 if ( material.aoMap ) {
27346
27347                         uv2ScaleMap = material.aoMap;
27348
27349                 } else if ( material.lightMap ) {
27350
27351                         uv2ScaleMap = material.lightMap;
27352
27353                 }
27354
27355                 if ( uv2ScaleMap !== undefined ) {
27356
27357                         // backwards compatibility
27358                         if ( uv2ScaleMap.isWebGLRenderTarget ) {
27359
27360                                 uv2ScaleMap = uv2ScaleMap.texture;
27361
27362                         }
27363
27364                         if ( uv2ScaleMap.matrixAutoUpdate === true ) {
27365
27366                                 uv2ScaleMap.updateMatrix();
27367
27368                         }
27369
27370                         uniforms.uv2Transform.value.copy( uv2ScaleMap.matrix );
27371
27372                 }
27373
27374         }
27375
27376         function refreshUniformsLine( uniforms, material ) {
27377
27378                 uniforms.diffuse.value.copy( material.color );
27379                 uniforms.opacity.value = material.opacity;
27380
27381         }
27382
27383         function refreshUniformsDash( uniforms, material ) {
27384
27385                 uniforms.dashSize.value = material.dashSize;
27386                 uniforms.totalSize.value = material.dashSize + material.gapSize;
27387                 uniforms.scale.value = material.scale;
27388
27389         }
27390
27391         function refreshUniformsPoints( uniforms, material, pixelRatio, height ) {
27392
27393                 uniforms.diffuse.value.copy( material.color );
27394                 uniforms.opacity.value = material.opacity;
27395                 uniforms.size.value = material.size * pixelRatio;
27396                 uniforms.scale.value = height * 0.5;
27397
27398                 if ( material.map ) {
27399
27400                         uniforms.map.value = material.map;
27401
27402                 }
27403
27404                 if ( material.alphaMap ) {
27405
27406                         uniforms.alphaMap.value = material.alphaMap;
27407
27408                 }
27409
27410                 if ( material.alphaTest > 0 ) {
27411
27412                         uniforms.alphaTest.value = material.alphaTest;
27413
27414                 }
27415
27416                 // uv repeat and offset setting priorities
27417                 // 1. color map
27418                 // 2. alpha map
27419
27420                 let uvScaleMap;
27421
27422                 if ( material.map ) {
27423
27424                         uvScaleMap = material.map;
27425
27426                 } else if ( material.alphaMap ) {
27427
27428                         uvScaleMap = material.alphaMap;
27429
27430                 }
27431
27432                 if ( uvScaleMap !== undefined ) {
27433
27434                         if ( uvScaleMap.matrixAutoUpdate === true ) {
27435
27436                                 uvScaleMap.updateMatrix();
27437
27438                         }
27439
27440                         uniforms.uvTransform.value.copy( uvScaleMap.matrix );
27441
27442                 }
27443
27444         }
27445
27446         function refreshUniformsSprites( uniforms, material ) {
27447
27448                 uniforms.diffuse.value.copy( material.color );
27449                 uniforms.opacity.value = material.opacity;
27450                 uniforms.rotation.value = material.rotation;
27451
27452                 if ( material.map ) {
27453
27454                         uniforms.map.value = material.map;
27455
27456                 }
27457
27458                 if ( material.alphaMap ) {
27459
27460                         uniforms.alphaMap.value = material.alphaMap;
27461
27462                 }
27463
27464                 if ( material.alphaTest > 0 ) {
27465
27466                         uniforms.alphaTest.value = material.alphaTest;
27467
27468                 }
27469
27470                 // uv repeat and offset setting priorities
27471                 // 1. color map
27472                 // 2. alpha map
27473
27474                 let uvScaleMap;
27475
27476                 if ( material.map ) {
27477
27478                         uvScaleMap = material.map;
27479
27480                 } else if ( material.alphaMap ) {
27481
27482                         uvScaleMap = material.alphaMap;
27483
27484                 }
27485
27486                 if ( uvScaleMap !== undefined ) {
27487
27488                         if ( uvScaleMap.matrixAutoUpdate === true ) {
27489
27490                                 uvScaleMap.updateMatrix();
27491
27492                         }
27493
27494                         uniforms.uvTransform.value.copy( uvScaleMap.matrix );
27495
27496                 }
27497
27498         }
27499
27500         function refreshUniformsLambert( uniforms, material ) {
27501
27502                 if ( material.emissiveMap ) {
27503
27504                         uniforms.emissiveMap.value = material.emissiveMap;
27505
27506                 }
27507
27508         }
27509
27510         function refreshUniformsPhong( uniforms, material ) {
27511
27512                 uniforms.specular.value.copy( material.specular );
27513                 uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 )
27514
27515                 if ( material.emissiveMap ) {
27516
27517                         uniforms.emissiveMap.value = material.emissiveMap;
27518
27519                 }
27520
27521                 if ( material.bumpMap ) {
27522
27523                         uniforms.bumpMap.value = material.bumpMap;
27524                         uniforms.bumpScale.value = material.bumpScale;
27525                         if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1;
27526
27527                 }
27528
27529                 if ( material.normalMap ) {
27530
27531                         uniforms.normalMap.value = material.normalMap;
27532                         uniforms.normalScale.value.copy( material.normalScale );
27533                         if ( material.side === BackSide ) uniforms.normalScale.value.negate();
27534
27535                 }
27536
27537                 if ( material.displacementMap ) {
27538
27539                         uniforms.displacementMap.value = material.displacementMap;
27540                         uniforms.displacementScale.value = material.displacementScale;
27541                         uniforms.displacementBias.value = material.displacementBias;
27542
27543                 }
27544
27545         }
27546
27547         function refreshUniformsToon( uniforms, material ) {
27548
27549                 if ( material.gradientMap ) {
27550
27551                         uniforms.gradientMap.value = material.gradientMap;
27552
27553                 }
27554
27555                 if ( material.emissiveMap ) {
27556
27557                         uniforms.emissiveMap.value = material.emissiveMap;
27558
27559                 }
27560
27561                 if ( material.bumpMap ) {
27562
27563                         uniforms.bumpMap.value = material.bumpMap;
27564                         uniforms.bumpScale.value = material.bumpScale;
27565                         if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1;
27566
27567                 }
27568
27569                 if ( material.normalMap ) {
27570
27571                         uniforms.normalMap.value = material.normalMap;
27572                         uniforms.normalScale.value.copy( material.normalScale );
27573                         if ( material.side === BackSide ) uniforms.normalScale.value.negate();
27574
27575                 }
27576
27577                 if ( material.displacementMap ) {
27578
27579                         uniforms.displacementMap.value = material.displacementMap;
27580                         uniforms.displacementScale.value = material.displacementScale;
27581                         uniforms.displacementBias.value = material.displacementBias;
27582
27583                 }
27584
27585         }
27586
27587         function refreshUniformsStandard( uniforms, material ) {
27588
27589                 uniforms.roughness.value = material.roughness;
27590                 uniforms.metalness.value = material.metalness;
27591
27592                 if ( material.roughnessMap ) {
27593
27594                         uniforms.roughnessMap.value = material.roughnessMap;
27595
27596                 }
27597
27598                 if ( material.metalnessMap ) {
27599
27600                         uniforms.metalnessMap.value = material.metalnessMap;
27601
27602                 }
27603
27604                 if ( material.emissiveMap ) {
27605
27606                         uniforms.emissiveMap.value = material.emissiveMap;
27607
27608                 }
27609
27610                 if ( material.bumpMap ) {
27611
27612                         uniforms.bumpMap.value = material.bumpMap;
27613                         uniforms.bumpScale.value = material.bumpScale;
27614                         if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1;
27615
27616                 }
27617
27618                 if ( material.normalMap ) {
27619
27620                         uniforms.normalMap.value = material.normalMap;
27621                         uniforms.normalScale.value.copy( material.normalScale );
27622                         if ( material.side === BackSide ) uniforms.normalScale.value.negate();
27623
27624                 }
27625
27626                 if ( material.displacementMap ) {
27627
27628                         uniforms.displacementMap.value = material.displacementMap;
27629                         uniforms.displacementScale.value = material.displacementScale;
27630                         uniforms.displacementBias.value = material.displacementBias;
27631
27632                 }
27633
27634                 const envMap = properties.get( material ).envMap;
27635
27636                 if ( envMap ) {
27637
27638                         //uniforms.envMap.value = material.envMap; // part of uniforms common
27639                         uniforms.envMapIntensity.value = material.envMapIntensity;
27640
27641                 }
27642
27643         }
27644
27645         function refreshUniformsPhysical( uniforms, material, transmissionRenderTarget ) {
27646
27647                 refreshUniformsStandard( uniforms, material );
27648
27649                 uniforms.ior.value = material.ior; // also part of uniforms common
27650
27651                 if ( material.sheen > 0 ) {
27652
27653                         uniforms.sheenColor.value.copy( material.sheenColor ).multiplyScalar( material.sheen );
27654
27655                         uniforms.sheenRoughness.value = material.sheenRoughness;
27656
27657                         if ( material.sheenColorMap ) {
27658
27659                                 uniforms.sheenColorMap.value = material.sheenColorMap;
27660
27661                         }
27662
27663                         if ( material.sheenRoughnessMap ) {
27664
27665                                 uniforms.sheenRoughnessMap.value = material.sheenRoughnessMap;
27666
27667                         }
27668
27669                 }
27670
27671                 if ( material.clearcoat > 0 ) {
27672
27673                         uniforms.clearcoat.value = material.clearcoat;
27674                         uniforms.clearcoatRoughness.value = material.clearcoatRoughness;
27675
27676                         if ( material.clearcoatMap ) {
27677
27678                                 uniforms.clearcoatMap.value = material.clearcoatMap;
27679
27680                         }
27681
27682                         if ( material.clearcoatRoughnessMap ) {
27683
27684                                 uniforms.clearcoatRoughnessMap.value = material.clearcoatRoughnessMap;
27685
27686                         }
27687
27688                         if ( material.clearcoatNormalMap ) {
27689
27690                                 uniforms.clearcoatNormalScale.value.copy( material.clearcoatNormalScale );
27691                                 uniforms.clearcoatNormalMap.value = material.clearcoatNormalMap;
27692
27693                                 if ( material.side === BackSide ) {
27694
27695                                         uniforms.clearcoatNormalScale.value.negate();
27696
27697                                 }
27698
27699                         }
27700
27701                 }
27702
27703                 if ( material.transmission > 0 ) {
27704
27705                         uniforms.transmission.value = material.transmission;
27706                         uniforms.transmissionSamplerMap.value = transmissionRenderTarget.texture;
27707                         uniforms.transmissionSamplerSize.value.set( transmissionRenderTarget.width, transmissionRenderTarget.height );
27708
27709                         if ( material.transmissionMap ) {
27710
27711                                 uniforms.transmissionMap.value = material.transmissionMap;
27712
27713                         }
27714
27715                         uniforms.thickness.value = material.thickness;
27716
27717                         if ( material.thicknessMap ) {
27718
27719                                 uniforms.thicknessMap.value = material.thicknessMap;
27720
27721                         }
27722
27723                         uniforms.attenuationDistance.value = material.attenuationDistance;
27724                         uniforms.attenuationColor.value.copy( material.attenuationColor );
27725
27726                 }
27727
27728                 uniforms.specularIntensity.value = material.specularIntensity;
27729                 uniforms.specularColor.value.copy( material.specularColor );
27730
27731                 if ( material.specularIntensityMap ) {
27732
27733                         uniforms.specularIntensityMap.value = material.specularIntensityMap;
27734
27735                 }
27736
27737                 if ( material.specularColorMap ) {
27738
27739                         uniforms.specularColorMap.value = material.specularColorMap;
27740
27741                 }
27742
27743         }
27744
27745         function refreshUniformsMatcap( uniforms, material ) {
27746
27747                 if ( material.matcap ) {
27748
27749                         uniforms.matcap.value = material.matcap;
27750
27751                 }
27752
27753                 if ( material.bumpMap ) {
27754
27755                         uniforms.bumpMap.value = material.bumpMap;
27756                         uniforms.bumpScale.value = material.bumpScale;
27757                         if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1;
27758
27759                 }
27760
27761                 if ( material.normalMap ) {
27762
27763                         uniforms.normalMap.value = material.normalMap;
27764                         uniforms.normalScale.value.copy( material.normalScale );
27765                         if ( material.side === BackSide ) uniforms.normalScale.value.negate();
27766
27767                 }
27768
27769                 if ( material.displacementMap ) {
27770
27771                         uniforms.displacementMap.value = material.displacementMap;
27772                         uniforms.displacementScale.value = material.displacementScale;
27773                         uniforms.displacementBias.value = material.displacementBias;
27774
27775                 }
27776
27777         }
27778
27779         function refreshUniformsDepth( uniforms, material ) {
27780
27781                 if ( material.displacementMap ) {
27782
27783                         uniforms.displacementMap.value = material.displacementMap;
27784                         uniforms.displacementScale.value = material.displacementScale;
27785                         uniforms.displacementBias.value = material.displacementBias;
27786
27787                 }
27788
27789         }
27790
27791         function refreshUniformsDistance( uniforms, material ) {
27792
27793                 if ( material.displacementMap ) {
27794
27795                         uniforms.displacementMap.value = material.displacementMap;
27796                         uniforms.displacementScale.value = material.displacementScale;
27797                         uniforms.displacementBias.value = material.displacementBias;
27798
27799                 }
27800
27801                 uniforms.referencePosition.value.copy( material.referencePosition );
27802                 uniforms.nearDistance.value = material.nearDistance;
27803                 uniforms.farDistance.value = material.farDistance;
27804
27805         }
27806
27807         function refreshUniformsNormal( uniforms, material ) {
27808
27809                 if ( material.bumpMap ) {
27810
27811                         uniforms.bumpMap.value = material.bumpMap;
27812                         uniforms.bumpScale.value = material.bumpScale;
27813                         if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1;
27814
27815                 }
27816
27817                 if ( material.normalMap ) {
27818
27819                         uniforms.normalMap.value = material.normalMap;
27820                         uniforms.normalScale.value.copy( material.normalScale );
27821                         if ( material.side === BackSide ) uniforms.normalScale.value.negate();
27822
27823                 }
27824
27825                 if ( material.displacementMap ) {
27826
27827                         uniforms.displacementMap.value = material.displacementMap;
27828                         uniforms.displacementScale.value = material.displacementScale;
27829                         uniforms.displacementBias.value = material.displacementBias;
27830
27831                 }
27832
27833         }
27834
27835         return {
27836                 refreshFogUniforms: refreshFogUniforms,
27837                 refreshMaterialUniforms: refreshMaterialUniforms
27838         };
27839
27840 }
27841
27842 function createCanvasElement() {
27843
27844         const canvas = createElementNS( 'canvas' );
27845         canvas.style.display = 'block';
27846         return canvas;
27847
27848 }
27849
27850 function WebGLRenderer( parameters = {} ) {
27851
27852         const _canvas = parameters.canvas !== undefined ? parameters.canvas : createCanvasElement(),
27853                 _context = parameters.context !== undefined ? parameters.context : null,
27854
27855                 _alpha = parameters.alpha !== undefined ? parameters.alpha : false,
27856                 _depth = parameters.depth !== undefined ? parameters.depth : true,
27857                 _stencil = parameters.stencil !== undefined ? parameters.stencil : true,
27858                 _antialias = parameters.antialias !== undefined ? parameters.antialias : false,
27859                 _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true,
27860                 _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false,
27861                 _powerPreference = parameters.powerPreference !== undefined ? parameters.powerPreference : 'default',
27862                 _failIfMajorPerformanceCaveat = parameters.failIfMajorPerformanceCaveat !== undefined ? parameters.failIfMajorPerformanceCaveat : false;
27863
27864         let currentRenderList = null;
27865         let currentRenderState = null;
27866
27867         // render() can be called from within a callback triggered by another render.
27868         // We track this so that the nested render call gets its list and state isolated from the parent render call.
27869
27870         const renderListStack = [];
27871         const renderStateStack = [];
27872
27873         // public properties
27874
27875         this.domElement = _canvas;
27876
27877         // Debug configuration container
27878         this.debug = {
27879
27880                 /**
27881                  * Enables error checking and reporting when shader programs are being compiled
27882                  * @type {boolean}
27883                  */
27884                 checkShaderErrors: true
27885         };
27886
27887         // clearing
27888
27889         this.autoClear = true;
27890         this.autoClearColor = true;
27891         this.autoClearDepth = true;
27892         this.autoClearStencil = true;
27893
27894         // scene graph
27895
27896         this.sortObjects = true;
27897
27898         // user-defined clipping
27899
27900         this.clippingPlanes = [];
27901         this.localClippingEnabled = false;
27902
27903         // physically based shading
27904
27905         this.gammaFactor = 2.0; // for backwards compatibility
27906         this.outputEncoding = LinearEncoding;
27907
27908         // physical lights
27909
27910         this.physicallyCorrectLights = false;
27911
27912         // tone mapping
27913
27914         this.toneMapping = NoToneMapping;
27915         this.toneMappingExposure = 1.0;
27916
27917         // internal properties
27918
27919         const _this = this;
27920
27921         let _isContextLost = false;
27922
27923         // internal state cache
27924
27925         let _currentActiveCubeFace = 0;
27926         let _currentActiveMipmapLevel = 0;
27927         let _currentRenderTarget = null;
27928         let _currentMaterialId = - 1;
27929
27930         let _currentCamera = null;
27931
27932         const _currentViewport = new Vector4();
27933         const _currentScissor = new Vector4();
27934         let _currentScissorTest = null;
27935
27936         //
27937
27938         let _width = _canvas.width;
27939         let _height = _canvas.height;
27940
27941         let _pixelRatio = 1;
27942         let _opaqueSort = null;
27943         let _transparentSort = null;
27944
27945         const _viewport = new Vector4( 0, 0, _width, _height );
27946         const _scissor = new Vector4( 0, 0, _width, _height );
27947         let _scissorTest = false;
27948
27949         //
27950
27951         const _currentDrawBuffers = [];
27952
27953         // frustum
27954
27955         const _frustum = new Frustum();
27956
27957         // clipping
27958
27959         let _clippingEnabled = false;
27960         let _localClippingEnabled = false;
27961
27962         // transmission
27963
27964         let _transmissionRenderTarget = null;
27965
27966         // camera matrices cache
27967
27968         const _projScreenMatrix = new Matrix4();
27969
27970         const _vector3 = new Vector3();
27971
27972         const _emptyScene = { background: null, fog: null, environment: null, overrideMaterial: null, isScene: true };
27973
27974         function getTargetPixelRatio() {
27975
27976                 return _currentRenderTarget === null ? _pixelRatio : 1;
27977
27978         }
27979
27980         // initialize
27981
27982         let _gl = _context;
27983
27984         function getContext( contextNames, contextAttributes ) {
27985
27986                 for ( let i = 0; i < contextNames.length; i ++ ) {
27987
27988                         const contextName = contextNames[ i ];
27989                         const context = _canvas.getContext( contextName, contextAttributes );
27990                         if ( context !== null ) return context;
27991
27992                 }
27993
27994                 return null;
27995
27996         }
27997
27998         try {
27999
28000                 const contextAttributes = {
28001                         alpha: _alpha,
28002                         depth: _depth,
28003                         stencil: _stencil,
28004                         antialias: _antialias,
28005                         premultipliedAlpha: _premultipliedAlpha,
28006                         preserveDrawingBuffer: _preserveDrawingBuffer,
28007                         powerPreference: _powerPreference,
28008                         failIfMajorPerformanceCaveat: _failIfMajorPerformanceCaveat
28009                 };
28010
28011                 // event listeners must be registered before WebGL context is created, see #12753
28012
28013                 _canvas.addEventListener( 'webglcontextlost', onContextLost, false );
28014                 _canvas.addEventListener( 'webglcontextrestored', onContextRestore, false );
28015
28016                 if ( _gl === null ) {
28017
28018                         const contextNames = [ 'webgl2', 'webgl', 'experimental-webgl' ];
28019
28020                         if ( _this.isWebGL1Renderer === true ) {
28021
28022                                 contextNames.shift();
28023
28024                         }
28025
28026                         _gl = getContext( contextNames, contextAttributes );
28027
28028                         if ( _gl === null ) {
28029
28030                                 if ( getContext( contextNames ) ) {
28031
28032                                         throw new Error( 'Error creating WebGL context with your selected attributes.' );
28033
28034                                 } else {
28035
28036                                         throw new Error( 'Error creating WebGL context.' );
28037
28038                                 }
28039
28040                         }
28041
28042                 }
28043
28044                 // Some experimental-webgl implementations do not have getShaderPrecisionFormat
28045
28046                 if ( _gl.getShaderPrecisionFormat === undefined ) {
28047
28048                         _gl.getShaderPrecisionFormat = function () {
28049
28050                                 return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 };
28051
28052                         };
28053
28054                 }
28055
28056         } catch ( error ) {
28057
28058                 console.error( 'THREE.WebGLRenderer: ' + error.message );
28059                 throw error;
28060
28061         }
28062
28063         let extensions, capabilities, state, info;
28064         let properties, textures, cubemaps, cubeuvmaps, attributes, geometries, objects;
28065         let programCache, materials, renderLists, renderStates, clipping, shadowMap;
28066
28067         let background, morphtargets, bufferRenderer, indexedBufferRenderer;
28068
28069         let utils, bindingStates;
28070
28071         function initGLContext() {
28072
28073                 extensions = new WebGLExtensions( _gl );
28074
28075                 capabilities = new WebGLCapabilities( _gl, extensions, parameters );
28076
28077                 extensions.init( capabilities );
28078
28079                 utils = new WebGLUtils( _gl, extensions, capabilities );
28080
28081                 state = new WebGLState( _gl, extensions, capabilities );
28082
28083                 _currentDrawBuffers[ 0 ] = 1029;
28084
28085                 info = new WebGLInfo( _gl );
28086                 properties = new WebGLProperties();
28087                 textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info );
28088                 cubemaps = new WebGLCubeMaps( _this );
28089                 cubeuvmaps = new WebGLCubeUVMaps( _this );
28090                 attributes = new WebGLAttributes( _gl, capabilities );
28091                 bindingStates = new WebGLBindingStates( _gl, extensions, attributes, capabilities );
28092                 geometries = new WebGLGeometries( _gl, attributes, info, bindingStates );
28093                 objects = new WebGLObjects( _gl, geometries, attributes, info );
28094                 morphtargets = new WebGLMorphtargets( _gl, capabilities, textures );
28095                 clipping = new WebGLClipping( properties );
28096                 programCache = new WebGLPrograms( _this, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping );
28097                 materials = new WebGLMaterials( properties );
28098                 renderLists = new WebGLRenderLists( properties );
28099                 renderStates = new WebGLRenderStates( extensions, capabilities );
28100                 background = new WebGLBackground( _this, cubemaps, state, objects, _premultipliedAlpha );
28101                 shadowMap = new WebGLShadowMap( _this, objects, capabilities );
28102
28103                 bufferRenderer = new WebGLBufferRenderer( _gl, extensions, info, capabilities );
28104                 indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info, capabilities );
28105
28106                 info.programs = programCache.programs;
28107
28108                 _this.capabilities = capabilities;
28109                 _this.extensions = extensions;
28110                 _this.properties = properties;
28111                 _this.renderLists = renderLists;
28112                 _this.shadowMap = shadowMap;
28113                 _this.state = state;
28114                 _this.info = info;
28115
28116         }
28117
28118         initGLContext();
28119
28120         // xr
28121
28122         const xr = new WebXRManager( _this, _gl );
28123
28124         this.xr = xr;
28125
28126         // API
28127
28128         this.getContext = function () {
28129
28130                 return _gl;
28131
28132         };
28133
28134         this.getContextAttributes = function () {
28135
28136                 return _gl.getContextAttributes();
28137
28138         };
28139
28140         this.forceContextLoss = function () {
28141
28142                 const extension = extensions.get( 'WEBGL_lose_context' );
28143                 if ( extension ) extension.loseContext();
28144
28145         };
28146
28147         this.forceContextRestore = function () {
28148
28149                 const extension = extensions.get( 'WEBGL_lose_context' );
28150                 if ( extension ) extension.restoreContext();
28151
28152         };
28153
28154         this.getPixelRatio = function () {
28155
28156                 return _pixelRatio;
28157
28158         };
28159
28160         this.setPixelRatio = function ( value ) {
28161
28162                 if ( value === undefined ) return;
28163
28164                 _pixelRatio = value;
28165
28166                 this.setSize( _width, _height, false );
28167
28168         };
28169
28170         this.getSize = function ( target ) {
28171
28172                 return target.set( _width, _height );
28173
28174         };
28175
28176         this.setSize = function ( width, height, updateStyle ) {
28177
28178                 if ( xr.isPresenting ) {
28179
28180                         console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' );
28181                         return;
28182
28183                 }
28184
28185                 _width = width;
28186                 _height = height;
28187
28188                 _canvas.width = Math.floor( width * _pixelRatio );
28189                 _canvas.height = Math.floor( height * _pixelRatio );
28190
28191                 if ( updateStyle !== false ) {
28192
28193                         _canvas.style.width = width + 'px';
28194                         _canvas.style.height = height + 'px';
28195
28196                 }
28197
28198                 this.setViewport( 0, 0, width, height );
28199
28200         };
28201
28202         this.getDrawingBufferSize = function ( target ) {
28203
28204                 return target.set( _width * _pixelRatio, _height * _pixelRatio ).floor();
28205
28206         };
28207
28208         this.setDrawingBufferSize = function ( width, height, pixelRatio ) {
28209
28210                 _width = width;
28211                 _height = height;
28212
28213                 _pixelRatio = pixelRatio;
28214
28215                 _canvas.width = Math.floor( width * pixelRatio );
28216                 _canvas.height = Math.floor( height * pixelRatio );
28217
28218                 this.setViewport( 0, 0, width, height );
28219
28220         };
28221
28222         this.getCurrentViewport = function ( target ) {
28223
28224                 return target.copy( _currentViewport );
28225
28226         };
28227
28228         this.getViewport = function ( target ) {
28229
28230                 return target.copy( _viewport );
28231
28232         };
28233
28234         this.setViewport = function ( x, y, width, height ) {
28235
28236                 if ( x.isVector4 ) {
28237
28238                         _viewport.set( x.x, x.y, x.z, x.w );
28239
28240                 } else {
28241
28242                         _viewport.set( x, y, width, height );
28243
28244                 }
28245
28246                 state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() );
28247
28248         };
28249
28250         this.getScissor = function ( target ) {
28251
28252                 return target.copy( _scissor );
28253
28254         };
28255
28256         this.setScissor = function ( x, y, width, height ) {
28257
28258                 if ( x.isVector4 ) {
28259
28260                         _scissor.set( x.x, x.y, x.z, x.w );
28261
28262                 } else {
28263
28264                         _scissor.set( x, y, width, height );
28265
28266                 }
28267
28268                 state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor() );
28269
28270         };
28271
28272         this.getScissorTest = function () {
28273
28274                 return _scissorTest;
28275
28276         };
28277
28278         this.setScissorTest = function ( boolean ) {
28279
28280                 state.setScissorTest( _scissorTest = boolean );
28281
28282         };
28283
28284         this.setOpaqueSort = function ( method ) {
28285
28286                 _opaqueSort = method;
28287
28288         };
28289
28290         this.setTransparentSort = function ( method ) {
28291
28292                 _transparentSort = method;
28293
28294         };
28295
28296         // Clearing
28297
28298         this.getClearColor = function ( target ) {
28299
28300                 return target.copy( background.getClearColor() );
28301
28302         };
28303
28304         this.setClearColor = function () {
28305
28306                 background.setClearColor.apply( background, arguments );
28307
28308         };
28309
28310         this.getClearAlpha = function () {
28311
28312                 return background.getClearAlpha();
28313
28314         };
28315
28316         this.setClearAlpha = function () {
28317
28318                 background.setClearAlpha.apply( background, arguments );
28319
28320         };
28321
28322         this.clear = function ( color, depth, stencil ) {
28323
28324                 let bits = 0;
28325
28326                 if ( color === undefined || color ) bits |= 16384;
28327                 if ( depth === undefined || depth ) bits |= 256;
28328                 if ( stencil === undefined || stencil ) bits |= 1024;
28329
28330                 _gl.clear( bits );
28331
28332         };
28333
28334         this.clearColor = function () {
28335
28336                 this.clear( true, false, false );
28337
28338         };
28339
28340         this.clearDepth = function () {
28341
28342                 this.clear( false, true, false );
28343
28344         };
28345
28346         this.clearStencil = function () {
28347
28348                 this.clear( false, false, true );
28349
28350         };
28351
28352         //
28353
28354         this.dispose = function () {
28355
28356                 _canvas.removeEventListener( 'webglcontextlost', onContextLost, false );
28357                 _canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false );
28358
28359                 renderLists.dispose();
28360                 renderStates.dispose();
28361                 properties.dispose();
28362                 cubemaps.dispose();
28363                 cubeuvmaps.dispose();
28364                 objects.dispose();
28365                 bindingStates.dispose();
28366
28367                 xr.dispose();
28368
28369                 xr.removeEventListener( 'sessionstart', onXRSessionStart );
28370                 xr.removeEventListener( 'sessionend', onXRSessionEnd );
28371
28372                 if ( _transmissionRenderTarget ) {
28373
28374                         _transmissionRenderTarget.dispose();
28375                         _transmissionRenderTarget = null;
28376
28377                 }
28378
28379                 animation.stop();
28380
28381         };
28382
28383         // Events
28384
28385         function onContextLost( event ) {
28386
28387                 event.preventDefault();
28388
28389                 console.log( 'THREE.WebGLRenderer: Context Lost.' );
28390
28391                 _isContextLost = true;
28392
28393         }
28394
28395         function onContextRestore( /* event */ ) {
28396
28397                 console.log( 'THREE.WebGLRenderer: Context Restored.' );
28398
28399                 _isContextLost = false;
28400
28401                 const infoAutoReset = info.autoReset;
28402                 const shadowMapEnabled = shadowMap.enabled;
28403                 const shadowMapAutoUpdate = shadowMap.autoUpdate;
28404                 const shadowMapNeedsUpdate = shadowMap.needsUpdate;
28405                 const shadowMapType = shadowMap.type;
28406
28407                 initGLContext();
28408
28409                 info.autoReset = infoAutoReset;
28410                 shadowMap.enabled = shadowMapEnabled;
28411                 shadowMap.autoUpdate = shadowMapAutoUpdate;
28412                 shadowMap.needsUpdate = shadowMapNeedsUpdate;
28413                 shadowMap.type = shadowMapType;
28414
28415         }
28416
28417         function onMaterialDispose( event ) {
28418
28419                 const material = event.target;
28420
28421                 material.removeEventListener( 'dispose', onMaterialDispose );
28422
28423                 deallocateMaterial( material );
28424
28425         }
28426
28427         // Buffer deallocation
28428
28429         function deallocateMaterial( material ) {
28430
28431                 releaseMaterialProgramReferences( material );
28432
28433                 properties.remove( material );
28434
28435         }
28436
28437
28438         function releaseMaterialProgramReferences( material ) {
28439
28440                 const programs = properties.get( material ).programs;
28441
28442                 if ( programs !== undefined ) {
28443
28444                         programs.forEach( function ( program ) {
28445
28446                                 programCache.releaseProgram( program );
28447
28448                         } );
28449
28450                 }
28451
28452         }
28453
28454         // Buffer rendering
28455
28456         this.renderBufferDirect = function ( camera, scene, geometry, material, object, group ) {
28457
28458                 if ( scene === null ) scene = _emptyScene; // renderBufferDirect second parameter used to be fog (could be null)
28459
28460                 const frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 );
28461
28462                 const program = setProgram( camera, scene, geometry, material, object );
28463
28464                 state.setMaterial( material, frontFaceCW );
28465
28466                 //
28467
28468                 let index = geometry.index;
28469                 const position = geometry.attributes.position;
28470
28471                 //
28472
28473                 if ( index === null ) {
28474
28475                         if ( position === undefined || position.count === 0 ) return;
28476
28477                 } else if ( index.count === 0 ) {
28478
28479                         return;
28480
28481                 }
28482
28483                 //
28484
28485                 let rangeFactor = 1;
28486
28487                 if ( material.wireframe === true ) {
28488
28489                         index = geometries.getWireframeAttribute( geometry );
28490                         rangeFactor = 2;
28491
28492                 }
28493
28494                 bindingStates.setup( object, material, program, geometry, index );
28495
28496                 let attribute;
28497                 let renderer = bufferRenderer;
28498
28499                 if ( index !== null ) {
28500
28501                         attribute = attributes.get( index );
28502
28503                         renderer = indexedBufferRenderer;
28504                         renderer.setIndex( attribute );
28505
28506                 }
28507
28508                 //
28509
28510                 const dataCount = ( index !== null ) ? index.count : position.count;
28511
28512                 const rangeStart = geometry.drawRange.start * rangeFactor;
28513                 const rangeCount = geometry.drawRange.count * rangeFactor;
28514
28515                 const groupStart = group !== null ? group.start * rangeFactor : 0;
28516                 const groupCount = group !== null ? group.count * rangeFactor : Infinity;
28517
28518                 const drawStart = Math.max( rangeStart, groupStart );
28519                 const drawEnd = Math.min( dataCount, rangeStart + rangeCount, groupStart + groupCount ) - 1;
28520
28521                 const drawCount = Math.max( 0, drawEnd - drawStart + 1 );
28522
28523                 if ( drawCount === 0 ) return;
28524
28525                 //
28526
28527                 if ( object.isMesh ) {
28528
28529                         if ( material.wireframe === true ) {
28530
28531                                 state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() );
28532                                 renderer.setMode( 1 );
28533
28534                         } else {
28535
28536                                 renderer.setMode( 4 );
28537
28538                         }
28539
28540                 } else if ( object.isLine ) {
28541
28542                         let lineWidth = material.linewidth;
28543
28544                         if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material
28545
28546                         state.setLineWidth( lineWidth * getTargetPixelRatio() );
28547
28548                         if ( object.isLineSegments ) {
28549
28550                                 renderer.setMode( 1 );
28551
28552                         } else if ( object.isLineLoop ) {
28553
28554                                 renderer.setMode( 2 );
28555
28556                         } else {
28557
28558                                 renderer.setMode( 3 );
28559
28560                         }
28561
28562                 } else if ( object.isPoints ) {
28563
28564                         renderer.setMode( 0 );
28565
28566                 } else if ( object.isSprite ) {
28567
28568                         renderer.setMode( 4 );
28569
28570                 }
28571
28572                 if ( object.isInstancedMesh ) {
28573
28574                         renderer.renderInstances( drawStart, drawCount, object.count );
28575
28576                 } else if ( geometry.isInstancedBufferGeometry ) {
28577
28578                         const instanceCount = Math.min( geometry.instanceCount, geometry._maxInstanceCount );
28579
28580                         renderer.renderInstances( drawStart, drawCount, instanceCount );
28581
28582                 } else {
28583
28584                         renderer.render( drawStart, drawCount );
28585
28586                 }
28587
28588         };
28589
28590         // Compile
28591
28592         this.compile = function ( scene, camera ) {
28593
28594                 currentRenderState = renderStates.get( scene );
28595                 currentRenderState.init();
28596
28597                 renderStateStack.push( currentRenderState );
28598
28599                 scene.traverseVisible( function ( object ) {
28600
28601                         if ( object.isLight && object.layers.test( camera.layers ) ) {
28602
28603                                 currentRenderState.pushLight( object );
28604
28605                                 if ( object.castShadow ) {
28606
28607                                         currentRenderState.pushShadow( object );
28608
28609                                 }
28610
28611                         }
28612
28613                 } );
28614
28615                 currentRenderState.setupLights( _this.physicallyCorrectLights );
28616
28617                 scene.traverse( function ( object ) {
28618
28619                         const material = object.material;
28620
28621                         if ( material ) {
28622
28623                                 if ( Array.isArray( material ) ) {
28624
28625                                         for ( let i = 0; i < material.length; i ++ ) {
28626
28627                                                 const material2 = material[ i ];
28628
28629                                                 getProgram( material2, scene, object );
28630
28631                                         }
28632
28633                                 } else {
28634
28635                                         getProgram( material, scene, object );
28636
28637                                 }
28638
28639                         }
28640
28641                 } );
28642
28643                 renderStateStack.pop();
28644                 currentRenderState = null;
28645
28646         };
28647
28648         // Animation Loop
28649
28650         let onAnimationFrameCallback = null;
28651
28652         function onAnimationFrame( time ) {
28653
28654                 if ( onAnimationFrameCallback ) onAnimationFrameCallback( time );
28655
28656         }
28657
28658         function onXRSessionStart() {
28659
28660                 animation.stop();
28661
28662         }
28663
28664         function onXRSessionEnd() {
28665
28666                 animation.start();
28667
28668         }
28669
28670         const animation = new WebGLAnimation();
28671         animation.setAnimationLoop( onAnimationFrame );
28672
28673         if ( typeof window !== 'undefined' ) animation.setContext( window );
28674
28675         this.setAnimationLoop = function ( callback ) {
28676
28677                 onAnimationFrameCallback = callback;
28678                 xr.setAnimationLoop( callback );
28679
28680                 ( callback === null ) ? animation.stop() : animation.start();
28681
28682         };
28683
28684         xr.addEventListener( 'sessionstart', onXRSessionStart );
28685         xr.addEventListener( 'sessionend', onXRSessionEnd );
28686
28687         // Rendering
28688
28689         this.render = function ( scene, camera ) {
28690
28691                 if ( camera !== undefined && camera.isCamera !== true ) {
28692
28693                         console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' );
28694                         return;
28695
28696                 }
28697
28698                 if ( _isContextLost === true ) return;
28699
28700                 // update scene graph
28701
28702                 if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
28703
28704                 // update camera matrices and frustum
28705
28706                 if ( camera.parent === null ) camera.updateMatrixWorld();
28707
28708                 if ( xr.enabled === true && xr.isPresenting === true ) {
28709
28710                         if ( xr.cameraAutoUpdate === true ) xr.updateCamera( camera );
28711
28712                         camera = xr.getCamera(); // use XR camera for rendering
28713
28714                 }
28715
28716                 //
28717                 if ( scene.isScene === true ) scene.onBeforeRender( _this, scene, camera, _currentRenderTarget );
28718
28719                 currentRenderState = renderStates.get( scene, renderStateStack.length );
28720                 currentRenderState.init();
28721
28722                 renderStateStack.push( currentRenderState );
28723
28724                 _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
28725                 _frustum.setFromProjectionMatrix( _projScreenMatrix );
28726
28727                 _localClippingEnabled = this.localClippingEnabled;
28728                 _clippingEnabled = clipping.init( this.clippingPlanes, _localClippingEnabled, camera );
28729
28730                 currentRenderList = renderLists.get( scene, renderListStack.length );
28731                 currentRenderList.init();
28732
28733                 renderListStack.push( currentRenderList );
28734
28735                 projectObject( scene, camera, 0, _this.sortObjects );
28736
28737                 currentRenderList.finish();
28738
28739                 if ( _this.sortObjects === true ) {
28740
28741                         currentRenderList.sort( _opaqueSort, _transparentSort );
28742
28743                 }
28744
28745                 //
28746
28747                 if ( _clippingEnabled === true ) clipping.beginShadows();
28748
28749                 const shadowsArray = currentRenderState.state.shadowsArray;
28750
28751                 shadowMap.render( shadowsArray, scene, camera );
28752
28753                 if ( _clippingEnabled === true ) clipping.endShadows();
28754
28755                 //
28756
28757                 if ( this.info.autoReset === true ) this.info.reset();
28758
28759                 //
28760
28761                 background.render( currentRenderList, scene );
28762
28763                 // render scene
28764
28765                 currentRenderState.setupLights( _this.physicallyCorrectLights );
28766
28767                 if ( camera.isArrayCamera ) {
28768
28769                         const cameras = camera.cameras;
28770
28771                         for ( let i = 0, l = cameras.length; i < l; i ++ ) {
28772
28773                                 const camera2 = cameras[ i ];
28774
28775                                 renderScene( currentRenderList, scene, camera2, camera2.viewport );
28776
28777                         }
28778
28779                 } else {
28780
28781                         renderScene( currentRenderList, scene, camera );
28782
28783                 }
28784
28785                 //
28786
28787                 if ( _currentRenderTarget !== null ) {
28788
28789                         // resolve multisample renderbuffers to a single-sample texture if necessary
28790
28791                         textures.updateMultisampleRenderTarget( _currentRenderTarget );
28792
28793                         // Generate mipmap if we're using any kind of mipmap filtering
28794
28795                         textures.updateRenderTargetMipmap( _currentRenderTarget );
28796
28797                 }
28798
28799                 //
28800
28801                 if ( scene.isScene === true ) scene.onAfterRender( _this, scene, camera );
28802
28803                 // Ensure depth buffer writing is enabled so it can be cleared on next render
28804
28805                 state.buffers.depth.setTest( true );
28806                 state.buffers.depth.setMask( true );
28807                 state.buffers.color.setMask( true );
28808
28809                 state.setPolygonOffset( false );
28810
28811                 // _gl.finish();
28812
28813                 bindingStates.resetDefaultState();
28814                 _currentMaterialId = - 1;
28815                 _currentCamera = null;
28816
28817                 renderStateStack.pop();
28818
28819                 if ( renderStateStack.length > 0 ) {
28820
28821                         currentRenderState = renderStateStack[ renderStateStack.length - 1 ];
28822
28823                 } else {
28824
28825                         currentRenderState = null;
28826
28827                 }
28828
28829                 renderListStack.pop();
28830
28831                 if ( renderListStack.length > 0 ) {
28832
28833                         currentRenderList = renderListStack[ renderListStack.length - 1 ];
28834
28835                 } else {
28836
28837                         currentRenderList = null;
28838
28839                 }
28840
28841         };
28842
28843         function projectObject( object, camera, groupOrder, sortObjects ) {
28844
28845                 if ( object.visible === false ) return;
28846
28847                 const visible = object.layers.test( camera.layers );
28848
28849                 if ( visible ) {
28850
28851                         if ( object.isGroup ) {
28852
28853                                 groupOrder = object.renderOrder;
28854
28855                         } else if ( object.isLOD ) {
28856
28857                                 if ( object.autoUpdate === true ) object.update( camera );
28858
28859                         } else if ( object.isLight ) {
28860
28861                                 currentRenderState.pushLight( object );
28862
28863                                 if ( object.castShadow ) {
28864
28865                                         currentRenderState.pushShadow( object );
28866
28867                                 }
28868
28869                         } else if ( object.isSprite ) {
28870
28871                                 if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) {
28872
28873                                         if ( sortObjects ) {
28874
28875                                                 _vector3.setFromMatrixPosition( object.matrixWorld )
28876                                                         .applyMatrix4( _projScreenMatrix );
28877
28878                                         }
28879
28880                                         const geometry = objects.update( object );
28881                                         const material = object.material;
28882
28883                                         if ( material.visible ) {
28884
28885                                                 currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null );
28886
28887                                         }
28888
28889                                 }
28890
28891                         } else if ( object.isMesh || object.isLine || object.isPoints ) {
28892
28893                                 if ( object.isSkinnedMesh ) {
28894
28895                                         // update skeleton only once in a frame
28896
28897                                         if ( object.skeleton.frame !== info.render.frame ) {
28898
28899                                                 object.skeleton.update();
28900                                                 object.skeleton.frame = info.render.frame;
28901
28902                                         }
28903
28904                                 }
28905
28906                                 if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) {
28907
28908                                         if ( sortObjects ) {
28909
28910                                                 _vector3.setFromMatrixPosition( object.matrixWorld )
28911                                                         .applyMatrix4( _projScreenMatrix );
28912
28913                                         }
28914
28915                                         const geometry = objects.update( object );
28916                                         const material = object.material;
28917
28918                                         if ( Array.isArray( material ) ) {
28919
28920                                                 const groups = geometry.groups;
28921
28922                                                 for ( let i = 0, l = groups.length; i < l; i ++ ) {
28923
28924                                                         const group = groups[ i ];
28925                                                         const groupMaterial = material[ group.materialIndex ];
28926
28927                                                         if ( groupMaterial && groupMaterial.visible ) {
28928
28929                                                                 currentRenderList.push( object, geometry, groupMaterial, groupOrder, _vector3.z, group );
28930
28931                                                         }
28932
28933                                                 }
28934
28935                                         } else if ( material.visible ) {
28936
28937                                                 currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null );
28938
28939                                         }
28940
28941                                 }
28942
28943                         }
28944
28945                 }
28946
28947                 const children = object.children;
28948
28949                 for ( let i = 0, l = children.length; i < l; i ++ ) {
28950
28951                         projectObject( children[ i ], camera, groupOrder, sortObjects );
28952
28953                 }
28954
28955         }
28956
28957         function renderScene( currentRenderList, scene, camera, viewport ) {
28958
28959                 const opaqueObjects = currentRenderList.opaque;
28960                 const transmissiveObjects = currentRenderList.transmissive;
28961                 const transparentObjects = currentRenderList.transparent;
28962
28963                 currentRenderState.setupLightsView( camera );
28964
28965                 if ( transmissiveObjects.length > 0 ) renderTransmissionPass( opaqueObjects, scene, camera );
28966
28967                 if ( viewport ) state.viewport( _currentViewport.copy( viewport ) );
28968
28969                 if ( opaqueObjects.length > 0 ) renderObjects( opaqueObjects, scene, camera );
28970                 if ( transmissiveObjects.length > 0 ) renderObjects( transmissiveObjects, scene, camera );
28971                 if ( transparentObjects.length > 0 ) renderObjects( transparentObjects, scene, camera );
28972
28973         }
28974
28975         function renderTransmissionPass( opaqueObjects, scene, camera ) {
28976
28977                 if ( _transmissionRenderTarget === null ) {
28978
28979                         const needsAntialias = _antialias === true && capabilities.isWebGL2 === true;
28980                         const renderTargetType = needsAntialias ? WebGLMultisampleRenderTarget : WebGLRenderTarget;
28981
28982                         _transmissionRenderTarget = new renderTargetType( 1024, 1024, {
28983                                 generateMipmaps: true,
28984                                 type: utils.convert( HalfFloatType ) !== null ? HalfFloatType : UnsignedByteType,
28985                                 minFilter: LinearMipmapLinearFilter,
28986                                 magFilter: NearestFilter,
28987                                 wrapS: ClampToEdgeWrapping,
28988                                 wrapT: ClampToEdgeWrapping
28989                         } );
28990
28991                 }
28992
28993                 const currentRenderTarget = _this.getRenderTarget();
28994                 _this.setRenderTarget( _transmissionRenderTarget );
28995                 _this.clear();
28996
28997                 // Turn off the features which can affect the frag color for opaque objects pass.
28998                 // Otherwise they are applied twice in opaque objects pass and transmission objects pass.
28999                 const currentToneMapping = _this.toneMapping;
29000                 _this.toneMapping = NoToneMapping;
29001
29002                 renderObjects( opaqueObjects, scene, camera );
29003
29004                 _this.toneMapping = currentToneMapping;
29005
29006                 textures.updateMultisampleRenderTarget( _transmissionRenderTarget );
29007                 textures.updateRenderTargetMipmap( _transmissionRenderTarget );
29008
29009                 _this.setRenderTarget( currentRenderTarget );
29010
29011         }
29012
29013         function renderObjects( renderList, scene, camera ) {
29014
29015                 const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null;
29016
29017                 for ( let i = 0, l = renderList.length; i < l; i ++ ) {
29018
29019                         const renderItem = renderList[ i ];
29020
29021                         const object = renderItem.object;
29022                         const geometry = renderItem.geometry;
29023                         const material = overrideMaterial === null ? renderItem.material : overrideMaterial;
29024                         const group = renderItem.group;
29025
29026                         if ( object.layers.test( camera.layers ) ) {
29027
29028                                 renderObject( object, scene, camera, geometry, material, group );
29029
29030                         }
29031
29032                 }
29033
29034         }
29035
29036         function renderObject( object, scene, camera, geometry, material, group ) {
29037
29038                 object.onBeforeRender( _this, scene, camera, geometry, material, group );
29039
29040                 object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
29041                 object.normalMatrix.getNormalMatrix( object.modelViewMatrix );
29042
29043                 material.onBeforeRender( _this, scene, camera, geometry, object, group );
29044
29045                 if ( material.transparent === true && material.side === DoubleSide ) {
29046
29047                         material.side = BackSide;
29048                         material.needsUpdate = true;
29049                         _this.renderBufferDirect( camera, scene, geometry, material, object, group );
29050
29051                         material.side = FrontSide;
29052                         material.needsUpdate = true;
29053                         _this.renderBufferDirect( camera, scene, geometry, material, object, group );
29054
29055                         material.side = DoubleSide;
29056
29057                 } else {
29058
29059                         _this.renderBufferDirect( camera, scene, geometry, material, object, group );
29060
29061                 }
29062
29063                 object.onAfterRender( _this, scene, camera, geometry, material, group );
29064
29065         }
29066
29067         function getProgram( material, scene, object ) {
29068
29069                 if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...
29070
29071                 const materialProperties = properties.get( material );
29072
29073                 const lights = currentRenderState.state.lights;
29074                 const shadowsArray = currentRenderState.state.shadowsArray;
29075
29076                 const lightsStateVersion = lights.state.version;
29077
29078                 const parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, object );
29079                 const programCacheKey = programCache.getProgramCacheKey( parameters );
29080
29081                 let programs = materialProperties.programs;
29082
29083                 // always update environment and fog - changing these trigger an getProgram call, but it's possible that the program doesn't change
29084
29085                 materialProperties.environment = material.isMeshStandardMaterial ? scene.environment : null;
29086                 materialProperties.fog = scene.fog;
29087                 materialProperties.envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || materialProperties.environment );
29088
29089                 if ( programs === undefined ) {
29090
29091                         // new material
29092
29093                         material.addEventListener( 'dispose', onMaterialDispose );
29094
29095                         programs = new Map();
29096                         materialProperties.programs = programs;
29097
29098                 }
29099
29100                 let program = programs.get( programCacheKey );
29101
29102                 if ( program !== undefined ) {
29103
29104                         // early out if program and light state is identical
29105
29106                         if ( materialProperties.currentProgram === program && materialProperties.lightsStateVersion === lightsStateVersion ) {
29107
29108                                 updateCommonMaterialProperties( material, parameters );
29109
29110                                 return program;
29111
29112                         }
29113
29114                 } else {
29115
29116                         parameters.uniforms = programCache.getUniforms( material );
29117
29118                         material.onBuild( object, parameters, _this );
29119
29120                         material.onBeforeCompile( parameters, _this );
29121
29122                         program = programCache.acquireProgram( parameters, programCacheKey );
29123                         programs.set( programCacheKey, program );
29124
29125                         materialProperties.uniforms = parameters.uniforms;
29126
29127                 }
29128
29129                 const uniforms = materialProperties.uniforms;
29130
29131                 if ( ( ! material.isShaderMaterial && ! material.isRawShaderMaterial ) || material.clipping === true ) {
29132
29133                         uniforms.clippingPlanes = clipping.uniform;
29134
29135                 }
29136
29137                 updateCommonMaterialProperties( material, parameters );
29138
29139                 // store the light setup it was created for
29140
29141                 materialProperties.needsLights = materialNeedsLights( material );
29142                 materialProperties.lightsStateVersion = lightsStateVersion;
29143
29144                 if ( materialProperties.needsLights ) {
29145
29146                         // wire up the material to this renderer's lighting state
29147
29148                         uniforms.ambientLightColor.value = lights.state.ambient;
29149                         uniforms.lightProbe.value = lights.state.probe;
29150                         uniforms.directionalLights.value = lights.state.directional;
29151                         uniforms.directionalLightShadows.value = lights.state.directionalShadow;
29152                         uniforms.spotLights.value = lights.state.spot;
29153                         uniforms.spotLightShadows.value = lights.state.spotShadow;
29154                         uniforms.rectAreaLights.value = lights.state.rectArea;
29155                         uniforms.ltc_1.value = lights.state.rectAreaLTC1;
29156                         uniforms.ltc_2.value = lights.state.rectAreaLTC2;
29157                         uniforms.pointLights.value = lights.state.point;
29158                         uniforms.pointLightShadows.value = lights.state.pointShadow;
29159                         uniforms.hemisphereLights.value = lights.state.hemi;
29160
29161                         uniforms.directionalShadowMap.value = lights.state.directionalShadowMap;
29162                         uniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix;
29163                         uniforms.spotShadowMap.value = lights.state.spotShadowMap;
29164                         uniforms.spotShadowMatrix.value = lights.state.spotShadowMatrix;
29165                         uniforms.pointShadowMap.value = lights.state.pointShadowMap;
29166                         uniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix;
29167                         // TODO (abelnation): add area lights shadow info to uniforms
29168
29169                 }
29170
29171                 const progUniforms = program.getUniforms();
29172                 const uniformsList = WebGLUniforms.seqWithValue( progUniforms.seq, uniforms );
29173
29174                 materialProperties.currentProgram = program;
29175                 materialProperties.uniformsList = uniformsList;
29176
29177                 return program;
29178
29179         }
29180
29181         function updateCommonMaterialProperties( material, parameters ) {
29182
29183                 const materialProperties = properties.get( material );
29184
29185                 materialProperties.outputEncoding = parameters.outputEncoding;
29186                 materialProperties.instancing = parameters.instancing;
29187                 materialProperties.skinning = parameters.skinning;
29188                 materialProperties.morphTargets = parameters.morphTargets;
29189                 materialProperties.morphNormals = parameters.morphNormals;
29190                 materialProperties.morphTargetsCount = parameters.morphTargetsCount;
29191                 materialProperties.numClippingPlanes = parameters.numClippingPlanes;
29192                 materialProperties.numIntersection = parameters.numClipIntersection;
29193                 materialProperties.vertexAlphas = parameters.vertexAlphas;
29194                 materialProperties.vertexTangents = parameters.vertexTangents;
29195
29196         }
29197
29198         function setProgram( camera, scene, geometry, material, object ) {
29199
29200                 if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...
29201
29202                 textures.resetTextureUnits();
29203
29204                 const fog = scene.fog;
29205                 const environment = material.isMeshStandardMaterial ? scene.environment : null;
29206                 const encoding = ( _currentRenderTarget === null ) ? _this.outputEncoding : _currentRenderTarget.texture.encoding;
29207                 const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment );
29208                 const vertexAlphas = material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4;
29209                 const vertexTangents = !! material.normalMap && !! geometry.attributes.tangent;
29210                 const morphTargets = !! geometry.morphAttributes.position;
29211                 const morphNormals = !! geometry.morphAttributes.normal;
29212                 const morphTargetsCount = !! geometry.morphAttributes.position ? geometry.morphAttributes.position.length : 0;
29213
29214                 const materialProperties = properties.get( material );
29215                 const lights = currentRenderState.state.lights;
29216
29217                 if ( _clippingEnabled === true ) {
29218
29219                         if ( _localClippingEnabled === true || camera !== _currentCamera ) {
29220
29221                                 const useCache =
29222                                         camera === _currentCamera &&
29223                                         material.id === _currentMaterialId;
29224
29225                                 // we might want to call this function with some ClippingGroup
29226                                 // object instead of the material, once it becomes feasible
29227                                 // (#8465, #8379)
29228                                 clipping.setState( material, camera, useCache );
29229
29230                         }
29231
29232                 }
29233
29234                 //
29235
29236                 let needsProgramChange = false;
29237
29238                 if ( material.version === materialProperties.__version ) {
29239
29240                         if ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) {
29241
29242                                 needsProgramChange = true;
29243
29244                         } else if ( materialProperties.outputEncoding !== encoding ) {
29245
29246                                 needsProgramChange = true;
29247
29248                         } else if ( object.isInstancedMesh && materialProperties.instancing === false ) {
29249
29250                                 needsProgramChange = true;
29251
29252                         } else if ( ! object.isInstancedMesh && materialProperties.instancing === true ) {
29253
29254                                 needsProgramChange = true;
29255
29256                         } else if ( object.isSkinnedMesh && materialProperties.skinning === false ) {
29257
29258                                 needsProgramChange = true;
29259
29260                         } else if ( ! object.isSkinnedMesh && materialProperties.skinning === true ) {
29261
29262                                 needsProgramChange = true;
29263
29264                         } else if ( materialProperties.envMap !== envMap ) {
29265
29266                                 needsProgramChange = true;
29267
29268                         } else if ( material.fog && materialProperties.fog !== fog ) {
29269
29270                                 needsProgramChange = true;
29271
29272                         } else if ( materialProperties.numClippingPlanes !== undefined &&
29273                                 ( materialProperties.numClippingPlanes !== clipping.numPlanes ||
29274                                 materialProperties.numIntersection !== clipping.numIntersection ) ) {
29275
29276                                 needsProgramChange = true;
29277
29278                         } else if ( materialProperties.vertexAlphas !== vertexAlphas ) {
29279
29280                                 needsProgramChange = true;
29281
29282                         } else if ( materialProperties.vertexTangents !== vertexTangents ) {
29283
29284                                 needsProgramChange = true;
29285
29286                         } else if ( materialProperties.morphTargets !== morphTargets ) {
29287
29288                                 needsProgramChange = true;
29289
29290                         } else if ( materialProperties.morphNormals !== morphNormals ) {
29291
29292                                 needsProgramChange = true;
29293
29294                         } else if ( capabilities.isWebGL2 === true && materialProperties.morphTargetsCount !== morphTargetsCount ) {
29295
29296                                 needsProgramChange = true;
29297
29298                         }
29299
29300                 } else {
29301
29302                         needsProgramChange = true;
29303                         materialProperties.__version = material.version;
29304
29305                 }
29306
29307                 //
29308
29309                 let program = materialProperties.currentProgram;
29310
29311                 if ( needsProgramChange === true ) {
29312
29313                         program = getProgram( material, scene, object );
29314
29315                 }
29316
29317                 let refreshProgram = false;
29318                 let refreshMaterial = false;
29319                 let refreshLights = false;
29320
29321                 const p_uniforms = program.getUniforms(),
29322                         m_uniforms = materialProperties.uniforms;
29323
29324                 if ( state.useProgram( program.program ) ) {
29325
29326                         refreshProgram = true;
29327                         refreshMaterial = true;
29328                         refreshLights = true;
29329
29330                 }
29331
29332                 if ( material.id !== _currentMaterialId ) {
29333
29334                         _currentMaterialId = material.id;
29335
29336                         refreshMaterial = true;
29337
29338                 }
29339
29340                 if ( refreshProgram || _currentCamera !== camera ) {
29341
29342                         p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );
29343
29344                         if ( capabilities.logarithmicDepthBuffer ) {
29345
29346                                 p_uniforms.setValue( _gl, 'logDepthBufFC',
29347                                         2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) );
29348
29349                         }
29350
29351                         if ( _currentCamera !== camera ) {
29352
29353                                 _currentCamera = camera;
29354
29355                                 // lighting uniforms depend on the camera so enforce an update
29356                                 // now, in case this material supports lights - or later, when
29357                                 // the next material that does gets activated:
29358
29359                                 refreshMaterial = true;         // set to true on material change
29360                                 refreshLights = true;           // remains set until update done
29361
29362                         }
29363
29364                         // load material specific uniforms
29365                         // (shader material also gets them for the sake of genericity)
29366
29367                         if ( material.isShaderMaterial ||
29368                                 material.isMeshPhongMaterial ||
29369                                 material.isMeshToonMaterial ||
29370                                 material.isMeshStandardMaterial ||
29371                                 material.envMap ) {
29372
29373                                 const uCamPos = p_uniforms.map.cameraPosition;
29374
29375                                 if ( uCamPos !== undefined ) {
29376
29377                                         uCamPos.setValue( _gl,
29378                                                 _vector3.setFromMatrixPosition( camera.matrixWorld ) );
29379
29380                                 }
29381
29382                         }
29383
29384                         if ( material.isMeshPhongMaterial ||
29385                                 material.isMeshToonMaterial ||
29386                                 material.isMeshLambertMaterial ||
29387                                 material.isMeshBasicMaterial ||
29388                                 material.isMeshStandardMaterial ||
29389                                 material.isShaderMaterial ) {
29390
29391                                 p_uniforms.setValue( _gl, 'isOrthographic', camera.isOrthographicCamera === true );
29392
29393                         }
29394
29395                         if ( material.isMeshPhongMaterial ||
29396                                 material.isMeshToonMaterial ||
29397                                 material.isMeshLambertMaterial ||
29398                                 material.isMeshBasicMaterial ||
29399                                 material.isMeshStandardMaterial ||
29400                                 material.isShaderMaterial ||
29401                                 material.isShadowMaterial ||
29402                                 object.isSkinnedMesh ) {
29403
29404                                 p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );
29405
29406                         }
29407
29408                 }
29409
29410                 // skinning and morph target uniforms must be set even if material didn't change
29411                 // auto-setting of texture unit for bone and morph texture must go before other textures
29412                 // otherwise textures used for skinning and morphing can take over texture units reserved for other material textures
29413
29414                 if ( object.isSkinnedMesh ) {
29415
29416                         p_uniforms.setOptional( _gl, object, 'bindMatrix' );
29417                         p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' );
29418
29419                         const skeleton = object.skeleton;
29420
29421                         if ( skeleton ) {
29422
29423                                 if ( capabilities.floatVertexTextures ) {
29424
29425                                         if ( skeleton.boneTexture === null ) skeleton.computeBoneTexture();
29426
29427                                         p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture, textures );
29428                                         p_uniforms.setValue( _gl, 'boneTextureSize', skeleton.boneTextureSize );
29429
29430                                 } else {
29431
29432                                         p_uniforms.setOptional( _gl, skeleton, 'boneMatrices' );
29433
29434                                 }
29435
29436                         }
29437
29438                 }
29439
29440                 if ( !! geometry && ( geometry.morphAttributes.position !== undefined || geometry.morphAttributes.normal !== undefined ) ) {
29441
29442                         morphtargets.update( object, geometry, material, program );
29443
29444                 }
29445
29446
29447                 if ( refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow ) {
29448
29449                         materialProperties.receiveShadow = object.receiveShadow;
29450                         p_uniforms.setValue( _gl, 'receiveShadow', object.receiveShadow );
29451
29452                 }
29453
29454                 if ( refreshMaterial ) {
29455
29456                         p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure );
29457
29458                         if ( materialProperties.needsLights ) {
29459
29460                                 // the current material requires lighting info
29461
29462                                 // note: all lighting uniforms are always set correctly
29463                                 // they simply reference the renderer's state for their
29464                                 // values
29465                                 //
29466                                 // use the current material's .needsUpdate flags to set
29467                                 // the GL state when required
29468
29469                                 markUniformsLightsNeedsUpdate( m_uniforms, refreshLights );
29470
29471                         }
29472
29473                         // refresh uniforms common to several materials
29474
29475                         if ( fog && material.fog ) {
29476
29477                                 materials.refreshFogUniforms( m_uniforms, fog );
29478
29479                         }
29480
29481                         materials.refreshMaterialUniforms( m_uniforms, material, _pixelRatio, _height, _transmissionRenderTarget );
29482
29483                         WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, textures );
29484
29485                 }
29486
29487                 if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) {
29488
29489                         WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, textures );
29490                         material.uniformsNeedUpdate = false;
29491
29492                 }
29493
29494                 if ( material.isSpriteMaterial ) {
29495
29496                         p_uniforms.setValue( _gl, 'center', object.center );
29497
29498                 }
29499
29500                 // common matrices
29501
29502                 p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix );
29503                 p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix );
29504                 p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld );
29505
29506                 return program;
29507
29508         }
29509
29510         // If uniforms are marked as clean, they don't need to be loaded to the GPU.
29511
29512         function markUniformsLightsNeedsUpdate( uniforms, value ) {
29513
29514                 uniforms.ambientLightColor.needsUpdate = value;
29515                 uniforms.lightProbe.needsUpdate = value;
29516
29517                 uniforms.directionalLights.needsUpdate = value;
29518                 uniforms.directionalLightShadows.needsUpdate = value;
29519                 uniforms.pointLights.needsUpdate = value;
29520                 uniforms.pointLightShadows.needsUpdate = value;
29521                 uniforms.spotLights.needsUpdate = value;
29522                 uniforms.spotLightShadows.needsUpdate = value;
29523                 uniforms.rectAreaLights.needsUpdate = value;
29524                 uniforms.hemisphereLights.needsUpdate = value;
29525
29526         }
29527
29528         function materialNeedsLights( material ) {
29529
29530                 return material.isMeshLambertMaterial || material.isMeshToonMaterial || material.isMeshPhongMaterial ||
29531                         material.isMeshStandardMaterial || material.isShadowMaterial ||
29532                         ( material.isShaderMaterial && material.lights === true );
29533
29534         }
29535
29536         this.getActiveCubeFace = function () {
29537
29538                 return _currentActiveCubeFace;
29539
29540         };
29541
29542         this.getActiveMipmapLevel = function () {
29543
29544                 return _currentActiveMipmapLevel;
29545
29546         };
29547
29548         this.getRenderTarget = function () {
29549
29550                 return _currentRenderTarget;
29551
29552         };
29553
29554         this.setRenderTarget = function ( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) {
29555
29556                 _currentRenderTarget = renderTarget;
29557                 _currentActiveCubeFace = activeCubeFace;
29558                 _currentActiveMipmapLevel = activeMipmapLevel;
29559
29560                 if ( renderTarget && properties.get( renderTarget ).__webglFramebuffer === undefined ) {
29561
29562                         textures.setupRenderTarget( renderTarget );
29563
29564                 }
29565
29566                 let framebuffer = null;
29567                 let isCube = false;
29568                 let isRenderTarget3D = false;
29569
29570                 if ( renderTarget ) {
29571
29572                         const texture = renderTarget.texture;
29573
29574                         if ( texture.isDataTexture3D || texture.isDataTexture2DArray ) {
29575
29576                                 isRenderTarget3D = true;
29577
29578                         }
29579
29580                         const __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer;
29581
29582                         if ( renderTarget.isWebGLCubeRenderTarget ) {
29583
29584                                 framebuffer = __webglFramebuffer[ activeCubeFace ];
29585                                 isCube = true;
29586
29587                         } else if ( renderTarget.isWebGLMultisampleRenderTarget ) {
29588
29589                                 framebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer;
29590
29591                         } else {
29592
29593                                 framebuffer = __webglFramebuffer;
29594
29595                         }
29596
29597                         _currentViewport.copy( renderTarget.viewport );
29598                         _currentScissor.copy( renderTarget.scissor );
29599                         _currentScissorTest = renderTarget.scissorTest;
29600
29601                 } else {
29602
29603                         _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor();
29604                         _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor();
29605                         _currentScissorTest = _scissorTest;
29606
29607                 }
29608
29609                 const framebufferBound = state.bindFramebuffer( 36160, framebuffer );
29610
29611                 if ( framebufferBound && capabilities.drawBuffers ) {
29612
29613                         let needsUpdate = false;
29614
29615                         if ( renderTarget ) {
29616
29617                                 if ( renderTarget.isWebGLMultipleRenderTargets ) {
29618
29619                                         const textures = renderTarget.texture;
29620
29621                                         if ( _currentDrawBuffers.length !== textures.length || _currentDrawBuffers[ 0 ] !== 36064 ) {
29622
29623                                                 for ( let i = 0, il = textures.length; i < il; i ++ ) {
29624
29625                                                         _currentDrawBuffers[ i ] = 36064 + i;
29626
29627                                                 }
29628
29629                                                 _currentDrawBuffers.length = textures.length;
29630
29631                                                 needsUpdate = true;
29632
29633                                         }
29634
29635                                 } else {
29636
29637                                         if ( _currentDrawBuffers.length !== 1 || _currentDrawBuffers[ 0 ] !== 36064 ) {
29638
29639                                                 _currentDrawBuffers[ 0 ] = 36064;
29640                                                 _currentDrawBuffers.length = 1;
29641
29642                                                 needsUpdate = true;
29643
29644                                         }
29645
29646                                 }
29647
29648                         } else {
29649
29650                                 if ( _currentDrawBuffers.length !== 1 || _currentDrawBuffers[ 0 ] !== 1029 ) {
29651
29652                                         _currentDrawBuffers[ 0 ] = 1029;
29653                                         _currentDrawBuffers.length = 1;
29654
29655                                         needsUpdate = true;
29656
29657                                 }
29658
29659                         }
29660
29661                         if ( needsUpdate ) {
29662
29663                                 if ( capabilities.isWebGL2 ) {
29664
29665                                         _gl.drawBuffers( _currentDrawBuffers );
29666
29667                                 } else {
29668
29669                                         extensions.get( 'WEBGL_draw_buffers' ).drawBuffersWEBGL( _currentDrawBuffers );
29670
29671                                 }
29672
29673                         }
29674
29675                 }
29676
29677                 state.viewport( _currentViewport );
29678                 state.scissor( _currentScissor );
29679                 state.setScissorTest( _currentScissorTest );
29680
29681                 if ( isCube ) {
29682
29683                         const textureProperties = properties.get( renderTarget.texture );
29684                         _gl.framebufferTexture2D( 36160, 36064, 34069 + activeCubeFace, textureProperties.__webglTexture, activeMipmapLevel );
29685
29686                 } else if ( isRenderTarget3D ) {
29687
29688                         const textureProperties = properties.get( renderTarget.texture );
29689                         const layer = activeCubeFace || 0;
29690                         _gl.framebufferTextureLayer( 36160, 36064, textureProperties.__webglTexture, activeMipmapLevel || 0, layer );
29691
29692                 }
29693
29694                 _currentMaterialId = - 1; // reset current material to ensure correct uniform bindings
29695
29696         };
29697
29698         this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex ) {
29699
29700                 if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) {
29701
29702                         console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );
29703                         return;
29704
29705                 }
29706
29707                 let framebuffer = properties.get( renderTarget ).__webglFramebuffer;
29708
29709                 if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) {
29710
29711                         framebuffer = framebuffer[ activeCubeFaceIndex ];
29712
29713                 }
29714
29715                 if ( framebuffer ) {
29716
29717                         state.bindFramebuffer( 36160, framebuffer );
29718
29719                         try {
29720
29721                                 const texture = renderTarget.texture;
29722                                 const textureFormat = texture.format;
29723                                 const textureType = texture.type;
29724
29725                                 if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( 35739 ) ) {
29726
29727                                         console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' );
29728                                         return;
29729
29730                                 }
29731
29732                                 const halfFloatSupportedByExt = ( textureType === HalfFloatType ) && ( extensions.has( 'EXT_color_buffer_half_float' ) || ( capabilities.isWebGL2 && extensions.has( 'EXT_color_buffer_float' ) ) );
29733
29734                                 if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( 35738 ) && // Edge and Chrome Mac < 52 (#9513)
29735                                         ! ( textureType === FloatType && ( capabilities.isWebGL2 || extensions.has( 'OES_texture_float' ) || extensions.has( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox
29736                                         ! halfFloatSupportedByExt ) {
29737
29738                                         console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' );
29739                                         return;
29740
29741                                 }
29742
29743                                 if ( _gl.checkFramebufferStatus( 36160 ) === 36053 ) {
29744
29745                                         // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)
29746
29747                                         if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {
29748
29749                                                 _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer );
29750
29751                                         }
29752
29753                                 } else {
29754
29755                                         console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' );
29756
29757                                 }
29758
29759                         } finally {
29760
29761                                 // restore framebuffer of current render target if necessary
29762
29763                                 const framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null;
29764                                 state.bindFramebuffer( 36160, framebuffer );
29765
29766                         }
29767
29768                 }
29769
29770         };
29771
29772         this.copyFramebufferToTexture = function ( position, texture, level = 0 ) {
29773
29774                 const levelScale = Math.pow( 2, - level );
29775                 const width = Math.floor( texture.image.width * levelScale );
29776                 const height = Math.floor( texture.image.height * levelScale );
29777
29778                 let glFormat = utils.convert( texture.format );
29779
29780                 if ( capabilities.isWebGL2 ) {
29781
29782                         // Workaround for https://bugs.chromium.org/p/chromium/issues/detail?id=1120100
29783                         // Not needed in Chrome 93+
29784
29785                         if ( glFormat === 6407 ) glFormat = 32849;
29786                         if ( glFormat === 6408 ) glFormat = 32856;
29787
29788                 }
29789
29790                 textures.setTexture2D( texture, 0 );
29791
29792                 _gl.copyTexImage2D( 3553, level, glFormat, position.x, position.y, width, height, 0 );
29793
29794                 state.unbindTexture();
29795
29796         };
29797
29798         this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level = 0 ) {
29799
29800                 const width = srcTexture.image.width;
29801                 const height = srcTexture.image.height;
29802                 const glFormat = utils.convert( dstTexture.format );
29803                 const glType = utils.convert( dstTexture.type );
29804
29805                 textures.setTexture2D( dstTexture, 0 );
29806
29807                 // As another texture upload may have changed pixelStorei
29808                 // parameters, make sure they are correct for the dstTexture
29809                 _gl.pixelStorei( 37440, dstTexture.flipY );
29810                 _gl.pixelStorei( 37441, dstTexture.premultiplyAlpha );
29811                 _gl.pixelStorei( 3317, dstTexture.unpackAlignment );
29812
29813                 if ( srcTexture.isDataTexture ) {
29814
29815                         _gl.texSubImage2D( 3553, level, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data );
29816
29817                 } else {
29818
29819                         if ( srcTexture.isCompressedTexture ) {
29820
29821                                 _gl.compressedTexSubImage2D( 3553, level, position.x, position.y, srcTexture.mipmaps[ 0 ].width, srcTexture.mipmaps[ 0 ].height, glFormat, srcTexture.mipmaps[ 0 ].data );
29822
29823                         } else {
29824
29825                                 _gl.texSubImage2D( 3553, level, position.x, position.y, glFormat, glType, srcTexture.image );
29826
29827                         }
29828
29829                 }
29830
29831                 // Generate mipmaps only when copying level 0
29832                 if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( 3553 );
29833
29834                 state.unbindTexture();
29835
29836         };
29837
29838         this.copyTextureToTexture3D = function ( sourceBox, position, srcTexture, dstTexture, level = 0 ) {
29839
29840                 if ( _this.isWebGL1Renderer ) {
29841
29842                         console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: can only be used with WebGL2.' );
29843                         return;
29844
29845                 }
29846
29847                 const width = sourceBox.max.x - sourceBox.min.x + 1;
29848                 const height = sourceBox.max.y - sourceBox.min.y + 1;
29849                 const depth = sourceBox.max.z - sourceBox.min.z + 1;
29850                 const glFormat = utils.convert( dstTexture.format );
29851                 const glType = utils.convert( dstTexture.type );
29852                 let glTarget;
29853
29854                 if ( dstTexture.isDataTexture3D ) {
29855
29856                         textures.setTexture3D( dstTexture, 0 );
29857                         glTarget = 32879;
29858
29859                 } else if ( dstTexture.isDataTexture2DArray ) {
29860
29861                         textures.setTexture2DArray( dstTexture, 0 );
29862                         glTarget = 35866;
29863
29864                 } else {
29865
29866                         console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.' );
29867                         return;
29868
29869                 }
29870
29871                 _gl.pixelStorei( 37440, dstTexture.flipY );
29872                 _gl.pixelStorei( 37441, dstTexture.premultiplyAlpha );
29873                 _gl.pixelStorei( 3317, dstTexture.unpackAlignment );
29874
29875                 const unpackRowLen = _gl.getParameter( 3314 );
29876                 const unpackImageHeight = _gl.getParameter( 32878 );
29877                 const unpackSkipPixels = _gl.getParameter( 3316 );
29878                 const unpackSkipRows = _gl.getParameter( 3315 );
29879                 const unpackSkipImages = _gl.getParameter( 32877 );
29880
29881                 const image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ 0 ] : srcTexture.image;
29882
29883                 _gl.pixelStorei( 3314, image.width );
29884                 _gl.pixelStorei( 32878, image.height );
29885                 _gl.pixelStorei( 3316, sourceBox.min.x );
29886                 _gl.pixelStorei( 3315, sourceBox.min.y );
29887                 _gl.pixelStorei( 32877, sourceBox.min.z );
29888
29889                 if ( srcTexture.isDataTexture || srcTexture.isDataTexture3D ) {
29890
29891                         _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image.data );
29892
29893                 } else {
29894
29895                         if ( srcTexture.isCompressedTexture ) {
29896
29897                                 console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: untested support for compressed srcTexture.' );
29898                                 _gl.compressedTexSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, image.data );
29899
29900                         } else {
29901
29902                                 _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image );
29903
29904                         }
29905
29906                 }
29907
29908                 _gl.pixelStorei( 3314, unpackRowLen );
29909                 _gl.pixelStorei( 32878, unpackImageHeight );
29910                 _gl.pixelStorei( 3316, unpackSkipPixels );
29911                 _gl.pixelStorei( 3315, unpackSkipRows );
29912                 _gl.pixelStorei( 32877, unpackSkipImages );
29913
29914                 // Generate mipmaps only when copying level 0
29915                 if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( glTarget );
29916
29917                 state.unbindTexture();
29918
29919         };
29920
29921         this.initTexture = function ( texture ) {
29922
29923                 textures.setTexture2D( texture, 0 );
29924
29925                 state.unbindTexture();
29926
29927         };
29928
29929         this.resetState = function () {
29930
29931                 _currentActiveCubeFace = 0;
29932                 _currentActiveMipmapLevel = 0;
29933                 _currentRenderTarget = null;
29934
29935                 state.reset();
29936                 bindingStates.reset();
29937
29938         };
29939
29940         if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {
29941
29942                 __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); // eslint-disable-line no-undef
29943
29944         }
29945
29946 }
29947
29948 WebGLRenderer.prototype.isWebGLRenderer = true;
29949
29950 class WebGL1Renderer extends WebGLRenderer {}
29951
29952 WebGL1Renderer.prototype.isWebGL1Renderer = true;
29953
29954 class Scene extends Object3D {
29955
29956         constructor() {
29957
29958                 super();
29959
29960                 this.type = 'Scene';
29961
29962                 this.background = null;
29963                 this.environment = null;
29964                 this.fog = null;
29965
29966                 this.overrideMaterial = null;
29967
29968                 this.autoUpdate = true; // checked by the renderer
29969
29970                 if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {
29971
29972                         __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); // eslint-disable-line no-undef
29973
29974                 }
29975
29976         }
29977
29978         copy( source, recursive ) {
29979
29980                 super.copy( source, recursive );
29981
29982                 if ( source.background !== null ) this.background = source.background.clone();
29983                 if ( source.environment !== null ) this.environment = source.environment.clone();
29984                 if ( source.fog !== null ) this.fog = source.fog.clone();
29985
29986                 if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone();
29987
29988                 this.autoUpdate = source.autoUpdate;
29989                 this.matrixAutoUpdate = source.matrixAutoUpdate;
29990
29991                 return this;
29992
29993         }
29994
29995         toJSON( meta ) {
29996
29997                 const data = super.toJSON( meta );
29998
29999                 if ( this.fog !== null ) data.object.fog = this.fog.toJSON();
30000
30001                 return data;
30002
30003         }
30004
30005 }
30006
30007 Scene.prototype.isScene = true;
30008
30009 class InterleavedBuffer {
30010
30011         constructor( array, stride ) {
30012
30013                 this.array = array;
30014                 this.stride = stride;
30015                 this.count = array !== undefined ? array.length / stride : 0;
30016
30017                 this.usage = StaticDrawUsage;
30018                 this.updateRange = { offset: 0, count: - 1 };
30019
30020                 this.version = 0;
30021
30022                 this.uuid = generateUUID();
30023
30024         }
30025
30026         onUploadCallback() {}
30027
30028         set needsUpdate( value ) {
30029
30030                 if ( value === true ) this.version ++;
30031
30032         }
30033
30034         setUsage( value ) {
30035
30036                 this.usage = value;
30037
30038                 return this;
30039
30040         }
30041
30042         copy( source ) {
30043
30044                 this.array = new source.array.constructor( source.array );
30045                 this.count = source.count;
30046                 this.stride = source.stride;
30047                 this.usage = source.usage;
30048
30049                 return this;
30050
30051         }
30052
30053         copyAt( index1, attribute, index2 ) {
30054
30055                 index1 *= this.stride;
30056                 index2 *= attribute.stride;
30057
30058                 for ( let i = 0, l = this.stride; i < l; i ++ ) {
30059
30060                         this.array[ index1 + i ] = attribute.array[ index2 + i ];
30061
30062                 }
30063
30064                 return this;
30065
30066         }
30067
30068         set( value, offset = 0 ) {
30069
30070                 this.array.set( value, offset );
30071
30072                 return this;
30073
30074         }
30075
30076         clone( data ) {
30077
30078                 if ( data.arrayBuffers === undefined ) {
30079
30080                         data.arrayBuffers = {};
30081
30082                 }
30083
30084                 if ( this.array.buffer._uuid === undefined ) {
30085
30086                         this.array.buffer._uuid = generateUUID();
30087
30088                 }
30089
30090                 if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) {
30091
30092                         data.arrayBuffers[ this.array.buffer._uuid ] = this.array.slice( 0 ).buffer;
30093
30094                 }
30095
30096                 const array = new this.array.constructor( data.arrayBuffers[ this.array.buffer._uuid ] );
30097
30098                 const ib = new this.constructor( array, this.stride );
30099                 ib.setUsage( this.usage );
30100
30101                 return ib;
30102
30103         }
30104
30105         onUpload( callback ) {
30106
30107                 this.onUploadCallback = callback;
30108
30109                 return this;
30110
30111         }
30112
30113         toJSON( data ) {
30114
30115                 if ( data.arrayBuffers === undefined ) {
30116
30117                         data.arrayBuffers = {};
30118
30119                 }
30120
30121                 // generate UUID for array buffer if necessary
30122
30123                 if ( this.array.buffer._uuid === undefined ) {
30124
30125                         this.array.buffer._uuid = generateUUID();
30126
30127                 }
30128
30129                 if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) {
30130
30131                         data.arrayBuffers[ this.array.buffer._uuid ] = Array.prototype.slice.call( new Uint32Array( this.array.buffer ) );
30132
30133                 }
30134
30135                 //
30136
30137                 return {
30138                         uuid: this.uuid,
30139                         buffer: this.array.buffer._uuid,
30140                         type: this.array.constructor.name,
30141                         stride: this.stride
30142                 };
30143
30144         }
30145
30146 }
30147
30148 InterleavedBuffer.prototype.isInterleavedBuffer = true;
30149
30150 const _vector$6 = /*@__PURE__*/ new Vector3();
30151
30152 class InterleavedBufferAttribute {
30153
30154         constructor( interleavedBuffer, itemSize, offset, normalized = false ) {
30155
30156                 this.name = '';
30157
30158                 this.data = interleavedBuffer;
30159                 this.itemSize = itemSize;
30160                 this.offset = offset;
30161
30162                 this.normalized = normalized === true;
30163
30164         }
30165
30166         get count() {
30167
30168                 return this.data.count;
30169
30170         }
30171
30172         get array() {
30173
30174                 return this.data.array;
30175
30176         }
30177
30178         set needsUpdate( value ) {
30179
30180                 this.data.needsUpdate = value;
30181
30182         }
30183
30184         applyMatrix4( m ) {
30185
30186                 for ( let i = 0, l = this.data.count; i < l; i ++ ) {
30187
30188                         _vector$6.x = this.getX( i );
30189                         _vector$6.y = this.getY( i );
30190                         _vector$6.z = this.getZ( i );
30191
30192                         _vector$6.applyMatrix4( m );
30193
30194                         this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z );
30195
30196                 }
30197
30198                 return this;
30199
30200         }
30201
30202         applyNormalMatrix( m ) {
30203
30204                 for ( let i = 0, l = this.count; i < l; i ++ ) {
30205
30206                         _vector$6.x = this.getX( i );
30207                         _vector$6.y = this.getY( i );
30208                         _vector$6.z = this.getZ( i );
30209
30210                         _vector$6.applyNormalMatrix( m );
30211
30212                         this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z );
30213
30214                 }
30215
30216                 return this;
30217
30218         }
30219
30220         transformDirection( m ) {
30221
30222                 for ( let i = 0, l = this.count; i < l; i ++ ) {
30223
30224                         _vector$6.x = this.getX( i );
30225                         _vector$6.y = this.getY( i );
30226                         _vector$6.z = this.getZ( i );
30227
30228                         _vector$6.transformDirection( m );
30229
30230                         this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z );
30231
30232                 }
30233
30234                 return this;
30235
30236         }
30237
30238         setX( index, x ) {
30239
30240                 this.data.array[ index * this.data.stride + this.offset ] = x;
30241
30242                 return this;
30243
30244         }
30245
30246         setY( index, y ) {
30247
30248                 this.data.array[ index * this.data.stride + this.offset + 1 ] = y;
30249
30250                 return this;
30251
30252         }
30253
30254         setZ( index, z ) {
30255
30256                 this.data.array[ index * this.data.stride + this.offset + 2 ] = z;
30257
30258                 return this;
30259
30260         }
30261
30262         setW( index, w ) {
30263
30264                 this.data.array[ index * this.data.stride + this.offset + 3 ] = w;
30265
30266                 return this;
30267
30268         }
30269
30270         getX( index ) {
30271
30272                 return this.data.array[ index * this.data.stride + this.offset ];
30273
30274         }
30275
30276         getY( index ) {
30277
30278                 return this.data.array[ index * this.data.stride + this.offset + 1 ];
30279
30280         }
30281
30282         getZ( index ) {
30283
30284                 return this.data.array[ index * this.data.stride + this.offset + 2 ];
30285
30286         }
30287
30288         getW( index ) {
30289
30290                 return this.data.array[ index * this.data.stride + this.offset + 3 ];
30291
30292         }
30293
30294         setXY( index, x, y ) {
30295
30296                 index = index * this.data.stride + this.offset;
30297
30298                 this.data.array[ index + 0 ] = x;
30299                 this.data.array[ index + 1 ] = y;
30300
30301                 return this;
30302
30303         }
30304
30305         setXYZ( index, x, y, z ) {
30306
30307                 index = index * this.data.stride + this.offset;
30308
30309                 this.data.array[ index + 0 ] = x;
30310                 this.data.array[ index + 1 ] = y;
30311                 this.data.array[ index + 2 ] = z;
30312
30313                 return this;
30314
30315         }
30316
30317         setXYZW( index, x, y, z, w ) {
30318
30319                 index = index * this.data.stride + this.offset;
30320
30321                 this.data.array[ index + 0 ] = x;
30322                 this.data.array[ index + 1 ] = y;
30323                 this.data.array[ index + 2 ] = z;
30324                 this.data.array[ index + 3 ] = w;
30325
30326                 return this;
30327
30328         }
30329
30330         clone( data ) {
30331
30332                 if ( data === undefined ) {
30333
30334                         console.log( 'THREE.InterleavedBufferAttribute.clone(): Cloning an interlaved buffer attribute will deinterleave buffer data.' );
30335
30336                         const array = [];
30337
30338                         for ( let i = 0; i < this.count; i ++ ) {
30339
30340                                 const index = i * this.data.stride + this.offset;
30341
30342                                 for ( let j = 0; j < this.itemSize; j ++ ) {
30343
30344                                         array.push( this.data.array[ index + j ] );
30345
30346                                 }
30347
30348                         }
30349
30350                         return new BufferAttribute( new this.array.constructor( array ), this.itemSize, this.normalized );
30351
30352                 } else {
30353
30354                         if ( data.interleavedBuffers === undefined ) {
30355
30356                                 data.interleavedBuffers = {};
30357
30358                         }
30359
30360                         if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) {
30361
30362                                 data.interleavedBuffers[ this.data.uuid ] = this.data.clone( data );
30363
30364                         }
30365
30366                         return new InterleavedBufferAttribute( data.interleavedBuffers[ this.data.uuid ], this.itemSize, this.offset, this.normalized );
30367
30368                 }
30369
30370         }
30371
30372         toJSON( data ) {
30373
30374                 if ( data === undefined ) {
30375
30376                         console.log( 'THREE.InterleavedBufferAttribute.toJSON(): Serializing an interlaved buffer attribute will deinterleave buffer data.' );
30377
30378                         const array = [];
30379
30380                         for ( let i = 0; i < this.count; i ++ ) {
30381
30382                                 const index = i * this.data.stride + this.offset;
30383
30384                                 for ( let j = 0; j < this.itemSize; j ++ ) {
30385
30386                                         array.push( this.data.array[ index + j ] );
30387
30388                                 }
30389
30390                         }
30391
30392                         // deinterleave data and save it as an ordinary buffer attribute for now
30393
30394                         return {
30395                                 itemSize: this.itemSize,
30396                                 type: this.array.constructor.name,
30397                                 array: array,
30398                                 normalized: this.normalized
30399                         };
30400
30401                 } else {
30402
30403                         // save as true interlaved attribtue
30404
30405                         if ( data.interleavedBuffers === undefined ) {
30406
30407                                 data.interleavedBuffers = {};
30408
30409                         }
30410
30411                         if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) {
30412
30413                                 data.interleavedBuffers[ this.data.uuid ] = this.data.toJSON( data );
30414
30415                         }
30416
30417                         return {
30418                                 isInterleavedBufferAttribute: true,
30419                                 itemSize: this.itemSize,
30420                                 data: this.data.uuid,
30421                                 offset: this.offset,
30422                                 normalized: this.normalized
30423                         };
30424
30425                 }
30426
30427         }
30428
30429 }
30430
30431 InterleavedBufferAttribute.prototype.isInterleavedBufferAttribute = true;
30432
30433 /**
30434  * parameters = {
30435  *  color: <hex>,
30436  *  map: new THREE.Texture( <Image> ),
30437  *  alphaMap: new THREE.Texture( <Image> ),
30438  *  rotation: <float>,
30439  *  sizeAttenuation: <bool>
30440  * }
30441  */
30442
30443 class SpriteMaterial extends Material {
30444
30445         constructor( parameters ) {
30446
30447                 super();
30448
30449                 this.type = 'SpriteMaterial';
30450
30451                 this.color = new Color( 0xffffff );
30452
30453                 this.map = null;
30454
30455                 this.alphaMap = null;
30456
30457                 this.rotation = 0;
30458
30459                 this.sizeAttenuation = true;
30460
30461                 this.transparent = true;
30462
30463                 this.setValues( parameters );
30464
30465         }
30466
30467         copy( source ) {
30468
30469                 super.copy( source );
30470
30471                 this.color.copy( source.color );
30472
30473                 this.map = source.map;
30474
30475                 this.alphaMap = source.alphaMap;
30476
30477                 this.rotation = source.rotation;
30478
30479                 this.sizeAttenuation = source.sizeAttenuation;
30480
30481                 return this;
30482
30483         }
30484
30485 }
30486
30487 SpriteMaterial.prototype.isSpriteMaterial = true;
30488
30489 let _geometry;
30490
30491 const _intersectPoint = /*@__PURE__*/ new Vector3();
30492 const _worldScale = /*@__PURE__*/ new Vector3();
30493 const _mvPosition = /*@__PURE__*/ new Vector3();
30494
30495 const _alignedPosition = /*@__PURE__*/ new Vector2();
30496 const _rotatedPosition = /*@__PURE__*/ new Vector2();
30497 const _viewWorldMatrix = /*@__PURE__*/ new Matrix4();
30498
30499 const _vA = /*@__PURE__*/ new Vector3();
30500 const _vB = /*@__PURE__*/ new Vector3();
30501 const _vC = /*@__PURE__*/ new Vector3();
30502
30503 const _uvA = /*@__PURE__*/ new Vector2();
30504 const _uvB = /*@__PURE__*/ new Vector2();
30505 const _uvC = /*@__PURE__*/ new Vector2();
30506
30507 class Sprite extends Object3D {
30508
30509         constructor( material ) {
30510
30511                 super();
30512
30513                 this.type = 'Sprite';
30514
30515                 if ( _geometry === undefined ) {
30516
30517                         _geometry = new BufferGeometry();
30518
30519                         const float32Array = new Float32Array( [
30520                                 - 0.5, - 0.5, 0, 0, 0,
30521                                 0.5, - 0.5, 0, 1, 0,
30522                                 0.5, 0.5, 0, 1, 1,
30523                                 - 0.5, 0.5, 0, 0, 1
30524                         ] );
30525
30526                         const interleavedBuffer = new InterleavedBuffer( float32Array, 5 );
30527
30528                         _geometry.setIndex( [ 0, 1, 2,  0, 2, 3 ] );
30529                         _geometry.setAttribute( 'position', new InterleavedBufferAttribute( interleavedBuffer, 3, 0, false ) );
30530                         _geometry.setAttribute( 'uv', new InterleavedBufferAttribute( interleavedBuffer, 2, 3, false ) );
30531
30532                 }
30533
30534                 this.geometry = _geometry;
30535                 this.material = ( material !== undefined ) ? material : new SpriteMaterial();
30536
30537                 this.center = new Vector2( 0.5, 0.5 );
30538
30539         }
30540
30541         raycast( raycaster, intersects ) {
30542
30543                 if ( raycaster.camera === null ) {
30544
30545                         console.error( 'THREE.Sprite: "Raycaster.camera" needs to be set in order to raycast against sprites.' );
30546
30547                 }
30548
30549                 _worldScale.setFromMatrixScale( this.matrixWorld );
30550
30551                 _viewWorldMatrix.copy( raycaster.camera.matrixWorld );
30552                 this.modelViewMatrix.multiplyMatrices( raycaster.camera.matrixWorldInverse, this.matrixWorld );
30553
30554                 _mvPosition.setFromMatrixPosition( this.modelViewMatrix );
30555
30556                 if ( raycaster.camera.isPerspectiveCamera && this.material.sizeAttenuation === false ) {
30557
30558                         _worldScale.multiplyScalar( - _mvPosition.z );
30559
30560                 }
30561
30562                 const rotation = this.material.rotation;
30563                 let sin, cos;
30564
30565                 if ( rotation !== 0 ) {
30566
30567                         cos = Math.cos( rotation );
30568                         sin = Math.sin( rotation );
30569
30570                 }
30571
30572                 const center = this.center;
30573
30574                 transformVertex( _vA.set( - 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
30575                 transformVertex( _vB.set( 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
30576                 transformVertex( _vC.set( 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
30577
30578                 _uvA.set( 0, 0 );
30579                 _uvB.set( 1, 0 );
30580                 _uvC.set( 1, 1 );
30581
30582                 // check first triangle
30583                 let intersect = raycaster.ray.intersectTriangle( _vA, _vB, _vC, false, _intersectPoint );
30584
30585                 if ( intersect === null ) {
30586
30587                         // check second triangle
30588                         transformVertex( _vB.set( - 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
30589                         _uvB.set( 0, 1 );
30590
30591                         intersect = raycaster.ray.intersectTriangle( _vA, _vC, _vB, false, _intersectPoint );
30592                         if ( intersect === null ) {
30593
30594                                 return;
30595
30596                         }
30597
30598                 }
30599
30600                 const distance = raycaster.ray.origin.distanceTo( _intersectPoint );
30601
30602                 if ( distance < raycaster.near || distance > raycaster.far ) return;
30603
30604                 intersects.push( {
30605
30606                         distance: distance,
30607                         point: _intersectPoint.clone(),
30608                         uv: Triangle.getUV( _intersectPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2() ),
30609                         face: null,
30610                         object: this
30611
30612                 } );
30613
30614         }
30615
30616         copy( source ) {
30617
30618                 super.copy( source );
30619
30620                 if ( source.center !== undefined ) this.center.copy( source.center );
30621
30622                 this.material = source.material;
30623
30624                 return this;
30625
30626         }
30627
30628 }
30629
30630 Sprite.prototype.isSprite = true;
30631
30632 function transformVertex( vertexPosition, mvPosition, center, scale, sin, cos ) {
30633
30634         // compute position in camera space
30635         _alignedPosition.subVectors( vertexPosition, center ).addScalar( 0.5 ).multiply( scale );
30636
30637         // to check if rotation is not zero
30638         if ( sin !== undefined ) {
30639
30640                 _rotatedPosition.x = ( cos * _alignedPosition.x ) - ( sin * _alignedPosition.y );
30641                 _rotatedPosition.y = ( sin * _alignedPosition.x ) + ( cos * _alignedPosition.y );
30642
30643         } else {
30644
30645                 _rotatedPosition.copy( _alignedPosition );
30646
30647         }
30648
30649
30650         vertexPosition.copy( mvPosition );
30651         vertexPosition.x += _rotatedPosition.x;
30652         vertexPosition.y += _rotatedPosition.y;
30653
30654         // transform to world space
30655         vertexPosition.applyMatrix4( _viewWorldMatrix );
30656
30657 }
30658
30659 const _basePosition = /*@__PURE__*/ new Vector3();
30660
30661 const _skinIndex = /*@__PURE__*/ new Vector4();
30662 const _skinWeight = /*@__PURE__*/ new Vector4();
30663
30664 const _vector$5 = /*@__PURE__*/ new Vector3();
30665 const _matrix = /*@__PURE__*/ new Matrix4();
30666
30667 class SkinnedMesh extends Mesh {
30668
30669         constructor( geometry, material ) {
30670
30671                 super( geometry, material );
30672
30673                 this.type = 'SkinnedMesh';
30674
30675                 this.bindMode = 'attached';
30676                 this.bindMatrix = new Matrix4();
30677                 this.bindMatrixInverse = new Matrix4();
30678
30679         }
30680
30681         copy( source ) {
30682
30683                 super.copy( source );
30684
30685                 this.bindMode = source.bindMode;
30686                 this.bindMatrix.copy( source.bindMatrix );
30687                 this.bindMatrixInverse.copy( source.bindMatrixInverse );
30688
30689                 this.skeleton = source.skeleton;
30690
30691                 return this;
30692
30693         }
30694
30695         bind( skeleton, bindMatrix ) {
30696
30697                 this.skeleton = skeleton;
30698
30699                 if ( bindMatrix === undefined ) {
30700
30701                         this.updateMatrixWorld( true );
30702
30703                         this.skeleton.calculateInverses();
30704
30705                         bindMatrix = this.matrixWorld;
30706
30707                 }
30708
30709                 this.bindMatrix.copy( bindMatrix );
30710                 this.bindMatrixInverse.copy( bindMatrix ).invert();
30711
30712         }
30713
30714         pose() {
30715
30716                 this.skeleton.pose();
30717
30718         }
30719
30720         normalizeSkinWeights() {
30721
30722                 const vector = new Vector4();
30723
30724                 const skinWeight = this.geometry.attributes.skinWeight;
30725
30726                 for ( let i = 0, l = skinWeight.count; i < l; i ++ ) {
30727
30728                         vector.x = skinWeight.getX( i );
30729                         vector.y = skinWeight.getY( i );
30730                         vector.z = skinWeight.getZ( i );
30731                         vector.w = skinWeight.getW( i );
30732
30733                         const scale = 1.0 / vector.manhattanLength();
30734
30735                         if ( scale !== Infinity ) {
30736
30737                                 vector.multiplyScalar( scale );
30738
30739                         } else {
30740
30741                                 vector.set( 1, 0, 0, 0 ); // do something reasonable
30742
30743                         }
30744
30745                         skinWeight.setXYZW( i, vector.x, vector.y, vector.z, vector.w );
30746
30747                 }
30748
30749         }
30750
30751         updateMatrixWorld( force ) {
30752
30753                 super.updateMatrixWorld( force );
30754
30755                 if ( this.bindMode === 'attached' ) {
30756
30757                         this.bindMatrixInverse.copy( this.matrixWorld ).invert();
30758
30759                 } else if ( this.bindMode === 'detached' ) {
30760
30761                         this.bindMatrixInverse.copy( this.bindMatrix ).invert();
30762
30763                 } else {
30764
30765                         console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode );
30766
30767                 }
30768
30769         }
30770
30771         boneTransform( index, target ) {
30772
30773                 const skeleton = this.skeleton;
30774                 const geometry = this.geometry;
30775
30776                 _skinIndex.fromBufferAttribute( geometry.attributes.skinIndex, index );
30777                 _skinWeight.fromBufferAttribute( geometry.attributes.skinWeight, index );
30778
30779                 _basePosition.copy( target ).applyMatrix4( this.bindMatrix );
30780
30781                 target.set( 0, 0, 0 );
30782
30783                 for ( let i = 0; i < 4; i ++ ) {
30784
30785                         const weight = _skinWeight.getComponent( i );
30786
30787                         if ( weight !== 0 ) {
30788
30789                                 const boneIndex = _skinIndex.getComponent( i );
30790
30791                                 _matrix.multiplyMatrices( skeleton.bones[ boneIndex ].matrixWorld, skeleton.boneInverses[ boneIndex ] );
30792
30793                                 target.addScaledVector( _vector$5.copy( _basePosition ).applyMatrix4( _matrix ), weight );
30794
30795                         }
30796
30797                 }
30798
30799                 return target.applyMatrix4( this.bindMatrixInverse );
30800
30801         }
30802
30803 }
30804
30805 SkinnedMesh.prototype.isSkinnedMesh = true;
30806
30807 class Bone extends Object3D {
30808
30809         constructor() {
30810
30811                 super();
30812
30813                 this.type = 'Bone';
30814
30815         }
30816
30817 }
30818
30819 Bone.prototype.isBone = true;
30820
30821 class DataTexture extends Texture {
30822
30823         constructor( data = null, width = 1, height = 1, format, type, mapping, wrapS, wrapT, magFilter = NearestFilter, minFilter = NearestFilter, anisotropy, encoding ) {
30824
30825                 super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
30826
30827                 this.image = { data: data, width: width, height: height };
30828
30829                 this.magFilter = magFilter;
30830                 this.minFilter = minFilter;
30831
30832                 this.generateMipmaps = false;
30833                 this.flipY = false;
30834                 this.unpackAlignment = 1;
30835
30836                 this.needsUpdate = true;
30837
30838         }
30839
30840 }
30841
30842 DataTexture.prototype.isDataTexture = true;
30843
30844 class InstancedBufferAttribute extends BufferAttribute {
30845
30846         constructor( array, itemSize, normalized, meshPerAttribute = 1 ) {
30847
30848                 if ( typeof normalized === 'number' ) {
30849
30850                         meshPerAttribute = normalized;
30851
30852                         normalized = false;
30853
30854                         console.error( 'THREE.InstancedBufferAttribute: The constructor now expects normalized as the third argument.' );
30855
30856                 }
30857
30858                 super( array, itemSize, normalized );
30859
30860                 this.meshPerAttribute = meshPerAttribute;
30861
30862         }
30863
30864         copy( source ) {
30865
30866                 super.copy( source );
30867
30868                 this.meshPerAttribute = source.meshPerAttribute;
30869
30870                 return this;
30871
30872         }
30873
30874         toJSON() {
30875
30876                 const data = super.toJSON();
30877
30878                 data.meshPerAttribute = this.meshPerAttribute;
30879
30880                 data.isInstancedBufferAttribute = true;
30881
30882                 return data;
30883
30884         }
30885
30886 }
30887
30888 InstancedBufferAttribute.prototype.isInstancedBufferAttribute = true;
30889
30890 const _instanceLocalMatrix = /*@__PURE__*/ new Matrix4();
30891 const _instanceWorldMatrix = /*@__PURE__*/ new Matrix4();
30892
30893 const _instanceIntersects = [];
30894
30895 const _mesh = /*@__PURE__*/ new Mesh();
30896
30897 class InstancedMesh extends Mesh {
30898
30899         constructor( geometry, material, count ) {
30900
30901                 super( geometry, material );
30902
30903                 this.instanceMatrix = new InstancedBufferAttribute( new Float32Array( count * 16 ), 16 );
30904                 this.instanceColor = null;
30905
30906                 this.count = count;
30907
30908                 this.frustumCulled = false;
30909
30910         }
30911
30912         copy( source ) {
30913
30914                 super.copy( source );
30915
30916                 this.instanceMatrix.copy( source.instanceMatrix );
30917
30918                 if ( source.instanceColor !== null ) this.instanceColor = source.instanceColor.clone();
30919
30920                 this.count = source.count;
30921
30922                 return this;
30923
30924         }
30925
30926         getColorAt( index, color ) {
30927
30928                 color.fromArray( this.instanceColor.array, index * 3 );
30929
30930         }
30931
30932         getMatrixAt( index, matrix ) {
30933
30934                 matrix.fromArray( this.instanceMatrix.array, index * 16 );
30935
30936         }
30937
30938         raycast( raycaster, intersects ) {
30939
30940                 const matrixWorld = this.matrixWorld;
30941                 const raycastTimes = this.count;
30942
30943                 _mesh.geometry = this.geometry;
30944                 _mesh.material = this.material;
30945
30946                 if ( _mesh.material === undefined ) return;
30947
30948                 for ( let instanceId = 0; instanceId < raycastTimes; instanceId ++ ) {
30949
30950                         // calculate the world matrix for each instance
30951
30952                         this.getMatrixAt( instanceId, _instanceLocalMatrix );
30953
30954                         _instanceWorldMatrix.multiplyMatrices( matrixWorld, _instanceLocalMatrix );
30955
30956                         // the mesh represents this single instance
30957
30958                         _mesh.matrixWorld = _instanceWorldMatrix;
30959
30960                         _mesh.raycast( raycaster, _instanceIntersects );
30961
30962                         // process the result of raycast
30963
30964                         for ( let i = 0, l = _instanceIntersects.length; i < l; i ++ ) {
30965
30966                                 const intersect = _instanceIntersects[ i ];
30967                                 intersect.instanceId = instanceId;
30968                                 intersect.object = this;
30969                                 intersects.push( intersect );
30970
30971                         }
30972
30973                         _instanceIntersects.length = 0;
30974
30975                 }
30976
30977         }
30978
30979         setColorAt( index, color ) {
30980
30981                 if ( this.instanceColor === null ) {
30982
30983                         this.instanceColor = new InstancedBufferAttribute( new Float32Array( this.instanceMatrix.count * 3 ), 3 );
30984
30985                 }
30986
30987                 color.toArray( this.instanceColor.array, index * 3 );
30988
30989         }
30990
30991         setMatrixAt( index, matrix ) {
30992
30993                 matrix.toArray( this.instanceMatrix.array, index * 16 );
30994
30995         }
30996
30997         updateMorphTargets() {
30998
30999         }
31000
31001         dispose() {
31002
31003                 this.dispatchEvent( { type: 'dispose' } );
31004
31005         }
31006
31007 }
31008
31009 InstancedMesh.prototype.isInstancedMesh = true;
31010
31011 /**
31012  * parameters = {
31013  *  color: <hex>,
31014  *  opacity: <float>,
31015  *
31016  *  linewidth: <float>,
31017  *  linecap: "round",
31018  *  linejoin: "round"
31019  * }
31020  */
31021
31022 class LineBasicMaterial extends Material {
31023
31024         constructor( parameters ) {
31025
31026                 super();
31027
31028                 this.type = 'LineBasicMaterial';
31029
31030                 this.color = new Color( 0xffffff );
31031
31032                 this.linewidth = 1;
31033                 this.linecap = 'round';
31034                 this.linejoin = 'round';
31035
31036                 this.setValues( parameters );
31037
31038         }
31039
31040
31041         copy( source ) {
31042
31043                 super.copy( source );
31044
31045                 this.color.copy( source.color );
31046
31047                 this.linewidth = source.linewidth;
31048                 this.linecap = source.linecap;
31049                 this.linejoin = source.linejoin;
31050
31051                 return this;
31052
31053         }
31054
31055 }
31056
31057 LineBasicMaterial.prototype.isLineBasicMaterial = true;
31058
31059 const _start$1 = /*@__PURE__*/ new Vector3();
31060 const _end$1 = /*@__PURE__*/ new Vector3();
31061 const _inverseMatrix$1 = /*@__PURE__*/ new Matrix4();
31062 const _ray$1 = /*@__PURE__*/ new Ray();
31063 const _sphere$1 = /*@__PURE__*/ new Sphere();
31064
31065 class Line extends Object3D {
31066
31067         constructor( geometry = new BufferGeometry(), material = new LineBasicMaterial() ) {
31068
31069                 super();
31070
31071                 this.type = 'Line';
31072
31073                 this.geometry = geometry;
31074                 this.material = material;
31075
31076                 this.updateMorphTargets();
31077
31078         }
31079
31080         copy( source ) {
31081
31082                 super.copy( source );
31083
31084                 this.material = source.material;
31085                 this.geometry = source.geometry;
31086
31087                 return this;
31088
31089         }
31090
31091         computeLineDistances() {
31092
31093                 const geometry = this.geometry;
31094
31095                 if ( geometry.isBufferGeometry ) {
31096
31097                         // we assume non-indexed geometry
31098
31099                         if ( geometry.index === null ) {
31100
31101                                 const positionAttribute = geometry.attributes.position;
31102                                 const lineDistances = [ 0 ];
31103
31104                                 for ( let i = 1, l = positionAttribute.count; i < l; i ++ ) {
31105
31106                                         _start$1.fromBufferAttribute( positionAttribute, i - 1 );
31107                                         _end$1.fromBufferAttribute( positionAttribute, i );
31108
31109                                         lineDistances[ i ] = lineDistances[ i - 1 ];
31110                                         lineDistances[ i ] += _start$1.distanceTo( _end$1 );
31111
31112                                 }
31113
31114                                 geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) );
31115
31116                         } else {
31117
31118                                 console.warn( 'THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' );
31119
31120                         }
31121
31122                 } else if ( geometry.isGeometry ) {
31123
31124                         console.error( 'THREE.Line.computeLineDistances() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' );
31125
31126                 }
31127
31128                 return this;
31129
31130         }
31131
31132         raycast( raycaster, intersects ) {
31133
31134                 const geometry = this.geometry;
31135                 const matrixWorld = this.matrixWorld;
31136                 const threshold = raycaster.params.Line.threshold;
31137                 const drawRange = geometry.drawRange;
31138
31139                 // Checking boundingSphere distance to ray
31140
31141                 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
31142
31143                 _sphere$1.copy( geometry.boundingSphere );
31144                 _sphere$1.applyMatrix4( matrixWorld );
31145                 _sphere$1.radius += threshold;
31146
31147                 if ( raycaster.ray.intersectsSphere( _sphere$1 ) === false ) return;
31148
31149                 //
31150
31151                 _inverseMatrix$1.copy( matrixWorld ).invert();
31152                 _ray$1.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$1 );
31153
31154                 const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );
31155                 const localThresholdSq = localThreshold * localThreshold;
31156
31157                 const vStart = new Vector3();
31158                 const vEnd = new Vector3();
31159                 const interSegment = new Vector3();
31160                 const interRay = new Vector3();
31161                 const step = this.isLineSegments ? 2 : 1;
31162
31163                 if ( geometry.isBufferGeometry ) {
31164
31165                         const index = geometry.index;
31166                         const attributes = geometry.attributes;
31167                         const positionAttribute = attributes.position;
31168
31169                         if ( index !== null ) {
31170
31171                                 const start = Math.max( 0, drawRange.start );
31172                                 const end = Math.min( index.count, ( drawRange.start + drawRange.count ) );
31173
31174                                 for ( let i = start, l = end - 1; i < l; i += step ) {
31175
31176                                         const a = index.getX( i );
31177                                         const b = index.getX( i + 1 );
31178
31179                                         vStart.fromBufferAttribute( positionAttribute, a );
31180                                         vEnd.fromBufferAttribute( positionAttribute, b );
31181
31182                                         const distSq = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment );
31183
31184                                         if ( distSq > localThresholdSq ) continue;
31185
31186                                         interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
31187
31188                                         const distance = raycaster.ray.origin.distanceTo( interRay );
31189
31190                                         if ( distance < raycaster.near || distance > raycaster.far ) continue;
31191
31192                                         intersects.push( {
31193
31194                                                 distance: distance,
31195                                                 // What do we want? intersection point on the ray or on the segment??
31196                                                 // point: raycaster.ray.at( distance ),
31197                                                 point: interSegment.clone().applyMatrix4( this.matrixWorld ),
31198                                                 index: i,
31199                                                 face: null,
31200                                                 faceIndex: null,
31201                                                 object: this
31202
31203                                         } );
31204
31205                                 }
31206
31207                         } else {
31208
31209                                 const start = Math.max( 0, drawRange.start );
31210                                 const end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) );
31211
31212                                 for ( let i = start, l = end - 1; i < l; i += step ) {
31213
31214                                         vStart.fromBufferAttribute( positionAttribute, i );
31215                                         vEnd.fromBufferAttribute( positionAttribute, i + 1 );
31216
31217                                         const distSq = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment );
31218
31219                                         if ( distSq > localThresholdSq ) continue;
31220
31221                                         interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
31222
31223                                         const distance = raycaster.ray.origin.distanceTo( interRay );
31224
31225                                         if ( distance < raycaster.near || distance > raycaster.far ) continue;
31226
31227                                         intersects.push( {
31228
31229                                                 distance: distance,
31230                                                 // What do we want? intersection point on the ray or on the segment??
31231                                                 // point: raycaster.ray.at( distance ),
31232                                                 point: interSegment.clone().applyMatrix4( this.matrixWorld ),
31233                                                 index: i,
31234                                                 face: null,
31235                                                 faceIndex: null,
31236                                                 object: this
31237
31238                                         } );
31239
31240                                 }
31241
31242                         }
31243
31244                 } else if ( geometry.isGeometry ) {
31245
31246                         console.error( 'THREE.Line.raycast() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' );
31247
31248                 }
31249
31250         }
31251
31252         updateMorphTargets() {
31253
31254                 const geometry = this.geometry;
31255
31256                 if ( geometry.isBufferGeometry ) {
31257
31258                         const morphAttributes = geometry.morphAttributes;
31259                         const keys = Object.keys( morphAttributes );
31260
31261                         if ( keys.length > 0 ) {
31262
31263                                 const morphAttribute = morphAttributes[ keys[ 0 ] ];
31264
31265                                 if ( morphAttribute !== undefined ) {
31266
31267                                         this.morphTargetInfluences = [];
31268                                         this.morphTargetDictionary = {};
31269
31270                                         for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {
31271
31272                                                 const name = morphAttribute[ m ].name || String( m );
31273
31274                                                 this.morphTargetInfluences.push( 0 );
31275                                                 this.morphTargetDictionary[ name ] = m;
31276
31277                                         }
31278
31279                                 }
31280
31281                         }
31282
31283                 } else {
31284
31285                         const morphTargets = geometry.morphTargets;
31286
31287                         if ( morphTargets !== undefined && morphTargets.length > 0 ) {
31288
31289                                 console.error( 'THREE.Line.updateMorphTargets() does not support THREE.Geometry. Use THREE.BufferGeometry instead.' );
31290
31291                         }
31292
31293                 }
31294
31295         }
31296
31297 }
31298
31299 Line.prototype.isLine = true;
31300
31301 const _start = /*@__PURE__*/ new Vector3();
31302 const _end = /*@__PURE__*/ new Vector3();
31303
31304 class LineSegments extends Line {
31305
31306         constructor( geometry, material ) {
31307
31308                 super( geometry, material );
31309
31310                 this.type = 'LineSegments';
31311
31312         }
31313
31314         computeLineDistances() {
31315
31316                 const geometry = this.geometry;
31317
31318                 if ( geometry.isBufferGeometry ) {
31319
31320                         // we assume non-indexed geometry
31321
31322                         if ( geometry.index === null ) {
31323
31324                                 const positionAttribute = geometry.attributes.position;
31325                                 const lineDistances = [];
31326
31327                                 for ( let i = 0, l = positionAttribute.count; i < l; i += 2 ) {
31328
31329                                         _start.fromBufferAttribute( positionAttribute, i );
31330                                         _end.fromBufferAttribute( positionAttribute, i + 1 );
31331
31332                                         lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ];
31333                                         lineDistances[ i + 1 ] = lineDistances[ i ] + _start.distanceTo( _end );
31334
31335                                 }
31336
31337                                 geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) );
31338
31339                         } else {
31340
31341                                 console.warn( 'THREE.LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' );
31342
31343                         }
31344
31345                 } else if ( geometry.isGeometry ) {
31346
31347                         console.error( 'THREE.LineSegments.computeLineDistances() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' );
31348
31349                 }
31350
31351                 return this;
31352
31353         }
31354
31355 }
31356
31357 LineSegments.prototype.isLineSegments = true;
31358
31359 class LineLoop extends Line {
31360
31361         constructor( geometry, material ) {
31362
31363                 super( geometry, material );
31364
31365                 this.type = 'LineLoop';
31366
31367         }
31368
31369 }
31370
31371 LineLoop.prototype.isLineLoop = true;
31372
31373 /**
31374  * parameters = {
31375  *  color: <hex>,
31376  *  opacity: <float>,
31377  *  map: new THREE.Texture( <Image> ),
31378  *  alphaMap: new THREE.Texture( <Image> ),
31379  *
31380  *  size: <float>,
31381  *  sizeAttenuation: <bool>
31382  *
31383  * }
31384  */
31385
31386 class PointsMaterial extends Material {
31387
31388         constructor( parameters ) {
31389
31390                 super();
31391
31392                 this.type = 'PointsMaterial';
31393
31394                 this.color = new Color( 0xffffff );
31395
31396                 this.map = null;
31397
31398                 this.alphaMap = null;
31399
31400                 this.size = 1;
31401                 this.sizeAttenuation = true;
31402
31403                 this.setValues( parameters );
31404
31405         }
31406
31407         copy( source ) {
31408
31409                 super.copy( source );
31410
31411                 this.color.copy( source.color );
31412
31413                 this.map = source.map;
31414
31415                 this.alphaMap = source.alphaMap;
31416
31417                 this.size = source.size;
31418                 this.sizeAttenuation = source.sizeAttenuation;
31419
31420                 return this;
31421
31422         }
31423
31424 }
31425
31426 PointsMaterial.prototype.isPointsMaterial = true;
31427
31428 const _inverseMatrix = /*@__PURE__*/ new Matrix4();
31429 const _ray = /*@__PURE__*/ new Ray();
31430 const _sphere = /*@__PURE__*/ new Sphere();
31431 const _position$2 = /*@__PURE__*/ new Vector3();
31432
31433 class Points extends Object3D {
31434
31435         constructor( geometry = new BufferGeometry(), material = new PointsMaterial() ) {
31436
31437                 super();
31438
31439                 this.type = 'Points';
31440
31441                 this.geometry = geometry;
31442                 this.material = material;
31443
31444                 this.updateMorphTargets();
31445
31446         }
31447
31448         copy( source ) {
31449
31450                 super.copy( source );
31451
31452                 this.material = source.material;
31453                 this.geometry = source.geometry;
31454
31455                 return this;
31456
31457         }
31458
31459         raycast( raycaster, intersects ) {
31460
31461                 const geometry = this.geometry;
31462                 const matrixWorld = this.matrixWorld;
31463                 const threshold = raycaster.params.Points.threshold;
31464                 const drawRange = geometry.drawRange;
31465
31466                 // Checking boundingSphere distance to ray
31467
31468                 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
31469
31470                 _sphere.copy( geometry.boundingSphere );
31471                 _sphere.applyMatrix4( matrixWorld );
31472                 _sphere.radius += threshold;
31473
31474                 if ( raycaster.ray.intersectsSphere( _sphere ) === false ) return;
31475
31476                 //
31477
31478                 _inverseMatrix.copy( matrixWorld ).invert();
31479                 _ray.copy( raycaster.ray ).applyMatrix4( _inverseMatrix );
31480
31481                 const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );
31482                 const localThresholdSq = localThreshold * localThreshold;
31483
31484                 if ( geometry.isBufferGeometry ) {
31485
31486                         const index = geometry.index;
31487                         const attributes = geometry.attributes;
31488                         const positionAttribute = attributes.position;
31489
31490                         if ( index !== null ) {
31491
31492                                 const start = Math.max( 0, drawRange.start );
31493                                 const end = Math.min( index.count, ( drawRange.start + drawRange.count ) );
31494
31495                                 for ( let i = start, il = end; i < il; i ++ ) {
31496
31497                                         const a = index.getX( i );
31498
31499                                         _position$2.fromBufferAttribute( positionAttribute, a );
31500
31501                                         testPoint( _position$2, a, localThresholdSq, matrixWorld, raycaster, intersects, this );
31502
31503                                 }
31504
31505                         } else {
31506
31507                                 const start = Math.max( 0, drawRange.start );
31508                                 const end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) );
31509
31510                                 for ( let i = start, l = end; i < l; i ++ ) {
31511
31512                                         _position$2.fromBufferAttribute( positionAttribute, i );
31513
31514                                         testPoint( _position$2, i, localThresholdSq, matrixWorld, raycaster, intersects, this );
31515
31516                                 }
31517
31518                         }
31519
31520                 } else {
31521
31522                         console.error( 'THREE.Points.raycast() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' );
31523
31524                 }
31525
31526         }
31527
31528         updateMorphTargets() {
31529
31530                 const geometry = this.geometry;
31531
31532                 if ( geometry.isBufferGeometry ) {
31533
31534                         const morphAttributes = geometry.morphAttributes;
31535                         const keys = Object.keys( morphAttributes );
31536
31537                         if ( keys.length > 0 ) {
31538
31539                                 const morphAttribute = morphAttributes[ keys[ 0 ] ];
31540
31541                                 if ( morphAttribute !== undefined ) {
31542
31543                                         this.morphTargetInfluences = [];
31544                                         this.morphTargetDictionary = {};
31545
31546                                         for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {
31547
31548                                                 const name = morphAttribute[ m ].name || String( m );
31549
31550                                                 this.morphTargetInfluences.push( 0 );
31551                                                 this.morphTargetDictionary[ name ] = m;
31552
31553                                         }
31554
31555                                 }
31556
31557                         }
31558
31559                 } else {
31560
31561                         const morphTargets = geometry.morphTargets;
31562
31563                         if ( morphTargets !== undefined && morphTargets.length > 0 ) {
31564
31565                                 console.error( 'THREE.Points.updateMorphTargets() does not support THREE.Geometry. Use THREE.BufferGeometry instead.' );
31566
31567                         }
31568
31569                 }
31570
31571         }
31572
31573 }
31574
31575 Points.prototype.isPoints = true;
31576
31577 function testPoint( point, index, localThresholdSq, matrixWorld, raycaster, intersects, object ) {
31578
31579         const rayPointDistanceSq = _ray.distanceSqToPoint( point );
31580
31581         if ( rayPointDistanceSq < localThresholdSq ) {
31582
31583                 const intersectPoint = new Vector3();
31584
31585                 _ray.closestPointToPoint( point, intersectPoint );
31586                 intersectPoint.applyMatrix4( matrixWorld );
31587
31588                 const distance = raycaster.ray.origin.distanceTo( intersectPoint );
31589
31590                 if ( distance < raycaster.near || distance > raycaster.far ) return;
31591
31592                 intersects.push( {
31593
31594                         distance: distance,
31595                         distanceToRay: Math.sqrt( rayPointDistanceSq ),
31596                         point: intersectPoint,
31597                         index: index,
31598                         face: null,
31599                         object: object
31600
31601                 } );
31602
31603         }
31604
31605 }
31606
31607 class VideoTexture extends Texture {
31608
31609         constructor( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
31610
31611                 super( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
31612
31613                 this.format = format !== undefined ? format : RGBFormat;
31614
31615                 this.minFilter = minFilter !== undefined ? minFilter : LinearFilter;
31616                 this.magFilter = magFilter !== undefined ? magFilter : LinearFilter;
31617
31618                 this.generateMipmaps = false;
31619
31620                 const scope = this;
31621
31622                 function updateVideo() {
31623
31624                         scope.needsUpdate = true;
31625                         video.requestVideoFrameCallback( updateVideo );
31626
31627                 }
31628
31629                 if ( 'requestVideoFrameCallback' in video ) {
31630
31631                         video.requestVideoFrameCallback( updateVideo );
31632
31633                 }
31634
31635         }
31636
31637         clone() {
31638
31639                 return new this.constructor( this.image ).copy( this );
31640
31641         }
31642
31643         update() {
31644
31645                 const video = this.image;
31646                 const hasVideoFrameCallback = 'requestVideoFrameCallback' in video;
31647
31648                 if ( hasVideoFrameCallback === false && video.readyState >= video.HAVE_CURRENT_DATA ) {
31649
31650                         this.needsUpdate = true;
31651
31652                 }
31653
31654         }
31655
31656 }
31657
31658 VideoTexture.prototype.isVideoTexture = true;
31659
31660 class CompressedTexture extends Texture {
31661
31662         constructor( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) {
31663
31664                 super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
31665
31666                 this.image = { width: width, height: height };
31667                 this.mipmaps = mipmaps;
31668
31669                 // no flipping for cube textures
31670                 // (also flipping doesn't work for compressed textures )
31671
31672                 this.flipY = false;
31673
31674                 // can't generate mipmaps for compressed textures
31675                 // mips must be embedded in DDS files
31676
31677                 this.generateMipmaps = false;
31678
31679         }
31680
31681 }
31682
31683 CompressedTexture.prototype.isCompressedTexture = true;
31684
31685 class CanvasTexture extends Texture {
31686
31687         constructor( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
31688
31689                 super( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
31690
31691                 this.needsUpdate = true;
31692
31693         }
31694
31695 }
31696
31697 CanvasTexture.prototype.isCanvasTexture = true;
31698
31699 class DepthTexture extends Texture {
31700
31701         constructor( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) {
31702
31703                 format = format !== undefined ? format : DepthFormat;
31704
31705                 if ( format !== DepthFormat && format !== DepthStencilFormat ) {
31706
31707                         throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' );
31708
31709                 }
31710
31711                 if ( type === undefined && format === DepthFormat ) type = UnsignedShortType;
31712                 if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type;
31713
31714                 super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
31715
31716                 this.image = { width: width, height: height };
31717
31718                 this.magFilter = magFilter !== undefined ? magFilter : NearestFilter;
31719                 this.minFilter = minFilter !== undefined ? minFilter : NearestFilter;
31720
31721                 this.flipY = false;
31722                 this.generateMipmaps    = false;
31723
31724         }
31725
31726
31727 }
31728
31729 DepthTexture.prototype.isDepthTexture = true;
31730
31731 class CircleGeometry extends BufferGeometry {
31732
31733         constructor( radius = 1, segments = 8, thetaStart = 0, thetaLength = Math.PI * 2 ) {
31734
31735                 super();
31736
31737                 this.type = 'CircleGeometry';
31738
31739                 this.parameters = {
31740                         radius: radius,
31741                         segments: segments,
31742                         thetaStart: thetaStart,
31743                         thetaLength: thetaLength
31744                 };
31745
31746                 segments = Math.max( 3, segments );
31747
31748                 // buffers
31749
31750                 const indices = [];
31751                 const vertices = [];
31752                 const normals = [];
31753                 const uvs = [];
31754
31755                 // helper variables
31756
31757                 const vertex = new Vector3();
31758                 const uv = new Vector2();
31759
31760                 // center point
31761
31762                 vertices.push( 0, 0, 0 );
31763                 normals.push( 0, 0, 1 );
31764                 uvs.push( 0.5, 0.5 );
31765
31766                 for ( let s = 0, i = 3; s <= segments; s ++, i += 3 ) {
31767
31768                         const segment = thetaStart + s / segments * thetaLength;
31769
31770                         // vertex
31771
31772                         vertex.x = radius * Math.cos( segment );
31773                         vertex.y = radius * Math.sin( segment );
31774
31775                         vertices.push( vertex.x, vertex.y, vertex.z );
31776
31777                         // normal
31778
31779                         normals.push( 0, 0, 1 );
31780
31781                         // uvs
31782
31783                         uv.x = ( vertices[ i ] / radius + 1 ) / 2;
31784                         uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2;
31785
31786                         uvs.push( uv.x, uv.y );
31787
31788                 }
31789
31790                 // indices
31791
31792                 for ( let i = 1; i <= segments; i ++ ) {
31793
31794                         indices.push( i, i + 1, 0 );
31795
31796                 }
31797
31798                 // build geometry
31799
31800                 this.setIndex( indices );
31801                 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
31802                 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
31803                 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
31804
31805         }
31806
31807         static fromJSON( data ) {
31808
31809                 return new CircleGeometry( data.radius, data.segments, data.thetaStart, data.thetaLength );
31810
31811         }
31812
31813 }
31814
31815 new Vector3();
31816 new Vector3();
31817 new Vector3();
31818 new Triangle();
31819
31820 /**
31821  * Extensible curve object.
31822  *
31823  * Some common of curve methods:
31824  * .getPoint( t, optionalTarget ), .getTangent( t, optionalTarget )
31825  * .getPointAt( u, optionalTarget ), .getTangentAt( u, optionalTarget )
31826  * .getPoints(), .getSpacedPoints()
31827  * .getLength()
31828  * .updateArcLengths()
31829  *
31830  * This following curves inherit from THREE.Curve:
31831  *
31832  * -- 2D curves --
31833  * THREE.ArcCurve
31834  * THREE.CubicBezierCurve
31835  * THREE.EllipseCurve
31836  * THREE.LineCurve
31837  * THREE.QuadraticBezierCurve
31838  * THREE.SplineCurve
31839  *
31840  * -- 3D curves --
31841  * THREE.CatmullRomCurve3
31842  * THREE.CubicBezierCurve3
31843  * THREE.LineCurve3
31844  * THREE.QuadraticBezierCurve3
31845  *
31846  * A series of curves can be represented as a THREE.CurvePath.
31847  *
31848  **/
31849
31850 class Curve {
31851
31852         constructor() {
31853
31854                 this.type = 'Curve';
31855
31856                 this.arcLengthDivisions = 200;
31857
31858         }
31859
31860         // Virtual base class method to overwrite and implement in subclasses
31861         //      - t [0 .. 1]
31862
31863         getPoint( /* t, optionalTarget */ ) {
31864
31865                 console.warn( 'THREE.Curve: .getPoint() not implemented.' );
31866                 return null;
31867
31868         }
31869
31870         // Get point at relative position in curve according to arc length
31871         // - u [0 .. 1]
31872
31873         getPointAt( u, optionalTarget ) {
31874
31875                 const t = this.getUtoTmapping( u );
31876                 return this.getPoint( t, optionalTarget );
31877
31878         }
31879
31880         // Get sequence of points using getPoint( t )
31881
31882         getPoints( divisions = 5 ) {
31883
31884                 const points = [];
31885
31886                 for ( let d = 0; d <= divisions; d ++ ) {
31887
31888                         points.push( this.getPoint( d / divisions ) );
31889
31890                 }
31891
31892                 return points;
31893
31894         }
31895
31896         // Get sequence of points using getPointAt( u )
31897
31898         getSpacedPoints( divisions = 5 ) {
31899
31900                 const points = [];
31901
31902                 for ( let d = 0; d <= divisions; d ++ ) {
31903
31904                         points.push( this.getPointAt( d / divisions ) );
31905
31906                 }
31907
31908                 return points;
31909
31910         }
31911
31912         // Get total curve arc length
31913
31914         getLength() {
31915
31916                 const lengths = this.getLengths();
31917                 return lengths[ lengths.length - 1 ];
31918
31919         }
31920
31921         // Get list of cumulative segment lengths
31922
31923         getLengths( divisions = this.arcLengthDivisions ) {
31924
31925                 if ( this.cacheArcLengths &&
31926                         ( this.cacheArcLengths.length === divisions + 1 ) &&
31927                         ! this.needsUpdate ) {
31928
31929                         return this.cacheArcLengths;
31930
31931                 }
31932
31933                 this.needsUpdate = false;
31934
31935                 const cache = [];
31936                 let current, last = this.getPoint( 0 );
31937                 let sum = 0;
31938
31939                 cache.push( 0 );
31940
31941                 for ( let p = 1; p <= divisions; p ++ ) {
31942
31943                         current = this.getPoint( p / divisions );
31944                         sum += current.distanceTo( last );
31945                         cache.push( sum );
31946                         last = current;
31947
31948                 }
31949
31950                 this.cacheArcLengths = cache;
31951
31952                 return cache; // { sums: cache, sum: sum }; Sum is in the last element.
31953
31954         }
31955
31956         updateArcLengths() {
31957
31958                 this.needsUpdate = true;
31959                 this.getLengths();
31960
31961         }
31962
31963         // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant
31964
31965         getUtoTmapping( u, distance ) {
31966
31967                 const arcLengths = this.getLengths();
31968
31969                 let i = 0;
31970                 const il = arcLengths.length;
31971
31972                 let targetArcLength; // The targeted u distance value to get
31973
31974                 if ( distance ) {
31975
31976                         targetArcLength = distance;
31977
31978                 } else {
31979
31980                         targetArcLength = u * arcLengths[ il - 1 ];
31981
31982                 }
31983
31984                 // binary search for the index with largest value smaller than target u distance
31985
31986                 let low = 0, high = il - 1, comparison;
31987
31988                 while ( low <= high ) {
31989
31990                         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
31991
31992                         comparison = arcLengths[ i ] - targetArcLength;
31993
31994                         if ( comparison < 0 ) {
31995
31996                                 low = i + 1;
31997
31998                         } else if ( comparison > 0 ) {
31999
32000                                 high = i - 1;
32001
32002                         } else {
32003
32004                                 high = i;
32005                                 break;
32006
32007                                 // DONE
32008
32009                         }
32010
32011                 }
32012
32013                 i = high;
32014
32015                 if ( arcLengths[ i ] === targetArcLength ) {
32016
32017                         return i / ( il - 1 );
32018
32019                 }
32020
32021                 // we could get finer grain at lengths, or use simple interpolation between two points
32022
32023                 const lengthBefore = arcLengths[ i ];
32024                 const lengthAfter = arcLengths[ i + 1 ];
32025
32026                 const segmentLength = lengthAfter - lengthBefore;
32027
32028                 // determine where we are between the 'before' and 'after' points
32029
32030                 const segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength;
32031
32032                 // add that fractional amount to t
32033
32034                 const t = ( i + segmentFraction ) / ( il - 1 );
32035
32036                 return t;
32037
32038         }
32039
32040         // Returns a unit vector tangent at t
32041         // In case any sub curve does not implement its tangent derivation,
32042         // 2 points a small delta apart will be used to find its gradient
32043         // which seems to give a reasonable approximation
32044
32045         getTangent( t, optionalTarget ) {
32046
32047                 const delta = 0.0001;
32048                 let t1 = t - delta;
32049                 let t2 = t + delta;
32050
32051                 // Capping in case of danger
32052
32053                 if ( t1 < 0 ) t1 = 0;
32054                 if ( t2 > 1 ) t2 = 1;
32055
32056                 const pt1 = this.getPoint( t1 );
32057                 const pt2 = this.getPoint( t2 );
32058
32059                 const tangent = optionalTarget || ( ( pt1.isVector2 ) ? new Vector2() : new Vector3() );
32060
32061                 tangent.copy( pt2 ).sub( pt1 ).normalize();
32062
32063                 return tangent;
32064
32065         }
32066
32067         getTangentAt( u, optionalTarget ) {
32068
32069                 const t = this.getUtoTmapping( u );
32070                 return this.getTangent( t, optionalTarget );
32071
32072         }
32073
32074         computeFrenetFrames( segments, closed ) {
32075
32076                 // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf
32077
32078                 const normal = new Vector3();
32079
32080                 const tangents = [];
32081                 const normals = [];
32082                 const binormals = [];
32083
32084                 const vec = new Vector3();
32085                 const mat = new Matrix4();
32086
32087                 // compute the tangent vectors for each segment on the curve
32088
32089                 for ( let i = 0; i <= segments; i ++ ) {
32090
32091                         const u = i / segments;
32092
32093                         tangents[ i ] = this.getTangentAt( u, new Vector3() );
32094
32095                 }
32096
32097                 // select an initial normal vector perpendicular to the first tangent vector,
32098                 // and in the direction of the minimum tangent xyz component
32099
32100                 normals[ 0 ] = new Vector3();
32101                 binormals[ 0 ] = new Vector3();
32102                 let min = Number.MAX_VALUE;
32103                 const tx = Math.abs( tangents[ 0 ].x );
32104                 const ty = Math.abs( tangents[ 0 ].y );
32105                 const tz = Math.abs( tangents[ 0 ].z );
32106
32107                 if ( tx <= min ) {
32108
32109                         min = tx;
32110                         normal.set( 1, 0, 0 );
32111
32112                 }
32113
32114                 if ( ty <= min ) {
32115
32116                         min = ty;
32117                         normal.set( 0, 1, 0 );
32118
32119                 }
32120
32121                 if ( tz <= min ) {
32122
32123                         normal.set( 0, 0, 1 );
32124
32125                 }
32126
32127                 vec.crossVectors( tangents[ 0 ], normal ).normalize();
32128
32129                 normals[ 0 ].crossVectors( tangents[ 0 ], vec );
32130                 binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] );
32131
32132
32133                 // compute the slowly-varying normal and binormal vectors for each segment on the curve
32134
32135                 for ( let i = 1; i <= segments; i ++ ) {
32136
32137                         normals[ i ] = normals[ i - 1 ].clone();
32138
32139                         binormals[ i ] = binormals[ i - 1 ].clone();
32140
32141                         vec.crossVectors( tangents[ i - 1 ], tangents[ i ] );
32142
32143                         if ( vec.length() > Number.EPSILON ) {
32144
32145                                 vec.normalize();
32146
32147                                 const theta = Math.acos( clamp$1( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors
32148
32149                                 normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) );
32150
32151                         }
32152
32153                         binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
32154
32155                 }
32156
32157                 // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same
32158
32159                 if ( closed === true ) {
32160
32161                         let theta = Math.acos( clamp$1( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) );
32162                         theta /= segments;
32163
32164                         if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) {
32165
32166                                 theta = - theta;
32167
32168                         }
32169
32170                         for ( let i = 1; i <= segments; i ++ ) {
32171
32172                                 // twist a little...
32173                                 normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) );
32174                                 binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
32175
32176                         }
32177
32178                 }
32179
32180                 return {
32181                         tangents: tangents,
32182                         normals: normals,
32183                         binormals: binormals
32184                 };
32185
32186         }
32187
32188         clone() {
32189
32190                 return new this.constructor().copy( this );
32191
32192         }
32193
32194         copy( source ) {
32195
32196                 this.arcLengthDivisions = source.arcLengthDivisions;
32197
32198                 return this;
32199
32200         }
32201
32202         toJSON() {
32203
32204                 const data = {
32205                         metadata: {
32206                                 version: 4.5,
32207                                 type: 'Curve',
32208                                 generator: 'Curve.toJSON'
32209                         }
32210                 };
32211
32212                 data.arcLengthDivisions = this.arcLengthDivisions;
32213                 data.type = this.type;
32214
32215                 return data;
32216
32217         }
32218
32219         fromJSON( json ) {
32220
32221                 this.arcLengthDivisions = json.arcLengthDivisions;
32222
32223                 return this;
32224
32225         }
32226
32227 }
32228
32229 class EllipseCurve extends Curve {
32230
32231         constructor( aX = 0, aY = 0, xRadius = 1, yRadius = 1, aStartAngle = 0, aEndAngle = Math.PI * 2, aClockwise = false, aRotation = 0 ) {
32232
32233                 super();
32234
32235                 this.type = 'EllipseCurve';
32236
32237                 this.aX = aX;
32238                 this.aY = aY;
32239
32240                 this.xRadius = xRadius;
32241                 this.yRadius = yRadius;
32242
32243                 this.aStartAngle = aStartAngle;
32244                 this.aEndAngle = aEndAngle;
32245
32246                 this.aClockwise = aClockwise;
32247
32248                 this.aRotation = aRotation;
32249
32250         }
32251
32252         getPoint( t, optionalTarget ) {
32253
32254                 const point = optionalTarget || new Vector2();
32255
32256                 const twoPi = Math.PI * 2;
32257                 let deltaAngle = this.aEndAngle - this.aStartAngle;
32258                 const samePoints = Math.abs( deltaAngle ) < Number.EPSILON;
32259
32260                 // ensures that deltaAngle is 0 .. 2 PI
32261                 while ( deltaAngle < 0 ) deltaAngle += twoPi;
32262                 while ( deltaAngle > twoPi ) deltaAngle -= twoPi;
32263
32264                 if ( deltaAngle < Number.EPSILON ) {
32265
32266                         if ( samePoints ) {
32267
32268                                 deltaAngle = 0;
32269
32270                         } else {
32271
32272                                 deltaAngle = twoPi;
32273
32274                         }
32275
32276                 }
32277
32278                 if ( this.aClockwise === true && ! samePoints ) {
32279
32280                         if ( deltaAngle === twoPi ) {
32281
32282                                 deltaAngle = - twoPi;
32283
32284                         } else {
32285
32286                                 deltaAngle = deltaAngle - twoPi;
32287
32288                         }
32289
32290                 }
32291
32292                 const angle = this.aStartAngle + t * deltaAngle;
32293                 let x = this.aX + this.xRadius * Math.cos( angle );
32294                 let y = this.aY + this.yRadius * Math.sin( angle );
32295
32296                 if ( this.aRotation !== 0 ) {
32297
32298                         const cos = Math.cos( this.aRotation );
32299                         const sin = Math.sin( this.aRotation );
32300
32301                         const tx = x - this.aX;
32302                         const ty = y - this.aY;
32303
32304                         // Rotate the point about the center of the ellipse.
32305                         x = tx * cos - ty * sin + this.aX;
32306                         y = tx * sin + ty * cos + this.aY;
32307
32308                 }
32309
32310                 return point.set( x, y );
32311
32312         }
32313
32314         copy( source ) {
32315
32316                 super.copy( source );
32317
32318                 this.aX = source.aX;
32319                 this.aY = source.aY;
32320
32321                 this.xRadius = source.xRadius;
32322                 this.yRadius = source.yRadius;
32323
32324                 this.aStartAngle = source.aStartAngle;
32325                 this.aEndAngle = source.aEndAngle;
32326
32327                 this.aClockwise = source.aClockwise;
32328
32329                 this.aRotation = source.aRotation;
32330
32331                 return this;
32332
32333         }
32334
32335         toJSON() {
32336
32337                 const data = super.toJSON();
32338
32339                 data.aX = this.aX;
32340                 data.aY = this.aY;
32341
32342                 data.xRadius = this.xRadius;
32343                 data.yRadius = this.yRadius;
32344
32345                 data.aStartAngle = this.aStartAngle;
32346                 data.aEndAngle = this.aEndAngle;
32347
32348                 data.aClockwise = this.aClockwise;
32349
32350                 data.aRotation = this.aRotation;
32351
32352                 return data;
32353
32354         }
32355
32356         fromJSON( json ) {
32357
32358                 super.fromJSON( json );
32359
32360                 this.aX = json.aX;
32361                 this.aY = json.aY;
32362
32363                 this.xRadius = json.xRadius;
32364                 this.yRadius = json.yRadius;
32365
32366                 this.aStartAngle = json.aStartAngle;
32367                 this.aEndAngle = json.aEndAngle;
32368
32369                 this.aClockwise = json.aClockwise;
32370
32371                 this.aRotation = json.aRotation;
32372
32373                 return this;
32374
32375         }
32376
32377 }
32378
32379 EllipseCurve.prototype.isEllipseCurve = true;
32380
32381 class ArcCurve extends EllipseCurve {
32382
32383         constructor( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
32384
32385                 super( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );
32386
32387                 this.type = 'ArcCurve';
32388
32389         }
32390
32391 }
32392
32393 ArcCurve.prototype.isArcCurve = true;
32394
32395 /**
32396  * Centripetal CatmullRom Curve - which is useful for avoiding
32397  * cusps and self-intersections in non-uniform catmull rom curves.
32398  * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf
32399  *
32400  * curve.type accepts centripetal(default), chordal and catmullrom
32401  * curve.tension is used for catmullrom which defaults to 0.5
32402  */
32403
32404
32405 /*
32406 Based on an optimized c++ solution in
32407  - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/
32408  - http://ideone.com/NoEbVM
32409
32410 This CubicPoly class could be used for reusing some variables and calculations,
32411 but for three.js curve use, it could be possible inlined and flatten into a single function call
32412 which can be placed in CurveUtils.
32413 */
32414
32415 function CubicPoly() {
32416
32417         let c0 = 0, c1 = 0, c2 = 0, c3 = 0;
32418
32419         /*
32420          * Compute coefficients for a cubic polynomial
32421          *   p(s) = c0 + c1*s + c2*s^2 + c3*s^3
32422          * such that
32423          *   p(0) = x0, p(1) = x1
32424          *  and
32425          *   p'(0) = t0, p'(1) = t1.
32426          */
32427         function init( x0, x1, t0, t1 ) {
32428
32429                 c0 = x0;
32430                 c1 = t0;
32431                 c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1;
32432                 c3 = 2 * x0 - 2 * x1 + t0 + t1;
32433
32434         }
32435
32436         return {
32437
32438                 initCatmullRom: function ( x0, x1, x2, x3, tension ) {
32439
32440                         init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) );
32441
32442                 },
32443
32444                 initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) {
32445
32446                         // compute tangents when parameterized in [t1,t2]
32447                         let t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1;
32448                         let t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2;
32449
32450                         // rescale tangents for parametrization in [0,1]
32451                         t1 *= dt1;
32452                         t2 *= dt1;
32453
32454                         init( x1, x2, t1, t2 );
32455
32456                 },
32457
32458                 calc: function ( t ) {
32459
32460                         const t2 = t * t;
32461                         const t3 = t2 * t;
32462                         return c0 + c1 * t + c2 * t2 + c3 * t3;
32463
32464                 }
32465
32466         };
32467
32468 }
32469
32470 //
32471
32472 const tmp = new Vector3();
32473 const px = new CubicPoly(), py = new CubicPoly(), pz = new CubicPoly();
32474
32475 class CatmullRomCurve3 extends Curve {
32476
32477         constructor( points = [], closed = false, curveType = 'centripetal', tension = 0.5 ) {
32478
32479                 super();
32480
32481                 this.type = 'CatmullRomCurve3';
32482
32483                 this.points = points;
32484                 this.closed = closed;
32485                 this.curveType = curveType;
32486                 this.tension = tension;
32487
32488         }
32489
32490         getPoint( t, optionalTarget = new Vector3() ) {
32491
32492                 const point = optionalTarget;
32493
32494                 const points = this.points;
32495                 const l = points.length;
32496
32497                 const p = ( l - ( this.closed ? 0 : 1 ) ) * t;
32498                 let intPoint = Math.floor( p );
32499                 let weight = p - intPoint;
32500
32501                 if ( this.closed ) {
32502
32503                         intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / l ) + 1 ) * l;
32504
32505                 } else if ( weight === 0 && intPoint === l - 1 ) {
32506
32507                         intPoint = l - 2;
32508                         weight = 1;
32509
32510                 }
32511
32512                 let p0, p3; // 4 points (p1 & p2 defined below)
32513
32514                 if ( this.closed || intPoint > 0 ) {
32515
32516                         p0 = points[ ( intPoint - 1 ) % l ];
32517
32518                 } else {
32519
32520                         // extrapolate first point
32521                         tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] );
32522                         p0 = tmp;
32523
32524                 }
32525
32526                 const p1 = points[ intPoint % l ];
32527                 const p2 = points[ ( intPoint + 1 ) % l ];
32528
32529                 if ( this.closed || intPoint + 2 < l ) {
32530
32531                         p3 = points[ ( intPoint + 2 ) % l ];
32532
32533                 } else {
32534
32535                         // extrapolate last point
32536                         tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] );
32537                         p3 = tmp;
32538
32539                 }
32540
32541                 if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) {
32542
32543                         // init Centripetal / Chordal Catmull-Rom
32544                         const pow = this.curveType === 'chordal' ? 0.5 : 0.25;
32545                         let dt0 = Math.pow( p0.distanceToSquared( p1 ), pow );
32546                         let dt1 = Math.pow( p1.distanceToSquared( p2 ), pow );
32547                         let dt2 = Math.pow( p2.distanceToSquared( p3 ), pow );
32548
32549                         // safety check for repeated points
32550                         if ( dt1 < 1e-4 ) dt1 = 1.0;
32551                         if ( dt0 < 1e-4 ) dt0 = dt1;
32552                         if ( dt2 < 1e-4 ) dt2 = dt1;
32553
32554                         px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 );
32555                         py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 );
32556                         pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 );
32557
32558                 } else if ( this.curveType === 'catmullrom' ) {
32559
32560                         px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, this.tension );
32561                         py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, this.tension );
32562                         pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, this.tension );
32563
32564                 }
32565
32566                 point.set(
32567                         px.calc( weight ),
32568                         py.calc( weight ),
32569                         pz.calc( weight )
32570                 );
32571
32572                 return point;
32573
32574         }
32575
32576         copy( source ) {
32577
32578                 super.copy( source );
32579
32580                 this.points = [];
32581
32582                 for ( let i = 0, l = source.points.length; i < l; i ++ ) {
32583
32584                         const point = source.points[ i ];
32585
32586                         this.points.push( point.clone() );
32587
32588                 }
32589
32590                 this.closed = source.closed;
32591                 this.curveType = source.curveType;
32592                 this.tension = source.tension;
32593
32594                 return this;
32595
32596         }
32597
32598         toJSON() {
32599
32600                 const data = super.toJSON();
32601
32602                 data.points = [];
32603
32604                 for ( let i = 0, l = this.points.length; i < l; i ++ ) {
32605
32606                         const point = this.points[ i ];
32607                         data.points.push( point.toArray() );
32608
32609                 }
32610
32611                 data.closed = this.closed;
32612                 data.curveType = this.curveType;
32613                 data.tension = this.tension;
32614
32615                 return data;
32616
32617         }
32618
32619         fromJSON( json ) {
32620
32621                 super.fromJSON( json );
32622
32623                 this.points = [];
32624
32625                 for ( let i = 0, l = json.points.length; i < l; i ++ ) {
32626
32627                         const point = json.points[ i ];
32628                         this.points.push( new Vector3().fromArray( point ) );
32629
32630                 }
32631
32632                 this.closed = json.closed;
32633                 this.curveType = json.curveType;
32634                 this.tension = json.tension;
32635
32636                 return this;
32637
32638         }
32639
32640 }
32641
32642 CatmullRomCurve3.prototype.isCatmullRomCurve3 = true;
32643
32644 /**
32645  * Bezier Curves formulas obtained from
32646  * http://en.wikipedia.org/wiki/Bézier_curve
32647  */
32648
32649 function CatmullRom( t, p0, p1, p2, p3 ) {
32650
32651         const v0 = ( p2 - p0 ) * 0.5;
32652         const v1 = ( p3 - p1 ) * 0.5;
32653         const t2 = t * t;
32654         const t3 = t * t2;
32655         return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1;
32656
32657 }
32658
32659 //
32660
32661 function QuadraticBezierP0( t, p ) {
32662
32663         const k = 1 - t;
32664         return k * k * p;
32665
32666 }
32667
32668 function QuadraticBezierP1( t, p ) {
32669
32670         return 2 * ( 1 - t ) * t * p;
32671
32672 }
32673
32674 function QuadraticBezierP2( t, p ) {
32675
32676         return t * t * p;
32677
32678 }
32679
32680 function QuadraticBezier( t, p0, p1, p2 ) {
32681
32682         return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) +
32683                 QuadraticBezierP2( t, p2 );
32684
32685 }
32686
32687 //
32688
32689 function CubicBezierP0( t, p ) {
32690
32691         const k = 1 - t;
32692         return k * k * k * p;
32693
32694 }
32695
32696 function CubicBezierP1( t, p ) {
32697
32698         const k = 1 - t;
32699         return 3 * k * k * t * p;
32700
32701 }
32702
32703 function CubicBezierP2( t, p ) {
32704
32705         return 3 * ( 1 - t ) * t * t * p;
32706
32707 }
32708
32709 function CubicBezierP3( t, p ) {
32710
32711         return t * t * t * p;
32712
32713 }
32714
32715 function CubicBezier( t, p0, p1, p2, p3 ) {
32716
32717         return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) +
32718                 CubicBezierP3( t, p3 );
32719
32720 }
32721
32722 class CubicBezierCurve extends Curve {
32723
32724         constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2(), v3 = new Vector2() ) {
32725
32726                 super();
32727
32728                 this.type = 'CubicBezierCurve';
32729
32730                 this.v0 = v0;
32731                 this.v1 = v1;
32732                 this.v2 = v2;
32733                 this.v3 = v3;
32734
32735         }
32736
32737         getPoint( t, optionalTarget = new Vector2() ) {
32738
32739                 const point = optionalTarget;
32740
32741                 const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;
32742
32743                 point.set(
32744                         CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
32745                         CubicBezier( t, v0.y, v1.y, v2.y, v3.y )
32746                 );
32747
32748                 return point;
32749
32750         }
32751
32752         copy( source ) {
32753
32754                 super.copy( source );
32755
32756                 this.v0.copy( source.v0 );
32757                 this.v1.copy( source.v1 );
32758                 this.v2.copy( source.v2 );
32759                 this.v3.copy( source.v3 );
32760
32761                 return this;
32762
32763         }
32764
32765         toJSON() {
32766
32767                 const data = super.toJSON();
32768
32769                 data.v0 = this.v0.toArray();
32770                 data.v1 = this.v1.toArray();
32771                 data.v2 = this.v2.toArray();
32772                 data.v3 = this.v3.toArray();
32773
32774                 return data;
32775
32776         }
32777
32778         fromJSON( json ) {
32779
32780                 super.fromJSON( json );
32781
32782                 this.v0.fromArray( json.v0 );
32783                 this.v1.fromArray( json.v1 );
32784                 this.v2.fromArray( json.v2 );
32785                 this.v3.fromArray( json.v3 );
32786
32787                 return this;
32788
32789         }
32790
32791 }
32792
32793 CubicBezierCurve.prototype.isCubicBezierCurve = true;
32794
32795 class CubicBezierCurve3 extends Curve {
32796
32797         constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3(), v3 = new Vector3() ) {
32798
32799                 super();
32800
32801                 this.type = 'CubicBezierCurve3';
32802
32803                 this.v0 = v0;
32804                 this.v1 = v1;
32805                 this.v2 = v2;
32806                 this.v3 = v3;
32807
32808         }
32809
32810         getPoint( t, optionalTarget = new Vector3() ) {
32811
32812                 const point = optionalTarget;
32813
32814                 const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;
32815
32816                 point.set(
32817                         CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
32818                         CubicBezier( t, v0.y, v1.y, v2.y, v3.y ),
32819                         CubicBezier( t, v0.z, v1.z, v2.z, v3.z )
32820                 );
32821
32822                 return point;
32823
32824         }
32825
32826         copy( source ) {
32827
32828                 super.copy( source );
32829
32830                 this.v0.copy( source.v0 );
32831                 this.v1.copy( source.v1 );
32832                 this.v2.copy( source.v2 );
32833                 this.v3.copy( source.v3 );
32834
32835                 return this;
32836
32837         }
32838
32839         toJSON() {
32840
32841                 const data = super.toJSON();
32842
32843                 data.v0 = this.v0.toArray();
32844                 data.v1 = this.v1.toArray();
32845                 data.v2 = this.v2.toArray();
32846                 data.v3 = this.v3.toArray();
32847
32848                 return data;
32849
32850         }
32851
32852         fromJSON( json ) {
32853
32854                 super.fromJSON( json );
32855
32856                 this.v0.fromArray( json.v0 );
32857                 this.v1.fromArray( json.v1 );
32858                 this.v2.fromArray( json.v2 );
32859                 this.v3.fromArray( json.v3 );
32860
32861                 return this;
32862
32863         }
32864
32865 }
32866
32867 CubicBezierCurve3.prototype.isCubicBezierCurve3 = true;
32868
32869 class LineCurve extends Curve {
32870
32871         constructor( v1 = new Vector2(), v2 = new Vector2() ) {
32872
32873                 super();
32874
32875                 this.type = 'LineCurve';
32876
32877                 this.v1 = v1;
32878                 this.v2 = v2;
32879
32880         }
32881
32882         getPoint( t, optionalTarget = new Vector2() ) {
32883
32884                 const point = optionalTarget;
32885
32886                 if ( t === 1 ) {
32887
32888                         point.copy( this.v2 );
32889
32890                 } else {
32891
32892                         point.copy( this.v2 ).sub( this.v1 );
32893                         point.multiplyScalar( t ).add( this.v1 );
32894
32895                 }
32896
32897                 return point;
32898
32899         }
32900
32901         // Line curve is linear, so we can overwrite default getPointAt
32902         getPointAt( u, optionalTarget ) {
32903
32904                 return this.getPoint( u, optionalTarget );
32905
32906         }
32907
32908         getTangent( t, optionalTarget ) {
32909
32910                 const tangent = optionalTarget || new Vector2();
32911
32912                 tangent.copy( this.v2 ).sub( this.v1 ).normalize();
32913
32914                 return tangent;
32915
32916         }
32917
32918         copy( source ) {
32919
32920                 super.copy( source );
32921
32922                 this.v1.copy( source.v1 );
32923                 this.v2.copy( source.v2 );
32924
32925                 return this;
32926
32927         }
32928
32929         toJSON() {
32930
32931                 const data = super.toJSON();
32932
32933                 data.v1 = this.v1.toArray();
32934                 data.v2 = this.v2.toArray();
32935
32936                 return data;
32937
32938         }
32939
32940         fromJSON( json ) {
32941
32942                 super.fromJSON( json );
32943
32944                 this.v1.fromArray( json.v1 );
32945                 this.v2.fromArray( json.v2 );
32946
32947                 return this;
32948
32949         }
32950
32951 }
32952
32953 LineCurve.prototype.isLineCurve = true;
32954
32955 class LineCurve3 extends Curve {
32956
32957         constructor( v1 = new Vector3(), v2 = new Vector3() ) {
32958
32959                 super();
32960
32961                 this.type = 'LineCurve3';
32962                 this.isLineCurve3 = true;
32963
32964                 this.v1 = v1;
32965                 this.v2 = v2;
32966
32967         }
32968         getPoint( t, optionalTarget = new Vector3() ) {
32969
32970                 const point = optionalTarget;
32971
32972                 if ( t === 1 ) {
32973
32974                         point.copy( this.v2 );
32975
32976                 } else {
32977
32978                         point.copy( this.v2 ).sub( this.v1 );
32979                         point.multiplyScalar( t ).add( this.v1 );
32980
32981                 }
32982
32983                 return point;
32984
32985         }
32986         // Line curve is linear, so we can overwrite default getPointAt
32987         getPointAt( u, optionalTarget ) {
32988
32989                 return this.getPoint( u, optionalTarget );
32990
32991         }
32992         copy( source ) {
32993
32994                 super.copy( source );
32995
32996                 this.v1.copy( source.v1 );
32997                 this.v2.copy( source.v2 );
32998
32999                 return this;
33000
33001         }
33002         toJSON() {
33003
33004                 const data = super.toJSON();
33005
33006                 data.v1 = this.v1.toArray();
33007                 data.v2 = this.v2.toArray();
33008
33009                 return data;
33010
33011         }
33012         fromJSON( json ) {
33013
33014                 super.fromJSON( json );
33015
33016                 this.v1.fromArray( json.v1 );
33017                 this.v2.fromArray( json.v2 );
33018
33019                 return this;
33020
33021         }
33022
33023 }
33024
33025 class QuadraticBezierCurve extends Curve {
33026
33027         constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2() ) {
33028
33029                 super();
33030
33031                 this.type = 'QuadraticBezierCurve';
33032
33033                 this.v0 = v0;
33034                 this.v1 = v1;
33035                 this.v2 = v2;
33036
33037         }
33038
33039         getPoint( t, optionalTarget = new Vector2() ) {
33040
33041                 const point = optionalTarget;
33042
33043                 const v0 = this.v0, v1 = this.v1, v2 = this.v2;
33044
33045                 point.set(
33046                         QuadraticBezier( t, v0.x, v1.x, v2.x ),
33047                         QuadraticBezier( t, v0.y, v1.y, v2.y )
33048                 );
33049
33050                 return point;
33051
33052         }
33053
33054         copy( source ) {
33055
33056                 super.copy( source );
33057
33058                 this.v0.copy( source.v0 );
33059                 this.v1.copy( source.v1 );
33060                 this.v2.copy( source.v2 );
33061
33062                 return this;
33063
33064         }
33065
33066         toJSON() {
33067
33068                 const data = super.toJSON();
33069
33070                 data.v0 = this.v0.toArray();
33071                 data.v1 = this.v1.toArray();
33072                 data.v2 = this.v2.toArray();
33073
33074                 return data;
33075
33076         }
33077
33078         fromJSON( json ) {
33079
33080                 super.fromJSON( json );
33081
33082                 this.v0.fromArray( json.v0 );
33083                 this.v1.fromArray( json.v1 );
33084                 this.v2.fromArray( json.v2 );
33085
33086                 return this;
33087
33088         }
33089
33090 }
33091
33092 QuadraticBezierCurve.prototype.isQuadraticBezierCurve = true;
33093
33094 class QuadraticBezierCurve3 extends Curve {
33095
33096         constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3() ) {
33097
33098                 super();
33099
33100                 this.type = 'QuadraticBezierCurve3';
33101
33102                 this.v0 = v0;
33103                 this.v1 = v1;
33104                 this.v2 = v2;
33105
33106         }
33107
33108         getPoint( t, optionalTarget = new Vector3() ) {
33109
33110                 const point = optionalTarget;
33111
33112                 const v0 = this.v0, v1 = this.v1, v2 = this.v2;
33113
33114                 point.set(
33115                         QuadraticBezier( t, v0.x, v1.x, v2.x ),
33116                         QuadraticBezier( t, v0.y, v1.y, v2.y ),
33117                         QuadraticBezier( t, v0.z, v1.z, v2.z )
33118                 );
33119
33120                 return point;
33121
33122         }
33123
33124         copy( source ) {
33125
33126                 super.copy( source );
33127
33128                 this.v0.copy( source.v0 );
33129                 this.v1.copy( source.v1 );
33130                 this.v2.copy( source.v2 );
33131
33132                 return this;
33133
33134         }
33135
33136         toJSON() {
33137
33138                 const data = super.toJSON();
33139
33140                 data.v0 = this.v0.toArray();
33141                 data.v1 = this.v1.toArray();
33142                 data.v2 = this.v2.toArray();
33143
33144                 return data;
33145
33146         }
33147
33148         fromJSON( json ) {
33149
33150                 super.fromJSON( json );
33151
33152                 this.v0.fromArray( json.v0 );
33153                 this.v1.fromArray( json.v1 );
33154                 this.v2.fromArray( json.v2 );
33155
33156                 return this;
33157
33158         }
33159
33160 }
33161
33162 QuadraticBezierCurve3.prototype.isQuadraticBezierCurve3 = true;
33163
33164 class SplineCurve extends Curve {
33165
33166         constructor( points = [] ) {
33167
33168                 super();
33169
33170                 this.type = 'SplineCurve';
33171
33172                 this.points = points;
33173
33174         }
33175
33176         getPoint( t, optionalTarget = new Vector2() ) {
33177
33178                 const point = optionalTarget;
33179
33180                 const points = this.points;
33181                 const p = ( points.length - 1 ) * t;
33182
33183                 const intPoint = Math.floor( p );
33184                 const weight = p - intPoint;
33185
33186                 const p0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ];
33187                 const p1 = points[ intPoint ];
33188                 const p2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ];
33189                 const p3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ];
33190
33191                 point.set(
33192                         CatmullRom( weight, p0.x, p1.x, p2.x, p3.x ),
33193                         CatmullRom( weight, p0.y, p1.y, p2.y, p3.y )
33194                 );
33195
33196                 return point;
33197
33198         }
33199
33200         copy( source ) {
33201
33202                 super.copy( source );
33203
33204                 this.points = [];
33205
33206                 for ( let i = 0, l = source.points.length; i < l; i ++ ) {
33207
33208                         const point = source.points[ i ];
33209
33210                         this.points.push( point.clone() );
33211
33212                 }
33213
33214                 return this;
33215
33216         }
33217
33218         toJSON() {
33219
33220                 const data = super.toJSON();
33221
33222                 data.points = [];
33223
33224                 for ( let i = 0, l = this.points.length; i < l; i ++ ) {
33225
33226                         const point = this.points[ i ];
33227                         data.points.push( point.toArray() );
33228
33229                 }
33230
33231                 return data;
33232
33233         }
33234
33235         fromJSON( json ) {
33236
33237                 super.fromJSON( json );
33238
33239                 this.points = [];
33240
33241                 for ( let i = 0, l = json.points.length; i < l; i ++ ) {
33242
33243                         const point = json.points[ i ];
33244                         this.points.push( new Vector2().fromArray( point ) );
33245
33246                 }
33247
33248                 return this;
33249
33250         }
33251
33252 }
33253
33254 SplineCurve.prototype.isSplineCurve = true;
33255
33256 var Curves = /*#__PURE__*/Object.freeze({
33257         __proto__: null,
33258         ArcCurve: ArcCurve,
33259         CatmullRomCurve3: CatmullRomCurve3,
33260         CubicBezierCurve: CubicBezierCurve,
33261         CubicBezierCurve3: CubicBezierCurve3,
33262         EllipseCurve: EllipseCurve,
33263         LineCurve: LineCurve,
33264         LineCurve3: LineCurve3,
33265         QuadraticBezierCurve: QuadraticBezierCurve,
33266         QuadraticBezierCurve3: QuadraticBezierCurve3,
33267         SplineCurve: SplineCurve
33268 });
33269
33270 /**************************************************************
33271  *      Curved Path - a curve path is simply a array of connected
33272  *  curves, but retains the api of a curve
33273  **************************************************************/
33274
33275 class CurvePath extends Curve {
33276
33277         constructor() {
33278
33279                 super();
33280
33281                 this.type = 'CurvePath';
33282
33283                 this.curves = [];
33284                 this.autoClose = false; // Automatically closes the path
33285
33286         }
33287
33288         add( curve ) {
33289
33290                 this.curves.push( curve );
33291
33292         }
33293
33294         closePath() {
33295
33296                 // Add a line curve if start and end of lines are not connected
33297                 const startPoint = this.curves[ 0 ].getPoint( 0 );
33298                 const endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 );
33299
33300                 if ( ! startPoint.equals( endPoint ) ) {
33301
33302                         this.curves.push( new LineCurve( endPoint, startPoint ) );
33303
33304                 }
33305
33306         }
33307
33308         // To get accurate point with reference to
33309         // entire path distance at time t,
33310         // following has to be done:
33311
33312         // 1. Length of each sub path have to be known
33313         // 2. Locate and identify type of curve
33314         // 3. Get t for the curve
33315         // 4. Return curve.getPointAt(t')
33316
33317         getPoint( t, optionalTarget ) {
33318
33319                 const d = t * this.getLength();
33320                 const curveLengths = this.getCurveLengths();
33321                 let i = 0;
33322
33323                 // To think about boundaries points.
33324
33325                 while ( i < curveLengths.length ) {
33326
33327                         if ( curveLengths[ i ] >= d ) {
33328
33329                                 const diff = curveLengths[ i ] - d;
33330                                 const curve = this.curves[ i ];
33331
33332                                 const segmentLength = curve.getLength();
33333                                 const u = segmentLength === 0 ? 0 : 1 - diff / segmentLength;
33334
33335                                 return curve.getPointAt( u, optionalTarget );
33336
33337                         }
33338
33339                         i ++;
33340
33341                 }
33342
33343                 return null;
33344
33345                 // loop where sum != 0, sum > d , sum+1 <d
33346
33347         }
33348
33349         // We cannot use the default THREE.Curve getPoint() with getLength() because in
33350         // THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath
33351         // getPoint() depends on getLength
33352
33353         getLength() {
33354
33355                 const lens = this.getCurveLengths();
33356                 return lens[ lens.length - 1 ];
33357
33358         }
33359
33360         // cacheLengths must be recalculated.
33361         updateArcLengths() {
33362
33363                 this.needsUpdate = true;
33364                 this.cacheLengths = null;
33365                 this.getCurveLengths();
33366
33367         }
33368
33369         // Compute lengths and cache them
33370         // We cannot overwrite getLengths() because UtoT mapping uses it.
33371
33372         getCurveLengths() {
33373
33374                 // We use cache values if curves and cache array are same length
33375
33376                 if ( this.cacheLengths && this.cacheLengths.length === this.curves.length ) {
33377
33378                         return this.cacheLengths;
33379
33380                 }
33381
33382                 // Get length of sub-curve
33383                 // Push sums into cached array
33384
33385                 const lengths = [];
33386                 let sums = 0;
33387
33388                 for ( let i = 0, l = this.curves.length; i < l; i ++ ) {
33389
33390                         sums += this.curves[ i ].getLength();
33391                         lengths.push( sums );
33392
33393                 }
33394
33395                 this.cacheLengths = lengths;
33396
33397                 return lengths;
33398
33399         }
33400
33401         getSpacedPoints( divisions = 40 ) {
33402
33403                 const points = [];
33404
33405                 for ( let i = 0; i <= divisions; i ++ ) {
33406
33407                         points.push( this.getPoint( i / divisions ) );
33408
33409                 }
33410
33411                 if ( this.autoClose ) {
33412
33413                         points.push( points[ 0 ] );
33414
33415                 }
33416
33417                 return points;
33418
33419         }
33420
33421         getPoints( divisions = 12 ) {
33422
33423                 const points = [];
33424                 let last;
33425
33426                 for ( let i = 0, curves = this.curves; i < curves.length; i ++ ) {
33427
33428                         const curve = curves[ i ];
33429                         const resolution = ( curve && curve.isEllipseCurve ) ? divisions * 2
33430                                 : ( curve && ( curve.isLineCurve || curve.isLineCurve3 ) ) ? 1
33431                                         : ( curve && curve.isSplineCurve ) ? divisions * curve.points.length
33432                                                 : divisions;
33433
33434                         const pts = curve.getPoints( resolution );
33435
33436                         for ( let j = 0; j < pts.length; j ++ ) {
33437
33438                                 const point = pts[ j ];
33439
33440                                 if ( last && last.equals( point ) ) continue; // ensures no consecutive points are duplicates
33441
33442                                 points.push( point );
33443                                 last = point;
33444
33445                         }
33446
33447                 }
33448
33449                 if ( this.autoClose && points.length > 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) {
33450
33451                         points.push( points[ 0 ] );
33452
33453                 }
33454
33455                 return points;
33456
33457         }
33458
33459         copy( source ) {
33460
33461                 super.copy( source );
33462
33463                 this.curves = [];
33464
33465                 for ( let i = 0, l = source.curves.length; i < l; i ++ ) {
33466
33467                         const curve = source.curves[ i ];
33468
33469                         this.curves.push( curve.clone() );
33470
33471                 }
33472
33473                 this.autoClose = source.autoClose;
33474
33475                 return this;
33476
33477         }
33478
33479         toJSON() {
33480
33481                 const data = super.toJSON();
33482
33483                 data.autoClose = this.autoClose;
33484                 data.curves = [];
33485
33486                 for ( let i = 0, l = this.curves.length; i < l; i ++ ) {
33487
33488                         const curve = this.curves[ i ];
33489                         data.curves.push( curve.toJSON() );
33490
33491                 }
33492
33493                 return data;
33494
33495         }
33496
33497         fromJSON( json ) {
33498
33499                 super.fromJSON( json );
33500
33501                 this.autoClose = json.autoClose;
33502                 this.curves = [];
33503
33504                 for ( let i = 0, l = json.curves.length; i < l; i ++ ) {
33505
33506                         const curve = json.curves[ i ];
33507                         this.curves.push( new Curves[ curve.type ]().fromJSON( curve ) );
33508
33509                 }
33510
33511                 return this;
33512
33513         }
33514
33515 }
33516
33517 class Path extends CurvePath {
33518
33519         constructor( points ) {
33520
33521                 super();
33522                 this.type = 'Path';
33523
33524                 this.currentPoint = new Vector2();
33525
33526                 if ( points ) {
33527
33528                         this.setFromPoints( points );
33529
33530                 }
33531
33532         }
33533
33534         setFromPoints( points ) {
33535
33536                 this.moveTo( points[ 0 ].x, points[ 0 ].y );
33537
33538                 for ( let i = 1, l = points.length; i < l; i ++ ) {
33539
33540                         this.lineTo( points[ i ].x, points[ i ].y );
33541
33542                 }
33543
33544                 return this;
33545
33546         }
33547
33548         moveTo( x, y ) {
33549
33550                 this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying?
33551
33552                 return this;
33553
33554         }
33555
33556         lineTo( x, y ) {
33557
33558                 const curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) );
33559                 this.curves.push( curve );
33560
33561                 this.currentPoint.set( x, y );
33562
33563                 return this;
33564
33565         }
33566
33567         quadraticCurveTo( aCPx, aCPy, aX, aY ) {
33568
33569                 const curve = new QuadraticBezierCurve(
33570                         this.currentPoint.clone(),
33571                         new Vector2( aCPx, aCPy ),
33572                         new Vector2( aX, aY )
33573                 );
33574
33575                 this.curves.push( curve );
33576
33577                 this.currentPoint.set( aX, aY );
33578
33579                 return this;
33580
33581         }
33582
33583         bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {
33584
33585                 const curve = new CubicBezierCurve(
33586                         this.currentPoint.clone(),
33587                         new Vector2( aCP1x, aCP1y ),
33588                         new Vector2( aCP2x, aCP2y ),
33589                         new Vector2( aX, aY )
33590                 );
33591
33592                 this.curves.push( curve );
33593
33594                 this.currentPoint.set( aX, aY );
33595
33596                 return this;
33597
33598         }
33599
33600         splineThru( pts /*Array of Vector*/ ) {
33601
33602                 const npts = [ this.currentPoint.clone() ].concat( pts );
33603
33604                 const curve = new SplineCurve( npts );
33605                 this.curves.push( curve );
33606
33607                 this.currentPoint.copy( pts[ pts.length - 1 ] );
33608
33609                 return this;
33610
33611         }
33612
33613         arc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
33614
33615                 const x0 = this.currentPoint.x;
33616                 const y0 = this.currentPoint.y;
33617
33618                 this.absarc( aX + x0, aY + y0, aRadius,
33619                         aStartAngle, aEndAngle, aClockwise );
33620
33621                 return this;
33622
33623         }
33624
33625         absarc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
33626
33627                 this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );
33628
33629                 return this;
33630
33631         }
33632
33633         ellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
33634
33635                 const x0 = this.currentPoint.x;
33636                 const y0 = this.currentPoint.y;
33637
33638                 this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );
33639
33640                 return this;
33641
33642         }
33643
33644         absellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
33645
33646                 const curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );
33647
33648                 if ( this.curves.length > 0 ) {
33649
33650                         // if a previous curve is present, attempt to join
33651                         const firstPoint = curve.getPoint( 0 );
33652
33653                         if ( ! firstPoint.equals( this.currentPoint ) ) {
33654
33655                                 this.lineTo( firstPoint.x, firstPoint.y );
33656
33657                         }
33658
33659                 }
33660
33661                 this.curves.push( curve );
33662
33663                 const lastPoint = curve.getPoint( 1 );
33664                 this.currentPoint.copy( lastPoint );
33665
33666                 return this;
33667
33668         }
33669
33670         copy( source ) {
33671
33672                 super.copy( source );
33673
33674                 this.currentPoint.copy( source.currentPoint );
33675
33676                 return this;
33677
33678         }
33679
33680         toJSON() {
33681
33682                 const data = super.toJSON();
33683
33684                 data.currentPoint = this.currentPoint.toArray();
33685
33686                 return data;
33687
33688         }
33689
33690         fromJSON( json ) {
33691
33692                 super.fromJSON( json );
33693
33694                 this.currentPoint.fromArray( json.currentPoint );
33695
33696                 return this;
33697
33698         }
33699
33700 }
33701
33702 class Shape extends Path {
33703
33704         constructor( points ) {
33705
33706                 super( points );
33707
33708                 this.uuid = generateUUID();
33709
33710                 this.type = 'Shape';
33711
33712                 this.holes = [];
33713
33714         }
33715
33716         getPointsHoles( divisions ) {
33717
33718                 const holesPts = [];
33719
33720                 for ( let i = 0, l = this.holes.length; i < l; i ++ ) {
33721
33722                         holesPts[ i ] = this.holes[ i ].getPoints( divisions );
33723
33724                 }
33725
33726                 return holesPts;
33727
33728         }
33729
33730         // get points of shape and holes (keypoints based on segments parameter)
33731
33732         extractPoints( divisions ) {
33733
33734                 return {
33735
33736                         shape: this.getPoints( divisions ),
33737                         holes: this.getPointsHoles( divisions )
33738
33739                 };
33740
33741         }
33742
33743         copy( source ) {
33744
33745                 super.copy( source );
33746
33747                 this.holes = [];
33748
33749                 for ( let i = 0, l = source.holes.length; i < l; i ++ ) {
33750
33751                         const hole = source.holes[ i ];
33752
33753                         this.holes.push( hole.clone() );
33754
33755                 }
33756
33757                 return this;
33758
33759         }
33760
33761         toJSON() {
33762
33763                 const data = super.toJSON();
33764
33765                 data.uuid = this.uuid;
33766                 data.holes = [];
33767
33768                 for ( let i = 0, l = this.holes.length; i < l; i ++ ) {
33769
33770                         const hole = this.holes[ i ];
33771                         data.holes.push( hole.toJSON() );
33772
33773                 }
33774
33775                 return data;
33776
33777         }
33778
33779         fromJSON( json ) {
33780
33781                 super.fromJSON( json );
33782
33783                 this.uuid = json.uuid;
33784                 this.holes = [];
33785
33786                 for ( let i = 0, l = json.holes.length; i < l; i ++ ) {
33787
33788                         const hole = json.holes[ i ];
33789                         this.holes.push( new Path().fromJSON( hole ) );
33790
33791                 }
33792
33793                 return this;
33794
33795         }
33796
33797 }
33798
33799 /**
33800  * Port from https://github.com/mapbox/earcut (v2.2.2)
33801  */
33802
33803 const Earcut = {
33804
33805         triangulate: function ( data, holeIndices, dim = 2 ) {
33806
33807                 const hasHoles = holeIndices && holeIndices.length;
33808                 const outerLen = hasHoles ? holeIndices[ 0 ] * dim : data.length;
33809                 let outerNode = linkedList$1( data, 0, outerLen, dim, true );
33810                 const triangles = [];
33811
33812                 if ( ! outerNode || outerNode.next === outerNode.prev ) return triangles;
33813
33814                 let minX, minY, maxX, maxY, x, y, invSize;
33815
33816                 if ( hasHoles ) outerNode = eliminateHoles$1( data, holeIndices, outerNode, dim );
33817
33818                 // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
33819                 if ( data.length > 80 * dim ) {
33820
33821                         minX = maxX = data[ 0 ];
33822                         minY = maxY = data[ 1 ];
33823
33824                         for ( let i = dim; i < outerLen; i += dim ) {
33825
33826                                 x = data[ i ];
33827                                 y = data[ i + 1 ];
33828                                 if ( x < minX ) minX = x;
33829                                 if ( y < minY ) minY = y;
33830                                 if ( x > maxX ) maxX = x;
33831                                 if ( y > maxY ) maxY = y;
33832
33833                         }
33834
33835                         // minX, minY and invSize are later used to transform coords into integers for z-order calculation
33836                         invSize = Math.max( maxX - minX, maxY - minY );
33837                         invSize = invSize !== 0 ? 1 / invSize : 0;
33838
33839                 }
33840
33841                 earcutLinked$1( outerNode, triangles, dim, minX, minY, invSize );
33842
33843                 return triangles;
33844
33845         }
33846
33847 };
33848
33849 // create a circular doubly linked list from polygon points in the specified winding order
33850 function linkedList$1( data, start, end, dim, clockwise ) {
33851
33852         let i, last;
33853
33854         if ( clockwise === ( signedArea$2( data, start, end, dim ) > 0 ) ) {
33855
33856                 for ( i = start; i < end; i += dim ) last = insertNode$2( i, data[ i ], data[ i + 1 ], last );
33857
33858         } else {
33859
33860                 for ( i = end - dim; i >= start; i -= dim ) last = insertNode$2( i, data[ i ], data[ i + 1 ], last );
33861
33862         }
33863
33864         if ( last && equals$2( last, last.next ) ) {
33865
33866                 removeNode$2( last );
33867                 last = last.next;
33868
33869         }
33870
33871         return last;
33872
33873 }
33874
33875 // eliminate colinear or duplicate points
33876 function filterPoints$1( start, end ) {
33877
33878         if ( ! start ) return start;
33879         if ( ! end ) end = start;
33880
33881         let p = start,
33882                 again;
33883         do {
33884
33885                 again = false;
33886
33887                 if ( ! p.steiner && ( equals$2( p, p.next ) || area$1( p.prev, p, p.next ) === 0 ) ) {
33888
33889                         removeNode$2( p );
33890                         p = end = p.prev;
33891                         if ( p === p.next ) break;
33892                         again = true;
33893
33894                 } else {
33895
33896                         p = p.next;
33897
33898                 }
33899
33900         } while ( again || p !== end );
33901
33902         return end;
33903
33904 }
33905
33906 // main ear slicing loop which triangulates a polygon (given as a linked list)
33907 function earcutLinked$1( ear, triangles, dim, minX, minY, invSize, pass ) {
33908
33909         if ( ! ear ) return;
33910
33911         // interlink polygon nodes in z-order
33912         if ( ! pass && invSize ) indexCurve$1( ear, minX, minY, invSize );
33913
33914         let stop = ear,
33915                 prev, next;
33916
33917         // iterate through ears, slicing them one by one
33918         while ( ear.prev !== ear.next ) {
33919
33920                 prev = ear.prev;
33921                 next = ear.next;
33922
33923                 if ( invSize ? isEarHashed$1( ear, minX, minY, invSize ) : isEar$1( ear ) ) {
33924
33925                         // cut off the triangle
33926                         triangles.push( prev.i / dim );
33927                         triangles.push( ear.i / dim );
33928                         triangles.push( next.i / dim );
33929
33930                         removeNode$2( ear );
33931
33932                         // skipping the next vertex leads to less sliver triangles
33933                         ear = next.next;
33934                         stop = next.next;
33935
33936                         continue;
33937
33938                 }
33939
33940                 ear = next;
33941
33942                 // if we looped through the whole remaining polygon and can't find any more ears
33943                 if ( ear === stop ) {
33944
33945                         // try filtering points and slicing again
33946                         if ( ! pass ) {
33947
33948                                 earcutLinked$1( filterPoints$1( ear ), triangles, dim, minX, minY, invSize, 1 );
33949
33950                                 // if this didn't work, try curing all small self-intersections locally
33951
33952                         } else if ( pass === 1 ) {
33953
33954                                 ear = cureLocalIntersections$1( filterPoints$1( ear ), triangles, dim );
33955                                 earcutLinked$1( ear, triangles, dim, minX, minY, invSize, 2 );
33956
33957                                 // as a last resort, try splitting the remaining polygon into two
33958
33959                         } else if ( pass === 2 ) {
33960
33961                                 splitEarcut$1( ear, triangles, dim, minX, minY, invSize );
33962
33963                         }
33964
33965                         break;
33966
33967                 }
33968
33969         }
33970
33971 }
33972
33973 // check whether a polygon node forms a valid ear with adjacent nodes
33974 function isEar$1( ear ) {
33975
33976         const a = ear.prev,
33977                 b = ear,
33978                 c = ear.next;
33979
33980         if ( area$1( a, b, c ) >= 0 ) return false; // reflex, can't be an ear
33981
33982         // now make sure we don't have other points inside the potential ear
33983         let p = ear.next.next;
33984
33985         while ( p !== ear.prev ) {
33986
33987                 if ( pointInTriangle$1( a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y ) &&
33988                         area$1( p.prev, p, p.next ) >= 0 ) return false;
33989                 p = p.next;
33990
33991         }
33992
33993         return true;
33994
33995 }
33996
33997 function isEarHashed$1( ear, minX, minY, invSize ) {
33998
33999         const a = ear.prev,
34000                 b = ear,
34001                 c = ear.next;
34002
34003         if ( area$1( a, b, c ) >= 0 ) return false; // reflex, can't be an ear
34004
34005         // triangle bbox; min & max are calculated like this for speed
34006         const minTX = a.x < b.x ? ( a.x < c.x ? a.x : c.x ) : ( b.x < c.x ? b.x : c.x ),
34007                 minTY = a.y < b.y ? ( a.y < c.y ? a.y : c.y ) : ( b.y < c.y ? b.y : c.y ),
34008                 maxTX = a.x > b.x ? ( a.x > c.x ? a.x : c.x ) : ( b.x > c.x ? b.x : c.x ),
34009                 maxTY = a.y > b.y ? ( a.y > c.y ? a.y : c.y ) : ( b.y > c.y ? b.y : c.y );
34010
34011         // z-order range for the current triangle bbox;
34012         const minZ = zOrder$1( minTX, minTY, minX, minY, invSize ),
34013                 maxZ = zOrder$1( maxTX, maxTY, minX, minY, invSize );
34014
34015         let p = ear.prevZ,
34016                 n = ear.nextZ;
34017
34018         // look for points inside the triangle in both directions
34019         while ( p && p.z >= minZ && n && n.z <= maxZ ) {
34020
34021                 if ( p !== ear.prev && p !== ear.next &&
34022                         pointInTriangle$1( a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y ) &&
34023                         area$1( p.prev, p, p.next ) >= 0 ) return false;
34024                 p = p.prevZ;
34025
34026                 if ( n !== ear.prev && n !== ear.next &&
34027                         pointInTriangle$1( a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y ) &&
34028                         area$1( n.prev, n, n.next ) >= 0 ) return false;
34029                 n = n.nextZ;
34030
34031         }
34032
34033         // look for remaining points in decreasing z-order
34034         while ( p && p.z >= minZ ) {
34035
34036                 if ( p !== ear.prev && p !== ear.next &&
34037                         pointInTriangle$1( a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y ) &&
34038                         area$1( p.prev, p, p.next ) >= 0 ) return false;
34039                 p = p.prevZ;
34040
34041         }
34042
34043         // look for remaining points in increasing z-order
34044         while ( n && n.z <= maxZ ) {
34045
34046                 if ( n !== ear.prev && n !== ear.next &&
34047                         pointInTriangle$1( a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y ) &&
34048                         area$1( n.prev, n, n.next ) >= 0 ) return false;
34049                 n = n.nextZ;
34050
34051         }
34052
34053         return true;
34054
34055 }
34056
34057 // go through all polygon nodes and cure small local self-intersections
34058 function cureLocalIntersections$1( start, triangles, dim ) {
34059
34060         let p = start;
34061         do {
34062
34063                 const a = p.prev,
34064                         b = p.next.next;
34065
34066                 if ( ! equals$2( a, b ) && intersects$2( a, p, p.next, b ) && locallyInside$1( a, b ) && locallyInside$1( b, a ) ) {
34067
34068                         triangles.push( a.i / dim );
34069                         triangles.push( p.i / dim );
34070                         triangles.push( b.i / dim );
34071
34072                         // remove two nodes involved
34073                         removeNode$2( p );
34074                         removeNode$2( p.next );
34075
34076                         p = start = b;
34077
34078                 }
34079
34080                 p = p.next;
34081
34082         } while ( p !== start );
34083
34084         return filterPoints$1( p );
34085
34086 }
34087
34088 // try splitting polygon into two and triangulate them independently
34089 function splitEarcut$1( start, triangles, dim, minX, minY, invSize ) {
34090
34091         // look for a valid diagonal that divides the polygon into two
34092         let a = start;
34093         do {
34094
34095                 let b = a.next.next;
34096                 while ( b !== a.prev ) {
34097
34098                         if ( a.i !== b.i && isValidDiagonal$1( a, b ) ) {
34099
34100                                 // split the polygon in two by the diagonal
34101                                 let c = splitPolygon$1( a, b );
34102
34103                                 // filter colinear points around the cuts
34104                                 a = filterPoints$1( a, a.next );
34105                                 c = filterPoints$1( c, c.next );
34106
34107                                 // run earcut on each half
34108                                 earcutLinked$1( a, triangles, dim, minX, minY, invSize );
34109                                 earcutLinked$1( c, triangles, dim, minX, minY, invSize );
34110                                 return;
34111
34112                         }
34113
34114                         b = b.next;
34115
34116                 }
34117
34118                 a = a.next;
34119
34120         } while ( a !== start );
34121
34122 }
34123
34124 // link every hole into the outer loop, producing a single-ring polygon without holes
34125 function eliminateHoles$1( data, holeIndices, outerNode, dim ) {
34126
34127         const queue = [];
34128         let i, len, start, end, list;
34129
34130         for ( i = 0, len = holeIndices.length; i < len; i ++ ) {
34131
34132                 start = holeIndices[ i ] * dim;
34133                 end = i < len - 1 ? holeIndices[ i + 1 ] * dim : data.length;
34134                 list = linkedList$1( data, start, end, dim, false );
34135                 if ( list === list.next ) list.steiner = true;
34136                 queue.push( getLeftmost$1( list ) );
34137
34138         }
34139
34140         queue.sort( compareX$1 );
34141
34142         // process holes from left to right
34143         for ( i = 0; i < queue.length; i ++ ) {
34144
34145                 eliminateHole$1( queue[ i ], outerNode );
34146                 outerNode = filterPoints$1( outerNode, outerNode.next );
34147
34148         }
34149
34150         return outerNode;
34151
34152 }
34153
34154 function compareX$1( a, b ) {
34155
34156         return a.x - b.x;
34157
34158 }
34159
34160 // find a bridge between vertices that connects hole with an outer ring and and link it
34161 function eliminateHole$1( hole, outerNode ) {
34162
34163         outerNode = findHoleBridge$1( hole, outerNode );
34164         if ( outerNode ) {
34165
34166                 const b = splitPolygon$1( outerNode, hole );
34167
34168                 // filter collinear points around the cuts
34169                 filterPoints$1( outerNode, outerNode.next );
34170                 filterPoints$1( b, b.next );
34171
34172         }
34173
34174 }
34175
34176 // David Eberly's algorithm for finding a bridge between hole and outer polygon
34177 function findHoleBridge$1( hole, outerNode ) {
34178
34179         let p = outerNode;
34180         const hx = hole.x;
34181         const hy = hole.y;
34182         let qx = - Infinity, m;
34183
34184         // find a segment intersected by a ray from the hole's leftmost point to the left;
34185         // segment's endpoint with lesser x will be potential connection point
34186         do {
34187
34188                 if ( hy <= p.y && hy >= p.next.y && p.next.y !== p.y ) {
34189
34190                         const x = p.x + ( hy - p.y ) * ( p.next.x - p.x ) / ( p.next.y - p.y );
34191                         if ( x <= hx && x > qx ) {
34192
34193                                 qx = x;
34194                                 if ( x === hx ) {
34195
34196                                         if ( hy === p.y ) return p;
34197                                         if ( hy === p.next.y ) return p.next;
34198
34199                                 }
34200
34201                                 m = p.x < p.next.x ? p : p.next;
34202
34203                         }
34204
34205                 }
34206
34207                 p = p.next;
34208
34209         } while ( p !== outerNode );
34210
34211         if ( ! m ) return null;
34212
34213         if ( hx === qx ) return m; // hole touches outer segment; pick leftmost endpoint
34214
34215         // look for points inside the triangle of hole point, segment intersection and endpoint;
34216         // if there are no points found, we have a valid connection;
34217         // otherwise choose the point of the minimum angle with the ray as connection point
34218
34219         const stop = m,
34220                 mx = m.x,
34221                 my = m.y;
34222         let tanMin = Infinity, tan;
34223
34224         p = m;
34225
34226         do {
34227
34228                 if ( hx >= p.x && p.x >= mx && hx !== p.x &&
34229                                 pointInTriangle$1( hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y ) ) {
34230
34231                         tan = Math.abs( hy - p.y ) / ( hx - p.x ); // tangential
34232
34233                         if ( locallyInside$1( p, hole ) && ( tan < tanMin || ( tan === tanMin && ( p.x > m.x || ( p.x === m.x && sectorContainsSector$1( m, p ) ) ) ) ) ) {
34234
34235                                 m = p;
34236                                 tanMin = tan;
34237
34238                         }
34239
34240                 }
34241
34242                 p = p.next;
34243
34244         } while ( p !== stop );
34245
34246         return m;
34247
34248 }
34249
34250 // whether sector in vertex m contains sector in vertex p in the same coordinates
34251 function sectorContainsSector$1( m, p ) {
34252
34253         return area$1( m.prev, m, p.prev ) < 0 && area$1( p.next, m, m.next ) < 0;
34254
34255 }
34256
34257 // interlink polygon nodes in z-order
34258 function indexCurve$1( start, minX, minY, invSize ) {
34259
34260         let p = start;
34261         do {
34262
34263                 if ( p.z === null ) p.z = zOrder$1( p.x, p.y, minX, minY, invSize );
34264                 p.prevZ = p.prev;
34265                 p.nextZ = p.next;
34266                 p = p.next;
34267
34268         } while ( p !== start );
34269
34270         p.prevZ.nextZ = null;
34271         p.prevZ = null;
34272
34273         sortLinked$1( p );
34274
34275 }
34276
34277 // Simon Tatham's linked list merge sort algorithm
34278 // http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
34279 function sortLinked$1( list ) {
34280
34281         let i, p, q, e, tail, numMerges, pSize, qSize,
34282                 inSize = 1;
34283
34284         do {
34285
34286                 p = list;
34287                 list = null;
34288                 tail = null;
34289                 numMerges = 0;
34290
34291                 while ( p ) {
34292
34293                         numMerges ++;
34294                         q = p;
34295                         pSize = 0;
34296                         for ( i = 0; i < inSize; i ++ ) {
34297
34298                                 pSize ++;
34299                                 q = q.nextZ;
34300                                 if ( ! q ) break;
34301
34302                         }
34303
34304                         qSize = inSize;
34305
34306                         while ( pSize > 0 || ( qSize > 0 && q ) ) {
34307
34308                                 if ( pSize !== 0 && ( qSize === 0 || ! q || p.z <= q.z ) ) {
34309
34310                                         e = p;
34311                                         p = p.nextZ;
34312                                         pSize --;
34313
34314                                 } else {
34315
34316                                         e = q;
34317                                         q = q.nextZ;
34318                                         qSize --;
34319
34320                                 }
34321
34322                                 if ( tail ) tail.nextZ = e;
34323                                 else list = e;
34324
34325                                 e.prevZ = tail;
34326                                 tail = e;
34327
34328                         }
34329
34330                         p = q;
34331
34332                 }
34333
34334                 tail.nextZ = null;
34335                 inSize *= 2;
34336
34337         } while ( numMerges > 1 );
34338
34339         return list;
34340
34341 }
34342
34343 // z-order of a point given coords and inverse of the longer side of data bbox
34344 function zOrder$1( x, y, minX, minY, invSize ) {
34345
34346         // coords are transformed into non-negative 15-bit integer range
34347         x = 32767 * ( x - minX ) * invSize;
34348         y = 32767 * ( y - minY ) * invSize;
34349
34350         x = ( x | ( x << 8 ) ) & 0x00FF00FF;
34351         x = ( x | ( x << 4 ) ) & 0x0F0F0F0F;
34352         x = ( x | ( x << 2 ) ) & 0x33333333;
34353         x = ( x | ( x << 1 ) ) & 0x55555555;
34354
34355         y = ( y | ( y << 8 ) ) & 0x00FF00FF;
34356         y = ( y | ( y << 4 ) ) & 0x0F0F0F0F;
34357         y = ( y | ( y << 2 ) ) & 0x33333333;
34358         y = ( y | ( y << 1 ) ) & 0x55555555;
34359
34360         return x | ( y << 1 );
34361
34362 }
34363
34364 // find the leftmost node of a polygon ring
34365 function getLeftmost$1( start ) {
34366
34367         let p = start,
34368                 leftmost = start;
34369         do {
34370
34371                 if ( p.x < leftmost.x || ( p.x === leftmost.x && p.y < leftmost.y ) ) leftmost = p;
34372                 p = p.next;
34373
34374         } while ( p !== start );
34375
34376         return leftmost;
34377
34378 }
34379
34380 // check if a point lies within a convex triangle
34381 function pointInTriangle$1( ax, ay, bx, by, cx, cy, px, py ) {
34382
34383         return ( cx - px ) * ( ay - py ) - ( ax - px ) * ( cy - py ) >= 0 &&
34384                         ( ax - px ) * ( by - py ) - ( bx - px ) * ( ay - py ) >= 0 &&
34385                         ( bx - px ) * ( cy - py ) - ( cx - px ) * ( by - py ) >= 0;
34386
34387 }
34388
34389 // check if a diagonal between two polygon nodes is valid (lies in polygon interior)
34390 function isValidDiagonal$1( a, b ) {
34391
34392         return a.next.i !== b.i && a.prev.i !== b.i && ! intersectsPolygon$1( a, b ) && // dones't intersect other edges
34393                 ( locallyInside$1( a, b ) && locallyInside$1( b, a ) && middleInside$1( a, b ) && // locally visible
34394                 ( area$1( a.prev, a, b.prev ) || area$1( a, b.prev, b ) ) || // does not create opposite-facing sectors
34395                 equals$2( a, b ) && area$1( a.prev, a, a.next ) > 0 && area$1( b.prev, b, b.next ) > 0 ); // special zero-length case
34396
34397 }
34398
34399 // signed area of a triangle
34400 function area$1( p, q, r ) {
34401
34402         return ( q.y - p.y ) * ( r.x - q.x ) - ( q.x - p.x ) * ( r.y - q.y );
34403
34404 }
34405
34406 // check if two points are equal
34407 function equals$2( p1, p2 ) {
34408
34409         return p1.x === p2.x && p1.y === p2.y;
34410
34411 }
34412
34413 // check if two segments intersect
34414 function intersects$2( p1, q1, p2, q2 ) {
34415
34416         const o1 = sign$2( area$1( p1, q1, p2 ) );
34417         const o2 = sign$2( area$1( p1, q1, q2 ) );
34418         const o3 = sign$2( area$1( p2, q2, p1 ) );
34419         const o4 = sign$2( area$1( p2, q2, q1 ) );
34420
34421         if ( o1 !== o2 && o3 !== o4 ) return true; // general case
34422
34423         if ( o1 === 0 && onSegment$1( p1, p2, q1 ) ) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1
34424         if ( o2 === 0 && onSegment$1( p1, q2, q1 ) ) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1
34425         if ( o3 === 0 && onSegment$1( p2, p1, q2 ) ) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2
34426         if ( o4 === 0 && onSegment$1( p2, q1, q2 ) ) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2
34427
34428         return false;
34429
34430 }
34431
34432 // for collinear points p, q, r, check if point q lies on segment pr
34433 function onSegment$1( p, q, r ) {
34434
34435         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 );
34436
34437 }
34438
34439 function sign$2( num ) {
34440
34441         return num > 0 ? 1 : num < 0 ? - 1 : 0;
34442
34443 }
34444
34445 // check if a polygon diagonal intersects any polygon segments
34446 function intersectsPolygon$1( a, b ) {
34447
34448         let p = a;
34449         do {
34450
34451                 if ( p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i &&
34452                                 intersects$2( p, p.next, a, b ) ) return true;
34453                 p = p.next;
34454
34455         } while ( p !== a );
34456
34457         return false;
34458
34459 }
34460
34461 // check if a polygon diagonal is locally inside the polygon
34462 function locallyInside$1( a, b ) {
34463
34464         return area$1( a.prev, a, a.next ) < 0 ?
34465                 area$1( a, b, a.next ) >= 0 && area$1( a, a.prev, b ) >= 0 :
34466                 area$1( a, b, a.prev ) < 0 || area$1( a, a.next, b ) < 0;
34467
34468 }
34469
34470 // check if the middle point of a polygon diagonal is inside the polygon
34471 function middleInside$1( a, b ) {
34472
34473         let p = a,
34474                 inside = false;
34475         const px = ( a.x + b.x ) / 2,
34476                 py = ( a.y + b.y ) / 2;
34477         do {
34478
34479                 if ( ( ( p.y > py ) !== ( p.next.y > py ) ) && p.next.y !== p.y &&
34480                                 ( px < ( p.next.x - p.x ) * ( py - p.y ) / ( p.next.y - p.y ) + p.x ) )
34481                         inside = ! inside;
34482                 p = p.next;
34483
34484         } while ( p !== a );
34485
34486         return inside;
34487
34488 }
34489
34490 // link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;
34491 // if one belongs to the outer ring and another to a hole, it merges it into a single ring
34492 function splitPolygon$1( a, b ) {
34493
34494         const a2 = new Node$1( a.i, a.x, a.y ),
34495                 b2 = new Node$1( b.i, b.x, b.y ),
34496                 an = a.next,
34497                 bp = b.prev;
34498
34499         a.next = b;
34500         b.prev = a;
34501
34502         a2.next = an;
34503         an.prev = a2;
34504
34505         b2.next = a2;
34506         a2.prev = b2;
34507
34508         bp.next = b2;
34509         b2.prev = bp;
34510
34511         return b2;
34512
34513 }
34514
34515 // create a node and optionally link it with previous one (in a circular doubly linked list)
34516 function insertNode$2( i, x, y, last ) {
34517
34518         const p = new Node$1( i, x, y );
34519
34520         if ( ! last ) {
34521
34522                 p.prev = p;
34523                 p.next = p;
34524
34525         } else {
34526
34527                 p.next = last.next;
34528                 p.prev = last;
34529                 last.next.prev = p;
34530                 last.next = p;
34531
34532         }
34533
34534         return p;
34535
34536 }
34537
34538 function removeNode$2( p ) {
34539
34540         p.next.prev = p.prev;
34541         p.prev.next = p.next;
34542
34543         if ( p.prevZ ) p.prevZ.nextZ = p.nextZ;
34544         if ( p.nextZ ) p.nextZ.prevZ = p.prevZ;
34545
34546 }
34547
34548 function Node$1( i, x, y ) {
34549
34550         // vertex index in coordinates array
34551         this.i = i;
34552
34553         // vertex coordinates
34554         this.x = x;
34555         this.y = y;
34556
34557         // previous and next vertex nodes in a polygon ring
34558         this.prev = null;
34559         this.next = null;
34560
34561         // z-order curve value
34562         this.z = null;
34563
34564         // previous and next nodes in z-order
34565         this.prevZ = null;
34566         this.nextZ = null;
34567
34568         // indicates whether this is a steiner point
34569         this.steiner = false;
34570
34571 }
34572
34573 function signedArea$2( data, start, end, dim ) {
34574
34575         let sum = 0;
34576         for ( let i = start, j = end - dim; i < end; i += dim ) {
34577
34578                 sum += ( data[ j ] - data[ i ] ) * ( data[ i + 1 ] + data[ j + 1 ] );
34579                 j = i;
34580
34581         }
34582
34583         return sum;
34584
34585 }
34586
34587 class ShapeUtils {
34588
34589         // calculate area of the contour polygon
34590
34591         static area( contour ) {
34592
34593                 const n = contour.length;
34594                 let a = 0.0;
34595
34596                 for ( let p = n - 1, q = 0; q < n; p = q ++ ) {
34597
34598                         a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y;
34599
34600                 }
34601
34602                 return a * 0.5;
34603
34604         }
34605
34606         static isClockWise( pts ) {
34607
34608                 return ShapeUtils.area( pts ) < 0;
34609
34610         }
34611
34612         static triangulateShape( contour, holes ) {
34613
34614                 const vertices = []; // flat array of vertices like [ x0,y0, x1,y1, x2,y2, ... ]
34615                 const holeIndices = []; // array of hole indices
34616                 const faces = []; // final array of vertex indices like [ [ a,b,d ], [ b,c,d ] ]
34617
34618                 removeDupEndPts( contour );
34619                 addContour( vertices, contour );
34620
34621                 //
34622
34623                 let holeIndex = contour.length;
34624
34625                 holes.forEach( removeDupEndPts );
34626
34627                 for ( let i = 0; i < holes.length; i ++ ) {
34628
34629                         holeIndices.push( holeIndex );
34630                         holeIndex += holes[ i ].length;
34631                         addContour( vertices, holes[ i ] );
34632
34633                 }
34634
34635                 //
34636
34637                 const triangles = Earcut.triangulate( vertices, holeIndices );
34638
34639                 //
34640
34641                 for ( let i = 0; i < triangles.length; i += 3 ) {
34642
34643                         faces.push( triangles.slice( i, i + 3 ) );
34644
34645                 }
34646
34647                 return faces;
34648
34649         }
34650
34651 }
34652
34653 function removeDupEndPts( points ) {
34654
34655         const l = points.length;
34656
34657         if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) {
34658
34659                 points.pop();
34660
34661         }
34662
34663 }
34664
34665 function addContour( vertices, contour ) {
34666
34667         for ( let i = 0; i < contour.length; i ++ ) {
34668
34669                 vertices.push( contour[ i ].x );
34670                 vertices.push( contour[ i ].y );
34671
34672         }
34673
34674 }
34675
34676 /**
34677  * Creates extruded geometry from a path shape.
34678  *
34679  * parameters = {
34680  *
34681  *  curveSegments: <int>, // number of points on the curves
34682  *  steps: <int>, // number of points for z-side extrusions / used for subdividing segments of extrude spline too
34683  *  depth: <float>, // Depth to extrude the shape
34684  *
34685  *  bevelEnabled: <bool>, // turn on bevel
34686  *  bevelThickness: <float>, // how deep into the original shape bevel goes
34687  *  bevelSize: <float>, // how far from shape outline (including bevelOffset) is bevel
34688  *  bevelOffset: <float>, // how far from shape outline does bevel start
34689  *  bevelSegments: <int>, // number of bevel layers
34690  *
34691  *  extrudePath: <THREE.Curve> // curve to extrude shape along
34692  *
34693  *  UVGenerator: <Object> // object that provides UV generator functions
34694  *
34695  * }
34696  */
34697
34698 class ExtrudeGeometry extends BufferGeometry {
34699
34700         constructor( shapes = new Shape( [ new Vector2( 0.5, 0.5 ), new Vector2( - 0.5, 0.5 ), new Vector2( - 0.5, - 0.5 ), new Vector2( 0.5, - 0.5 ) ] ), options = {} ) {
34701
34702                 super();
34703
34704                 this.type = 'ExtrudeGeometry';
34705
34706                 this.parameters = {
34707                         shapes: shapes,
34708                         options: options
34709                 };
34710
34711                 shapes = Array.isArray( shapes ) ? shapes : [ shapes ];
34712
34713                 const scope = this;
34714
34715                 const verticesArray = [];
34716                 const uvArray = [];
34717
34718                 for ( let i = 0, l = shapes.length; i < l; i ++ ) {
34719
34720                         const shape = shapes[ i ];
34721                         addShape( shape );
34722
34723                 }
34724
34725                 // build geometry
34726
34727                 this.setAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) );
34728                 this.setAttribute( 'uv', new Float32BufferAttribute( uvArray, 2 ) );
34729
34730                 this.computeVertexNormals();
34731
34732                 // functions
34733
34734                 function addShape( shape ) {
34735
34736                         const placeholder = [];
34737
34738                         // options
34739
34740                         const curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12;
34741                         const steps = options.steps !== undefined ? options.steps : 1;
34742                         let depth = options.depth !== undefined ? options.depth : 1;
34743
34744                         let bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true;
34745                         let bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 0.2;
34746                         let bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 0.1;
34747                         let bevelOffset = options.bevelOffset !== undefined ? options.bevelOffset : 0;
34748                         let bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3;
34749
34750                         const extrudePath = options.extrudePath;
34751
34752                         const uvgen = options.UVGenerator !== undefined ? options.UVGenerator : WorldUVGenerator;
34753
34754                         // deprecated options
34755
34756                         if ( options.amount !== undefined ) {
34757
34758                                 console.warn( 'THREE.ExtrudeBufferGeometry: amount has been renamed to depth.' );
34759                                 depth = options.amount;
34760
34761                         }
34762
34763                         //
34764
34765                         let extrudePts, extrudeByPath = false;
34766                         let splineTube, binormal, normal, position2;
34767
34768                         if ( extrudePath ) {
34769
34770                                 extrudePts = extrudePath.getSpacedPoints( steps );
34771
34772                                 extrudeByPath = true;
34773                                 bevelEnabled = false; // bevels not supported for path extrusion
34774
34775                                 // SETUP TNB variables
34776
34777                                 // TODO1 - have a .isClosed in spline?
34778
34779                                 splineTube = extrudePath.computeFrenetFrames( steps, false );
34780
34781                                 // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length);
34782
34783                                 binormal = new Vector3();
34784                                 normal = new Vector3();
34785                                 position2 = new Vector3();
34786
34787                         }
34788
34789                         // Safeguards if bevels are not enabled
34790
34791                         if ( ! bevelEnabled ) {
34792
34793                                 bevelSegments = 0;
34794                                 bevelThickness = 0;
34795                                 bevelSize = 0;
34796                                 bevelOffset = 0;
34797
34798                         }
34799
34800                         // Variables initialization
34801
34802                         const shapePoints = shape.extractPoints( curveSegments );
34803
34804                         let vertices = shapePoints.shape;
34805                         const holes = shapePoints.holes;
34806
34807                         const reverse = ! ShapeUtils.isClockWise( vertices );
34808
34809                         if ( reverse ) {
34810
34811                                 vertices = vertices.reverse();
34812
34813                                 // Maybe we should also check if holes are in the opposite direction, just to be safe ...
34814
34815                                 for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
34816
34817                                         const ahole = holes[ h ];
34818
34819                                         if ( ShapeUtils.isClockWise( ahole ) ) {
34820
34821                                                 holes[ h ] = ahole.reverse();
34822
34823                                         }
34824
34825                                 }
34826
34827                         }
34828
34829
34830                         const faces = ShapeUtils.triangulateShape( vertices, holes );
34831
34832                         /* Vertices */
34833
34834                         const contour = vertices; // vertices has all points but contour has only points of circumference
34835
34836                         for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
34837
34838                                 const ahole = holes[ h ];
34839
34840                                 vertices = vertices.concat( ahole );
34841
34842                         }
34843
34844
34845                         function scalePt2( pt, vec, size ) {
34846
34847                                 if ( ! vec ) console.error( 'THREE.ExtrudeGeometry: vec does not exist' );
34848
34849                                 return vec.clone().multiplyScalar( size ).add( pt );
34850
34851                         }
34852
34853                         const vlen = vertices.length, flen = faces.length;
34854
34855
34856                         // Find directions for point movement
34857
34858
34859                         function getBevelVec( inPt, inPrev, inNext ) {
34860
34861                                 // computes for inPt the corresponding point inPt' on a new contour
34862                                 //   shifted by 1 unit (length of normalized vector) to the left
34863                                 // if we walk along contour clockwise, this new contour is outside the old one
34864                                 //
34865                                 // inPt' is the intersection of the two lines parallel to the two
34866                                 //  adjacent edges of inPt at a distance of 1 unit on the left side.
34867
34868                                 let v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt
34869
34870                                 // good reading for geometry algorithms (here: line-line intersection)
34871                                 // http://geomalgorithms.com/a05-_intersect-1.html
34872
34873                                 const v_prev_x = inPt.x - inPrev.x,
34874                                         v_prev_y = inPt.y - inPrev.y;
34875                                 const v_next_x = inNext.x - inPt.x,
34876                                         v_next_y = inNext.y - inPt.y;
34877
34878                                 const v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y );
34879
34880                                 // check for collinear edges
34881                                 const collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x );
34882
34883                                 if ( Math.abs( collinear0 ) > Number.EPSILON ) {
34884
34885                                         // not collinear
34886
34887                                         // length of vectors for normalizing
34888
34889                                         const v_prev_len = Math.sqrt( v_prev_lensq );
34890                                         const v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y );
34891
34892                                         // shift adjacent points by unit vectors to the left
34893
34894                                         const ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len );
34895                                         const ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len );
34896
34897                                         const ptNextShift_x = ( inNext.x - v_next_y / v_next_len );
34898                                         const ptNextShift_y = ( inNext.y + v_next_x / v_next_len );
34899
34900                                         // scaling factor for v_prev to intersection point
34901
34902                                         const sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y -
34903                                                         ( ptNextShift_y - ptPrevShift_y ) * v_next_x ) /
34904                                                 ( v_prev_x * v_next_y - v_prev_y * v_next_x );
34905
34906                                         // vector from inPt to intersection point
34907
34908                                         v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x );
34909                                         v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y );
34910
34911                                         // Don't normalize!, otherwise sharp corners become ugly
34912                                         //  but prevent crazy spikes
34913                                         const v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y );
34914                                         if ( v_trans_lensq <= 2 ) {
34915
34916                                                 return new Vector2( v_trans_x, v_trans_y );
34917
34918                                         } else {
34919
34920                                                 shrink_by = Math.sqrt( v_trans_lensq / 2 );
34921
34922                                         }
34923
34924                                 } else {
34925
34926                                         // handle special case of collinear edges
34927
34928                                         let direction_eq = false; // assumes: opposite
34929
34930                                         if ( v_prev_x > Number.EPSILON ) {
34931
34932                                                 if ( v_next_x > Number.EPSILON ) {
34933
34934                                                         direction_eq = true;
34935
34936                                                 }
34937
34938                                         } else {
34939
34940                                                 if ( v_prev_x < - Number.EPSILON ) {
34941
34942                                                         if ( v_next_x < - Number.EPSILON ) {
34943
34944                                                                 direction_eq = true;
34945
34946                                                         }
34947
34948                                                 } else {
34949
34950                                                         if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) {
34951
34952                                                                 direction_eq = true;
34953
34954                                                         }
34955
34956                                                 }
34957
34958                                         }
34959
34960                                         if ( direction_eq ) {
34961
34962                                                 // console.log("Warning: lines are a straight sequence");
34963                                                 v_trans_x = - v_prev_y;
34964                                                 v_trans_y = v_prev_x;
34965                                                 shrink_by = Math.sqrt( v_prev_lensq );
34966
34967                                         } else {
34968
34969                                                 // console.log("Warning: lines are a straight spike");
34970                                                 v_trans_x = v_prev_x;
34971                                                 v_trans_y = v_prev_y;
34972                                                 shrink_by = Math.sqrt( v_prev_lensq / 2 );
34973
34974                                         }
34975
34976                                 }
34977
34978                                 return new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by );
34979
34980                         }
34981
34982
34983                         const contourMovements = [];
34984
34985                         for ( let i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {
34986
34987                                 if ( j === il ) j = 0;
34988                                 if ( k === il ) k = 0;
34989
34990                                 //  (j)---(i)---(k)
34991                                 // console.log('i,j,k', i, j , k)
34992
34993                                 contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] );
34994
34995                         }
34996
34997                         const holesMovements = [];
34998                         let oneHoleMovements, verticesMovements = contourMovements.concat();
34999
35000                         for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
35001
35002                                 const ahole = holes[ h ];
35003
35004                                 oneHoleMovements = [];
35005
35006                                 for ( let i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {
35007
35008                                         if ( j === il ) j = 0;
35009                                         if ( k === il ) k = 0;
35010
35011                                         //  (j)---(i)---(k)
35012                                         oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] );
35013
35014                                 }
35015
35016                                 holesMovements.push( oneHoleMovements );
35017                                 verticesMovements = verticesMovements.concat( oneHoleMovements );
35018
35019                         }
35020
35021
35022                         // Loop bevelSegments, 1 for the front, 1 for the back
35023
35024                         for ( let b = 0; b < bevelSegments; b ++ ) {
35025
35026                                 //for ( b = bevelSegments; b > 0; b -- ) {
35027
35028                                 const t = b / bevelSegments;
35029                                 const z = bevelThickness * Math.cos( t * Math.PI / 2 );
35030                                 const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset;
35031
35032                                 // contract shape
35033
35034                                 for ( let i = 0, il = contour.length; i < il; i ++ ) {
35035
35036                                         const vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
35037
35038                                         v( vert.x, vert.y, - z );
35039
35040                                 }
35041
35042                                 // expand holes
35043
35044                                 for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
35045
35046                                         const ahole = holes[ h ];
35047                                         oneHoleMovements = holesMovements[ h ];
35048
35049                                         for ( let i = 0, il = ahole.length; i < il; i ++ ) {
35050
35051                                                 const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
35052
35053                                                 v( vert.x, vert.y, - z );
35054
35055                                         }
35056
35057                                 }
35058
35059                         }
35060
35061                         const bs = bevelSize + bevelOffset;
35062
35063                         // Back facing vertices
35064
35065                         for ( let i = 0; i < vlen; i ++ ) {
35066
35067                                 const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
35068
35069                                 if ( ! extrudeByPath ) {
35070
35071                                         v( vert.x, vert.y, 0 );
35072
35073                                 } else {
35074
35075                                         // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x );
35076
35077                                         normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x );
35078                                         binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y );
35079
35080                                         position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal );
35081
35082                                         v( position2.x, position2.y, position2.z );
35083
35084                                 }
35085
35086                         }
35087
35088                         // Add stepped vertices...
35089                         // Including front facing vertices
35090
35091                         for ( let s = 1; s <= steps; s ++ ) {
35092
35093                                 for ( let i = 0; i < vlen; i ++ ) {
35094
35095                                         const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
35096
35097                                         if ( ! extrudeByPath ) {
35098
35099                                                 v( vert.x, vert.y, depth / steps * s );
35100
35101                                         } else {
35102
35103                                                 // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x );
35104
35105                                                 normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x );
35106                                                 binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y );
35107
35108                                                 position2.copy( extrudePts[ s ] ).add( normal ).add( binormal );
35109
35110                                                 v( position2.x, position2.y, position2.z );
35111
35112                                         }
35113
35114                                 }
35115
35116                         }
35117
35118
35119                         // Add bevel segments planes
35120
35121                         //for ( b = 1; b <= bevelSegments; b ++ ) {
35122                         for ( let b = bevelSegments - 1; b >= 0; b -- ) {
35123
35124                                 const t = b / bevelSegments;
35125                                 const z = bevelThickness * Math.cos( t * Math.PI / 2 );
35126                                 const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset;
35127
35128                                 // contract shape
35129
35130                                 for ( let i = 0, il = contour.length; i < il; i ++ ) {
35131
35132                                         const vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
35133                                         v( vert.x, vert.y, depth + z );
35134
35135                                 }
35136
35137                                 // expand holes
35138
35139                                 for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
35140
35141                                         const ahole = holes[ h ];
35142                                         oneHoleMovements = holesMovements[ h ];
35143
35144                                         for ( let i = 0, il = ahole.length; i < il; i ++ ) {
35145
35146                                                 const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
35147
35148                                                 if ( ! extrudeByPath ) {
35149
35150                                                         v( vert.x, vert.y, depth + z );
35151
35152                                                 } else {
35153
35154                                                         v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z );
35155
35156                                                 }
35157
35158                                         }
35159
35160                                 }
35161
35162                         }
35163
35164                         /* Faces */
35165
35166                         // Top and bottom faces
35167
35168                         buildLidFaces();
35169
35170                         // Sides faces
35171
35172                         buildSideFaces();
35173
35174
35175                         /////  Internal functions
35176
35177                         function buildLidFaces() {
35178
35179                                 const start = verticesArray.length / 3;
35180
35181                                 if ( bevelEnabled ) {
35182
35183                                         let layer = 0; // steps + 1
35184                                         let offset = vlen * layer;
35185
35186                                         // Bottom faces
35187
35188                                         for ( let i = 0; i < flen; i ++ ) {
35189
35190                                                 const face = faces[ i ];
35191                                                 f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset );
35192
35193                                         }
35194
35195                                         layer = steps + bevelSegments * 2;
35196                                         offset = vlen * layer;
35197
35198                                         // Top faces
35199
35200                                         for ( let i = 0; i < flen; i ++ ) {
35201
35202                                                 const face = faces[ i ];
35203                                                 f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset );
35204
35205                                         }
35206
35207                                 } else {
35208
35209                                         // Bottom faces
35210
35211                                         for ( let i = 0; i < flen; i ++ ) {
35212
35213                                                 const face = faces[ i ];
35214                                                 f3( face[ 2 ], face[ 1 ], face[ 0 ] );
35215
35216                                         }
35217
35218                                         // Top faces
35219
35220                                         for ( let i = 0; i < flen; i ++ ) {
35221
35222                                                 const face = faces[ i ];
35223                                                 f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps );
35224
35225                                         }
35226
35227                                 }
35228
35229                                 scope.addGroup( start, verticesArray.length / 3 - start, 0 );
35230
35231                         }
35232
35233                         // Create faces for the z-sides of the shape
35234
35235                         function buildSideFaces() {
35236
35237                                 const start = verticesArray.length / 3;
35238                                 let layeroffset = 0;
35239                                 sidewalls( contour, layeroffset );
35240                                 layeroffset += contour.length;
35241
35242                                 for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
35243
35244                                         const ahole = holes[ h ];
35245                                         sidewalls( ahole, layeroffset );
35246
35247                                         //, true
35248                                         layeroffset += ahole.length;
35249
35250                                 }
35251
35252
35253                                 scope.addGroup( start, verticesArray.length / 3 - start, 1 );
35254
35255
35256                         }
35257
35258                         function sidewalls( contour, layeroffset ) {
35259
35260                                 let i = contour.length;
35261
35262                                 while ( -- i >= 0 ) {
35263
35264                                         const j = i;
35265                                         let k = i - 1;
35266                                         if ( k < 0 ) k = contour.length - 1;
35267
35268                                         //console.log('b', i,j, i-1, k,vertices.length);
35269
35270                                         for ( let s = 0, sl = ( steps + bevelSegments * 2 ); s < sl; s ++ ) {
35271
35272                                                 const slen1 = vlen * s;
35273                                                 const slen2 = vlen * ( s + 1 );
35274
35275                                                 const a = layeroffset + j + slen1,
35276                                                         b = layeroffset + k + slen1,
35277                                                         c = layeroffset + k + slen2,
35278                                                         d = layeroffset + j + slen2;
35279
35280                                                 f4( a, b, c, d );
35281
35282                                         }
35283
35284                                 }
35285
35286                         }
35287
35288                         function v( x, y, z ) {
35289
35290                                 placeholder.push( x );
35291                                 placeholder.push( y );
35292                                 placeholder.push( z );
35293
35294                         }
35295
35296
35297                         function f3( a, b, c ) {
35298
35299                                 addVertex( a );
35300                                 addVertex( b );
35301                                 addVertex( c );
35302
35303                                 const nextIndex = verticesArray.length / 3;
35304                                 const uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 );
35305
35306                                 addUV( uvs[ 0 ] );
35307                                 addUV( uvs[ 1 ] );
35308                                 addUV( uvs[ 2 ] );
35309
35310                         }
35311
35312                         function f4( a, b, c, d ) {
35313
35314                                 addVertex( a );
35315                                 addVertex( b );
35316                                 addVertex( d );
35317
35318                                 addVertex( b );
35319                                 addVertex( c );
35320                                 addVertex( d );
35321
35322
35323                                 const nextIndex = verticesArray.length / 3;
35324                                 const uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 );
35325
35326                                 addUV( uvs[ 0 ] );
35327                                 addUV( uvs[ 1 ] );
35328                                 addUV( uvs[ 3 ] );
35329
35330                                 addUV( uvs[ 1 ] );
35331                                 addUV( uvs[ 2 ] );
35332                                 addUV( uvs[ 3 ] );
35333
35334                         }
35335
35336                         function addVertex( index ) {
35337
35338                                 verticesArray.push( placeholder[ index * 3 + 0 ] );
35339                                 verticesArray.push( placeholder[ index * 3 + 1 ] );
35340                                 verticesArray.push( placeholder[ index * 3 + 2 ] );
35341
35342                         }
35343
35344
35345                         function addUV( vector2 ) {
35346
35347                                 uvArray.push( vector2.x );
35348                                 uvArray.push( vector2.y );
35349
35350                         }
35351
35352                 }
35353
35354         }
35355
35356         toJSON() {
35357
35358                 const data = super.toJSON();
35359
35360                 const shapes = this.parameters.shapes;
35361                 const options = this.parameters.options;
35362
35363                 return toJSON$1( shapes, options, data );
35364
35365         }
35366
35367         static fromJSON( data, shapes ) {
35368
35369                 const geometryShapes = [];
35370
35371                 for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) {
35372
35373                         const shape = shapes[ data.shapes[ j ] ];
35374
35375                         geometryShapes.push( shape );
35376
35377                 }
35378
35379                 const extrudePath = data.options.extrudePath;
35380
35381                 if ( extrudePath !== undefined ) {
35382
35383                         data.options.extrudePath = new Curves[ extrudePath.type ]().fromJSON( extrudePath );
35384
35385                 }
35386
35387                 return new ExtrudeGeometry( geometryShapes, data.options );
35388
35389         }
35390
35391 }
35392
35393 const WorldUVGenerator = {
35394
35395         generateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) {
35396
35397                 const a_x = vertices[ indexA * 3 ];
35398                 const a_y = vertices[ indexA * 3 + 1 ];
35399                 const b_x = vertices[ indexB * 3 ];
35400                 const b_y = vertices[ indexB * 3 + 1 ];
35401                 const c_x = vertices[ indexC * 3 ];
35402                 const c_y = vertices[ indexC * 3 + 1 ];
35403
35404                 return [
35405                         new Vector2( a_x, a_y ),
35406                         new Vector2( b_x, b_y ),
35407                         new Vector2( c_x, c_y )
35408                 ];
35409
35410         },
35411
35412         generateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) {
35413
35414                 const a_x = vertices[ indexA * 3 ];
35415                 const a_y = vertices[ indexA * 3 + 1 ];
35416                 const a_z = vertices[ indexA * 3 + 2 ];
35417                 const b_x = vertices[ indexB * 3 ];
35418                 const b_y = vertices[ indexB * 3 + 1 ];
35419                 const b_z = vertices[ indexB * 3 + 2 ];
35420                 const c_x = vertices[ indexC * 3 ];
35421                 const c_y = vertices[ indexC * 3 + 1 ];
35422                 const c_z = vertices[ indexC * 3 + 2 ];
35423                 const d_x = vertices[ indexD * 3 ];
35424                 const d_y = vertices[ indexD * 3 + 1 ];
35425                 const d_z = vertices[ indexD * 3 + 2 ];
35426
35427                 if ( Math.abs( a_y - b_y ) < Math.abs( a_x - b_x ) ) {
35428
35429                         return [
35430                                 new Vector2( a_x, 1 - a_z ),
35431                                 new Vector2( b_x, 1 - b_z ),
35432                                 new Vector2( c_x, 1 - c_z ),
35433                                 new Vector2( d_x, 1 - d_z )
35434                         ];
35435
35436                 } else {
35437
35438                         return [
35439                                 new Vector2( a_y, 1 - a_z ),
35440                                 new Vector2( b_y, 1 - b_z ),
35441                                 new Vector2( c_y, 1 - c_z ),
35442                                 new Vector2( d_y, 1 - d_z )
35443                         ];
35444
35445                 }
35446
35447         }
35448
35449 };
35450
35451 function toJSON$1( shapes, options, data ) {
35452
35453         data.shapes = [];
35454
35455         if ( Array.isArray( shapes ) ) {
35456
35457                 for ( let i = 0, l = shapes.length; i < l; i ++ ) {
35458
35459                         const shape = shapes[ i ];
35460
35461                         data.shapes.push( shape.uuid );
35462
35463                 }
35464
35465         } else {
35466
35467                 data.shapes.push( shapes.uuid );
35468
35469         }
35470
35471         if ( options.extrudePath !== undefined ) data.options.extrudePath = options.extrudePath.toJSON();
35472
35473         return data;
35474
35475 }
35476
35477 class ShapeGeometry extends BufferGeometry {
35478
35479         constructor( shapes = new Shape( [ new Vector2( 0, 0.5 ), new Vector2( - 0.5, - 0.5 ), new Vector2( 0.5, - 0.5 ) ] ), curveSegments = 12 ) {
35480
35481                 super();
35482                 this.type = 'ShapeGeometry';
35483
35484                 this.parameters = {
35485                         shapes: shapes,
35486                         curveSegments: curveSegments
35487                 };
35488
35489                 // buffers
35490
35491                 const indices = [];
35492                 const vertices = [];
35493                 const normals = [];
35494                 const uvs = [];
35495
35496                 // helper variables
35497
35498                 let groupStart = 0;
35499                 let groupCount = 0;
35500
35501                 // allow single and array values for "shapes" parameter
35502
35503                 if ( Array.isArray( shapes ) === false ) {
35504
35505                         addShape( shapes );
35506
35507                 } else {
35508
35509                         for ( let i = 0; i < shapes.length; i ++ ) {
35510
35511                                 addShape( shapes[ i ] );
35512
35513                                 this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support
35514
35515                                 groupStart += groupCount;
35516                                 groupCount = 0;
35517
35518                         }
35519
35520                 }
35521
35522                 // build geometry
35523
35524                 this.setIndex( indices );
35525                 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
35526                 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
35527                 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
35528
35529
35530                 // helper functions
35531
35532                 function addShape( shape ) {
35533
35534                         const indexOffset = vertices.length / 3;
35535                         const points = shape.extractPoints( curveSegments );
35536
35537                         let shapeVertices = points.shape;
35538                         const shapeHoles = points.holes;
35539
35540                         // check direction of vertices
35541
35542                         if ( ShapeUtils.isClockWise( shapeVertices ) === false ) {
35543
35544                                 shapeVertices = shapeVertices.reverse();
35545
35546                         }
35547
35548                         for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) {
35549
35550                                 const shapeHole = shapeHoles[ i ];
35551
35552                                 if ( ShapeUtils.isClockWise( shapeHole ) === true ) {
35553
35554                                         shapeHoles[ i ] = shapeHole.reverse();
35555
35556                                 }
35557
35558                         }
35559
35560                         const faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles );
35561
35562                         // join vertices of inner and outer paths to a single array
35563
35564                         for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) {
35565
35566                                 const shapeHole = shapeHoles[ i ];
35567                                 shapeVertices = shapeVertices.concat( shapeHole );
35568
35569                         }
35570
35571                         // vertices, normals, uvs
35572
35573                         for ( let i = 0, l = shapeVertices.length; i < l; i ++ ) {
35574
35575                                 const vertex = shapeVertices[ i ];
35576
35577                                 vertices.push( vertex.x, vertex.y, 0 );
35578                                 normals.push( 0, 0, 1 );
35579                                 uvs.push( vertex.x, vertex.y ); // world uvs
35580
35581                         }
35582
35583                         // incides
35584
35585                         for ( let i = 0, l = faces.length; i < l; i ++ ) {
35586
35587                                 const face = faces[ i ];
35588
35589                                 const a = face[ 0 ] + indexOffset;
35590                                 const b = face[ 1 ] + indexOffset;
35591                                 const c = face[ 2 ] + indexOffset;
35592
35593                                 indices.push( a, b, c );
35594                                 groupCount += 3;
35595
35596                         }
35597
35598                 }
35599
35600         }
35601
35602         toJSON() {
35603
35604                 const data = super.toJSON();
35605
35606                 const shapes = this.parameters.shapes;
35607
35608                 return toJSON( shapes, data );
35609
35610         }
35611
35612         static fromJSON( data, shapes ) {
35613
35614                 const geometryShapes = [];
35615
35616                 for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) {
35617
35618                         const shape = shapes[ data.shapes[ j ] ];
35619
35620                         geometryShapes.push( shape );
35621
35622                 }
35623
35624                 return new ShapeGeometry( geometryShapes, data.curveSegments );
35625
35626         }
35627
35628 }
35629
35630 function toJSON( shapes, data ) {
35631
35632         data.shapes = [];
35633
35634         if ( Array.isArray( shapes ) ) {
35635
35636                 for ( let i = 0, l = shapes.length; i < l; i ++ ) {
35637
35638                         const shape = shapes[ i ];
35639
35640                         data.shapes.push( shape.uuid );
35641
35642                 }
35643
35644         } else {
35645
35646                 data.shapes.push( shapes.uuid );
35647
35648         }
35649
35650         return data;
35651
35652 }
35653
35654 class SphereGeometry extends BufferGeometry {
35655
35656         constructor( radius = 1, widthSegments = 32, heightSegments = 16, phiStart = 0, phiLength = Math.PI * 2, thetaStart = 0, thetaLength = Math.PI ) {
35657
35658                 super();
35659                 this.type = 'SphereGeometry';
35660
35661                 this.parameters = {
35662                         radius: radius,
35663                         widthSegments: widthSegments,
35664                         heightSegments: heightSegments,
35665                         phiStart: phiStart,
35666                         phiLength: phiLength,
35667                         thetaStart: thetaStart,
35668                         thetaLength: thetaLength
35669                 };
35670
35671                 widthSegments = Math.max( 3, Math.floor( widthSegments ) );
35672                 heightSegments = Math.max( 2, Math.floor( heightSegments ) );
35673
35674                 const thetaEnd = Math.min( thetaStart + thetaLength, Math.PI );
35675
35676                 let index = 0;
35677                 const grid = [];
35678
35679                 const vertex = new Vector3();
35680                 const normal = new Vector3();
35681
35682                 // buffers
35683
35684                 const indices = [];
35685                 const vertices = [];
35686                 const normals = [];
35687                 const uvs = [];
35688
35689                 // generate vertices, normals and uvs
35690
35691                 for ( let iy = 0; iy <= heightSegments; iy ++ ) {
35692
35693                         const verticesRow = [];
35694
35695                         const v = iy / heightSegments;
35696
35697                         // special case for the poles
35698
35699                         let uOffset = 0;
35700
35701                         if ( iy == 0 && thetaStart == 0 ) {
35702
35703                                 uOffset = 0.5 / widthSegments;
35704
35705                         } else if ( iy == heightSegments && thetaEnd == Math.PI ) {
35706
35707                                 uOffset = - 0.5 / widthSegments;
35708
35709                         }
35710
35711                         for ( let ix = 0; ix <= widthSegments; ix ++ ) {
35712
35713                                 const u = ix / widthSegments;
35714
35715                                 // vertex
35716
35717                                 vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
35718                                 vertex.y = radius * Math.cos( thetaStart + v * thetaLength );
35719                                 vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
35720
35721                                 vertices.push( vertex.x, vertex.y, vertex.z );
35722
35723                                 // normal
35724
35725                                 normal.copy( vertex ).normalize();
35726                                 normals.push( normal.x, normal.y, normal.z );
35727
35728                                 // uv
35729
35730                                 uvs.push( u + uOffset, 1 - v );
35731
35732                                 verticesRow.push( index ++ );
35733
35734                         }
35735
35736                         grid.push( verticesRow );
35737
35738                 }
35739
35740                 // indices
35741
35742                 for ( let iy = 0; iy < heightSegments; iy ++ ) {
35743
35744                         for ( let ix = 0; ix < widthSegments; ix ++ ) {
35745
35746                                 const a = grid[ iy ][ ix + 1 ];
35747                                 const b = grid[ iy ][ ix ];
35748                                 const c = grid[ iy + 1 ][ ix ];
35749                                 const d = grid[ iy + 1 ][ ix + 1 ];
35750
35751                                 if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d );
35752                                 if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d );
35753
35754                         }
35755
35756                 }
35757
35758                 // build geometry
35759
35760                 this.setIndex( indices );
35761                 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
35762                 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
35763                 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
35764
35765         }
35766
35767         static fromJSON( data ) {
35768
35769                 return new SphereGeometry( data.radius, data.widthSegments, data.heightSegments, data.phiStart, data.phiLength, data.thetaStart, data.thetaLength );
35770
35771         }
35772
35773 }
35774
35775 /**
35776  * parameters = {
35777  *  color: <THREE.Color>
35778  * }
35779  */
35780
35781 class ShadowMaterial extends Material {
35782
35783         constructor( parameters ) {
35784
35785                 super();
35786
35787                 this.type = 'ShadowMaterial';
35788
35789                 this.color = new Color( 0x000000 );
35790                 this.transparent = true;
35791
35792                 this.setValues( parameters );
35793
35794         }
35795
35796         copy( source ) {
35797
35798                 super.copy( source );
35799
35800                 this.color.copy( source.color );
35801
35802                 return this;
35803
35804         }
35805
35806 }
35807
35808 ShadowMaterial.prototype.isShadowMaterial = true;
35809
35810 /**
35811  * parameters = {
35812  *  color: <hex>,
35813  *  roughness: <float>,
35814  *  metalness: <float>,
35815  *  opacity: <float>,
35816  *
35817  *  map: new THREE.Texture( <Image> ),
35818  *
35819  *  lightMap: new THREE.Texture( <Image> ),
35820  *  lightMapIntensity: <float>
35821  *
35822  *  aoMap: new THREE.Texture( <Image> ),
35823  *  aoMapIntensity: <float>
35824  *
35825  *  emissive: <hex>,
35826  *  emissiveIntensity: <float>
35827  *  emissiveMap: new THREE.Texture( <Image> ),
35828  *
35829  *  bumpMap: new THREE.Texture( <Image> ),
35830  *  bumpScale: <float>,
35831  *
35832  *  normalMap: new THREE.Texture( <Image> ),
35833  *  normalMapType: THREE.TangentSpaceNormalMap,
35834  *  normalScale: <Vector2>,
35835  *
35836  *  displacementMap: new THREE.Texture( <Image> ),
35837  *  displacementScale: <float>,
35838  *  displacementBias: <float>,
35839  *
35840  *  roughnessMap: new THREE.Texture( <Image> ),
35841  *
35842  *  metalnessMap: new THREE.Texture( <Image> ),
35843  *
35844  *  alphaMap: new THREE.Texture( <Image> ),
35845  *
35846  *  envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
35847  *  envMapIntensity: <float>
35848  *
35849  *  refractionRatio: <float>,
35850  *
35851  *  wireframe: <boolean>,
35852  *  wireframeLinewidth: <float>,
35853  *
35854  *  flatShading: <bool>
35855  * }
35856  */
35857
35858 class MeshStandardMaterial extends Material {
35859
35860         constructor( parameters ) {
35861
35862                 super();
35863
35864                 this.defines = { 'STANDARD': '' };
35865
35866                 this.type = 'MeshStandardMaterial';
35867
35868                 this.color = new Color( 0xffffff ); // diffuse
35869                 this.roughness = 1.0;
35870                 this.metalness = 0.0;
35871
35872                 this.map = null;
35873
35874                 this.lightMap = null;
35875                 this.lightMapIntensity = 1.0;
35876
35877                 this.aoMap = null;
35878                 this.aoMapIntensity = 1.0;
35879
35880                 this.emissive = new Color( 0x000000 );
35881                 this.emissiveIntensity = 1.0;
35882                 this.emissiveMap = null;
35883
35884                 this.bumpMap = null;
35885                 this.bumpScale = 1;
35886
35887                 this.normalMap = null;
35888                 this.normalMapType = TangentSpaceNormalMap;
35889                 this.normalScale = new Vector2( 1, 1 );
35890
35891                 this.displacementMap = null;
35892                 this.displacementScale = 1;
35893                 this.displacementBias = 0;
35894
35895                 this.roughnessMap = null;
35896
35897                 this.metalnessMap = null;
35898
35899                 this.alphaMap = null;
35900
35901                 this.envMap = null;
35902                 this.envMapIntensity = 1.0;
35903
35904                 this.refractionRatio = 0.98;
35905
35906                 this.wireframe = false;
35907                 this.wireframeLinewidth = 1;
35908                 this.wireframeLinecap = 'round';
35909                 this.wireframeLinejoin = 'round';
35910
35911                 this.flatShading = false;
35912
35913                 this.setValues( parameters );
35914
35915         }
35916
35917         copy( source ) {
35918
35919                 super.copy( source );
35920
35921                 this.defines = { 'STANDARD': '' };
35922
35923                 this.color.copy( source.color );
35924                 this.roughness = source.roughness;
35925                 this.metalness = source.metalness;
35926
35927                 this.map = source.map;
35928
35929                 this.lightMap = source.lightMap;
35930                 this.lightMapIntensity = source.lightMapIntensity;
35931
35932                 this.aoMap = source.aoMap;
35933                 this.aoMapIntensity = source.aoMapIntensity;
35934
35935                 this.emissive.copy( source.emissive );
35936                 this.emissiveMap = source.emissiveMap;
35937                 this.emissiveIntensity = source.emissiveIntensity;
35938
35939                 this.bumpMap = source.bumpMap;
35940                 this.bumpScale = source.bumpScale;
35941
35942                 this.normalMap = source.normalMap;
35943                 this.normalMapType = source.normalMapType;
35944                 this.normalScale.copy( source.normalScale );
35945
35946                 this.displacementMap = source.displacementMap;
35947                 this.displacementScale = source.displacementScale;
35948                 this.displacementBias = source.displacementBias;
35949
35950                 this.roughnessMap = source.roughnessMap;
35951
35952                 this.metalnessMap = source.metalnessMap;
35953
35954                 this.alphaMap = source.alphaMap;
35955
35956                 this.envMap = source.envMap;
35957                 this.envMapIntensity = source.envMapIntensity;
35958
35959                 this.refractionRatio = source.refractionRatio;
35960
35961                 this.wireframe = source.wireframe;
35962                 this.wireframeLinewidth = source.wireframeLinewidth;
35963                 this.wireframeLinecap = source.wireframeLinecap;
35964                 this.wireframeLinejoin = source.wireframeLinejoin;
35965
35966                 this.flatShading = source.flatShading;
35967
35968                 return this;
35969
35970         }
35971
35972 }
35973
35974 MeshStandardMaterial.prototype.isMeshStandardMaterial = true;
35975
35976 /**
35977  * parameters = {
35978  *  clearcoat: <float>,
35979  *  clearcoatMap: new THREE.Texture( <Image> ),
35980  *  clearcoatRoughness: <float>,
35981  *  clearcoatRoughnessMap: new THREE.Texture( <Image> ),
35982  *  clearcoatNormalScale: <Vector2>,
35983  *  clearcoatNormalMap: new THREE.Texture( <Image> ),
35984  *
35985  *  ior: <float>,
35986  *  reflectivity: <float>,
35987  *
35988  *  sheen: <float>,
35989  *  sheenColor: <Color>,
35990  *  sheenColorMap: new THREE.Texture( <Image> ),
35991  *  sheenRoughness: <float>,
35992  *  sheenRoughnessMap: new THREE.Texture( <Image> ),
35993  *
35994  *  transmission: <float>,
35995  *  transmissionMap: new THREE.Texture( <Image> ),
35996  *
35997  *  thickness: <float>,
35998  *  thicknessMap: new THREE.Texture( <Image> ),
35999  *  attenuationDistance: <float>,
36000  *  attenuationColor: <Color>,
36001  *
36002  *  specularIntensity: <float>,
36003  *  specularIntensityMap: new THREE.Texture( <Image> ),
36004  *  specularColor: <Color>,
36005  *  specularColorMap: new THREE.Texture( <Image> )
36006  * }
36007  */
36008
36009 class MeshPhysicalMaterial extends MeshStandardMaterial {
36010
36011         constructor( parameters ) {
36012
36013                 super();
36014
36015                 this.defines = {
36016
36017                         'STANDARD': '',
36018                         'PHYSICAL': ''
36019
36020                 };
36021
36022                 this.type = 'MeshPhysicalMaterial';
36023
36024                 this.clearcoatMap = null;
36025                 this.clearcoatRoughness = 0.0;
36026                 this.clearcoatRoughnessMap = null;
36027                 this.clearcoatNormalScale = new Vector2( 1, 1 );
36028                 this.clearcoatNormalMap = null;
36029
36030                 this.ior = 1.5;
36031
36032                 Object.defineProperty( this, 'reflectivity', {
36033                         get: function () {
36034
36035                                 return ( clamp$1( 2.5 * ( this.ior - 1 ) / ( this.ior + 1 ), 0, 1 ) );
36036
36037                         },
36038                         set: function ( reflectivity ) {
36039
36040                                 this.ior = ( 1 + 0.4 * reflectivity ) / ( 1 - 0.4 * reflectivity );
36041
36042                         }
36043                 } );
36044
36045                 this.sheenColor = new Color( 0x000000 );
36046                 this.sheenColorMap = null;
36047                 this.sheenRoughness = 1.0;
36048                 this.sheenRoughnessMap = null;
36049
36050                 this.transmissionMap = null;
36051
36052                 this.thickness = 0.01;
36053                 this.thicknessMap = null;
36054                 this.attenuationDistance = 0.0;
36055                 this.attenuationColor = new Color( 1, 1, 1 );
36056
36057                 this.specularIntensity = 1.0;
36058                 this.specularIntensityMap = null;
36059                 this.specularColor = new Color( 1, 1, 1 );
36060                 this.specularColorMap = null;
36061
36062                 this._sheen = 0.0;
36063                 this._clearcoat = 0;
36064                 this._transmission = 0;
36065
36066                 this.setValues( parameters );
36067
36068         }
36069
36070         get sheen() {
36071
36072                 return this._sheen;
36073
36074         }
36075
36076         set sheen( value ) {
36077
36078                 if ( this._sheen > 0 !== value > 0 ) {
36079
36080                         this.version ++;
36081
36082                 }
36083
36084                 this._sheen = value;
36085
36086         }
36087
36088         get clearcoat() {
36089
36090                 return this._clearcoat;
36091
36092         }
36093
36094         set clearcoat( value ) {
36095
36096                 if ( this._clearcoat > 0 !== value > 0 ) {
36097
36098                         this.version ++;
36099
36100                 }
36101
36102                 this._clearcoat = value;
36103
36104         }
36105
36106         get transmission() {
36107
36108                 return this._transmission;
36109
36110         }
36111
36112         set transmission( value ) {
36113
36114                 if ( this._transmission > 0 !== value > 0 ) {
36115
36116                         this.version ++;
36117
36118                 }
36119
36120                 this._transmission = value;
36121
36122         }
36123
36124         copy( source ) {
36125
36126                 super.copy( source );
36127
36128                 this.defines = {
36129
36130                         'STANDARD': '',
36131                         'PHYSICAL': ''
36132
36133                 };
36134
36135                 this.clearcoat = source.clearcoat;
36136                 this.clearcoatMap = source.clearcoatMap;
36137                 this.clearcoatRoughness = source.clearcoatRoughness;
36138                 this.clearcoatRoughnessMap = source.clearcoatRoughnessMap;
36139                 this.clearcoatNormalMap = source.clearcoatNormalMap;
36140                 this.clearcoatNormalScale.copy( source.clearcoatNormalScale );
36141
36142                 this.ior = source.ior;
36143
36144                 this.sheen = source.sheen;
36145                 this.sheenColor.copy( source.sheenColor );
36146                 this.sheenColorMap = source.sheenColorMap;
36147                 this.sheenRoughness = source.sheenRoughness;
36148                 this.sheenRoughnessMap = source.sheenRoughnessMap;
36149
36150                 this.transmission = source.transmission;
36151                 this.transmissionMap = source.transmissionMap;
36152
36153                 this.thickness = source.thickness;
36154                 this.thicknessMap = source.thicknessMap;
36155                 this.attenuationDistance = source.attenuationDistance;
36156                 this.attenuationColor.copy( source.attenuationColor );
36157
36158                 this.specularIntensity = source.specularIntensity;
36159                 this.specularIntensityMap = source.specularIntensityMap;
36160                 this.specularColor.copy( source.specularColor );
36161                 this.specularColorMap = source.specularColorMap;
36162
36163                 return this;
36164
36165         }
36166
36167 }
36168
36169 MeshPhysicalMaterial.prototype.isMeshPhysicalMaterial = true;
36170
36171 /**
36172  * parameters = {
36173  *  color: <hex>,
36174  *  specular: <hex>,
36175  *  shininess: <float>,
36176  *  opacity: <float>,
36177  *
36178  *  map: new THREE.Texture( <Image> ),
36179  *
36180  *  lightMap: new THREE.Texture( <Image> ),
36181  *  lightMapIntensity: <float>
36182  *
36183  *  aoMap: new THREE.Texture( <Image> ),
36184  *  aoMapIntensity: <float>
36185  *
36186  *  emissive: <hex>,
36187  *  emissiveIntensity: <float>
36188  *  emissiveMap: new THREE.Texture( <Image> ),
36189  *
36190  *  bumpMap: new THREE.Texture( <Image> ),
36191  *  bumpScale: <float>,
36192  *
36193  *  normalMap: new THREE.Texture( <Image> ),
36194  *  normalMapType: THREE.TangentSpaceNormalMap,
36195  *  normalScale: <Vector2>,
36196  *
36197  *  displacementMap: new THREE.Texture( <Image> ),
36198  *  displacementScale: <float>,
36199  *  displacementBias: <float>,
36200  *
36201  *  specularMap: new THREE.Texture( <Image> ),
36202  *
36203  *  alphaMap: new THREE.Texture( <Image> ),
36204  *
36205  *  envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
36206  *  combine: THREE.MultiplyOperation,
36207  *  reflectivity: <float>,
36208  *  refractionRatio: <float>,
36209  *
36210  *  wireframe: <boolean>,
36211  *  wireframeLinewidth: <float>,
36212  *
36213  *  flatShading: <bool>
36214  * }
36215  */
36216
36217 class MeshPhongMaterial extends Material {
36218
36219         constructor( parameters ) {
36220
36221                 super();
36222
36223                 this.type = 'MeshPhongMaterial';
36224
36225                 this.color = new Color( 0xffffff ); // diffuse
36226                 this.specular = new Color( 0x111111 );
36227                 this.shininess = 30;
36228
36229                 this.map = null;
36230
36231                 this.lightMap = null;
36232                 this.lightMapIntensity = 1.0;
36233
36234                 this.aoMap = null;
36235                 this.aoMapIntensity = 1.0;
36236
36237                 this.emissive = new Color( 0x000000 );
36238                 this.emissiveIntensity = 1.0;
36239                 this.emissiveMap = null;
36240
36241                 this.bumpMap = null;
36242                 this.bumpScale = 1;
36243
36244                 this.normalMap = null;
36245                 this.normalMapType = TangentSpaceNormalMap;
36246                 this.normalScale = new Vector2( 1, 1 );
36247
36248                 this.displacementMap = null;
36249                 this.displacementScale = 1;
36250                 this.displacementBias = 0;
36251
36252                 this.specularMap = null;
36253
36254                 this.alphaMap = null;
36255
36256                 this.envMap = null;
36257                 this.combine = MultiplyOperation;
36258                 this.reflectivity = 1;
36259                 this.refractionRatio = 0.98;
36260
36261                 this.wireframe = false;
36262                 this.wireframeLinewidth = 1;
36263                 this.wireframeLinecap = 'round';
36264                 this.wireframeLinejoin = 'round';
36265
36266                 this.flatShading = false;
36267
36268                 this.setValues( parameters );
36269
36270         }
36271
36272         copy( source ) {
36273
36274                 super.copy( source );
36275
36276                 this.color.copy( source.color );
36277                 this.specular.copy( source.specular );
36278                 this.shininess = source.shininess;
36279
36280                 this.map = source.map;
36281
36282                 this.lightMap = source.lightMap;
36283                 this.lightMapIntensity = source.lightMapIntensity;
36284
36285                 this.aoMap = source.aoMap;
36286                 this.aoMapIntensity = source.aoMapIntensity;
36287
36288                 this.emissive.copy( source.emissive );
36289                 this.emissiveMap = source.emissiveMap;
36290                 this.emissiveIntensity = source.emissiveIntensity;
36291
36292                 this.bumpMap = source.bumpMap;
36293                 this.bumpScale = source.bumpScale;
36294
36295                 this.normalMap = source.normalMap;
36296                 this.normalMapType = source.normalMapType;
36297                 this.normalScale.copy( source.normalScale );
36298
36299                 this.displacementMap = source.displacementMap;
36300                 this.displacementScale = source.displacementScale;
36301                 this.displacementBias = source.displacementBias;
36302
36303                 this.specularMap = source.specularMap;
36304
36305                 this.alphaMap = source.alphaMap;
36306
36307                 this.envMap = source.envMap;
36308                 this.combine = source.combine;
36309                 this.reflectivity = source.reflectivity;
36310                 this.refractionRatio = source.refractionRatio;
36311
36312                 this.wireframe = source.wireframe;
36313                 this.wireframeLinewidth = source.wireframeLinewidth;
36314                 this.wireframeLinecap = source.wireframeLinecap;
36315                 this.wireframeLinejoin = source.wireframeLinejoin;
36316
36317                 this.flatShading = source.flatShading;
36318
36319                 return this;
36320
36321         }
36322
36323 }
36324
36325 MeshPhongMaterial.prototype.isMeshPhongMaterial = true;
36326
36327 /**
36328  * parameters = {
36329  *  color: <hex>,
36330  *
36331  *  map: new THREE.Texture( <Image> ),
36332  *  gradientMap: new THREE.Texture( <Image> ),
36333  *
36334  *  lightMap: new THREE.Texture( <Image> ),
36335  *  lightMapIntensity: <float>
36336  *
36337  *  aoMap: new THREE.Texture( <Image> ),
36338  *  aoMapIntensity: <float>
36339  *
36340  *  emissive: <hex>,
36341  *  emissiveIntensity: <float>
36342  *  emissiveMap: new THREE.Texture( <Image> ),
36343  *
36344  *  bumpMap: new THREE.Texture( <Image> ),
36345  *  bumpScale: <float>,
36346  *
36347  *  normalMap: new THREE.Texture( <Image> ),
36348  *  normalMapType: THREE.TangentSpaceNormalMap,
36349  *  normalScale: <Vector2>,
36350  *
36351  *  displacementMap: new THREE.Texture( <Image> ),
36352  *  displacementScale: <float>,
36353  *  displacementBias: <float>,
36354  *
36355  *  alphaMap: new THREE.Texture( <Image> ),
36356  *
36357  *  wireframe: <boolean>,
36358  *  wireframeLinewidth: <float>,
36359  *
36360  * }
36361  */
36362
36363 class MeshToonMaterial extends Material {
36364
36365         constructor( parameters ) {
36366
36367                 super();
36368
36369                 this.defines = { 'TOON': '' };
36370
36371                 this.type = 'MeshToonMaterial';
36372
36373                 this.color = new Color( 0xffffff );
36374
36375                 this.map = null;
36376                 this.gradientMap = null;
36377
36378                 this.lightMap = null;
36379                 this.lightMapIntensity = 1.0;
36380
36381                 this.aoMap = null;
36382                 this.aoMapIntensity = 1.0;
36383
36384                 this.emissive = new Color( 0x000000 );
36385                 this.emissiveIntensity = 1.0;
36386                 this.emissiveMap = null;
36387
36388                 this.bumpMap = null;
36389                 this.bumpScale = 1;
36390
36391                 this.normalMap = null;
36392                 this.normalMapType = TangentSpaceNormalMap;
36393                 this.normalScale = new Vector2( 1, 1 );
36394
36395                 this.displacementMap = null;
36396                 this.displacementScale = 1;
36397                 this.displacementBias = 0;
36398
36399                 this.alphaMap = null;
36400
36401                 this.wireframe = false;
36402                 this.wireframeLinewidth = 1;
36403                 this.wireframeLinecap = 'round';
36404                 this.wireframeLinejoin = 'round';
36405
36406                 this.setValues( parameters );
36407
36408         }
36409
36410         copy( source ) {
36411
36412                 super.copy( source );
36413
36414                 this.color.copy( source.color );
36415
36416                 this.map = source.map;
36417                 this.gradientMap = source.gradientMap;
36418
36419                 this.lightMap = source.lightMap;
36420                 this.lightMapIntensity = source.lightMapIntensity;
36421
36422                 this.aoMap = source.aoMap;
36423                 this.aoMapIntensity = source.aoMapIntensity;
36424
36425                 this.emissive.copy( source.emissive );
36426                 this.emissiveMap = source.emissiveMap;
36427                 this.emissiveIntensity = source.emissiveIntensity;
36428
36429                 this.bumpMap = source.bumpMap;
36430                 this.bumpScale = source.bumpScale;
36431
36432                 this.normalMap = source.normalMap;
36433                 this.normalMapType = source.normalMapType;
36434                 this.normalScale.copy( source.normalScale );
36435
36436                 this.displacementMap = source.displacementMap;
36437                 this.displacementScale = source.displacementScale;
36438                 this.displacementBias = source.displacementBias;
36439
36440                 this.alphaMap = source.alphaMap;
36441
36442                 this.wireframe = source.wireframe;
36443                 this.wireframeLinewidth = source.wireframeLinewidth;
36444                 this.wireframeLinecap = source.wireframeLinecap;
36445                 this.wireframeLinejoin = source.wireframeLinejoin;
36446
36447                 return this;
36448
36449         }
36450
36451 }
36452
36453 MeshToonMaterial.prototype.isMeshToonMaterial = true;
36454
36455 /**
36456  * parameters = {
36457  *  opacity: <float>,
36458  *
36459  *  bumpMap: new THREE.Texture( <Image> ),
36460  *  bumpScale: <float>,
36461  *
36462  *  normalMap: new THREE.Texture( <Image> ),
36463  *  normalMapType: THREE.TangentSpaceNormalMap,
36464  *  normalScale: <Vector2>,
36465  *
36466  *  displacementMap: new THREE.Texture( <Image> ),
36467  *  displacementScale: <float>,
36468  *  displacementBias: <float>,
36469  *
36470  *  wireframe: <boolean>,
36471  *  wireframeLinewidth: <float>
36472  *
36473  *  flatShading: <bool>
36474  * }
36475  */
36476
36477 class MeshNormalMaterial extends Material {
36478
36479         constructor( parameters ) {
36480
36481                 super();
36482
36483                 this.type = 'MeshNormalMaterial';
36484
36485                 this.bumpMap = null;
36486                 this.bumpScale = 1;
36487
36488                 this.normalMap = null;
36489                 this.normalMapType = TangentSpaceNormalMap;
36490                 this.normalScale = new Vector2( 1, 1 );
36491
36492                 this.displacementMap = null;
36493                 this.displacementScale = 1;
36494                 this.displacementBias = 0;
36495
36496                 this.wireframe = false;
36497                 this.wireframeLinewidth = 1;
36498
36499                 this.fog = false;
36500
36501                 this.flatShading = false;
36502
36503                 this.setValues( parameters );
36504
36505         }
36506
36507         copy( source ) {
36508
36509                 super.copy( source );
36510
36511                 this.bumpMap = source.bumpMap;
36512                 this.bumpScale = source.bumpScale;
36513
36514                 this.normalMap = source.normalMap;
36515                 this.normalMapType = source.normalMapType;
36516                 this.normalScale.copy( source.normalScale );
36517
36518                 this.displacementMap = source.displacementMap;
36519                 this.displacementScale = source.displacementScale;
36520                 this.displacementBias = source.displacementBias;
36521
36522                 this.wireframe = source.wireframe;
36523                 this.wireframeLinewidth = source.wireframeLinewidth;
36524
36525                 this.flatShading = source.flatShading;
36526
36527                 return this;
36528
36529         }
36530
36531 }
36532
36533 MeshNormalMaterial.prototype.isMeshNormalMaterial = true;
36534
36535 /**
36536  * parameters = {
36537  *  color: <hex>,
36538  *  opacity: <float>,
36539  *
36540  *  map: new THREE.Texture( <Image> ),
36541  *
36542  *  lightMap: new THREE.Texture( <Image> ),
36543  *  lightMapIntensity: <float>
36544  *
36545  *  aoMap: new THREE.Texture( <Image> ),
36546  *  aoMapIntensity: <float>
36547  *
36548  *  emissive: <hex>,
36549  *  emissiveIntensity: <float>
36550  *  emissiveMap: new THREE.Texture( <Image> ),
36551  *
36552  *  specularMap: new THREE.Texture( <Image> ),
36553  *
36554  *  alphaMap: new THREE.Texture( <Image> ),
36555  *
36556  *  envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
36557  *  combine: THREE.Multiply,
36558  *  reflectivity: <float>,
36559  *  refractionRatio: <float>,
36560  *
36561  *  wireframe: <boolean>,
36562  *  wireframeLinewidth: <float>,
36563  *
36564  * }
36565  */
36566
36567 class MeshLambertMaterial extends Material {
36568
36569         constructor( parameters ) {
36570
36571                 super();
36572
36573                 this.type = 'MeshLambertMaterial';
36574
36575                 this.color = new Color( 0xffffff ); // diffuse
36576
36577                 this.map = null;
36578
36579                 this.lightMap = null;
36580                 this.lightMapIntensity = 1.0;
36581
36582                 this.aoMap = null;
36583                 this.aoMapIntensity = 1.0;
36584
36585                 this.emissive = new Color( 0x000000 );
36586                 this.emissiveIntensity = 1.0;
36587                 this.emissiveMap = null;
36588
36589                 this.specularMap = null;
36590
36591                 this.alphaMap = null;
36592
36593                 this.envMap = null;
36594                 this.combine = MultiplyOperation;
36595                 this.reflectivity = 1;
36596                 this.refractionRatio = 0.98;
36597
36598                 this.wireframe = false;
36599                 this.wireframeLinewidth = 1;
36600                 this.wireframeLinecap = 'round';
36601                 this.wireframeLinejoin = 'round';
36602
36603                 this.setValues( parameters );
36604
36605         }
36606
36607         copy( source ) {
36608
36609                 super.copy( source );
36610
36611                 this.color.copy( source.color );
36612
36613                 this.map = source.map;
36614
36615                 this.lightMap = source.lightMap;
36616                 this.lightMapIntensity = source.lightMapIntensity;
36617
36618                 this.aoMap = source.aoMap;
36619                 this.aoMapIntensity = source.aoMapIntensity;
36620
36621                 this.emissive.copy( source.emissive );
36622                 this.emissiveMap = source.emissiveMap;
36623                 this.emissiveIntensity = source.emissiveIntensity;
36624
36625                 this.specularMap = source.specularMap;
36626
36627                 this.alphaMap = source.alphaMap;
36628
36629                 this.envMap = source.envMap;
36630                 this.combine = source.combine;
36631                 this.reflectivity = source.reflectivity;
36632                 this.refractionRatio = source.refractionRatio;
36633
36634                 this.wireframe = source.wireframe;
36635                 this.wireframeLinewidth = source.wireframeLinewidth;
36636                 this.wireframeLinecap = source.wireframeLinecap;
36637                 this.wireframeLinejoin = source.wireframeLinejoin;
36638
36639                 return this;
36640
36641         }
36642
36643 }
36644
36645 MeshLambertMaterial.prototype.isMeshLambertMaterial = true;
36646
36647 /**
36648  * parameters = {
36649  *  color: <hex>,
36650  *  opacity: <float>,
36651  *
36652  *  matcap: new THREE.Texture( <Image> ),
36653  *
36654  *  map: new THREE.Texture( <Image> ),
36655  *
36656  *  bumpMap: new THREE.Texture( <Image> ),
36657  *  bumpScale: <float>,
36658  *
36659  *  normalMap: new THREE.Texture( <Image> ),
36660  *  normalMapType: THREE.TangentSpaceNormalMap,
36661  *  normalScale: <Vector2>,
36662  *
36663  *  displacementMap: new THREE.Texture( <Image> ),
36664  *  displacementScale: <float>,
36665  *  displacementBias: <float>,
36666  *
36667  *  alphaMap: new THREE.Texture( <Image> ),
36668  *
36669  *  flatShading: <bool>
36670  * }
36671  */
36672
36673 class MeshMatcapMaterial extends Material {
36674
36675         constructor( parameters ) {
36676
36677                 super();
36678
36679                 this.defines = { 'MATCAP': '' };
36680
36681                 this.type = 'MeshMatcapMaterial';
36682
36683                 this.color = new Color( 0xffffff ); // diffuse
36684
36685                 this.matcap = null;
36686
36687                 this.map = null;
36688
36689                 this.bumpMap = null;
36690                 this.bumpScale = 1;
36691
36692                 this.normalMap = null;
36693                 this.normalMapType = TangentSpaceNormalMap;
36694                 this.normalScale = new Vector2( 1, 1 );
36695
36696                 this.displacementMap = null;
36697                 this.displacementScale = 1;
36698                 this.displacementBias = 0;
36699
36700                 this.alphaMap = null;
36701
36702                 this.flatShading = false;
36703
36704                 this.setValues( parameters );
36705
36706         }
36707
36708
36709         copy( source ) {
36710
36711                 super.copy( source );
36712
36713                 this.defines = { 'MATCAP': '' };
36714
36715                 this.color.copy( source.color );
36716
36717                 this.matcap = source.matcap;
36718
36719                 this.map = source.map;
36720
36721                 this.bumpMap = source.bumpMap;
36722                 this.bumpScale = source.bumpScale;
36723
36724                 this.normalMap = source.normalMap;
36725                 this.normalMapType = source.normalMapType;
36726                 this.normalScale.copy( source.normalScale );
36727
36728                 this.displacementMap = source.displacementMap;
36729                 this.displacementScale = source.displacementScale;
36730                 this.displacementBias = source.displacementBias;
36731
36732                 this.alphaMap = source.alphaMap;
36733
36734                 this.flatShading = source.flatShading;
36735
36736                 return this;
36737
36738         }
36739
36740 }
36741
36742 MeshMatcapMaterial.prototype.isMeshMatcapMaterial = true;
36743
36744 /**
36745  * parameters = {
36746  *  color: <hex>,
36747  *  opacity: <float>,
36748  *
36749  *  linewidth: <float>,
36750  *
36751  *  scale: <float>,
36752  *  dashSize: <float>,
36753  *  gapSize: <float>
36754  * }
36755  */
36756
36757 class LineDashedMaterial extends LineBasicMaterial {
36758
36759         constructor( parameters ) {
36760
36761                 super();
36762
36763                 this.type = 'LineDashedMaterial';
36764
36765                 this.scale = 1;
36766                 this.dashSize = 3;
36767                 this.gapSize = 1;
36768
36769                 this.setValues( parameters );
36770
36771         }
36772
36773         copy( source ) {
36774
36775                 super.copy( source );
36776
36777                 this.scale = source.scale;
36778                 this.dashSize = source.dashSize;
36779                 this.gapSize = source.gapSize;
36780
36781                 return this;
36782
36783         }
36784
36785 }
36786
36787 LineDashedMaterial.prototype.isLineDashedMaterial = true;
36788
36789 const AnimationUtils = {
36790
36791         // same as Array.prototype.slice, but also works on typed arrays
36792         arraySlice: function ( array, from, to ) {
36793
36794                 if ( AnimationUtils.isTypedArray( array ) ) {
36795
36796                         // in ios9 array.subarray(from, undefined) will return empty array
36797                         // but array.subarray(from) or array.subarray(from, len) is correct
36798                         return new array.constructor( array.subarray( from, to !== undefined ? to : array.length ) );
36799
36800                 }
36801
36802                 return array.slice( from, to );
36803
36804         },
36805
36806         // converts an array to a specific type
36807         convertArray: function ( array, type, forceClone ) {
36808
36809                 if ( ! array || // let 'undefined' and 'null' pass
36810                         ! forceClone && array.constructor === type ) return array;
36811
36812                 if ( typeof type.BYTES_PER_ELEMENT === 'number' ) {
36813
36814                         return new type( array ); // create typed array
36815
36816                 }
36817
36818                 return Array.prototype.slice.call( array ); // create Array
36819
36820         },
36821
36822         isTypedArray: function ( object ) {
36823
36824                 return ArrayBuffer.isView( object ) &&
36825                         ! ( object instanceof DataView );
36826
36827         },
36828
36829         // returns an array by which times and values can be sorted
36830         getKeyframeOrder: function ( times ) {
36831
36832                 function compareTime( i, j ) {
36833
36834                         return times[ i ] - times[ j ];
36835
36836                 }
36837
36838                 const n = times.length;
36839                 const result = new Array( n );
36840                 for ( let i = 0; i !== n; ++ i ) result[ i ] = i;
36841
36842                 result.sort( compareTime );
36843
36844                 return result;
36845
36846         },
36847
36848         // uses the array previously returned by 'getKeyframeOrder' to sort data
36849         sortedArray: function ( values, stride, order ) {
36850
36851                 const nValues = values.length;
36852                 const result = new values.constructor( nValues );
36853
36854                 for ( let i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) {
36855
36856                         const srcOffset = order[ i ] * stride;
36857
36858                         for ( let j = 0; j !== stride; ++ j ) {
36859
36860                                 result[ dstOffset ++ ] = values[ srcOffset + j ];
36861
36862                         }
36863
36864                 }
36865
36866                 return result;
36867
36868         },
36869
36870         // function for parsing AOS keyframe formats
36871         flattenJSON: function ( jsonKeys, times, values, valuePropertyName ) {
36872
36873                 let i = 1, key = jsonKeys[ 0 ];
36874
36875                 while ( key !== undefined && key[ valuePropertyName ] === undefined ) {
36876
36877                         key = jsonKeys[ i ++ ];
36878
36879                 }
36880
36881                 if ( key === undefined ) return; // no data
36882
36883                 let value = key[ valuePropertyName ];
36884                 if ( value === undefined ) return; // no data
36885
36886                 if ( Array.isArray( value ) ) {
36887
36888                         do {
36889
36890                                 value = key[ valuePropertyName ];
36891
36892                                 if ( value !== undefined ) {
36893
36894                                         times.push( key.time );
36895                                         values.push.apply( values, value ); // push all elements
36896
36897                                 }
36898
36899                                 key = jsonKeys[ i ++ ];
36900
36901                         } while ( key !== undefined );
36902
36903                 } else if ( value.toArray !== undefined ) {
36904
36905                         // ...assume THREE.Math-ish
36906
36907                         do {
36908
36909                                 value = key[ valuePropertyName ];
36910
36911                                 if ( value !== undefined ) {
36912
36913                                         times.push( key.time );
36914                                         value.toArray( values, values.length );
36915
36916                                 }
36917
36918                                 key = jsonKeys[ i ++ ];
36919
36920                         } while ( key !== undefined );
36921
36922                 } else {
36923
36924                         // otherwise push as-is
36925
36926                         do {
36927
36928                                 value = key[ valuePropertyName ];
36929
36930                                 if ( value !== undefined ) {
36931
36932                                         times.push( key.time );
36933                                         values.push( value );
36934
36935                                 }
36936
36937                                 key = jsonKeys[ i ++ ];
36938
36939                         } while ( key !== undefined );
36940
36941                 }
36942
36943         },
36944
36945         subclip: function ( sourceClip, name, startFrame, endFrame, fps = 30 ) {
36946
36947                 const clip = sourceClip.clone();
36948
36949                 clip.name = name;
36950
36951                 const tracks = [];
36952
36953                 for ( let i = 0; i < clip.tracks.length; ++ i ) {
36954
36955                         const track = clip.tracks[ i ];
36956                         const valueSize = track.getValueSize();
36957
36958                         const times = [];
36959                         const values = [];
36960
36961                         for ( let j = 0; j < track.times.length; ++ j ) {
36962
36963                                 const frame = track.times[ j ] * fps;
36964
36965                                 if ( frame < startFrame || frame >= endFrame ) continue;
36966
36967                                 times.push( track.times[ j ] );
36968
36969                                 for ( let k = 0; k < valueSize; ++ k ) {
36970
36971                                         values.push( track.values[ j * valueSize + k ] );
36972
36973                                 }
36974
36975                         }
36976
36977                         if ( times.length === 0 ) continue;
36978
36979                         track.times = AnimationUtils.convertArray( times, track.times.constructor );
36980                         track.values = AnimationUtils.convertArray( values, track.values.constructor );
36981
36982                         tracks.push( track );
36983
36984                 }
36985
36986                 clip.tracks = tracks;
36987
36988                 // find minimum .times value across all tracks in the trimmed clip
36989
36990                 let minStartTime = Infinity;
36991
36992                 for ( let i = 0; i < clip.tracks.length; ++ i ) {
36993
36994                         if ( minStartTime > clip.tracks[ i ].times[ 0 ] ) {
36995
36996                                 minStartTime = clip.tracks[ i ].times[ 0 ];
36997
36998                         }
36999
37000                 }
37001
37002                 // shift all tracks such that clip begins at t=0
37003
37004                 for ( let i = 0; i < clip.tracks.length; ++ i ) {
37005
37006                         clip.tracks[ i ].shift( - 1 * minStartTime );
37007
37008                 }
37009
37010                 clip.resetDuration();
37011
37012                 return clip;
37013
37014         },
37015
37016         makeClipAdditive: function ( targetClip, referenceFrame = 0, referenceClip = targetClip, fps = 30 ) {
37017
37018                 if ( fps <= 0 ) fps = 30;
37019
37020                 const numTracks = referenceClip.tracks.length;
37021                 const referenceTime = referenceFrame / fps;
37022
37023                 // Make each track's values relative to the values at the reference frame
37024                 for ( let i = 0; i < numTracks; ++ i ) {
37025
37026                         const referenceTrack = referenceClip.tracks[ i ];
37027                         const referenceTrackType = referenceTrack.ValueTypeName;
37028
37029                         // Skip this track if it's non-numeric
37030                         if ( referenceTrackType === 'bool' || referenceTrackType === 'string' ) continue;
37031
37032                         // Find the track in the target clip whose name and type matches the reference track
37033                         const targetTrack = targetClip.tracks.find( function ( track ) {
37034
37035                                 return track.name === referenceTrack.name
37036                                         && track.ValueTypeName === referenceTrackType;
37037
37038                         } );
37039
37040                         if ( targetTrack === undefined ) continue;
37041
37042                         let referenceOffset = 0;
37043                         const referenceValueSize = referenceTrack.getValueSize();
37044
37045                         if ( referenceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) {
37046
37047                                 referenceOffset = referenceValueSize / 3;
37048
37049                         }
37050
37051                         let targetOffset = 0;
37052                         const targetValueSize = targetTrack.getValueSize();
37053
37054                         if ( targetTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) {
37055
37056                                 targetOffset = targetValueSize / 3;
37057
37058                         }
37059
37060                         const lastIndex = referenceTrack.times.length - 1;
37061                         let referenceValue;
37062
37063                         // Find the value to subtract out of the track
37064                         if ( referenceTime <= referenceTrack.times[ 0 ] ) {
37065
37066                                 // Reference frame is earlier than the first keyframe, so just use the first keyframe
37067                                 const startIndex = referenceOffset;
37068                                 const endIndex = referenceValueSize - referenceOffset;
37069                                 referenceValue = AnimationUtils.arraySlice( referenceTrack.values, startIndex, endIndex );
37070
37071                         } else if ( referenceTime >= referenceTrack.times[ lastIndex ] ) {
37072
37073                                 // Reference frame is after the last keyframe, so just use the last keyframe
37074                                 const startIndex = lastIndex * referenceValueSize + referenceOffset;
37075                                 const endIndex = startIndex + referenceValueSize - referenceOffset;
37076                                 referenceValue = AnimationUtils.arraySlice( referenceTrack.values, startIndex, endIndex );
37077
37078                         } else {
37079
37080                                 // Interpolate to the reference value
37081                                 const interpolant = referenceTrack.createInterpolant();
37082                                 const startIndex = referenceOffset;
37083                                 const endIndex = referenceValueSize - referenceOffset;
37084                                 interpolant.evaluate( referenceTime );
37085                                 referenceValue = AnimationUtils.arraySlice( interpolant.resultBuffer, startIndex, endIndex );
37086
37087                         }
37088
37089                         // Conjugate the quaternion
37090                         if ( referenceTrackType === 'quaternion' ) {
37091
37092                                 const referenceQuat = new Quaternion().fromArray( referenceValue ).normalize().conjugate();
37093                                 referenceQuat.toArray( referenceValue );
37094
37095                         }
37096
37097                         // Subtract the reference value from all of the track values
37098
37099                         const numTimes = targetTrack.times.length;
37100                         for ( let j = 0; j < numTimes; ++ j ) {
37101
37102                                 const valueStart = j * targetValueSize + targetOffset;
37103
37104                                 if ( referenceTrackType === 'quaternion' ) {
37105
37106                                         // Multiply the conjugate for quaternion track types
37107                                         Quaternion.multiplyQuaternionsFlat(
37108                                                 targetTrack.values,
37109                                                 valueStart,
37110                                                 referenceValue,
37111                                                 0,
37112                                                 targetTrack.values,
37113                                                 valueStart
37114                                         );
37115
37116                                 } else {
37117
37118                                         const valueEnd = targetValueSize - targetOffset * 2;
37119
37120                                         // Subtract each value for all other numeric track types
37121                                         for ( let k = 0; k < valueEnd; ++ k ) {
37122
37123                                                 targetTrack.values[ valueStart + k ] -= referenceValue[ k ];
37124
37125                                         }
37126
37127                                 }
37128
37129                         }
37130
37131                 }
37132
37133                 targetClip.blendMode = AdditiveAnimationBlendMode;
37134
37135                 return targetClip;
37136
37137         }
37138
37139 };
37140
37141 /**
37142  * Abstract base class of interpolants over parametric samples.
37143  *
37144  * The parameter domain is one dimensional, typically the time or a path
37145  * along a curve defined by the data.
37146  *
37147  * The sample values can have any dimensionality and derived classes may
37148  * apply special interpretations to the data.
37149  *
37150  * This class provides the interval seek in a Template Method, deferring
37151  * the actual interpolation to derived classes.
37152  *
37153  * Time complexity is O(1) for linear access crossing at most two points
37154  * and O(log N) for random access, where N is the number of positions.
37155  *
37156  * References:
37157  *
37158  *              http://www.oodesign.com/template-method-pattern.html
37159  *
37160  */
37161
37162 class Interpolant {
37163
37164         constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
37165
37166                 this.parameterPositions = parameterPositions;
37167                 this._cachedIndex = 0;
37168
37169                 this.resultBuffer = resultBuffer !== undefined ?
37170                         resultBuffer : new sampleValues.constructor( sampleSize );
37171                 this.sampleValues = sampleValues;
37172                 this.valueSize = sampleSize;
37173
37174                 this.settings = null;
37175                 this.DefaultSettings_ = {};
37176
37177         }
37178
37179         evaluate( t ) {
37180
37181                 const pp = this.parameterPositions;
37182                 let i1 = this._cachedIndex,
37183                         t1 = pp[ i1 ],
37184                         t0 = pp[ i1 - 1 ];
37185
37186                 validate_interval: {
37187
37188                         seek: {
37189
37190                                 let right;
37191
37192                                 linear_scan: {
37193
37194                                         //- See http://jsperf.com/comparison-to-undefined/3
37195                                         //- slower code:
37196                                         //-
37197                                         //-                             if ( t >= t1 || t1 === undefined ) {
37198                                         forward_scan: if ( ! ( t < t1 ) ) {
37199
37200                                                 for ( let giveUpAt = i1 + 2; ; ) {
37201
37202                                                         if ( t1 === undefined ) {
37203
37204                                                                 if ( t < t0 ) break forward_scan;
37205
37206                                                                 // after end
37207
37208                                                                 i1 = pp.length;
37209                                                                 this._cachedIndex = i1;
37210                                                                 return this.afterEnd_( i1 - 1, t, t0 );
37211
37212                                                         }
37213
37214                                                         if ( i1 === giveUpAt ) break; // this loop
37215
37216                                                         t0 = t1;
37217                                                         t1 = pp[ ++ i1 ];
37218
37219                                                         if ( t < t1 ) {
37220
37221                                                                 // we have arrived at the sought interval
37222                                                                 break seek;
37223
37224                                                         }
37225
37226                                                 }
37227
37228                                                 // prepare binary search on the right side of the index
37229                                                 right = pp.length;
37230                                                 break linear_scan;
37231
37232                                         }
37233
37234                                         //- slower code:
37235                                         //-                                     if ( t < t0 || t0 === undefined ) {
37236                                         if ( ! ( t >= t0 ) ) {
37237
37238                                                 // looping?
37239
37240                                                 const t1global = pp[ 1 ];
37241
37242                                                 if ( t < t1global ) {
37243
37244                                                         i1 = 2; // + 1, using the scan for the details
37245                                                         t0 = t1global;
37246
37247                                                 }
37248
37249                                                 // linear reverse scan
37250
37251                                                 for ( let giveUpAt = i1 - 2; ; ) {
37252
37253                                                         if ( t0 === undefined ) {
37254
37255                                                                 // before start
37256
37257                                                                 this._cachedIndex = 0;
37258                                                                 return this.beforeStart_( 0, t, t1 );
37259
37260                                                         }
37261
37262                                                         if ( i1 === giveUpAt ) break; // this loop
37263
37264                                                         t1 = t0;
37265                                                         t0 = pp[ -- i1 - 1 ];
37266
37267                                                         if ( t >= t0 ) {
37268
37269                                                                 // we have arrived at the sought interval
37270                                                                 break seek;
37271
37272                                                         }
37273
37274                                                 }
37275
37276                                                 // prepare binary search on the left side of the index
37277                                                 right = i1;
37278                                                 i1 = 0;
37279                                                 break linear_scan;
37280
37281                                         }
37282
37283                                         // the interval is valid
37284
37285                                         break validate_interval;
37286
37287                                 } // linear scan
37288
37289                                 // binary search
37290
37291                                 while ( i1 < right ) {
37292
37293                                         const mid = ( i1 + right ) >>> 1;
37294
37295                                         if ( t < pp[ mid ] ) {
37296
37297                                                 right = mid;
37298
37299                                         } else {
37300
37301                                                 i1 = mid + 1;
37302
37303                                         }
37304
37305                                 }
37306
37307                                 t1 = pp[ i1 ];
37308                                 t0 = pp[ i1 - 1 ];
37309
37310                                 // check boundary cases, again
37311
37312                                 if ( t0 === undefined ) {
37313
37314                                         this._cachedIndex = 0;
37315                                         return this.beforeStart_( 0, t, t1 );
37316
37317                                 }
37318
37319                                 if ( t1 === undefined ) {
37320
37321                                         i1 = pp.length;
37322                                         this._cachedIndex = i1;
37323                                         return this.afterEnd_( i1 - 1, t0, t );
37324
37325                                 }
37326
37327                         } // seek
37328
37329                         this._cachedIndex = i1;
37330
37331                         this.intervalChanged_( i1, t0, t1 );
37332
37333                 } // validate_interval
37334
37335                 return this.interpolate_( i1, t0, t, t1 );
37336
37337         }
37338
37339         getSettings_() {
37340
37341                 return this.settings || this.DefaultSettings_;
37342
37343         }
37344
37345         copySampleValue_( index ) {
37346
37347                 // copies a sample value to the result buffer
37348
37349                 const result = this.resultBuffer,
37350                         values = this.sampleValues,
37351                         stride = this.valueSize,
37352                         offset = index * stride;
37353
37354                 for ( let i = 0; i !== stride; ++ i ) {
37355
37356                         result[ i ] = values[ offset + i ];
37357
37358                 }
37359
37360                 return result;
37361
37362         }
37363
37364         // Template methods for derived classes:
37365
37366         interpolate_( /* i1, t0, t, t1 */ ) {
37367
37368                 throw new Error( 'call to abstract method' );
37369                 // implementations shall return this.resultBuffer
37370
37371         }
37372
37373         intervalChanged_( /* i1, t0, t1 */ ) {
37374
37375                 // empty
37376
37377         }
37378
37379 }
37380
37381 // ALIAS DEFINITIONS
37382
37383 Interpolant.prototype.beforeStart_ = Interpolant.prototype.copySampleValue_;
37384 Interpolant.prototype.afterEnd_ = Interpolant.prototype.copySampleValue_;
37385
37386 /**
37387  * Fast and simple cubic spline interpolant.
37388  *
37389  * It was derived from a Hermitian construction setting the first derivative
37390  * at each sample position to the linear slope between neighboring positions
37391  * over their parameter interval.
37392  */
37393
37394 class CubicInterpolant extends Interpolant {
37395
37396         constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
37397
37398                 super( parameterPositions, sampleValues, sampleSize, resultBuffer );
37399
37400                 this._weightPrev = - 0;
37401                 this._offsetPrev = - 0;
37402                 this._weightNext = - 0;
37403                 this._offsetNext = - 0;
37404
37405                 this.DefaultSettings_ = {
37406
37407                         endingStart: ZeroCurvatureEnding,
37408                         endingEnd: ZeroCurvatureEnding
37409
37410                 };
37411
37412         }
37413
37414         intervalChanged_( i1, t0, t1 ) {
37415
37416                 const pp = this.parameterPositions;
37417                 let iPrev = i1 - 2,
37418                         iNext = i1 + 1,
37419
37420                         tPrev = pp[ iPrev ],
37421                         tNext = pp[ iNext ];
37422
37423                 if ( tPrev === undefined ) {
37424
37425                         switch ( this.getSettings_().endingStart ) {
37426
37427                                 case ZeroSlopeEnding:
37428
37429                                         // f'(t0) = 0
37430                                         iPrev = i1;
37431                                         tPrev = 2 * t0 - t1;
37432
37433                                         break;
37434
37435                                 case WrapAroundEnding:
37436
37437                                         // use the other end of the curve
37438                                         iPrev = pp.length - 2;
37439                                         tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ];
37440
37441                                         break;
37442
37443                                 default: // ZeroCurvatureEnding
37444
37445                                         // f''(t0) = 0 a.k.a. Natural Spline
37446                                         iPrev = i1;
37447                                         tPrev = t1;
37448
37449                         }
37450
37451                 }
37452
37453                 if ( tNext === undefined ) {
37454
37455                         switch ( this.getSettings_().endingEnd ) {
37456
37457                                 case ZeroSlopeEnding:
37458
37459                                         // f'(tN) = 0
37460                                         iNext = i1;
37461                                         tNext = 2 * t1 - t0;
37462
37463                                         break;
37464
37465                                 case WrapAroundEnding:
37466
37467                                         // use the other end of the curve
37468                                         iNext = 1;
37469                                         tNext = t1 + pp[ 1 ] - pp[ 0 ];
37470
37471                                         break;
37472
37473                                 default: // ZeroCurvatureEnding
37474
37475                                         // f''(tN) = 0, a.k.a. Natural Spline
37476                                         iNext = i1 - 1;
37477                                         tNext = t0;
37478
37479                         }
37480
37481                 }
37482
37483                 const halfDt = ( t1 - t0 ) * 0.5,
37484                         stride = this.valueSize;
37485
37486                 this._weightPrev = halfDt / ( t0 - tPrev );
37487                 this._weightNext = halfDt / ( tNext - t1 );
37488                 this._offsetPrev = iPrev * stride;
37489                 this._offsetNext = iNext * stride;
37490
37491         }
37492
37493         interpolate_( i1, t0, t, t1 ) {
37494
37495                 const result = this.resultBuffer,
37496                         values = this.sampleValues,
37497                         stride = this.valueSize,
37498
37499                         o1 = i1 * stride,               o0 = o1 - stride,
37500                         oP = this._offsetPrev,  oN = this._offsetNext,
37501                         wP = this._weightPrev,  wN = this._weightNext,
37502
37503                         p = ( t - t0 ) / ( t1 - t0 ),
37504                         pp = p * p,
37505                         ppp = pp * p;
37506
37507                 // evaluate polynomials
37508
37509                 const sP = - wP * ppp + 2 * wP * pp - wP * p;
37510                 const s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP ) * p + 1;
37511                 const s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p;
37512                 const sN = wN * ppp - wN * pp;
37513
37514                 // combine data linearly
37515
37516                 for ( let i = 0; i !== stride; ++ i ) {
37517
37518                         result[ i ] =
37519                                         sP * values[ oP + i ] +
37520                                         s0 * values[ o0 + i ] +
37521                                         s1 * values[ o1 + i ] +
37522                                         sN * values[ oN + i ];
37523
37524                 }
37525
37526                 return result;
37527
37528         }
37529
37530 }
37531
37532 class LinearInterpolant extends Interpolant {
37533
37534         constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
37535
37536                 super( parameterPositions, sampleValues, sampleSize, resultBuffer );
37537
37538         }
37539
37540         interpolate_( i1, t0, t, t1 ) {
37541
37542                 const result = this.resultBuffer,
37543                         values = this.sampleValues,
37544                         stride = this.valueSize,
37545
37546                         offset1 = i1 * stride,
37547                         offset0 = offset1 - stride,
37548
37549                         weight1 = ( t - t0 ) / ( t1 - t0 ),
37550                         weight0 = 1 - weight1;
37551
37552                 for ( let i = 0; i !== stride; ++ i ) {
37553
37554                         result[ i ] =
37555                                         values[ offset0 + i ] * weight0 +
37556                                         values[ offset1 + i ] * weight1;
37557
37558                 }
37559
37560                 return result;
37561
37562         }
37563
37564 }
37565
37566 /**
37567  *
37568  * Interpolant that evaluates to the sample value at the position preceeding
37569  * the parameter.
37570  */
37571
37572 class DiscreteInterpolant extends Interpolant {
37573
37574         constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
37575
37576                 super( parameterPositions, sampleValues, sampleSize, resultBuffer );
37577
37578         }
37579
37580         interpolate_( i1 /*, t0, t, t1 */ ) {
37581
37582                 return this.copySampleValue_( i1 - 1 );
37583
37584         }
37585
37586 }
37587
37588 class KeyframeTrack {
37589
37590         constructor( name, times, values, interpolation ) {
37591
37592                 if ( name === undefined ) throw new Error( 'THREE.KeyframeTrack: track name is undefined' );
37593                 if ( times === undefined || times.length === 0 ) throw new Error( 'THREE.KeyframeTrack: no keyframes in track named ' + name );
37594
37595                 this.name = name;
37596
37597                 this.times = AnimationUtils.convertArray( times, this.TimeBufferType );
37598                 this.values = AnimationUtils.convertArray( values, this.ValueBufferType );
37599
37600                 this.setInterpolation( interpolation || this.DefaultInterpolation );
37601
37602         }
37603
37604         // Serialization (in static context, because of constructor invocation
37605         // and automatic invocation of .toJSON):
37606
37607         static toJSON( track ) {
37608
37609                 const trackType = track.constructor;
37610
37611                 let json;
37612
37613                 // derived classes can define a static toJSON method
37614                 if ( trackType.toJSON !== this.toJSON ) {
37615
37616                         json = trackType.toJSON( track );
37617
37618                 } else {
37619
37620                         // by default, we assume the data can be serialized as-is
37621                         json = {
37622
37623                                 'name': track.name,
37624                                 'times': AnimationUtils.convertArray( track.times, Array ),
37625                                 'values': AnimationUtils.convertArray( track.values, Array )
37626
37627                         };
37628
37629                         const interpolation = track.getInterpolation();
37630
37631                         if ( interpolation !== track.DefaultInterpolation ) {
37632
37633                                 json.interpolation = interpolation;
37634
37635                         }
37636
37637                 }
37638
37639                 json.type = track.ValueTypeName; // mandatory
37640
37641                 return json;
37642
37643         }
37644
37645         InterpolantFactoryMethodDiscrete( result ) {
37646
37647                 return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result );
37648
37649         }
37650
37651         InterpolantFactoryMethodLinear( result ) {
37652
37653                 return new LinearInterpolant( this.times, this.values, this.getValueSize(), result );
37654
37655         }
37656
37657         InterpolantFactoryMethodSmooth( result ) {
37658
37659                 return new CubicInterpolant( this.times, this.values, this.getValueSize(), result );
37660
37661         }
37662
37663         setInterpolation( interpolation ) {
37664
37665                 let factoryMethod;
37666
37667                 switch ( interpolation ) {
37668
37669                         case InterpolateDiscrete:
37670
37671                                 factoryMethod = this.InterpolantFactoryMethodDiscrete;
37672
37673                                 break;
37674
37675                         case InterpolateLinear:
37676
37677                                 factoryMethod = this.InterpolantFactoryMethodLinear;
37678
37679                                 break;
37680
37681                         case InterpolateSmooth:
37682
37683                                 factoryMethod = this.InterpolantFactoryMethodSmooth;
37684
37685                                 break;
37686
37687                 }
37688
37689                 if ( factoryMethod === undefined ) {
37690
37691                         const message = 'unsupported interpolation for ' +
37692                                 this.ValueTypeName + ' keyframe track named ' + this.name;
37693
37694                         if ( this.createInterpolant === undefined ) {
37695
37696                                 // fall back to default, unless the default itself is messed up
37697                                 if ( interpolation !== this.DefaultInterpolation ) {
37698
37699                                         this.setInterpolation( this.DefaultInterpolation );
37700
37701                                 } else {
37702
37703                                         throw new Error( message ); // fatal, in this case
37704
37705                                 }
37706
37707                         }
37708
37709                         console.warn( 'THREE.KeyframeTrack:', message );
37710                         return this;
37711
37712                 }
37713
37714                 this.createInterpolant = factoryMethod;
37715
37716                 return this;
37717
37718         }
37719
37720         getInterpolation() {
37721
37722                 switch ( this.createInterpolant ) {
37723
37724                         case this.InterpolantFactoryMethodDiscrete:
37725
37726                                 return InterpolateDiscrete;
37727
37728                         case this.InterpolantFactoryMethodLinear:
37729
37730                                 return InterpolateLinear;
37731
37732                         case this.InterpolantFactoryMethodSmooth:
37733
37734                                 return InterpolateSmooth;
37735
37736                 }
37737
37738         }
37739
37740         getValueSize() {
37741
37742                 return this.values.length / this.times.length;
37743
37744         }
37745
37746         // move all keyframes either forwards or backwards in time
37747         shift( timeOffset ) {
37748
37749                 if ( timeOffset !== 0.0 ) {
37750
37751                         const times = this.times;
37752
37753                         for ( let i = 0, n = times.length; i !== n; ++ i ) {
37754
37755                                 times[ i ] += timeOffset;
37756
37757                         }
37758
37759                 }
37760
37761                 return this;
37762
37763         }
37764
37765         // scale all keyframe times by a factor (useful for frame <-> seconds conversions)
37766         scale( timeScale ) {
37767
37768                 if ( timeScale !== 1.0 ) {
37769
37770                         const times = this.times;
37771
37772                         for ( let i = 0, n = times.length; i !== n; ++ i ) {
37773
37774                                 times[ i ] *= timeScale;
37775
37776                         }
37777
37778                 }
37779
37780                 return this;
37781
37782         }
37783
37784         // removes keyframes before and after animation without changing any values within the range [startTime, endTime].
37785         // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values
37786         trim( startTime, endTime ) {
37787
37788                 const times = this.times,
37789                         nKeys = times.length;
37790
37791                 let from = 0,
37792                         to = nKeys - 1;
37793
37794                 while ( from !== nKeys && times[ from ] < startTime ) {
37795
37796                         ++ from;
37797
37798                 }
37799
37800                 while ( to !== - 1 && times[ to ] > endTime ) {
37801
37802                         -- to;
37803
37804                 }
37805
37806                 ++ to; // inclusive -> exclusive bound
37807
37808                 if ( from !== 0 || to !== nKeys ) {
37809
37810                         // empty tracks are forbidden, so keep at least one keyframe
37811                         if ( from >= to ) {
37812
37813                                 to = Math.max( to, 1 );
37814                                 from = to - 1;
37815
37816                         }
37817
37818                         const stride = this.getValueSize();
37819                         this.times = AnimationUtils.arraySlice( times, from, to );
37820                         this.values = AnimationUtils.arraySlice( this.values, from * stride, to * stride );
37821
37822                 }
37823
37824                 return this;
37825
37826         }
37827
37828         // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable
37829         validate() {
37830
37831                 let valid = true;
37832
37833                 const valueSize = this.getValueSize();
37834                 if ( valueSize - Math.floor( valueSize ) !== 0 ) {
37835
37836                         console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this );
37837                         valid = false;
37838
37839                 }
37840
37841                 const times = this.times,
37842                         values = this.values,
37843
37844                         nKeys = times.length;
37845
37846                 if ( nKeys === 0 ) {
37847
37848                         console.error( 'THREE.KeyframeTrack: Track is empty.', this );
37849                         valid = false;
37850
37851                 }
37852
37853                 let prevTime = null;
37854
37855                 for ( let i = 0; i !== nKeys; i ++ ) {
37856
37857                         const currTime = times[ i ];
37858
37859                         if ( typeof currTime === 'number' && isNaN( currTime ) ) {
37860
37861                                 console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime );
37862                                 valid = false;
37863                                 break;
37864
37865                         }
37866
37867                         if ( prevTime !== null && prevTime > currTime ) {
37868
37869                                 console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime );
37870                                 valid = false;
37871                                 break;
37872
37873                         }
37874
37875                         prevTime = currTime;
37876
37877                 }
37878
37879                 if ( values !== undefined ) {
37880
37881                         if ( AnimationUtils.isTypedArray( values ) ) {
37882
37883                                 for ( let i = 0, n = values.length; i !== n; ++ i ) {
37884
37885                                         const value = values[ i ];
37886
37887                                         if ( isNaN( value ) ) {
37888
37889                                                 console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value );
37890                                                 valid = false;
37891                                                 break;
37892
37893                                         }
37894
37895                                 }
37896
37897                         }
37898
37899                 }
37900
37901                 return valid;
37902
37903         }
37904
37905         // removes equivalent sequential keys as common in morph target sequences
37906         // (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0)
37907         optimize() {
37908
37909                 // times or values may be shared with other tracks, so overwriting is unsafe
37910                 const times = AnimationUtils.arraySlice( this.times ),
37911                         values = AnimationUtils.arraySlice( this.values ),
37912                         stride = this.getValueSize(),
37913
37914                         smoothInterpolation = this.getInterpolation() === InterpolateSmooth,
37915
37916                         lastIndex = times.length - 1;
37917
37918                 let writeIndex = 1;
37919
37920                 for ( let i = 1; i < lastIndex; ++ i ) {
37921
37922                         let keep = false;
37923
37924                         const time = times[ i ];
37925                         const timeNext = times[ i + 1 ];
37926
37927                         // remove adjacent keyframes scheduled at the same time
37928
37929                         if ( time !== timeNext && ( i !== 1 || time !== times[ 0 ] ) ) {
37930
37931                                 if ( ! smoothInterpolation ) {
37932
37933                                         // remove unnecessary keyframes same as their neighbors
37934
37935                                         const offset = i * stride,
37936                                                 offsetP = offset - stride,
37937                                                 offsetN = offset + stride;
37938
37939                                         for ( let j = 0; j !== stride; ++ j ) {
37940
37941                                                 const value = values[ offset + j ];
37942
37943                                                 if ( value !== values[ offsetP + j ] ||
37944                                                         value !== values[ offsetN + j ] ) {
37945
37946                                                         keep = true;
37947                                                         break;
37948
37949                                                 }
37950
37951                                         }
37952
37953                                 } else {
37954
37955                                         keep = true;
37956
37957                                 }
37958
37959                         }
37960
37961                         // in-place compaction
37962
37963                         if ( keep ) {
37964
37965                                 if ( i !== writeIndex ) {
37966
37967                                         times[ writeIndex ] = times[ i ];
37968
37969                                         const readOffset = i * stride,
37970                                                 writeOffset = writeIndex * stride;
37971
37972                                         for ( let j = 0; j !== stride; ++ j ) {
37973
37974                                                 values[ writeOffset + j ] = values[ readOffset + j ];
37975
37976                                         }
37977
37978                                 }
37979
37980                                 ++ writeIndex;
37981
37982                         }
37983
37984                 }
37985
37986                 // flush last keyframe (compaction looks ahead)
37987
37988                 if ( lastIndex > 0 ) {
37989
37990                         times[ writeIndex ] = times[ lastIndex ];
37991
37992                         for ( let readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) {
37993
37994                                 values[ writeOffset + j ] = values[ readOffset + j ];
37995
37996                         }
37997
37998                         ++ writeIndex;
37999
38000                 }
38001
38002                 if ( writeIndex !== times.length ) {
38003
38004                         this.times = AnimationUtils.arraySlice( times, 0, writeIndex );
38005                         this.values = AnimationUtils.arraySlice( values, 0, writeIndex * stride );
38006
38007                 } else {
38008
38009                         this.times = times;
38010                         this.values = values;
38011
38012                 }
38013
38014                 return this;
38015
38016         }
38017
38018         clone() {
38019
38020                 const times = AnimationUtils.arraySlice( this.times, 0 );
38021                 const values = AnimationUtils.arraySlice( this.values, 0 );
38022
38023                 const TypedKeyframeTrack = this.constructor;
38024                 const track = new TypedKeyframeTrack( this.name, times, values );
38025
38026                 // Interpolant argument to constructor is not saved, so copy the factory method directly.
38027                 track.createInterpolant = this.createInterpolant;
38028
38029                 return track;
38030
38031         }
38032
38033 }
38034
38035 KeyframeTrack.prototype.TimeBufferType = Float32Array;
38036 KeyframeTrack.prototype.ValueBufferType = Float32Array;
38037 KeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear;
38038
38039 /**
38040  * A Track of Boolean keyframe values.
38041  */
38042 class BooleanKeyframeTrack extends KeyframeTrack {}
38043
38044 BooleanKeyframeTrack.prototype.ValueTypeName = 'bool';
38045 BooleanKeyframeTrack.prototype.ValueBufferType = Array;
38046 BooleanKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete;
38047 BooleanKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined;
38048 BooleanKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined;
38049
38050 /**
38051  * A Track of keyframe values that represent color.
38052  */
38053 class ColorKeyframeTrack extends KeyframeTrack {}
38054
38055 ColorKeyframeTrack.prototype.ValueTypeName = 'color';
38056
38057 /**
38058  * A Track of numeric keyframe values.
38059  */
38060 class NumberKeyframeTrack extends KeyframeTrack {}
38061
38062 NumberKeyframeTrack.prototype.ValueTypeName = 'number';
38063
38064 /**
38065  * Spherical linear unit quaternion interpolant.
38066  */
38067
38068 class QuaternionLinearInterpolant extends Interpolant {
38069
38070         constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
38071
38072                 super( parameterPositions, sampleValues, sampleSize, resultBuffer );
38073
38074         }
38075
38076         interpolate_( i1, t0, t, t1 ) {
38077
38078                 const result = this.resultBuffer,
38079                         values = this.sampleValues,
38080                         stride = this.valueSize,
38081
38082                         alpha = ( t - t0 ) / ( t1 - t0 );
38083
38084                 let offset = i1 * stride;
38085
38086                 for ( let end = offset + stride; offset !== end; offset += 4 ) {
38087
38088                         Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha );
38089
38090                 }
38091
38092                 return result;
38093
38094         }
38095
38096 }
38097
38098 /**
38099  * A Track of quaternion keyframe values.
38100  */
38101 class QuaternionKeyframeTrack extends KeyframeTrack {
38102
38103         InterpolantFactoryMethodLinear( result ) {
38104
38105                 return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result );
38106
38107         }
38108
38109 }
38110
38111 QuaternionKeyframeTrack.prototype.ValueTypeName = 'quaternion';
38112 // ValueBufferType is inherited
38113 QuaternionKeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear;
38114 QuaternionKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined;
38115
38116 /**
38117  * A Track that interpolates Strings
38118  */
38119 class StringKeyframeTrack extends KeyframeTrack {}
38120
38121 StringKeyframeTrack.prototype.ValueTypeName = 'string';
38122 StringKeyframeTrack.prototype.ValueBufferType = Array;
38123 StringKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete;
38124 StringKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined;
38125 StringKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined;
38126
38127 /**
38128  * A Track of vectored keyframe values.
38129  */
38130 class VectorKeyframeTrack extends KeyframeTrack {}
38131
38132 VectorKeyframeTrack.prototype.ValueTypeName = 'vector';
38133
38134 class AnimationClip {
38135
38136         constructor( name, duration = - 1, tracks, blendMode = NormalAnimationBlendMode ) {
38137
38138                 this.name = name;
38139                 this.tracks = tracks;
38140                 this.duration = duration;
38141                 this.blendMode = blendMode;
38142
38143                 this.uuid = generateUUID();
38144
38145                 // this means it should figure out its duration by scanning the tracks
38146                 if ( this.duration < 0 ) {
38147
38148                         this.resetDuration();
38149
38150                 }
38151
38152         }
38153
38154
38155         static parse( json ) {
38156
38157                 const tracks = [],
38158                         jsonTracks = json.tracks,
38159                         frameTime = 1.0 / ( json.fps || 1.0 );
38160
38161                 for ( let i = 0, n = jsonTracks.length; i !== n; ++ i ) {
38162
38163                         tracks.push( parseKeyframeTrack( jsonTracks[ i ] ).scale( frameTime ) );
38164
38165                 }
38166
38167                 const clip = new this( json.name, json.duration, tracks, json.blendMode );
38168                 clip.uuid = json.uuid;
38169
38170                 return clip;
38171
38172         }
38173
38174         static toJSON( clip ) {
38175
38176                 const tracks = [],
38177                         clipTracks = clip.tracks;
38178
38179                 const json = {
38180
38181                         'name': clip.name,
38182                         'duration': clip.duration,
38183                         'tracks': tracks,
38184                         'uuid': clip.uuid,
38185                         'blendMode': clip.blendMode
38186
38187                 };
38188
38189                 for ( let i = 0, n = clipTracks.length; i !== n; ++ i ) {
38190
38191                         tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) );
38192
38193                 }
38194
38195                 return json;
38196
38197         }
38198
38199         static CreateFromMorphTargetSequence( name, morphTargetSequence, fps, noLoop ) {
38200
38201                 const numMorphTargets = morphTargetSequence.length;
38202                 const tracks = [];
38203
38204                 for ( let i = 0; i < numMorphTargets; i ++ ) {
38205
38206                         let times = [];
38207                         let values = [];
38208
38209                         times.push(
38210                                 ( i + numMorphTargets - 1 ) % numMorphTargets,
38211                                 i,
38212                                 ( i + 1 ) % numMorphTargets );
38213
38214                         values.push( 0, 1, 0 );
38215
38216                         const order = AnimationUtils.getKeyframeOrder( times );
38217                         times = AnimationUtils.sortedArray( times, 1, order );
38218                         values = AnimationUtils.sortedArray( values, 1, order );
38219
38220                         // if there is a key at the first frame, duplicate it as the
38221                         // last frame as well for perfect loop.
38222                         if ( ! noLoop && times[ 0 ] === 0 ) {
38223
38224                                 times.push( numMorphTargets );
38225                                 values.push( values[ 0 ] );
38226
38227                         }
38228
38229                         tracks.push(
38230                                 new NumberKeyframeTrack(
38231                                         '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']',
38232                                         times, values
38233                                 ).scale( 1.0 / fps ) );
38234
38235                 }
38236
38237                 return new this( name, - 1, tracks );
38238
38239         }
38240
38241         static findByName( objectOrClipArray, name ) {
38242
38243                 let clipArray = objectOrClipArray;
38244
38245                 if ( ! Array.isArray( objectOrClipArray ) ) {
38246
38247                         const o = objectOrClipArray;
38248                         clipArray = o.geometry && o.geometry.animations || o.animations;
38249
38250                 }
38251
38252                 for ( let i = 0; i < clipArray.length; i ++ ) {
38253
38254                         if ( clipArray[ i ].name === name ) {
38255
38256                                 return clipArray[ i ];
38257
38258                         }
38259
38260                 }
38261
38262                 return null;
38263
38264         }
38265
38266         static CreateClipsFromMorphTargetSequences( morphTargets, fps, noLoop ) {
38267
38268                 const animationToMorphTargets = {};
38269
38270                 // tested with https://regex101.com/ on trick sequences
38271                 // such flamingo_flyA_003, flamingo_run1_003, crdeath0059
38272                 const pattern = /^([\w-]*?)([\d]+)$/;
38273
38274                 // sort morph target names into animation groups based
38275                 // patterns like Walk_001, Walk_002, Run_001, Run_002
38276                 for ( let i = 0, il = morphTargets.length; i < il; i ++ ) {
38277
38278                         const morphTarget = morphTargets[ i ];
38279                         const parts = morphTarget.name.match( pattern );
38280
38281                         if ( parts && parts.length > 1 ) {
38282
38283                                 const name = parts[ 1 ];
38284
38285                                 let animationMorphTargets = animationToMorphTargets[ name ];
38286
38287                                 if ( ! animationMorphTargets ) {
38288
38289                                         animationToMorphTargets[ name ] = animationMorphTargets = [];
38290
38291                                 }
38292
38293                                 animationMorphTargets.push( morphTarget );
38294
38295                         }
38296
38297                 }
38298
38299                 const clips = [];
38300
38301                 for ( const name in animationToMorphTargets ) {
38302
38303                         clips.push( this.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) );
38304
38305                 }
38306
38307                 return clips;
38308
38309         }
38310
38311         // parse the animation.hierarchy format
38312         static parseAnimation( animation, bones ) {
38313
38314                 if ( ! animation ) {
38315
38316                         console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' );
38317                         return null;
38318
38319                 }
38320
38321                 const addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) {
38322
38323                         // only return track if there are actually keys.
38324                         if ( animationKeys.length !== 0 ) {
38325
38326                                 const times = [];
38327                                 const values = [];
38328
38329                                 AnimationUtils.flattenJSON( animationKeys, times, values, propertyName );
38330
38331                                 // empty keys are filtered out, so check again
38332                                 if ( times.length !== 0 ) {
38333
38334                                         destTracks.push( new trackType( trackName, times, values ) );
38335
38336                                 }
38337
38338                         }
38339
38340                 };
38341
38342                 const tracks = [];
38343
38344                 const clipName = animation.name || 'default';
38345                 const fps = animation.fps || 30;
38346                 const blendMode = animation.blendMode;
38347
38348                 // automatic length determination in AnimationClip.
38349                 let duration = animation.length || - 1;
38350
38351                 const hierarchyTracks = animation.hierarchy || [];
38352
38353                 for ( let h = 0; h < hierarchyTracks.length; h ++ ) {
38354
38355                         const animationKeys = hierarchyTracks[ h ].keys;
38356
38357                         // skip empty tracks
38358                         if ( ! animationKeys || animationKeys.length === 0 ) continue;
38359
38360                         // process morph targets
38361                         if ( animationKeys[ 0 ].morphTargets ) {
38362
38363                                 // figure out all morph targets used in this track
38364                                 const morphTargetNames = {};
38365
38366                                 let k;
38367
38368                                 for ( k = 0; k < animationKeys.length; k ++ ) {
38369
38370                                         if ( animationKeys[ k ].morphTargets ) {
38371
38372                                                 for ( let m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) {
38373
38374                                                         morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1;
38375
38376                                                 }
38377
38378                                         }
38379
38380                                 }
38381
38382                                 // create a track for each morph target with all zero
38383                                 // morphTargetInfluences except for the keys in which
38384                                 // the morphTarget is named.
38385                                 for ( const morphTargetName in morphTargetNames ) {
38386
38387                                         const times = [];
38388                                         const values = [];
38389
38390                                         for ( let m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) {
38391
38392                                                 const animationKey = animationKeys[ k ];
38393
38394                                                 times.push( animationKey.time );
38395                                                 values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 );
38396
38397                                         }
38398
38399                                         tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) );
38400
38401                                 }
38402
38403                                 duration = morphTargetNames.length * ( fps || 1.0 );
38404
38405                         } else {
38406
38407                                 // ...assume skeletal animation
38408
38409                                 const boneName = '.bones[' + bones[ h ].name + ']';
38410
38411                                 addNonemptyTrack(
38412                                         VectorKeyframeTrack, boneName + '.position',
38413                                         animationKeys, 'pos', tracks );
38414
38415                                 addNonemptyTrack(
38416                                         QuaternionKeyframeTrack, boneName + '.quaternion',
38417                                         animationKeys, 'rot', tracks );
38418
38419                                 addNonemptyTrack(
38420                                         VectorKeyframeTrack, boneName + '.scale',
38421                                         animationKeys, 'scl', tracks );
38422
38423                         }
38424
38425                 }
38426
38427                 if ( tracks.length === 0 ) {
38428
38429                         return null;
38430
38431                 }
38432
38433                 const clip = new this( clipName, duration, tracks, blendMode );
38434
38435                 return clip;
38436
38437         }
38438
38439         resetDuration() {
38440
38441                 const tracks = this.tracks;
38442                 let duration = 0;
38443
38444                 for ( let i = 0, n = tracks.length; i !== n; ++ i ) {
38445
38446                         const track = this.tracks[ i ];
38447
38448                         duration = Math.max( duration, track.times[ track.times.length - 1 ] );
38449
38450                 }
38451
38452                 this.duration = duration;
38453
38454                 return this;
38455
38456         }
38457
38458         trim() {
38459
38460                 for ( let i = 0; i < this.tracks.length; i ++ ) {
38461
38462                         this.tracks[ i ].trim( 0, this.duration );
38463
38464                 }
38465
38466                 return this;
38467
38468         }
38469
38470         validate() {
38471
38472                 let valid = true;
38473
38474                 for ( let i = 0; i < this.tracks.length; i ++ ) {
38475
38476                         valid = valid && this.tracks[ i ].validate();
38477
38478                 }
38479
38480                 return valid;
38481
38482         }
38483
38484         optimize() {
38485
38486                 for ( let i = 0; i < this.tracks.length; i ++ ) {
38487
38488                         this.tracks[ i ].optimize();
38489
38490                 }
38491
38492                 return this;
38493
38494         }
38495
38496         clone() {
38497
38498                 const tracks = [];
38499
38500                 for ( let i = 0; i < this.tracks.length; i ++ ) {
38501
38502                         tracks.push( this.tracks[ i ].clone() );
38503
38504                 }
38505
38506                 return new this.constructor( this.name, this.duration, tracks, this.blendMode );
38507
38508         }
38509
38510         toJSON() {
38511
38512                 return this.constructor.toJSON( this );
38513
38514         }
38515
38516 }
38517
38518 function getTrackTypeForValueTypeName( typeName ) {
38519
38520         switch ( typeName.toLowerCase() ) {
38521
38522                 case 'scalar':
38523                 case 'double':
38524                 case 'float':
38525                 case 'number':
38526                 case 'integer':
38527
38528                         return NumberKeyframeTrack;
38529
38530                 case 'vector':
38531                 case 'vector2':
38532                 case 'vector3':
38533                 case 'vector4':
38534
38535                         return VectorKeyframeTrack;
38536
38537                 case 'color':
38538
38539                         return ColorKeyframeTrack;
38540
38541                 case 'quaternion':
38542
38543                         return QuaternionKeyframeTrack;
38544
38545                 case 'bool':
38546                 case 'boolean':
38547
38548                         return BooleanKeyframeTrack;
38549
38550                 case 'string':
38551
38552                         return StringKeyframeTrack;
38553
38554         }
38555
38556         throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName );
38557
38558 }
38559
38560 function parseKeyframeTrack( json ) {
38561
38562         if ( json.type === undefined ) {
38563
38564                 throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' );
38565
38566         }
38567
38568         const trackType = getTrackTypeForValueTypeName( json.type );
38569
38570         if ( json.times === undefined ) {
38571
38572                 const times = [], values = [];
38573
38574                 AnimationUtils.flattenJSON( json.keys, times, values, 'value' );
38575
38576                 json.times = times;
38577                 json.values = values;
38578
38579         }
38580
38581         // derived classes can define a static parse method
38582         if ( trackType.parse !== undefined ) {
38583
38584                 return trackType.parse( json );
38585
38586         } else {
38587
38588                 // by default, we assume a constructor compatible with the base
38589                 return new trackType( json.name, json.times, json.values, json.interpolation );
38590
38591         }
38592
38593 }
38594
38595 const Cache = {
38596
38597         enabled: false,
38598
38599         files: {},
38600
38601         add: function ( key, file ) {
38602
38603                 if ( this.enabled === false ) return;
38604
38605                 // console.log( 'THREE.Cache', 'Adding key:', key );
38606
38607                 this.files[ key ] = file;
38608
38609         },
38610
38611         get: function ( key ) {
38612
38613                 if ( this.enabled === false ) return;
38614
38615                 // console.log( 'THREE.Cache', 'Checking key:', key );
38616
38617                 return this.files[ key ];
38618
38619         },
38620
38621         remove: function ( key ) {
38622
38623                 delete this.files[ key ];
38624
38625         },
38626
38627         clear: function () {
38628
38629                 this.files = {};
38630
38631         }
38632
38633 };
38634
38635 class LoadingManager {
38636
38637         constructor( onLoad, onProgress, onError ) {
38638
38639                 const scope = this;
38640
38641                 let isLoading = false;
38642                 let itemsLoaded = 0;
38643                 let itemsTotal = 0;
38644                 let urlModifier = undefined;
38645                 const handlers = [];
38646
38647                 // Refer to #5689 for the reason why we don't set .onStart
38648                 // in the constructor
38649
38650                 this.onStart = undefined;
38651                 this.onLoad = onLoad;
38652                 this.onProgress = onProgress;
38653                 this.onError = onError;
38654
38655                 this.itemStart = function ( url ) {
38656
38657                         itemsTotal ++;
38658
38659                         if ( isLoading === false ) {
38660
38661                                 if ( scope.onStart !== undefined ) {
38662
38663                                         scope.onStart( url, itemsLoaded, itemsTotal );
38664
38665                                 }
38666
38667                         }
38668
38669                         isLoading = true;
38670
38671                 };
38672
38673                 this.itemEnd = function ( url ) {
38674
38675                         itemsLoaded ++;
38676
38677                         if ( scope.onProgress !== undefined ) {
38678
38679                                 scope.onProgress( url, itemsLoaded, itemsTotal );
38680
38681                         }
38682
38683                         if ( itemsLoaded === itemsTotal ) {
38684
38685                                 isLoading = false;
38686
38687                                 if ( scope.onLoad !== undefined ) {
38688
38689                                         scope.onLoad();
38690
38691                                 }
38692
38693                         }
38694
38695                 };
38696
38697                 this.itemError = function ( url ) {
38698
38699                         if ( scope.onError !== undefined ) {
38700
38701                                 scope.onError( url );
38702
38703                         }
38704
38705                 };
38706
38707                 this.resolveURL = function ( url ) {
38708
38709                         if ( urlModifier ) {
38710
38711                                 return urlModifier( url );
38712
38713                         }
38714
38715                         return url;
38716
38717                 };
38718
38719                 this.setURLModifier = function ( transform ) {
38720
38721                         urlModifier = transform;
38722
38723                         return this;
38724
38725                 };
38726
38727                 this.addHandler = function ( regex, loader ) {
38728
38729                         handlers.push( regex, loader );
38730
38731                         return this;
38732
38733                 };
38734
38735                 this.removeHandler = function ( regex ) {
38736
38737                         const index = handlers.indexOf( regex );
38738
38739                         if ( index !== - 1 ) {
38740
38741                                 handlers.splice( index, 2 );
38742
38743                         }
38744
38745                         return this;
38746
38747                 };
38748
38749                 this.getHandler = function ( file ) {
38750
38751                         for ( let i = 0, l = handlers.length; i < l; i += 2 ) {
38752
38753                                 const regex = handlers[ i ];
38754                                 const loader = handlers[ i + 1 ];
38755
38756                                 if ( regex.global ) regex.lastIndex = 0; // see #17920
38757
38758                                 if ( regex.test( file ) ) {
38759
38760                                         return loader;
38761
38762                                 }
38763
38764                         }
38765
38766                         return null;
38767
38768                 };
38769
38770         }
38771
38772 }
38773
38774 const DefaultLoadingManager = new LoadingManager();
38775
38776 class Loader {
38777
38778         constructor( manager ) {
38779
38780                 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
38781
38782                 this.crossOrigin = 'anonymous';
38783                 this.withCredentials = false;
38784                 this.path = '';
38785                 this.resourcePath = '';
38786                 this.requestHeader = {};
38787
38788         }
38789
38790         load( /* url, onLoad, onProgress, onError */ ) {}
38791
38792         loadAsync( url, onProgress ) {
38793
38794                 const scope = this;
38795
38796                 return new Promise( function ( resolve, reject ) {
38797
38798                         scope.load( url, resolve, onProgress, reject );
38799
38800                 } );
38801
38802         }
38803
38804         parse( /* data */ ) {}
38805
38806         setCrossOrigin( crossOrigin ) {
38807
38808                 this.crossOrigin = crossOrigin;
38809                 return this;
38810
38811         }
38812
38813         setWithCredentials( value ) {
38814
38815                 this.withCredentials = value;
38816                 return this;
38817
38818         }
38819
38820         setPath( path ) {
38821
38822                 this.path = path;
38823                 return this;
38824
38825         }
38826
38827         setResourcePath( resourcePath ) {
38828
38829                 this.resourcePath = resourcePath;
38830                 return this;
38831
38832         }
38833
38834         setRequestHeader( requestHeader ) {
38835
38836                 this.requestHeader = requestHeader;
38837                 return this;
38838
38839         }
38840
38841 }
38842
38843 const loading = {};
38844
38845 class FileLoader extends Loader {
38846
38847         constructor( manager ) {
38848
38849                 super( manager );
38850
38851         }
38852
38853         load( url, onLoad, onProgress, onError ) {
38854
38855                 if ( url === undefined ) url = '';
38856
38857                 if ( this.path !== undefined ) url = this.path + url;
38858
38859                 url = this.manager.resolveURL( url );
38860
38861                 const cached = Cache.get( url );
38862
38863                 if ( cached !== undefined ) {
38864
38865                         this.manager.itemStart( url );
38866
38867                         setTimeout( () => {
38868
38869                                 if ( onLoad ) onLoad( cached );
38870
38871                                 this.manager.itemEnd( url );
38872
38873                         }, 0 );
38874
38875                         return cached;
38876
38877                 }
38878
38879                 // Check if request is duplicate
38880
38881                 if ( loading[ url ] !== undefined ) {
38882
38883                         loading[ url ].push( {
38884
38885                                 onLoad: onLoad,
38886                                 onProgress: onProgress,
38887                                 onError: onError
38888
38889                         } );
38890
38891                         return;
38892
38893                 }
38894
38895                 // Initialise array for duplicate requests
38896                 loading[ url ] = [];
38897
38898                 loading[ url ].push( {
38899                         onLoad: onLoad,
38900                         onProgress: onProgress,
38901                         onError: onError,
38902                 } );
38903
38904                 // create request
38905                 const req = new Request( url, {
38906                         headers: new Headers( this.requestHeader ),
38907                         credentials: this.withCredentials ? 'include' : 'same-origin',
38908                         // An abort controller could be added within a future PR
38909                 } );
38910
38911                 // start the fetch
38912                 fetch( req )
38913                         .then( response => {
38914
38915                                 if ( response.status === 200 || response.status === 0 ) {
38916
38917                                         // Some browsers return HTTP Status 0 when using non-http protocol
38918                                         // e.g. 'file://' or 'data://'. Handle as success.
38919
38920                                         if ( response.status === 0 ) {
38921
38922                                                 console.warn( 'THREE.FileLoader: HTTP Status 0 received.' );
38923
38924                                         }
38925
38926                                         const callbacks = loading[ url ];
38927                                         const reader = response.body.getReader();
38928                                         const contentLength = response.headers.get( 'Content-Length' );
38929                                         const total = contentLength ? parseInt( contentLength ) : 0;
38930                                         const lengthComputable = total !== 0;
38931                                         let loaded = 0;
38932
38933                                         // periodically read data into the new stream tracking while download progress
38934                                         return new ReadableStream( {
38935                                                 start( controller ) {
38936
38937                                                         readData();
38938
38939                                                         function readData() {
38940
38941                                                                 reader.read().then( ( { done, value } ) => {
38942
38943                                                                         if ( done ) {
38944
38945                                                                                 controller.close();
38946
38947                                                                         } else {
38948
38949                                                                                 loaded += value.byteLength;
38950
38951                                                                                 const event = new ProgressEvent( 'progress', { lengthComputable, loaded, total } );
38952                                                                                 for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
38953
38954                                                                                         const callback = callbacks[ i ];
38955                                                                                         if ( callback.onProgress ) callback.onProgress( event );
38956
38957                                                                                 }
38958
38959                                                                                 controller.enqueue( value );
38960                                                                                 readData();
38961
38962                                                                         }
38963
38964                                                                 } );
38965
38966                                                         }
38967
38968                                                 }
38969
38970                                         } );
38971
38972                                 } else {
38973
38974                                         throw Error( `fetch for "${response.url}" responded with ${response.status}: ${response.statusText}` );
38975
38976                                 }
38977
38978                         } )
38979                         .then( stream => {
38980
38981                                 const response = new Response( stream );
38982
38983                                 switch ( this.responseType ) {
38984
38985                                         case 'arraybuffer':
38986
38987                                                 return response.arrayBuffer();
38988
38989                                         case 'blob':
38990
38991                                                 return response.blob();
38992
38993                                         case 'document':
38994
38995                                                 return response.text()
38996                                                         .then( text => {
38997
38998                                                                 const parser = new DOMParser();
38999                                                                 return parser.parseFromString( text, this.mimeType );
39000
39001                                                         } );
39002
39003                                         case 'json':
39004
39005                                                 return response.json();
39006
39007                                         default:
39008
39009                                                 return response.text();
39010
39011                                 }
39012
39013                         } )
39014                         .then( data => {
39015
39016                                 // Add to cache only on HTTP success, so that we do not cache
39017                                 // error response bodies as proper responses to requests.
39018                                 Cache.add( url, data );
39019
39020                                 const callbacks = loading[ url ];
39021                                 delete loading[ url ];
39022
39023                                 for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
39024
39025                                         const callback = callbacks[ i ];
39026                                         if ( callback.onLoad ) callback.onLoad( data );
39027
39028                                 }
39029
39030                                 this.manager.itemEnd( url );
39031
39032                         } )
39033                         .catch( err => {
39034
39035                                 // Abort errors and other errors are handled the same
39036
39037                                 const callbacks = loading[ url ];
39038                                 delete loading[ url ];
39039
39040                                 for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
39041
39042                                         const callback = callbacks[ i ];
39043                                         if ( callback.onError ) callback.onError( err );
39044
39045                                 }
39046
39047                                 this.manager.itemError( url );
39048                                 this.manager.itemEnd( url );
39049
39050                         } );
39051
39052                 this.manager.itemStart( url );
39053
39054         }
39055
39056         setResponseType( value ) {
39057
39058                 this.responseType = value;
39059                 return this;
39060
39061         }
39062
39063         setMimeType( value ) {
39064
39065                 this.mimeType = value;
39066                 return this;
39067
39068         }
39069
39070 }
39071
39072 class ImageLoader extends Loader {
39073
39074         constructor( manager ) {
39075
39076                 super( manager );
39077
39078         }
39079
39080         load( url, onLoad, onProgress, onError ) {
39081
39082                 if ( this.path !== undefined ) url = this.path + url;
39083
39084                 url = this.manager.resolveURL( url );
39085
39086                 const scope = this;
39087
39088                 const cached = Cache.get( url );
39089
39090                 if ( cached !== undefined ) {
39091
39092                         scope.manager.itemStart( url );
39093
39094                         setTimeout( function () {
39095
39096                                 if ( onLoad ) onLoad( cached );
39097
39098                                 scope.manager.itemEnd( url );
39099
39100                         }, 0 );
39101
39102                         return cached;
39103
39104                 }
39105
39106                 const image = createElementNS( 'img' );
39107
39108                 function onImageLoad() {
39109
39110                         removeEventListeners();
39111
39112                         Cache.add( url, this );
39113
39114                         if ( onLoad ) onLoad( this );
39115
39116                         scope.manager.itemEnd( url );
39117
39118                 }
39119
39120                 function onImageError( event ) {
39121
39122                         removeEventListeners();
39123
39124                         if ( onError ) onError( event );
39125
39126                         scope.manager.itemError( url );
39127                         scope.manager.itemEnd( url );
39128
39129                 }
39130
39131                 function removeEventListeners() {
39132
39133                         image.removeEventListener( 'load', onImageLoad, false );
39134                         image.removeEventListener( 'error', onImageError, false );
39135
39136                 }
39137
39138                 image.addEventListener( 'load', onImageLoad, false );
39139                 image.addEventListener( 'error', onImageError, false );
39140
39141                 if ( url.substr( 0, 5 ) !== 'data:' ) {
39142
39143                         if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin;
39144
39145                 }
39146
39147                 scope.manager.itemStart( url );
39148
39149                 image.src = url;
39150
39151                 return image;
39152
39153         }
39154
39155 }
39156
39157 class CubeTextureLoader extends Loader {
39158
39159         constructor( manager ) {
39160
39161                 super( manager );
39162
39163         }
39164
39165         load( urls, onLoad, onProgress, onError ) {
39166
39167                 const texture = new CubeTexture();
39168
39169                 const loader = new ImageLoader( this.manager );
39170                 loader.setCrossOrigin( this.crossOrigin );
39171                 loader.setPath( this.path );
39172
39173                 let loaded = 0;
39174
39175                 function loadTexture( i ) {
39176
39177                         loader.load( urls[ i ], function ( image ) {
39178
39179                                 texture.images[ i ] = image;
39180
39181                                 loaded ++;
39182
39183                                 if ( loaded === 6 ) {
39184
39185                                         texture.needsUpdate = true;
39186
39187                                         if ( onLoad ) onLoad( texture );
39188
39189                                 }
39190
39191                         }, undefined, onError );
39192
39193                 }
39194
39195                 for ( let i = 0; i < urls.length; ++ i ) {
39196
39197                         loadTexture( i );
39198
39199                 }
39200
39201                 return texture;
39202
39203         }
39204
39205 }
39206
39207 class TextureLoader extends Loader {
39208
39209         constructor( manager ) {
39210
39211                 super( manager );
39212
39213         }
39214
39215         load( url, onLoad, onProgress, onError ) {
39216
39217                 const texture = new Texture();
39218
39219                 const loader = new ImageLoader( this.manager );
39220                 loader.setCrossOrigin( this.crossOrigin );
39221                 loader.setPath( this.path );
39222
39223                 loader.load( url, function ( image ) {
39224
39225                         texture.image = image;
39226                         texture.needsUpdate = true;
39227
39228                         if ( onLoad !== undefined ) {
39229
39230                                 onLoad( texture );
39231
39232                         }
39233
39234                 }, onProgress, onError );
39235
39236                 return texture;
39237
39238         }
39239
39240 }
39241
39242 class Light extends Object3D {
39243
39244         constructor( color, intensity = 1 ) {
39245
39246                 super();
39247
39248                 this.type = 'Light';
39249
39250                 this.color = new Color( color );
39251                 this.intensity = intensity;
39252
39253         }
39254
39255         dispose() {
39256
39257                 // Empty here in base class; some subclasses override.
39258
39259         }
39260
39261         copy( source ) {
39262
39263                 super.copy( source );
39264
39265                 this.color.copy( source.color );
39266                 this.intensity = source.intensity;
39267
39268                 return this;
39269
39270         }
39271
39272         toJSON( meta ) {
39273
39274                 const data = super.toJSON( meta );
39275
39276                 data.object.color = this.color.getHex();
39277                 data.object.intensity = this.intensity;
39278
39279                 if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex();
39280
39281                 if ( this.distance !== undefined ) data.object.distance = this.distance;
39282                 if ( this.angle !== undefined ) data.object.angle = this.angle;
39283                 if ( this.decay !== undefined ) data.object.decay = this.decay;
39284                 if ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra;
39285
39286                 if ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON();
39287
39288                 return data;
39289
39290         }
39291
39292 }
39293
39294 Light.prototype.isLight = true;
39295
39296 class HemisphereLight extends Light {
39297
39298         constructor( skyColor, groundColor, intensity ) {
39299
39300                 super( skyColor, intensity );
39301
39302                 this.type = 'HemisphereLight';
39303
39304                 this.position.copy( Object3D.DefaultUp );
39305                 this.updateMatrix();
39306
39307                 this.groundColor = new Color( groundColor );
39308
39309         }
39310
39311         copy( source ) {
39312
39313                 Light.prototype.copy.call( this, source );
39314
39315                 this.groundColor.copy( source.groundColor );
39316
39317                 return this;
39318
39319         }
39320
39321 }
39322
39323 HemisphereLight.prototype.isHemisphereLight = true;
39324
39325 const _projScreenMatrix$1 = /*@__PURE__*/ new Matrix4();
39326 const _lightPositionWorld$1 = /*@__PURE__*/ new Vector3();
39327 const _lookTarget$1 = /*@__PURE__*/ new Vector3();
39328
39329 class LightShadow {
39330
39331         constructor( camera ) {
39332
39333                 this.camera = camera;
39334
39335                 this.bias = 0;
39336                 this.normalBias = 0;
39337                 this.radius = 1;
39338                 this.blurSamples = 8;
39339
39340                 this.mapSize = new Vector2( 512, 512 );
39341
39342                 this.map = null;
39343                 this.mapPass = null;
39344                 this.matrix = new Matrix4();
39345
39346                 this.autoUpdate = true;
39347                 this.needsUpdate = false;
39348
39349                 this._frustum = new Frustum();
39350                 this._frameExtents = new Vector2( 1, 1 );
39351
39352                 this._viewportCount = 1;
39353
39354                 this._viewports = [
39355
39356                         new Vector4( 0, 0, 1, 1 )
39357
39358                 ];
39359
39360         }
39361
39362         getViewportCount() {
39363
39364                 return this._viewportCount;
39365
39366         }
39367
39368         getFrustum() {
39369
39370                 return this._frustum;
39371
39372         }
39373
39374         updateMatrices( light ) {
39375
39376                 const shadowCamera = this.camera;
39377                 const shadowMatrix = this.matrix;
39378
39379                 _lightPositionWorld$1.setFromMatrixPosition( light.matrixWorld );
39380                 shadowCamera.position.copy( _lightPositionWorld$1 );
39381
39382                 _lookTarget$1.setFromMatrixPosition( light.target.matrixWorld );
39383                 shadowCamera.lookAt( _lookTarget$1 );
39384                 shadowCamera.updateMatrixWorld();
39385
39386                 _projScreenMatrix$1.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );
39387                 this._frustum.setFromProjectionMatrix( _projScreenMatrix$1 );
39388
39389                 shadowMatrix.set(
39390                         0.5, 0.0, 0.0, 0.5,
39391                         0.0, 0.5, 0.0, 0.5,
39392                         0.0, 0.0, 0.5, 0.5,
39393                         0.0, 0.0, 0.0, 1.0
39394                 );
39395
39396                 shadowMatrix.multiply( shadowCamera.projectionMatrix );
39397                 shadowMatrix.multiply( shadowCamera.matrixWorldInverse );
39398
39399         }
39400
39401         getViewport( viewportIndex ) {
39402
39403                 return this._viewports[ viewportIndex ];
39404
39405         }
39406
39407         getFrameExtents() {
39408
39409                 return this._frameExtents;
39410
39411         }
39412
39413         dispose() {
39414
39415                 if ( this.map ) {
39416
39417                         this.map.dispose();
39418
39419                 }
39420
39421                 if ( this.mapPass ) {
39422
39423                         this.mapPass.dispose();
39424
39425                 }
39426
39427         }
39428
39429         copy( source ) {
39430
39431                 this.camera = source.camera.clone();
39432
39433                 this.bias = source.bias;
39434                 this.radius = source.radius;
39435
39436                 this.mapSize.copy( source.mapSize );
39437
39438                 return this;
39439
39440         }
39441
39442         clone() {
39443
39444                 return new this.constructor().copy( this );
39445
39446         }
39447
39448         toJSON() {
39449
39450                 const object = {};
39451
39452                 if ( this.bias !== 0 ) object.bias = this.bias;
39453                 if ( this.normalBias !== 0 ) object.normalBias = this.normalBias;
39454                 if ( this.radius !== 1 ) object.radius = this.radius;
39455                 if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray();
39456
39457                 object.camera = this.camera.toJSON( false ).object;
39458                 delete object.camera.matrix;
39459
39460                 return object;
39461
39462         }
39463
39464 }
39465
39466 class SpotLightShadow extends LightShadow {
39467
39468         constructor() {
39469
39470                 super( new PerspectiveCamera( 50, 1, 0.5, 500 ) );
39471
39472                 this.focus = 1;
39473
39474         }
39475
39476         updateMatrices( light ) {
39477
39478                 const camera = this.camera;
39479
39480                 const fov = RAD2DEG$1 * 2 * light.angle * this.focus;
39481                 const aspect = this.mapSize.width / this.mapSize.height;
39482                 const far = light.distance || camera.far;
39483
39484                 if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) {
39485
39486                         camera.fov = fov;
39487                         camera.aspect = aspect;
39488                         camera.far = far;
39489                         camera.updateProjectionMatrix();
39490
39491                 }
39492
39493                 super.updateMatrices( light );
39494
39495         }
39496
39497         copy( source ) {
39498
39499                 super.copy( source );
39500
39501                 this.focus = source.focus;
39502
39503                 return this;
39504
39505         }
39506
39507 }
39508
39509 SpotLightShadow.prototype.isSpotLightShadow = true;
39510
39511 class SpotLight extends Light {
39512
39513         constructor( color, intensity, distance = 0, angle = Math.PI / 3, penumbra = 0, decay = 1 ) {
39514
39515                 super( color, intensity );
39516
39517                 this.type = 'SpotLight';
39518
39519                 this.position.copy( Object3D.DefaultUp );
39520                 this.updateMatrix();
39521
39522                 this.target = new Object3D();
39523
39524                 this.distance = distance;
39525                 this.angle = angle;
39526                 this.penumbra = penumbra;
39527                 this.decay = decay; // for physically correct lights, should be 2.
39528
39529                 this.shadow = new SpotLightShadow();
39530
39531         }
39532
39533         get power() {
39534
39535                 // compute the light's luminous power (in lumens) from its intensity (in candela)
39536                 // by convention for a spotlight, luminous power (lm) = π * luminous intensity (cd)
39537                 return this.intensity * Math.PI;
39538
39539         }
39540
39541         set power( power ) {
39542
39543                 // set the light's intensity (in candela) from the desired luminous power (in lumens)
39544                 this.intensity = power / Math.PI;
39545
39546         }
39547
39548         dispose() {
39549
39550                 this.shadow.dispose();
39551
39552         }
39553
39554         copy( source ) {
39555
39556                 super.copy( source );
39557
39558                 this.distance = source.distance;
39559                 this.angle = source.angle;
39560                 this.penumbra = source.penumbra;
39561                 this.decay = source.decay;
39562
39563                 this.target = source.target.clone();
39564
39565                 this.shadow = source.shadow.clone();
39566
39567                 return this;
39568
39569         }
39570
39571 }
39572
39573 SpotLight.prototype.isSpotLight = true;
39574
39575 const _projScreenMatrix = /*@__PURE__*/ new Matrix4();
39576 const _lightPositionWorld = /*@__PURE__*/ new Vector3();
39577 const _lookTarget = /*@__PURE__*/ new Vector3();
39578
39579 class PointLightShadow extends LightShadow {
39580
39581         constructor() {
39582
39583                 super( new PerspectiveCamera( 90, 1, 0.5, 500 ) );
39584
39585                 this._frameExtents = new Vector2( 4, 2 );
39586
39587                 this._viewportCount = 6;
39588
39589                 this._viewports = [
39590                         // These viewports map a cube-map onto a 2D texture with the
39591                         // following orientation:
39592                         //
39593                         //  xzXZ
39594                         //   y Y
39595                         //
39596                         // X - Positive x direction
39597                         // x - Negative x direction
39598                         // Y - Positive y direction
39599                         // y - Negative y direction
39600                         // Z - Positive z direction
39601                         // z - Negative z direction
39602
39603                         // positive X
39604                         new Vector4( 2, 1, 1, 1 ),
39605                         // negative X
39606                         new Vector4( 0, 1, 1, 1 ),
39607                         // positive Z
39608                         new Vector4( 3, 1, 1, 1 ),
39609                         // negative Z
39610                         new Vector4( 1, 1, 1, 1 ),
39611                         // positive Y
39612                         new Vector4( 3, 0, 1, 1 ),
39613                         // negative Y
39614                         new Vector4( 1, 0, 1, 1 )
39615                 ];
39616
39617                 this._cubeDirections = [
39618                         new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ),
39619                         new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 )
39620                 ];
39621
39622                 this._cubeUps = [
39623                         new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ),
39624                         new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ), new Vector3( 0, 0, - 1 )
39625                 ];
39626
39627         }
39628
39629         updateMatrices( light, viewportIndex = 0 ) {
39630
39631                 const camera = this.camera;
39632                 const shadowMatrix = this.matrix;
39633
39634                 const far = light.distance || camera.far;
39635
39636                 if ( far !== camera.far ) {
39637
39638                         camera.far = far;
39639                         camera.updateProjectionMatrix();
39640
39641                 }
39642
39643                 _lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
39644                 camera.position.copy( _lightPositionWorld );
39645
39646                 _lookTarget.copy( camera.position );
39647                 _lookTarget.add( this._cubeDirections[ viewportIndex ] );
39648                 camera.up.copy( this._cubeUps[ viewportIndex ] );
39649                 camera.lookAt( _lookTarget );
39650                 camera.updateMatrixWorld();
39651
39652                 shadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z );
39653
39654                 _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
39655                 this._frustum.setFromProjectionMatrix( _projScreenMatrix );
39656
39657         }
39658
39659 }
39660
39661 PointLightShadow.prototype.isPointLightShadow = true;
39662
39663 class PointLight extends Light {
39664
39665         constructor( color, intensity, distance = 0, decay = 1 ) {
39666
39667                 super( color, intensity );
39668
39669                 this.type = 'PointLight';
39670
39671                 this.distance = distance;
39672                 this.decay = decay; // for physically correct lights, should be 2.
39673
39674                 this.shadow = new PointLightShadow();
39675
39676         }
39677
39678         get power() {
39679
39680                 // compute the light's luminous power (in lumens) from its intensity (in candela)
39681                 // for an isotropic light source, luminous power (lm) = 4 π luminous intensity (cd)
39682                 return this.intensity * 4 * Math.PI;
39683
39684         }
39685
39686         set power( power ) {
39687
39688                 // set the light's intensity (in candela) from the desired luminous power (in lumens)
39689                 this.intensity = power / ( 4 * Math.PI );
39690
39691         }
39692
39693         dispose() {
39694
39695                 this.shadow.dispose();
39696
39697         }
39698
39699         copy( source ) {
39700
39701                 super.copy( source );
39702
39703                 this.distance = source.distance;
39704                 this.decay = source.decay;
39705
39706                 this.shadow = source.shadow.clone();
39707
39708                 return this;
39709
39710         }
39711
39712 }
39713
39714 PointLight.prototype.isPointLight = true;
39715
39716 class DirectionalLightShadow extends LightShadow {
39717
39718         constructor() {
39719
39720                 super( new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) );
39721
39722         }
39723
39724 }
39725
39726 DirectionalLightShadow.prototype.isDirectionalLightShadow = true;
39727
39728 class DirectionalLight extends Light {
39729
39730         constructor( color, intensity ) {
39731
39732                 super( color, intensity );
39733
39734                 this.type = 'DirectionalLight';
39735
39736                 this.position.copy( Object3D.DefaultUp );
39737                 this.updateMatrix();
39738
39739                 this.target = new Object3D();
39740
39741                 this.shadow = new DirectionalLightShadow();
39742
39743         }
39744
39745         dispose() {
39746
39747                 this.shadow.dispose();
39748
39749         }
39750
39751         copy( source ) {
39752
39753                 super.copy( source );
39754
39755                 this.target = source.target.clone();
39756                 this.shadow = source.shadow.clone();
39757
39758                 return this;
39759
39760         }
39761
39762 }
39763
39764 DirectionalLight.prototype.isDirectionalLight = true;
39765
39766 class AmbientLight extends Light {
39767
39768         constructor( color, intensity ) {
39769
39770                 super( color, intensity );
39771
39772                 this.type = 'AmbientLight';
39773
39774         }
39775
39776 }
39777
39778 AmbientLight.prototype.isAmbientLight = true;
39779
39780 class RectAreaLight extends Light {
39781
39782         constructor( color, intensity, width = 10, height = 10 ) {
39783
39784                 super( color, intensity );
39785
39786                 this.type = 'RectAreaLight';
39787
39788                 this.width = width;
39789                 this.height = height;
39790
39791         }
39792
39793         get power() {
39794
39795                 // compute the light's luminous power (in lumens) from its intensity (in nits)
39796                 return this.intensity * this.width * this.height * Math.PI;
39797
39798         }
39799
39800         set power( power ) {
39801
39802                 // set the light's intensity (in nits) from the desired luminous power (in lumens)
39803                 this.intensity = power / ( this.width * this.height * Math.PI );
39804
39805         }
39806
39807         copy( source ) {
39808
39809                 super.copy( source );
39810
39811                 this.width = source.width;
39812                 this.height = source.height;
39813
39814                 return this;
39815
39816         }
39817
39818         toJSON( meta ) {
39819
39820                 const data = super.toJSON( meta );
39821
39822                 data.object.width = this.width;
39823                 data.object.height = this.height;
39824
39825                 return data;
39826
39827         }
39828
39829 }
39830
39831 RectAreaLight.prototype.isRectAreaLight = true;
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                 this.coefficients = [];
39848
39849                 for ( let i = 0; i < 9; i ++ ) {
39850
39851                         this.coefficients.push( new Vector3() );
39852
39853                 }
39854
39855         }
39856
39857         set( coefficients ) {
39858
39859                 for ( let i = 0; i < 9; i ++ ) {
39860
39861                         this.coefficients[ i ].copy( coefficients[ i ] );
39862
39863                 }
39864
39865                 return this;
39866
39867         }
39868
39869         zero() {
39870
39871                 for ( let i = 0; i < 9; i ++ ) {
39872
39873                         this.coefficients[ i ].set( 0, 0, 0 );
39874
39875                 }
39876
39877                 return this;
39878
39879         }
39880
39881         // get the radiance in the direction of the normal
39882         // target is a Vector3
39883         getAt( normal, target ) {
39884
39885                 // normal is assumed to be unit length
39886
39887                 const x = normal.x, y = normal.y, z = normal.z;
39888
39889                 const coeff = this.coefficients;
39890
39891                 // band 0
39892                 target.copy( coeff[ 0 ] ).multiplyScalar( 0.282095 );
39893
39894                 // band 1
39895                 target.addScaledVector( coeff[ 1 ], 0.488603 * y );
39896                 target.addScaledVector( coeff[ 2 ], 0.488603 * z );
39897                 target.addScaledVector( coeff[ 3 ], 0.488603 * x );
39898
39899                 // band 2
39900                 target.addScaledVector( coeff[ 4 ], 1.092548 * ( x * y ) );
39901                 target.addScaledVector( coeff[ 5 ], 1.092548 * ( y * z ) );
39902                 target.addScaledVector( coeff[ 6 ], 0.315392 * ( 3.0 * z * z - 1.0 ) );
39903                 target.addScaledVector( coeff[ 7 ], 1.092548 * ( x * z ) );
39904                 target.addScaledVector( coeff[ 8 ], 0.546274 * ( x * x - y * y ) );
39905
39906                 return target;
39907
39908         }
39909
39910         // get the irradiance (radiance convolved with cosine lobe) in the direction of the normal
39911         // target is a Vector3
39912         // https://graphics.stanford.edu/papers/envmap/envmap.pdf
39913         getIrradianceAt( normal, target ) {
39914
39915                 // normal is assumed to be unit length
39916
39917                 const x = normal.x, y = normal.y, z = normal.z;
39918
39919                 const coeff = this.coefficients;
39920
39921                 // band 0
39922                 target.copy( coeff[ 0 ] ).multiplyScalar( 0.886227 ); // π * 0.282095
39923
39924                 // band 1
39925                 target.addScaledVector( coeff[ 1 ], 2.0 * 0.511664 * y ); // ( 2 * π / 3 ) * 0.488603
39926                 target.addScaledVector( coeff[ 2 ], 2.0 * 0.511664 * z );
39927                 target.addScaledVector( coeff[ 3 ], 2.0 * 0.511664 * x );
39928
39929                 // band 2
39930                 target.addScaledVector( coeff[ 4 ], 2.0 * 0.429043 * x * y ); // ( π / 4 ) * 1.092548
39931                 target.addScaledVector( coeff[ 5 ], 2.0 * 0.429043 * y * z );
39932                 target.addScaledVector( coeff[ 6 ], 0.743125 * z * z - 0.247708 ); // ( π / 4 ) * 0.315392 * 3
39933                 target.addScaledVector( coeff[ 7 ], 2.0 * 0.429043 * x * z );
39934                 target.addScaledVector( coeff[ 8 ], 0.429043 * ( x * x - y * y ) ); // ( π / 4 ) * 0.546274
39935
39936                 return target;
39937
39938         }
39939
39940         add( sh ) {
39941
39942                 for ( let i = 0; i < 9; i ++ ) {
39943
39944                         this.coefficients[ i ].add( sh.coefficients[ i ] );
39945
39946                 }
39947
39948                 return this;
39949
39950         }
39951
39952         addScaledSH( sh, s ) {
39953
39954                 for ( let i = 0; i < 9; i ++ ) {
39955
39956                         this.coefficients[ i ].addScaledVector( sh.coefficients[ i ], s );
39957
39958                 }
39959
39960                 return this;
39961
39962         }
39963
39964         scale( s ) {
39965
39966                 for ( let i = 0; i < 9; i ++ ) {
39967
39968                         this.coefficients[ i ].multiplyScalar( s );
39969
39970                 }
39971
39972                 return this;
39973
39974         }
39975
39976         lerp( sh, alpha ) {
39977
39978                 for ( let i = 0; i < 9; i ++ ) {
39979
39980                         this.coefficients[ i ].lerp( sh.coefficients[ i ], alpha );
39981
39982                 }
39983
39984                 return this;
39985
39986         }
39987
39988         equals( sh ) {
39989
39990                 for ( let i = 0; i < 9; i ++ ) {
39991
39992                         if ( ! this.coefficients[ i ].equals( sh.coefficients[ i ] ) ) {
39993
39994                                 return false;
39995
39996                         }
39997
39998                 }
39999
40000                 return true;
40001
40002         }
40003
40004         copy( sh ) {
40005
40006                 return this.set( sh.coefficients );
40007
40008         }
40009
40010         clone() {
40011
40012                 return new this.constructor().copy( this );
40013
40014         }
40015
40016         fromArray( array, offset = 0 ) {
40017
40018                 const coefficients = this.coefficients;
40019
40020                 for ( let i = 0; i < 9; i ++ ) {
40021
40022                         coefficients[ i ].fromArray( array, offset + ( i * 3 ) );
40023
40024                 }
40025
40026                 return this;
40027
40028         }
40029
40030         toArray( array = [], offset = 0 ) {
40031
40032                 const coefficients = this.coefficients;
40033
40034                 for ( let i = 0; i < 9; i ++ ) {
40035
40036                         coefficients[ i ].toArray( array, offset + ( i * 3 ) );
40037
40038                 }
40039
40040                 return array;
40041
40042         }
40043
40044         // evaluate the basis functions
40045         // shBasis is an Array[ 9 ]
40046         static getBasisAt( normal, shBasis ) {
40047
40048                 // normal is assumed to be unit length
40049
40050                 const x = normal.x, y = normal.y, z = normal.z;
40051
40052                 // band 0
40053                 shBasis[ 0 ] = 0.282095;
40054
40055                 // band 1
40056                 shBasis[ 1 ] = 0.488603 * y;
40057                 shBasis[ 2 ] = 0.488603 * z;
40058                 shBasis[ 3 ] = 0.488603 * x;
40059
40060                 // band 2
40061                 shBasis[ 4 ] = 1.092548 * x * y;
40062                 shBasis[ 5 ] = 1.092548 * y * z;
40063                 shBasis[ 6 ] = 0.315392 * ( 3 * z * z - 1 );
40064                 shBasis[ 7 ] = 1.092548 * x * z;
40065                 shBasis[ 8 ] = 0.546274 * ( x * x - y * y );
40066
40067         }
40068
40069 }
40070
40071 SphericalHarmonics3.prototype.isSphericalHarmonics3 = true;
40072
40073 class LightProbe extends Light {
40074
40075         constructor( sh = new SphericalHarmonics3(), intensity = 1 ) {
40076
40077                 super( undefined, intensity );
40078
40079                 this.sh = sh;
40080
40081         }
40082
40083         copy( source ) {
40084
40085                 super.copy( source );
40086
40087                 this.sh.copy( source.sh );
40088
40089                 return this;
40090
40091         }
40092
40093         fromJSON( json ) {
40094
40095                 this.intensity = json.intensity; // TODO: Move this bit to Light.fromJSON();
40096                 this.sh.fromArray( json.sh );
40097
40098                 return this;
40099
40100         }
40101
40102         toJSON( meta ) {
40103
40104                 const data = super.toJSON( meta );
40105
40106                 data.object.sh = this.sh.toArray();
40107
40108                 return data;
40109
40110         }
40111
40112 }
40113
40114 LightProbe.prototype.isLightProbe = true;
40115
40116 class LoaderUtils {
40117
40118         static decodeText( array ) {
40119
40120                 if ( typeof TextDecoder !== 'undefined' ) {
40121
40122                         return new TextDecoder().decode( array );
40123
40124                 }
40125
40126                 // Avoid the String.fromCharCode.apply(null, array) shortcut, which
40127                 // throws a "maximum call stack size exceeded" error for large arrays.
40128
40129                 let s = '';
40130
40131                 for ( let i = 0, il = array.length; i < il; i ++ ) {
40132
40133                         // Implicitly assumes little-endian.
40134                         s += String.fromCharCode( array[ i ] );
40135
40136                 }
40137
40138                 try {
40139
40140                         // merges multi-byte utf-8 characters.
40141
40142                         return decodeURIComponent( escape( s ) );
40143
40144                 } catch ( e ) { // see #16358
40145
40146                         return s;
40147
40148                 }
40149
40150         }
40151
40152         static extractUrlBase( url ) {
40153
40154                 const index = url.lastIndexOf( '/' );
40155
40156                 if ( index === - 1 ) return './';
40157
40158                 return url.substr( 0, index + 1 );
40159
40160         }
40161
40162         static resolveURL( url, path ) {
40163
40164                 // Invalid URL
40165                 if ( typeof url !== 'string' || url === '' ) return '';
40166
40167                 // Host Relative URL
40168                 if ( /^https?:\/\//i.test( path ) && /^\//.test( url ) ) {
40169
40170                         path = path.replace( /(^https?:\/\/[^\/]+).*/i, '$1' );
40171
40172                 }
40173
40174                 // Absolute URL http://,https://,//
40175                 if ( /^(https?:)?\/\//i.test( url ) ) return url;
40176
40177                 // Data URI
40178                 if ( /^data:.*,.*$/i.test( url ) ) return url;
40179
40180                 // Blob URL
40181                 if ( /^blob:.*$/i.test( url ) ) return url;
40182
40183                 // Relative URL
40184                 return path + url;
40185
40186         }
40187
40188 }
40189
40190 class InstancedBufferGeometry extends BufferGeometry {
40191
40192         constructor() {
40193
40194                 super();
40195
40196                 this.type = 'InstancedBufferGeometry';
40197                 this.instanceCount = Infinity;
40198
40199         }
40200
40201         copy( source ) {
40202
40203                 super.copy( source );
40204
40205                 this.instanceCount = source.instanceCount;
40206
40207                 return this;
40208
40209         }
40210
40211         clone() {
40212
40213                 return new this.constructor().copy( this );
40214
40215         }
40216
40217         toJSON() {
40218
40219                 const data = super.toJSON( this );
40220
40221                 data.instanceCount = this.instanceCount;
40222
40223                 data.isInstancedBufferGeometry = true;
40224
40225                 return data;
40226
40227         }
40228
40229 }
40230
40231 InstancedBufferGeometry.prototype.isInstancedBufferGeometry = true;
40232
40233 class ImageBitmapLoader extends Loader {
40234
40235         constructor( manager ) {
40236
40237                 super( manager );
40238
40239                 if ( typeof createImageBitmap === 'undefined' ) {
40240
40241                         console.warn( 'THREE.ImageBitmapLoader: createImageBitmap() not supported.' );
40242
40243                 }
40244
40245                 if ( typeof fetch === 'undefined' ) {
40246
40247                         console.warn( 'THREE.ImageBitmapLoader: fetch() not supported.' );
40248
40249                 }
40250
40251                 this.options = { premultiplyAlpha: 'none' };
40252
40253         }
40254
40255         setOptions( options ) {
40256
40257                 this.options = options;
40258
40259                 return this;
40260
40261         }
40262
40263         load( url, onLoad, onProgress, onError ) {
40264
40265                 if ( url === undefined ) url = '';
40266
40267                 if ( this.path !== undefined ) url = this.path + url;
40268
40269                 url = this.manager.resolveURL( url );
40270
40271                 const scope = this;
40272
40273                 const cached = Cache.get( url );
40274
40275                 if ( cached !== undefined ) {
40276
40277                         scope.manager.itemStart( url );
40278
40279                         setTimeout( function () {
40280
40281                                 if ( onLoad ) onLoad( cached );
40282
40283                                 scope.manager.itemEnd( url );
40284
40285                         }, 0 );
40286
40287                         return cached;
40288
40289                 }
40290
40291                 const fetchOptions = {};
40292                 fetchOptions.credentials = ( this.crossOrigin === 'anonymous' ) ? 'same-origin' : 'include';
40293                 fetchOptions.headers = this.requestHeader;
40294
40295                 fetch( url, fetchOptions ).then( function ( res ) {
40296
40297                         return res.blob();
40298
40299                 } ).then( function ( blob ) {
40300
40301                         return createImageBitmap( blob, Object.assign( scope.options, { colorSpaceConversion: 'none' } ) );
40302
40303                 } ).then( function ( imageBitmap ) {
40304
40305                         Cache.add( url, imageBitmap );
40306
40307                         if ( onLoad ) onLoad( imageBitmap );
40308
40309                         scope.manager.itemEnd( url );
40310
40311                 } ).catch( function ( e ) {
40312
40313                         if ( onError ) onError( e );
40314
40315                         scope.manager.itemError( url );
40316                         scope.manager.itemEnd( url );
40317
40318                 } );
40319
40320                 scope.manager.itemStart( url );
40321
40322         }
40323
40324 }
40325
40326 ImageBitmapLoader.prototype.isImageBitmapLoader = true;
40327
40328 let _context;
40329
40330 const AudioContext = {
40331
40332         getContext: function () {
40333
40334                 if ( _context === undefined ) {
40335
40336                         _context = new ( window.AudioContext || window.webkitAudioContext )();
40337
40338                 }
40339
40340                 return _context;
40341
40342         },
40343
40344         setContext: function ( value ) {
40345
40346                 _context = value;
40347
40348         }
40349
40350 };
40351
40352 class AudioLoader extends Loader {
40353
40354         constructor( manager ) {
40355
40356                 super( manager );
40357
40358         }
40359
40360         load( url, onLoad, onProgress, onError ) {
40361
40362                 const scope = this;
40363
40364                 const loader = new FileLoader( this.manager );
40365                 loader.setResponseType( 'arraybuffer' );
40366                 loader.setPath( this.path );
40367                 loader.setRequestHeader( this.requestHeader );
40368                 loader.setWithCredentials( this.withCredentials );
40369                 loader.load( url, function ( buffer ) {
40370
40371                         try {
40372
40373                                 // Create a copy of the buffer. The `decodeAudioData` method
40374                                 // detaches the buffer when complete, preventing reuse.
40375                                 const bufferCopy = buffer.slice( 0 );
40376
40377                                 const context = AudioContext.getContext();
40378                                 context.decodeAudioData( bufferCopy, function ( audioBuffer ) {
40379
40380                                         onLoad( audioBuffer );
40381
40382                                 } );
40383
40384                         } catch ( e ) {
40385
40386                                 if ( onError ) {
40387
40388                                         onError( e );
40389
40390                                 } else {
40391
40392                                         console.error( e );
40393
40394                                 }
40395
40396                                 scope.manager.itemError( url );
40397
40398                         }
40399
40400                 }, onProgress, onError );
40401
40402         }
40403
40404 }
40405
40406 class HemisphereLightProbe extends LightProbe {
40407
40408         constructor( skyColor, groundColor, intensity = 1 ) {
40409
40410                 super( undefined, intensity );
40411
40412                 const color1 = new Color().set( skyColor );
40413                 const color2 = new Color().set( groundColor );
40414
40415                 const sky = new Vector3( color1.r, color1.g, color1.b );
40416                 const ground = new Vector3( color2.r, color2.g, color2.b );
40417
40418                 // without extra factor of PI in the shader, should = 1 / Math.sqrt( Math.PI );
40419                 const c0 = Math.sqrt( Math.PI );
40420                 const c1 = c0 * Math.sqrt( 0.75 );
40421
40422                 this.sh.coefficients[ 0 ].copy( sky ).add( ground ).multiplyScalar( c0 );
40423                 this.sh.coefficients[ 1 ].copy( sky ).sub( ground ).multiplyScalar( c1 );
40424
40425         }
40426
40427 }
40428
40429 HemisphereLightProbe.prototype.isHemisphereLightProbe = true;
40430
40431 class AmbientLightProbe extends LightProbe {
40432
40433         constructor( color, intensity = 1 ) {
40434
40435                 super( undefined, intensity );
40436
40437                 const color1 = new Color().set( color );
40438
40439                 // without extra factor of PI in the shader, would be 2 / Math.sqrt( Math.PI );
40440                 this.sh.coefficients[ 0 ].set( color1.r, color1.g, color1.b ).multiplyScalar( 2 * Math.sqrt( Math.PI ) );
40441
40442         }
40443
40444 }
40445
40446 AmbientLightProbe.prototype.isAmbientLightProbe = true;
40447
40448 class Clock {
40449
40450         constructor( autoStart = true ) {
40451
40452                 this.autoStart = autoStart;
40453
40454                 this.startTime = 0;
40455                 this.oldTime = 0;
40456                 this.elapsedTime = 0;
40457
40458                 this.running = false;
40459
40460         }
40461
40462         start() {
40463
40464                 this.startTime = now();
40465
40466                 this.oldTime = this.startTime;
40467                 this.elapsedTime = 0;
40468                 this.running = true;
40469
40470         }
40471
40472         stop() {
40473
40474                 this.getElapsedTime();
40475                 this.running = false;
40476                 this.autoStart = false;
40477
40478         }
40479
40480         getElapsedTime() {
40481
40482                 this.getDelta();
40483                 return this.elapsedTime;
40484
40485         }
40486
40487         getDelta() {
40488
40489                 let diff = 0;
40490
40491                 if ( this.autoStart && ! this.running ) {
40492
40493                         this.start();
40494                         return 0;
40495
40496                 }
40497
40498                 if ( this.running ) {
40499
40500                         const newTime = now();
40501
40502                         diff = ( newTime - this.oldTime ) / 1000;
40503                         this.oldTime = newTime;
40504
40505                         this.elapsedTime += diff;
40506
40507                 }
40508
40509                 return diff;
40510
40511         }
40512
40513 }
40514
40515 function now() {
40516
40517         return ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732
40518
40519 }
40520
40521 class Audio extends Object3D {
40522
40523         constructor( listener ) {
40524
40525                 super();
40526
40527                 this.type = 'Audio';
40528
40529                 this.listener = listener;
40530                 this.context = listener.context;
40531
40532                 this.gain = this.context.createGain();
40533                 this.gain.connect( listener.getInput() );
40534
40535                 this.autoplay = false;
40536
40537                 this.buffer = null;
40538                 this.detune = 0;
40539                 this.loop = false;
40540                 this.loopStart = 0;
40541                 this.loopEnd = 0;
40542                 this.offset = 0;
40543                 this.duration = undefined;
40544                 this.playbackRate = 1;
40545                 this.isPlaying = false;
40546                 this.hasPlaybackControl = true;
40547                 this.source = null;
40548                 this.sourceType = 'empty';
40549
40550                 this._startedAt = 0;
40551                 this._progress = 0;
40552                 this._connected = false;
40553
40554                 this.filters = [];
40555
40556         }
40557
40558         getOutput() {
40559
40560                 return this.gain;
40561
40562         }
40563
40564         setNodeSource( audioNode ) {
40565
40566                 this.hasPlaybackControl = false;
40567                 this.sourceType = 'audioNode';
40568                 this.source = audioNode;
40569                 this.connect();
40570
40571                 return this;
40572
40573         }
40574
40575         setMediaElementSource( mediaElement ) {
40576
40577                 this.hasPlaybackControl = false;
40578                 this.sourceType = 'mediaNode';
40579                 this.source = this.context.createMediaElementSource( mediaElement );
40580                 this.connect();
40581
40582                 return this;
40583
40584         }
40585
40586         setMediaStreamSource( mediaStream ) {
40587
40588                 this.hasPlaybackControl = false;
40589                 this.sourceType = 'mediaStreamNode';
40590                 this.source = this.context.createMediaStreamSource( mediaStream );
40591                 this.connect();
40592
40593                 return this;
40594
40595         }
40596
40597         setBuffer( audioBuffer ) {
40598
40599                 this.buffer = audioBuffer;
40600                 this.sourceType = 'buffer';
40601
40602                 if ( this.autoplay ) this.play();
40603
40604                 return this;
40605
40606         }
40607
40608         play( delay = 0 ) {
40609
40610                 if ( this.isPlaying === true ) {
40611
40612                         console.warn( 'THREE.Audio: Audio is already playing.' );
40613                         return;
40614
40615                 }
40616
40617                 if ( this.hasPlaybackControl === false ) {
40618
40619                         console.warn( 'THREE.Audio: this Audio has no playback control.' );
40620                         return;
40621
40622                 }
40623
40624                 this._startedAt = this.context.currentTime + delay;
40625
40626                 const source = this.context.createBufferSource();
40627                 source.buffer = this.buffer;
40628                 source.loop = this.loop;
40629                 source.loopStart = this.loopStart;
40630                 source.loopEnd = this.loopEnd;
40631                 source.onended = this.onEnded.bind( this );
40632                 source.start( this._startedAt, this._progress + this.offset, this.duration );
40633
40634                 this.isPlaying = true;
40635
40636                 this.source = source;
40637
40638                 this.setDetune( this.detune );
40639                 this.setPlaybackRate( this.playbackRate );
40640
40641                 return this.connect();
40642
40643         }
40644
40645         pause() {
40646
40647                 if ( this.hasPlaybackControl === false ) {
40648
40649                         console.warn( 'THREE.Audio: this Audio has no playback control.' );
40650                         return;
40651
40652                 }
40653
40654                 if ( this.isPlaying === true ) {
40655
40656                         // update current progress
40657
40658                         this._progress += Math.max( this.context.currentTime - this._startedAt, 0 ) * this.playbackRate;
40659
40660                         if ( this.loop === true ) {
40661
40662                                 // ensure _progress does not exceed duration with looped audios
40663
40664                                 this._progress = this._progress % ( this.duration || this.buffer.duration );
40665
40666                         }
40667
40668                         this.source.stop();
40669                         this.source.onended = null;
40670
40671                         this.isPlaying = false;
40672
40673                 }
40674
40675                 return this;
40676
40677         }
40678
40679         stop() {
40680
40681                 if ( this.hasPlaybackControl === false ) {
40682
40683                         console.warn( 'THREE.Audio: this Audio has no playback control.' );
40684                         return;
40685
40686                 }
40687
40688                 this._progress = 0;
40689
40690                 this.source.stop();
40691                 this.source.onended = null;
40692                 this.isPlaying = false;
40693
40694                 return this;
40695
40696         }
40697
40698         connect() {
40699
40700                 if ( this.filters.length > 0 ) {
40701
40702                         this.source.connect( this.filters[ 0 ] );
40703
40704                         for ( let i = 1, l = this.filters.length; i < l; i ++ ) {
40705
40706                                 this.filters[ i - 1 ].connect( this.filters[ i ] );
40707
40708                         }
40709
40710                         this.filters[ this.filters.length - 1 ].connect( this.getOutput() );
40711
40712                 } else {
40713
40714                         this.source.connect( this.getOutput() );
40715
40716                 }
40717
40718                 this._connected = true;
40719
40720                 return this;
40721
40722         }
40723
40724         disconnect() {
40725
40726                 if ( this.filters.length > 0 ) {
40727
40728                         this.source.disconnect( this.filters[ 0 ] );
40729
40730                         for ( let i = 1, l = this.filters.length; i < l; i ++ ) {
40731
40732                                 this.filters[ i - 1 ].disconnect( this.filters[ i ] );
40733
40734                         }
40735
40736                         this.filters[ this.filters.length - 1 ].disconnect( this.getOutput() );
40737
40738                 } else {
40739
40740                         this.source.disconnect( this.getOutput() );
40741
40742                 }
40743
40744                 this._connected = false;
40745
40746                 return this;
40747
40748         }
40749
40750         getFilters() {
40751
40752                 return this.filters;
40753
40754         }
40755
40756         setFilters( value ) {
40757
40758                 if ( ! value ) value = [];
40759
40760                 if ( this._connected === true ) {
40761
40762                         this.disconnect();
40763                         this.filters = value.slice();
40764                         this.connect();
40765
40766                 } else {
40767
40768                         this.filters = value.slice();
40769
40770                 }
40771
40772                 return this;
40773
40774         }
40775
40776         setDetune( value ) {
40777
40778                 this.detune = value;
40779
40780                 if ( this.source.detune === undefined ) return; // only set detune when available
40781
40782                 if ( this.isPlaying === true ) {
40783
40784                         this.source.detune.setTargetAtTime( this.detune, this.context.currentTime, 0.01 );
40785
40786                 }
40787
40788                 return this;
40789
40790         }
40791
40792         getDetune() {
40793
40794                 return this.detune;
40795
40796         }
40797
40798         getFilter() {
40799
40800                 return this.getFilters()[ 0 ];
40801
40802         }
40803
40804         setFilter( filter ) {
40805
40806                 return this.setFilters( filter ? [ filter ] : [] );
40807
40808         }
40809
40810         setPlaybackRate( value ) {
40811
40812                 if ( this.hasPlaybackControl === false ) {
40813
40814                         console.warn( 'THREE.Audio: this Audio has no playback control.' );
40815                         return;
40816
40817                 }
40818
40819                 this.playbackRate = value;
40820
40821                 if ( this.isPlaying === true ) {
40822
40823                         this.source.playbackRate.setTargetAtTime( this.playbackRate, this.context.currentTime, 0.01 );
40824
40825                 }
40826
40827                 return this;
40828
40829         }
40830
40831         getPlaybackRate() {
40832
40833                 return this.playbackRate;
40834
40835         }
40836
40837         onEnded() {
40838
40839                 this.isPlaying = false;
40840
40841         }
40842
40843         getLoop() {
40844
40845                 if ( this.hasPlaybackControl === false ) {
40846
40847                         console.warn( 'THREE.Audio: this Audio has no playback control.' );
40848                         return false;
40849
40850                 }
40851
40852                 return this.loop;
40853
40854         }
40855
40856         setLoop( value ) {
40857
40858                 if ( this.hasPlaybackControl === false ) {
40859
40860                         console.warn( 'THREE.Audio: this Audio has no playback control.' );
40861                         return;
40862
40863                 }
40864
40865                 this.loop = value;
40866
40867                 if ( this.isPlaying === true ) {
40868
40869                         this.source.loop = this.loop;
40870
40871                 }
40872
40873                 return this;
40874
40875         }
40876
40877         setLoopStart( value ) {
40878
40879                 this.loopStart = value;
40880
40881                 return this;
40882
40883         }
40884
40885         setLoopEnd( value ) {
40886
40887                 this.loopEnd = value;
40888
40889                 return this;
40890
40891         }
40892
40893         getVolume() {
40894
40895                 return this.gain.gain.value;
40896
40897         }
40898
40899         setVolume( value ) {
40900
40901                 this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 );
40902
40903                 return this;
40904
40905         }
40906
40907 }
40908
40909 class PropertyMixer {
40910
40911         constructor( binding, typeName, valueSize ) {
40912
40913                 this.binding = binding;
40914                 this.valueSize = valueSize;
40915
40916                 let mixFunction,
40917                         mixFunctionAdditive,
40918                         setIdentity;
40919
40920                 // buffer layout: [ incoming | accu0 | accu1 | orig | addAccu | (optional work) ]
40921                 //
40922                 // interpolators can use .buffer as their .result
40923                 // the data then goes to 'incoming'
40924                 //
40925                 // 'accu0' and 'accu1' are used frame-interleaved for
40926                 // the cumulative result and are compared to detect
40927                 // changes
40928                 //
40929                 // 'orig' stores the original state of the property
40930                 //
40931                 // 'add' is used for additive cumulative results
40932                 //
40933                 // 'work' is optional and is only present for quaternion types. It is used
40934                 // to store intermediate quaternion multiplication results
40935
40936                 switch ( typeName ) {
40937
40938                         case 'quaternion':
40939                                 mixFunction = this._slerp;
40940                                 mixFunctionAdditive = this._slerpAdditive;
40941                                 setIdentity = this._setAdditiveIdentityQuaternion;
40942
40943                                 this.buffer = new Float64Array( valueSize * 6 );
40944                                 this._workIndex = 5;
40945                                 break;
40946
40947                         case 'string':
40948                         case 'bool':
40949                                 mixFunction = this._select;
40950
40951                                 // Use the regular mix function and for additive on these types,
40952                                 // additive is not relevant for non-numeric types
40953                                 mixFunctionAdditive = this._select;
40954
40955                                 setIdentity = this._setAdditiveIdentityOther;
40956
40957                                 this.buffer = new Array( valueSize * 5 );
40958                                 break;
40959
40960                         default:
40961                                 mixFunction = this._lerp;
40962                                 mixFunctionAdditive = this._lerpAdditive;
40963                                 setIdentity = this._setAdditiveIdentityNumeric;
40964
40965                                 this.buffer = new Float64Array( valueSize * 5 );
40966
40967                 }
40968
40969                 this._mixBufferRegion = mixFunction;
40970                 this._mixBufferRegionAdditive = mixFunctionAdditive;
40971                 this._setIdentity = setIdentity;
40972                 this._origIndex = 3;
40973                 this._addIndex = 4;
40974
40975                 this.cumulativeWeight = 0;
40976                 this.cumulativeWeightAdditive = 0;
40977
40978                 this.useCount = 0;
40979                 this.referenceCount = 0;
40980
40981         }
40982
40983         // accumulate data in the 'incoming' region into 'accu<i>'
40984         accumulate( accuIndex, weight ) {
40985
40986                 // note: happily accumulating nothing when weight = 0, the caller knows
40987                 // the weight and shouldn't have made the call in the first place
40988
40989                 const buffer = this.buffer,
40990                         stride = this.valueSize,
40991                         offset = accuIndex * stride + stride;
40992
40993                 let currentWeight = this.cumulativeWeight;
40994
40995                 if ( currentWeight === 0 ) {
40996
40997                         // accuN := incoming * weight
40998
40999                         for ( let i = 0; i !== stride; ++ i ) {
41000
41001                                 buffer[ offset + i ] = buffer[ i ];
41002
41003                         }
41004
41005                         currentWeight = weight;
41006
41007                 } else {
41008
41009                         // accuN := accuN + incoming * weight
41010
41011                         currentWeight += weight;
41012                         const mix = weight / currentWeight;
41013                         this._mixBufferRegion( buffer, offset, 0, mix, stride );
41014
41015                 }
41016
41017                 this.cumulativeWeight = currentWeight;
41018
41019         }
41020
41021         // accumulate data in the 'incoming' region into 'add'
41022         accumulateAdditive( weight ) {
41023
41024                 const buffer = this.buffer,
41025                         stride = this.valueSize,
41026                         offset = stride * this._addIndex;
41027
41028                 if ( this.cumulativeWeightAdditive === 0 ) {
41029
41030                         // add = identity
41031
41032                         this._setIdentity();
41033
41034                 }
41035
41036                 // add := add + incoming * weight
41037
41038                 this._mixBufferRegionAdditive( buffer, offset, 0, weight, stride );
41039                 this.cumulativeWeightAdditive += weight;
41040
41041         }
41042
41043         // apply the state of 'accu<i>' to the binding when accus differ
41044         apply( accuIndex ) {
41045
41046                 const stride = this.valueSize,
41047                         buffer = this.buffer,
41048                         offset = accuIndex * stride + stride,
41049
41050                         weight = this.cumulativeWeight,
41051                         weightAdditive = this.cumulativeWeightAdditive,
41052
41053                         binding = this.binding;
41054
41055                 this.cumulativeWeight = 0;
41056                 this.cumulativeWeightAdditive = 0;
41057
41058                 if ( weight < 1 ) {
41059
41060                         // accuN := accuN + original * ( 1 - cumulativeWeight )
41061
41062                         const originalValueOffset = stride * this._origIndex;
41063
41064                         this._mixBufferRegion(
41065                                 buffer, offset, originalValueOffset, 1 - weight, stride );
41066
41067                 }
41068
41069                 if ( weightAdditive > 0 ) {
41070
41071                         // accuN := accuN + additive accuN
41072
41073                         this._mixBufferRegionAdditive( buffer, offset, this._addIndex * stride, 1, stride );
41074
41075                 }
41076
41077                 for ( let i = stride, e = stride + stride; i !== e; ++ i ) {
41078
41079                         if ( buffer[ i ] !== buffer[ i + stride ] ) {
41080
41081                                 // value has changed -> update scene graph
41082
41083                                 binding.setValue( buffer, offset );
41084                                 break;
41085
41086                         }
41087
41088                 }
41089
41090         }
41091
41092         // remember the state of the bound property and copy it to both accus
41093         saveOriginalState() {
41094
41095                 const binding = this.binding;
41096
41097                 const buffer = this.buffer,
41098                         stride = this.valueSize,
41099
41100                         originalValueOffset = stride * this._origIndex;
41101
41102                 binding.getValue( buffer, originalValueOffset );
41103
41104                 // accu[0..1] := orig -- initially detect changes against the original
41105                 for ( let i = stride, e = originalValueOffset; i !== e; ++ i ) {
41106
41107                         buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ];
41108
41109                 }
41110
41111                 // Add to identity for additive
41112                 this._setIdentity();
41113
41114                 this.cumulativeWeight = 0;
41115                 this.cumulativeWeightAdditive = 0;
41116
41117         }
41118
41119         // apply the state previously taken via 'saveOriginalState' to the binding
41120         restoreOriginalState() {
41121
41122                 const originalValueOffset = this.valueSize * 3;
41123                 this.binding.setValue( this.buffer, originalValueOffset );
41124
41125         }
41126
41127         _setAdditiveIdentityNumeric() {
41128
41129                 const startIndex = this._addIndex * this.valueSize;
41130                 const endIndex = startIndex + this.valueSize;
41131
41132                 for ( let i = startIndex; i < endIndex; i ++ ) {
41133
41134                         this.buffer[ i ] = 0;
41135
41136                 }
41137
41138         }
41139
41140         _setAdditiveIdentityQuaternion() {
41141
41142                 this._setAdditiveIdentityNumeric();
41143                 this.buffer[ this._addIndex * this.valueSize + 3 ] = 1;
41144
41145         }
41146
41147         _setAdditiveIdentityOther() {
41148
41149                 const startIndex = this._origIndex * this.valueSize;
41150                 const targetIndex = this._addIndex * this.valueSize;
41151
41152                 for ( let i = 0; i < this.valueSize; i ++ ) {
41153
41154                         this.buffer[ targetIndex + i ] = this.buffer[ startIndex + i ];
41155
41156                 }
41157
41158         }
41159
41160
41161         // mix functions
41162
41163         _select( buffer, dstOffset, srcOffset, t, stride ) {
41164
41165                 if ( t >= 0.5 ) {
41166
41167                         for ( let i = 0; i !== stride; ++ i ) {
41168
41169                                 buffer[ dstOffset + i ] = buffer[ srcOffset + i ];
41170
41171                         }
41172
41173                 }
41174
41175         }
41176
41177         _slerp( buffer, dstOffset, srcOffset, t ) {
41178
41179                 Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t );
41180
41181         }
41182
41183         _slerpAdditive( buffer, dstOffset, srcOffset, t, stride ) {
41184
41185                 const workOffset = this._workIndex * stride;
41186
41187                 // Store result in intermediate buffer offset
41188                 Quaternion.multiplyQuaternionsFlat( buffer, workOffset, buffer, dstOffset, buffer, srcOffset );
41189
41190                 // Slerp to the intermediate result
41191                 Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, workOffset, t );
41192
41193         }
41194
41195         _lerp( buffer, dstOffset, srcOffset, t, stride ) {
41196
41197                 const s = 1 - t;
41198
41199                 for ( let i = 0; i !== stride; ++ i ) {
41200
41201                         const j = dstOffset + i;
41202
41203                         buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t;
41204
41205                 }
41206
41207         }
41208
41209         _lerpAdditive( buffer, dstOffset, srcOffset, t, stride ) {
41210
41211                 for ( let i = 0; i !== stride; ++ i ) {
41212
41213                         const j = dstOffset + i;
41214
41215                         buffer[ j ] = buffer[ j ] + buffer[ srcOffset + i ] * t;
41216
41217                 }
41218
41219         }
41220
41221 }
41222
41223 // Characters [].:/ are reserved for track binding syntax.
41224 const _RESERVED_CHARS_RE = '\\[\\]\\.:\\/';
41225 const _reservedRe = new RegExp( '[' + _RESERVED_CHARS_RE + ']', 'g' );
41226
41227 // Attempts to allow node names from any language. ES5's `\w` regexp matches
41228 // only latin characters, and the unicode \p{L} is not yet supported. So
41229 // instead, we exclude reserved characters and match everything else.
41230 const _wordChar = '[^' + _RESERVED_CHARS_RE + ']';
41231 const _wordCharOrDot = '[^' + _RESERVED_CHARS_RE.replace( '\\.', '' ) + ']';
41232
41233 // Parent directories, delimited by '/' or ':'. Currently unused, but must
41234 // be matched to parse the rest of the track name.
41235 const _directoryRe = /((?:WC+[\/:])*)/.source.replace( 'WC', _wordChar );
41236
41237 // Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'.
41238 const _nodeRe = /(WCOD+)?/.source.replace( 'WCOD', _wordCharOrDot );
41239
41240 // Object on target node, and accessor. May not contain reserved
41241 // characters. Accessor may contain any character except closing bracket.
41242 const _objectRe = /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace( 'WC', _wordChar );
41243
41244 // Property and accessor. May not contain reserved characters. Accessor may
41245 // contain any non-bracket characters.
41246 const _propertyRe = /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC', _wordChar );
41247
41248 const _trackRe = new RegExp( ''
41249         + '^'
41250         + _directoryRe
41251         + _nodeRe
41252         + _objectRe
41253         + _propertyRe
41254         + '$'
41255 );
41256
41257 const _supportedObjectNames = [ 'material', 'materials', 'bones' ];
41258
41259 class Composite {
41260
41261         constructor( targetGroup, path, optionalParsedPath ) {
41262
41263                 const parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path );
41264
41265                 this._targetGroup = targetGroup;
41266                 this._bindings = targetGroup.subscribe_( path, parsedPath );
41267
41268         }
41269
41270         getValue( array, offset ) {
41271
41272                 this.bind(); // bind all binding
41273
41274                 const firstValidIndex = this._targetGroup.nCachedObjects_,
41275                         binding = this._bindings[ firstValidIndex ];
41276
41277                 // and only call .getValue on the first
41278                 if ( binding !== undefined ) binding.getValue( array, offset );
41279
41280         }
41281
41282         setValue( array, offset ) {
41283
41284                 const bindings = this._bindings;
41285
41286                 for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {
41287
41288                         bindings[ i ].setValue( array, offset );
41289
41290                 }
41291
41292         }
41293
41294         bind() {
41295
41296                 const bindings = this._bindings;
41297
41298                 for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {
41299
41300                         bindings[ i ].bind();
41301
41302                 }
41303
41304         }
41305
41306         unbind() {
41307
41308                 const bindings = this._bindings;
41309
41310                 for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {
41311
41312                         bindings[ i ].unbind();
41313
41314                 }
41315
41316         }
41317
41318 }
41319
41320 // Note: This class uses a State pattern on a per-method basis:
41321 // 'bind' sets 'this.getValue' / 'setValue' and shadows the
41322 // prototype version of these methods with one that represents
41323 // the bound state. When the property is not found, the methods
41324 // become no-ops.
41325 class PropertyBinding {
41326
41327         constructor( rootNode, path, parsedPath ) {
41328
41329                 this.path = path;
41330                 this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path );
41331
41332                 this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName ) || rootNode;
41333
41334                 this.rootNode = rootNode;
41335
41336                 // initial state of these methods that calls 'bind'
41337                 this.getValue = this._getValue_unbound;
41338                 this.setValue = this._setValue_unbound;
41339
41340         }
41341
41342
41343         static create( root, path, parsedPath ) {
41344
41345                 if ( ! ( root && root.isAnimationObjectGroup ) ) {
41346
41347                         return new PropertyBinding( root, path, parsedPath );
41348
41349                 } else {
41350
41351                         return new PropertyBinding.Composite( root, path, parsedPath );
41352
41353                 }
41354
41355         }
41356
41357         /**
41358          * Replaces spaces with underscores and removes unsupported characters from
41359          * node names, to ensure compatibility with parseTrackName().
41360          *
41361          * @param {string} name Node name to be sanitized.
41362          * @return {string}
41363          */
41364         static sanitizeNodeName( name ) {
41365
41366                 return name.replace( /\s/g, '_' ).replace( _reservedRe, '' );
41367
41368         }
41369
41370         static parseTrackName( trackName ) {
41371
41372                 const matches = _trackRe.exec( trackName );
41373
41374                 if ( ! matches ) {
41375
41376                         throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName );
41377
41378                 }
41379
41380                 const results = {
41381                         // directoryName: matches[ 1 ], // (tschw) currently unused
41382                         nodeName: matches[ 2 ],
41383                         objectName: matches[ 3 ],
41384                         objectIndex: matches[ 4 ],
41385                         propertyName: matches[ 5 ], // required
41386                         propertyIndex: matches[ 6 ]
41387                 };
41388
41389                 const lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' );
41390
41391                 if ( lastDot !== undefined && lastDot !== - 1 ) {
41392
41393                         const objectName = results.nodeName.substring( lastDot + 1 );
41394
41395                         // Object names must be checked against an allowlist. Otherwise, there
41396                         // is no way to parse 'foo.bar.baz': 'baz' must be a property, but
41397                         // 'bar' could be the objectName, or part of a nodeName (which can
41398                         // include '.' characters).
41399                         if ( _supportedObjectNames.indexOf( objectName ) !== - 1 ) {
41400
41401                                 results.nodeName = results.nodeName.substring( 0, lastDot );
41402                                 results.objectName = objectName;
41403
41404                         }
41405
41406                 }
41407
41408                 if ( results.propertyName === null || results.propertyName.length === 0 ) {
41409
41410                         throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName );
41411
41412                 }
41413
41414                 return results;
41415
41416         }
41417
41418         static findNode( root, nodeName ) {
41419
41420                 if ( ! nodeName || nodeName === '' || nodeName === '.' || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) {
41421
41422                         return root;
41423
41424                 }
41425
41426                 // search into skeleton bones.
41427                 if ( root.skeleton ) {
41428
41429                         const bone = root.skeleton.getBoneByName( nodeName );
41430
41431                         if ( bone !== undefined ) {
41432
41433                                 return bone;
41434
41435                         }
41436
41437                 }
41438
41439                 // search into node subtree.
41440                 if ( root.children ) {
41441
41442                         const searchNodeSubtree = function ( children ) {
41443
41444                                 for ( let i = 0; i < children.length; i ++ ) {
41445
41446                                         const childNode = children[ i ];
41447
41448                                         if ( childNode.name === nodeName || childNode.uuid === nodeName ) {
41449
41450                                                 return childNode;
41451
41452                                         }
41453
41454                                         const result = searchNodeSubtree( childNode.children );
41455
41456                                         if ( result ) return result;
41457
41458                                 }
41459
41460                                 return null;
41461
41462                         };
41463
41464                         const subTreeNode = searchNodeSubtree( root.children );
41465
41466                         if ( subTreeNode ) {
41467
41468                                 return subTreeNode;
41469
41470                         }
41471
41472                 }
41473
41474                 return null;
41475
41476         }
41477
41478         // these are used to "bind" a nonexistent property
41479         _getValue_unavailable() {}
41480         _setValue_unavailable() {}
41481
41482         // Getters
41483
41484         _getValue_direct( buffer, offset ) {
41485
41486                 buffer[ offset ] = this.targetObject[ this.propertyName ];
41487
41488         }
41489
41490         _getValue_array( buffer, offset ) {
41491
41492                 const source = this.resolvedProperty;
41493
41494                 for ( let i = 0, n = source.length; i !== n; ++ i ) {
41495
41496                         buffer[ offset ++ ] = source[ i ];
41497
41498                 }
41499
41500         }
41501
41502         _getValue_arrayElement( buffer, offset ) {
41503
41504                 buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ];
41505
41506         }
41507
41508         _getValue_toArray( buffer, offset ) {
41509
41510                 this.resolvedProperty.toArray( buffer, offset );
41511
41512         }
41513
41514         // Direct
41515
41516         _setValue_direct( buffer, offset ) {
41517
41518                 this.targetObject[ this.propertyName ] = buffer[ offset ];
41519
41520         }
41521
41522         _setValue_direct_setNeedsUpdate( buffer, offset ) {
41523
41524                 this.targetObject[ this.propertyName ] = buffer[ offset ];
41525                 this.targetObject.needsUpdate = true;
41526
41527         }
41528
41529         _setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) {
41530
41531                 this.targetObject[ this.propertyName ] = buffer[ offset ];
41532                 this.targetObject.matrixWorldNeedsUpdate = true;
41533
41534         }
41535
41536         // EntireArray
41537
41538         _setValue_array( buffer, offset ) {
41539
41540                 const dest = this.resolvedProperty;
41541
41542                 for ( let i = 0, n = dest.length; i !== n; ++ i ) {
41543
41544                         dest[ i ] = buffer[ offset ++ ];
41545
41546                 }
41547
41548         }
41549
41550         _setValue_array_setNeedsUpdate( buffer, offset ) {
41551
41552                 const dest = this.resolvedProperty;
41553
41554                 for ( let i = 0, n = dest.length; i !== n; ++ i ) {
41555
41556                         dest[ i ] = buffer[ offset ++ ];
41557
41558                 }
41559
41560                 this.targetObject.needsUpdate = true;
41561
41562         }
41563
41564         _setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) {
41565
41566                 const dest = this.resolvedProperty;
41567
41568                 for ( let i = 0, n = dest.length; i !== n; ++ i ) {
41569
41570                         dest[ i ] = buffer[ offset ++ ];
41571
41572                 }
41573
41574                 this.targetObject.matrixWorldNeedsUpdate = true;
41575
41576         }
41577
41578         // ArrayElement
41579
41580         _setValue_arrayElement( buffer, offset ) {
41581
41582                 this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
41583
41584         }
41585
41586         _setValue_arrayElement_setNeedsUpdate( buffer, offset ) {
41587
41588                 this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
41589                 this.targetObject.needsUpdate = true;
41590
41591         }
41592
41593         _setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) {
41594
41595                 this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
41596                 this.targetObject.matrixWorldNeedsUpdate = true;
41597
41598         }
41599
41600         // HasToFromArray
41601
41602         _setValue_fromArray( buffer, offset ) {
41603
41604                 this.resolvedProperty.fromArray( buffer, offset );
41605
41606         }
41607
41608         _setValue_fromArray_setNeedsUpdate( buffer, offset ) {
41609
41610                 this.resolvedProperty.fromArray( buffer, offset );
41611                 this.targetObject.needsUpdate = true;
41612
41613         }
41614
41615         _setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) {
41616
41617                 this.resolvedProperty.fromArray( buffer, offset );
41618                 this.targetObject.matrixWorldNeedsUpdate = true;
41619
41620         }
41621
41622         _getValue_unbound( targetArray, offset ) {
41623
41624                 this.bind();
41625                 this.getValue( targetArray, offset );
41626
41627         }
41628
41629         _setValue_unbound( sourceArray, offset ) {
41630
41631                 this.bind();
41632                 this.setValue( sourceArray, offset );
41633
41634         }
41635
41636         // create getter / setter pair for a property in the scene graph
41637         bind() {
41638
41639                 let targetObject = this.node;
41640                 const parsedPath = this.parsedPath;
41641
41642                 const objectName = parsedPath.objectName;
41643                 const propertyName = parsedPath.propertyName;
41644                 let propertyIndex = parsedPath.propertyIndex;
41645
41646                 if ( ! targetObject ) {
41647
41648                         targetObject = PropertyBinding.findNode( this.rootNode, parsedPath.nodeName ) || this.rootNode;
41649
41650                         this.node = targetObject;
41651
41652                 }
41653
41654                 // set fail state so we can just 'return' on error
41655                 this.getValue = this._getValue_unavailable;
41656                 this.setValue = this._setValue_unavailable;
41657
41658                 // ensure there is a value node
41659                 if ( ! targetObject ) {
41660
41661                         console.error( 'THREE.PropertyBinding: Trying to update node for track: ' + this.path + ' but it wasn\'t found.' );
41662                         return;
41663
41664                 }
41665
41666                 if ( objectName ) {
41667
41668                         let objectIndex = parsedPath.objectIndex;
41669
41670                         // special cases were we need to reach deeper into the hierarchy to get the face materials....
41671                         switch ( objectName ) {
41672
41673                                 case 'materials':
41674
41675                                         if ( ! targetObject.material ) {
41676
41677                                                 console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this );
41678                                                 return;
41679
41680                                         }
41681
41682                                         if ( ! targetObject.material.materials ) {
41683
41684                                                 console.error( 'THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this );
41685                                                 return;
41686
41687                                         }
41688
41689                                         targetObject = targetObject.material.materials;
41690
41691                                         break;
41692
41693                                 case 'bones':
41694
41695                                         if ( ! targetObject.skeleton ) {
41696
41697                                                 console.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this );
41698                                                 return;
41699
41700                                         }
41701
41702                                         // potential future optimization: skip this if propertyIndex is already an integer
41703                                         // and convert the integer string to a true integer.
41704
41705                                         targetObject = targetObject.skeleton.bones;
41706
41707                                         // support resolving morphTarget names into indices.
41708                                         for ( let i = 0; i < targetObject.length; i ++ ) {
41709
41710                                                 if ( targetObject[ i ].name === objectIndex ) {
41711
41712                                                         objectIndex = i;
41713                                                         break;
41714
41715                                                 }
41716
41717                                         }
41718
41719                                         break;
41720
41721                                 default:
41722
41723                                         if ( targetObject[ objectName ] === undefined ) {
41724
41725                                                 console.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this );
41726                                                 return;
41727
41728                                         }
41729
41730                                         targetObject = targetObject[ objectName ];
41731
41732                         }
41733
41734
41735                         if ( objectIndex !== undefined ) {
41736
41737                                 if ( targetObject[ objectIndex ] === undefined ) {
41738
41739                                         console.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject );
41740                                         return;
41741
41742                                 }
41743
41744                                 targetObject = targetObject[ objectIndex ];
41745
41746                         }
41747
41748                 }
41749
41750                 // resolve property
41751                 const nodeProperty = targetObject[ propertyName ];
41752
41753                 if ( nodeProperty === undefined ) {
41754
41755                         const nodeName = parsedPath.nodeName;
41756
41757                         console.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName +
41758                                 '.' + propertyName + ' but it wasn\'t found.', targetObject );
41759                         return;
41760
41761                 }
41762
41763                 // determine versioning scheme
41764                 let versioning = this.Versioning.None;
41765
41766                 this.targetObject = targetObject;
41767
41768                 if ( targetObject.needsUpdate !== undefined ) { // material
41769
41770                         versioning = this.Versioning.NeedsUpdate;
41771
41772                 } else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform
41773
41774                         versioning = this.Versioning.MatrixWorldNeedsUpdate;
41775
41776                 }
41777
41778                 // determine how the property gets bound
41779                 let bindingType = this.BindingType.Direct;
41780
41781                 if ( propertyIndex !== undefined ) {
41782
41783                         // access a sub element of the property array (only primitives are supported right now)
41784
41785                         if ( propertyName === 'morphTargetInfluences' ) {
41786
41787                                 // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer.
41788
41789                                 // support resolving morphTarget names into indices.
41790                                 if ( ! targetObject.geometry ) {
41791
41792                                         console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this );
41793                                         return;
41794
41795                                 }
41796
41797                                 if ( targetObject.geometry.isBufferGeometry ) {
41798
41799                                         if ( ! targetObject.geometry.morphAttributes ) {
41800
41801                                                 console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this );
41802                                                 return;
41803
41804                                         }
41805
41806                                         if ( targetObject.morphTargetDictionary[ propertyIndex ] !== undefined ) {
41807
41808                                                 propertyIndex = targetObject.morphTargetDictionary[ propertyIndex ];
41809
41810                                         }
41811
41812
41813                                 } else {
41814
41815                                         console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences on THREE.Geometry. Use THREE.BufferGeometry instead.', this );
41816                                         return;
41817
41818                                 }
41819
41820                         }
41821
41822                         bindingType = this.BindingType.ArrayElement;
41823
41824                         this.resolvedProperty = nodeProperty;
41825                         this.propertyIndex = propertyIndex;
41826
41827                 } else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) {
41828
41829                         // must use copy for Object3D.Euler/Quaternion
41830
41831                         bindingType = this.BindingType.HasFromToArray;
41832
41833                         this.resolvedProperty = nodeProperty;
41834
41835                 } else if ( Array.isArray( nodeProperty ) ) {
41836
41837                         bindingType = this.BindingType.EntireArray;
41838
41839                         this.resolvedProperty = nodeProperty;
41840
41841                 } else {
41842
41843                         this.propertyName = propertyName;
41844
41845                 }
41846
41847                 // select getter / setter
41848                 this.getValue = this.GetterByBindingType[ bindingType ];
41849                 this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ];
41850
41851         }
41852
41853         unbind() {
41854
41855                 this.node = null;
41856
41857                 // back to the prototype version of getValue / setValue
41858                 // note: avoiding to mutate the shape of 'this' via 'delete'
41859                 this.getValue = this._getValue_unbound;
41860                 this.setValue = this._setValue_unbound;
41861
41862         }
41863
41864 }
41865
41866 PropertyBinding.Composite = Composite;
41867
41868 PropertyBinding.prototype.BindingType = {
41869         Direct: 0,
41870         EntireArray: 1,
41871         ArrayElement: 2,
41872         HasFromToArray: 3
41873 };
41874
41875 PropertyBinding.prototype.Versioning = {
41876         None: 0,
41877         NeedsUpdate: 1,
41878         MatrixWorldNeedsUpdate: 2
41879 };
41880
41881 PropertyBinding.prototype.GetterByBindingType = [
41882
41883         PropertyBinding.prototype._getValue_direct,
41884         PropertyBinding.prototype._getValue_array,
41885         PropertyBinding.prototype._getValue_arrayElement,
41886         PropertyBinding.prototype._getValue_toArray,
41887
41888 ];
41889
41890 PropertyBinding.prototype.SetterByBindingTypeAndVersioning = [
41891
41892         [
41893                 // Direct
41894                 PropertyBinding.prototype._setValue_direct,
41895                 PropertyBinding.prototype._setValue_direct_setNeedsUpdate,
41896                 PropertyBinding.prototype._setValue_direct_setMatrixWorldNeedsUpdate,
41897
41898         ], [
41899
41900                 // EntireArray
41901
41902                 PropertyBinding.prototype._setValue_array,
41903                 PropertyBinding.prototype._setValue_array_setNeedsUpdate,
41904                 PropertyBinding.prototype._setValue_array_setMatrixWorldNeedsUpdate,
41905
41906         ], [
41907
41908                 // ArrayElement
41909                 PropertyBinding.prototype._setValue_arrayElement,
41910                 PropertyBinding.prototype._setValue_arrayElement_setNeedsUpdate,
41911                 PropertyBinding.prototype._setValue_arrayElement_setMatrixWorldNeedsUpdate,
41912
41913         ], [
41914
41915                 // HasToFromArray
41916                 PropertyBinding.prototype._setValue_fromArray,
41917                 PropertyBinding.prototype._setValue_fromArray_setNeedsUpdate,
41918                 PropertyBinding.prototype._setValue_fromArray_setMatrixWorldNeedsUpdate,
41919
41920         ]
41921
41922 ];
41923
41924 class AnimationAction {
41925
41926         constructor( mixer, clip, localRoot = null, blendMode = clip.blendMode ) {
41927
41928                 this._mixer = mixer;
41929                 this._clip = clip;
41930                 this._localRoot = localRoot;
41931                 this.blendMode = blendMode;
41932
41933                 const tracks = clip.tracks,
41934                         nTracks = tracks.length,
41935                         interpolants = new Array( nTracks );
41936
41937                 const interpolantSettings = {
41938                         endingStart: ZeroCurvatureEnding,
41939                         endingEnd: ZeroCurvatureEnding
41940                 };
41941
41942                 for ( let i = 0; i !== nTracks; ++ i ) {
41943
41944                         const interpolant = tracks[ i ].createInterpolant( null );
41945                         interpolants[ i ] = interpolant;
41946                         interpolant.settings = interpolantSettings;
41947
41948                 }
41949
41950                 this._interpolantSettings = interpolantSettings;
41951
41952                 this._interpolants = interpolants; // bound by the mixer
41953
41954                 // inside: PropertyMixer (managed by the mixer)
41955                 this._propertyBindings = new Array( nTracks );
41956
41957                 this._cacheIndex = null; // for the memory manager
41958                 this._byClipCacheIndex = null; // for the memory manager
41959
41960                 this._timeScaleInterpolant = null;
41961                 this._weightInterpolant = null;
41962
41963                 this.loop = LoopRepeat;
41964                 this._loopCount = - 1;
41965
41966                 // global mixer time when the action is to be started
41967                 // it's set back to 'null' upon start of the action
41968                 this._startTime = null;
41969
41970                 // scaled local time of the action
41971                 // gets clamped or wrapped to 0..clip.duration according to loop
41972                 this.time = 0;
41973
41974                 this.timeScale = 1;
41975                 this._effectiveTimeScale = 1;
41976
41977                 this.weight = 1;
41978                 this._effectiveWeight = 1;
41979
41980                 this.repetitions = Infinity; // no. of repetitions when looping
41981
41982                 this.paused = false; // true -> zero effective time scale
41983                 this.enabled = true; // false -> zero effective weight
41984
41985                 this.clampWhenFinished = false;// keep feeding the last frame?
41986
41987                 this.zeroSlopeAtStart = true;// for smooth interpolation w/o separate
41988                 this.zeroSlopeAtEnd = true;// clips for start, loop and end
41989
41990         }
41991
41992         // State & Scheduling
41993
41994         play() {
41995
41996                 this._mixer._activateAction( this );
41997
41998                 return this;
41999
42000         }
42001
42002         stop() {
42003
42004                 this._mixer._deactivateAction( this );
42005
42006                 return this.reset();
42007
42008         }
42009
42010         reset() {
42011
42012                 this.paused = false;
42013                 this.enabled = true;
42014
42015                 this.time = 0; // restart clip
42016                 this._loopCount = - 1;// forget previous loops
42017                 this._startTime = null;// forget scheduling
42018
42019                 return this.stopFading().stopWarping();
42020
42021         }
42022
42023         isRunning() {
42024
42025                 return this.enabled && ! this.paused && this.timeScale !== 0 &&
42026                         this._startTime === null && this._mixer._isActiveAction( this );
42027
42028         }
42029
42030         // return true when play has been called
42031         isScheduled() {
42032
42033                 return this._mixer._isActiveAction( this );
42034
42035         }
42036
42037         startAt( time ) {
42038
42039                 this._startTime = time;
42040
42041                 return this;
42042
42043         }
42044
42045         setLoop( mode, repetitions ) {
42046
42047                 this.loop = mode;
42048                 this.repetitions = repetitions;
42049
42050                 return this;
42051
42052         }
42053
42054         // Weight
42055
42056         // set the weight stopping any scheduled fading
42057         // although .enabled = false yields an effective weight of zero, this
42058         // method does *not* change .enabled, because it would be confusing
42059         setEffectiveWeight( weight ) {
42060
42061                 this.weight = weight;
42062
42063                 // note: same logic as when updated at runtime
42064                 this._effectiveWeight = this.enabled ? weight : 0;
42065
42066                 return this.stopFading();
42067
42068         }
42069
42070         // return the weight considering fading and .enabled
42071         getEffectiveWeight() {
42072
42073                 return this._effectiveWeight;
42074
42075         }
42076
42077         fadeIn( duration ) {
42078
42079                 return this._scheduleFading( duration, 0, 1 );
42080
42081         }
42082
42083         fadeOut( duration ) {
42084
42085                 return this._scheduleFading( duration, 1, 0 );
42086
42087         }
42088
42089         crossFadeFrom( fadeOutAction, duration, warp ) {
42090
42091                 fadeOutAction.fadeOut( duration );
42092                 this.fadeIn( duration );
42093
42094                 if ( warp ) {
42095
42096                         const fadeInDuration = this._clip.duration,
42097                                 fadeOutDuration = fadeOutAction._clip.duration,
42098
42099                                 startEndRatio = fadeOutDuration / fadeInDuration,
42100                                 endStartRatio = fadeInDuration / fadeOutDuration;
42101
42102                         fadeOutAction.warp( 1.0, startEndRatio, duration );
42103                         this.warp( endStartRatio, 1.0, duration );
42104
42105                 }
42106
42107                 return this;
42108
42109         }
42110
42111         crossFadeTo( fadeInAction, duration, warp ) {
42112
42113                 return fadeInAction.crossFadeFrom( this, duration, warp );
42114
42115         }
42116
42117         stopFading() {
42118
42119                 const weightInterpolant = this._weightInterpolant;
42120
42121                 if ( weightInterpolant !== null ) {
42122
42123                         this._weightInterpolant = null;
42124                         this._mixer._takeBackControlInterpolant( weightInterpolant );
42125
42126                 }
42127
42128                 return this;
42129
42130         }
42131
42132         // Time Scale Control
42133
42134         // set the time scale stopping any scheduled warping
42135         // although .paused = true yields an effective time scale of zero, this
42136         // method does *not* change .paused, because it would be confusing
42137         setEffectiveTimeScale( timeScale ) {
42138
42139                 this.timeScale = timeScale;
42140                 this._effectiveTimeScale = this.paused ? 0 : timeScale;
42141
42142                 return this.stopWarping();
42143
42144         }
42145
42146         // return the time scale considering warping and .paused
42147         getEffectiveTimeScale() {
42148
42149                 return this._effectiveTimeScale;
42150
42151         }
42152
42153         setDuration( duration ) {
42154
42155                 this.timeScale = this._clip.duration / duration;
42156
42157                 return this.stopWarping();
42158
42159         }
42160
42161         syncWith( action ) {
42162
42163                 this.time = action.time;
42164                 this.timeScale = action.timeScale;
42165
42166                 return this.stopWarping();
42167
42168         }
42169
42170         halt( duration ) {
42171
42172                 return this.warp( this._effectiveTimeScale, 0, duration );
42173
42174         }
42175
42176         warp( startTimeScale, endTimeScale, duration ) {
42177
42178                 const mixer = this._mixer,
42179                         now = mixer.time,
42180                         timeScale = this.timeScale;
42181
42182                 let interpolant = this._timeScaleInterpolant;
42183
42184                 if ( interpolant === null ) {
42185
42186                         interpolant = mixer._lendControlInterpolant();
42187                         this._timeScaleInterpolant = interpolant;
42188
42189                 }
42190
42191                 const times = interpolant.parameterPositions,
42192                         values = interpolant.sampleValues;
42193
42194                 times[ 0 ] = now;
42195                 times[ 1 ] = now + duration;
42196
42197                 values[ 0 ] = startTimeScale / timeScale;
42198                 values[ 1 ] = endTimeScale / timeScale;
42199
42200                 return this;
42201
42202         }
42203
42204         stopWarping() {
42205
42206                 const timeScaleInterpolant = this._timeScaleInterpolant;
42207
42208                 if ( timeScaleInterpolant !== null ) {
42209
42210                         this._timeScaleInterpolant = null;
42211                         this._mixer._takeBackControlInterpolant( timeScaleInterpolant );
42212
42213                 }
42214
42215                 return this;
42216
42217         }
42218
42219         // Object Accessors
42220
42221         getMixer() {
42222
42223                 return this._mixer;
42224
42225         }
42226
42227         getClip() {
42228
42229                 return this._clip;
42230
42231         }
42232
42233         getRoot() {
42234
42235                 return this._localRoot || this._mixer._root;
42236
42237         }
42238
42239         // Interna
42240
42241         _update( time, deltaTime, timeDirection, accuIndex ) {
42242
42243                 // called by the mixer
42244
42245                 if ( ! this.enabled ) {
42246
42247                         // call ._updateWeight() to update ._effectiveWeight
42248
42249                         this._updateWeight( time );
42250                         return;
42251
42252                 }
42253
42254                 const startTime = this._startTime;
42255
42256                 if ( startTime !== null ) {
42257
42258                         // check for scheduled start of action
42259
42260                         const timeRunning = ( time - startTime ) * timeDirection;
42261                         if ( timeRunning < 0 || timeDirection === 0 ) {
42262
42263                                 return; // yet to come / don't decide when delta = 0
42264
42265                         }
42266
42267                         // start
42268
42269                         this._startTime = null; // unschedule
42270                         deltaTime = timeDirection * timeRunning;
42271
42272                 }
42273
42274                 // apply time scale and advance time
42275
42276                 deltaTime *= this._updateTimeScale( time );
42277                 const clipTime = this._updateTime( deltaTime );
42278
42279                 // note: _updateTime may disable the action resulting in
42280                 // an effective weight of 0
42281
42282                 const weight = this._updateWeight( time );
42283
42284                 if ( weight > 0 ) {
42285
42286                         const interpolants = this._interpolants;
42287                         const propertyMixers = this._propertyBindings;
42288
42289                         switch ( this.blendMode ) {
42290
42291                                 case AdditiveAnimationBlendMode:
42292
42293                                         for ( let j = 0, m = interpolants.length; j !== m; ++ j ) {
42294
42295                                                 interpolants[ j ].evaluate( clipTime );
42296                                                 propertyMixers[ j ].accumulateAdditive( weight );
42297
42298                                         }
42299
42300                                         break;
42301
42302                                 case NormalAnimationBlendMode:
42303                                 default:
42304
42305                                         for ( let j = 0, m = interpolants.length; j !== m; ++ j ) {
42306
42307                                                 interpolants[ j ].evaluate( clipTime );
42308                                                 propertyMixers[ j ].accumulate( accuIndex, weight );
42309
42310                                         }
42311
42312                         }
42313
42314                 }
42315
42316         }
42317
42318         _updateWeight( time ) {
42319
42320                 let weight = 0;
42321
42322                 if ( this.enabled ) {
42323
42324                         weight = this.weight;
42325                         const interpolant = this._weightInterpolant;
42326
42327                         if ( interpolant !== null ) {
42328
42329                                 const interpolantValue = interpolant.evaluate( time )[ 0 ];
42330
42331                                 weight *= interpolantValue;
42332
42333                                 if ( time > interpolant.parameterPositions[ 1 ] ) {
42334
42335                                         this.stopFading();
42336
42337                                         if ( interpolantValue === 0 ) {
42338
42339                                                 // faded out, disable
42340                                                 this.enabled = false;
42341
42342                                         }
42343
42344                                 }
42345
42346                         }
42347
42348                 }
42349
42350                 this._effectiveWeight = weight;
42351                 return weight;
42352
42353         }
42354
42355         _updateTimeScale( time ) {
42356
42357                 let timeScale = 0;
42358
42359                 if ( ! this.paused ) {
42360
42361                         timeScale = this.timeScale;
42362
42363                         const interpolant = this._timeScaleInterpolant;
42364
42365                         if ( interpolant !== null ) {
42366
42367                                 const interpolantValue = interpolant.evaluate( time )[ 0 ];
42368
42369                                 timeScale *= interpolantValue;
42370
42371                                 if ( time > interpolant.parameterPositions[ 1 ] ) {
42372
42373                                         this.stopWarping();
42374
42375                                         if ( timeScale === 0 ) {
42376
42377                                                 // motion has halted, pause
42378                                                 this.paused = true;
42379
42380                                         } else {
42381
42382                                                 // warp done - apply final time scale
42383                                                 this.timeScale = timeScale;
42384
42385                                         }
42386
42387                                 }
42388
42389                         }
42390
42391                 }
42392
42393                 this._effectiveTimeScale = timeScale;
42394                 return timeScale;
42395
42396         }
42397
42398         _updateTime( deltaTime ) {
42399
42400                 const duration = this._clip.duration;
42401                 const loop = this.loop;
42402
42403                 let time = this.time + deltaTime;
42404                 let loopCount = this._loopCount;
42405
42406                 const pingPong = ( loop === LoopPingPong );
42407
42408                 if ( deltaTime === 0 ) {
42409
42410                         if ( loopCount === - 1 ) return time;
42411
42412                         return ( pingPong && ( loopCount & 1 ) === 1 ) ? duration - time : time;
42413
42414                 }
42415
42416                 if ( loop === LoopOnce ) {
42417
42418                         if ( loopCount === - 1 ) {
42419
42420                                 // just started
42421
42422                                 this._loopCount = 0;
42423                                 this._setEndings( true, true, false );
42424
42425                         }
42426
42427                         handle_stop: {
42428
42429                                 if ( time >= duration ) {
42430
42431                                         time = duration;
42432
42433                                 } else if ( time < 0 ) {
42434
42435                                         time = 0;
42436
42437                                 } else {
42438
42439                                         this.time = time;
42440
42441                                         break handle_stop;
42442
42443                                 }
42444
42445                                 if ( this.clampWhenFinished ) this.paused = true;
42446                                 else this.enabled = false;
42447
42448                                 this.time = time;
42449
42450                                 this._mixer.dispatchEvent( {
42451                                         type: 'finished', action: this,
42452                                         direction: deltaTime < 0 ? - 1 : 1
42453                                 } );
42454
42455                         }
42456
42457                 } else { // repetitive Repeat or PingPong
42458
42459                         if ( loopCount === - 1 ) {
42460
42461                                 // just started
42462
42463                                 if ( deltaTime >= 0 ) {
42464
42465                                         loopCount = 0;
42466
42467                                         this._setEndings( true, this.repetitions === 0, pingPong );
42468
42469                                 } else {
42470
42471                                         // when looping in reverse direction, the initial
42472                                         // transition through zero counts as a repetition,
42473                                         // so leave loopCount at -1
42474
42475                                         this._setEndings( this.repetitions === 0, true, pingPong );
42476
42477                                 }
42478
42479                         }
42480
42481                         if ( time >= duration || time < 0 ) {
42482
42483                                 // wrap around
42484
42485                                 const loopDelta = Math.floor( time / duration ); // signed
42486                                 time -= duration * loopDelta;
42487
42488                                 loopCount += Math.abs( loopDelta );
42489
42490                                 const pending = this.repetitions - loopCount;
42491
42492                                 if ( pending <= 0 ) {
42493
42494                                         // have to stop (switch state, clamp time, fire event)
42495
42496                                         if ( this.clampWhenFinished ) this.paused = true;
42497                                         else this.enabled = false;
42498
42499                                         time = deltaTime > 0 ? duration : 0;
42500
42501                                         this.time = time;
42502
42503                                         this._mixer.dispatchEvent( {
42504                                                 type: 'finished', action: this,
42505                                                 direction: deltaTime > 0 ? 1 : - 1
42506                                         } );
42507
42508                                 } else {
42509
42510                                         // keep running
42511
42512                                         if ( pending === 1 ) {
42513
42514                                                 // entering the last round
42515
42516                                                 const atStart = deltaTime < 0;
42517                                                 this._setEndings( atStart, ! atStart, pingPong );
42518
42519                                         } else {
42520
42521                                                 this._setEndings( false, false, pingPong );
42522
42523                                         }
42524
42525                                         this._loopCount = loopCount;
42526
42527                                         this.time = time;
42528
42529                                         this._mixer.dispatchEvent( {
42530                                                 type: 'loop', action: this, loopDelta: loopDelta
42531                                         } );
42532
42533                                 }
42534
42535                         } else {
42536
42537                                 this.time = time;
42538
42539                         }
42540
42541                         if ( pingPong && ( loopCount & 1 ) === 1 ) {
42542
42543                                 // invert time for the "pong round"
42544
42545                                 return duration - time;
42546
42547                         }
42548
42549                 }
42550
42551                 return time;
42552
42553         }
42554
42555         _setEndings( atStart, atEnd, pingPong ) {
42556
42557                 const settings = this._interpolantSettings;
42558
42559                 if ( pingPong ) {
42560
42561                         settings.endingStart = ZeroSlopeEnding;
42562                         settings.endingEnd = ZeroSlopeEnding;
42563
42564                 } else {
42565
42566                         // assuming for LoopOnce atStart == atEnd == true
42567
42568                         if ( atStart ) {
42569
42570                                 settings.endingStart = this.zeroSlopeAtStart ? ZeroSlopeEnding : ZeroCurvatureEnding;
42571
42572                         } else {
42573
42574                                 settings.endingStart = WrapAroundEnding;
42575
42576                         }
42577
42578                         if ( atEnd ) {
42579
42580                                 settings.endingEnd = this.zeroSlopeAtEnd ? ZeroSlopeEnding : ZeroCurvatureEnding;
42581
42582                         } else {
42583
42584                                 settings.endingEnd       = WrapAroundEnding;
42585
42586                         }
42587
42588                 }
42589
42590         }
42591
42592         _scheduleFading( duration, weightNow, weightThen ) {
42593
42594                 const mixer = this._mixer, now = mixer.time;
42595                 let interpolant = this._weightInterpolant;
42596
42597                 if ( interpolant === null ) {
42598
42599                         interpolant = mixer._lendControlInterpolant();
42600                         this._weightInterpolant = interpolant;
42601
42602                 }
42603
42604                 const times = interpolant.parameterPositions,
42605                         values = interpolant.sampleValues;
42606
42607                 times[ 0 ] = now;
42608                 values[ 0 ] = weightNow;
42609                 times[ 1 ] = now + duration;
42610                 values[ 1 ] = weightThen;
42611
42612                 return this;
42613
42614         }
42615
42616 }
42617
42618 class AnimationMixer extends EventDispatcher {
42619
42620         constructor( root ) {
42621
42622                 super();
42623
42624                 this._root = root;
42625                 this._initMemoryManager();
42626                 this._accuIndex = 0;
42627                 this.time = 0;
42628                 this.timeScale = 1.0;
42629
42630         }
42631
42632         _bindAction( action, prototypeAction ) {
42633
42634                 const root = action._localRoot || this._root,
42635                         tracks = action._clip.tracks,
42636                         nTracks = tracks.length,
42637                         bindings = action._propertyBindings,
42638                         interpolants = action._interpolants,
42639                         rootUuid = root.uuid,
42640                         bindingsByRoot = this._bindingsByRootAndName;
42641
42642                 let bindingsByName = bindingsByRoot[ rootUuid ];
42643
42644                 if ( bindingsByName === undefined ) {
42645
42646                         bindingsByName = {};
42647                         bindingsByRoot[ rootUuid ] = bindingsByName;
42648
42649                 }
42650
42651                 for ( let i = 0; i !== nTracks; ++ i ) {
42652
42653                         const track = tracks[ i ],
42654                                 trackName = track.name;
42655
42656                         let binding = bindingsByName[ trackName ];
42657
42658                         if ( binding !== undefined ) {
42659
42660                                 bindings[ i ] = binding;
42661
42662                         } else {
42663
42664                                 binding = bindings[ i ];
42665
42666                                 if ( binding !== undefined ) {
42667
42668                                         // existing binding, make sure the cache knows
42669
42670                                         if ( binding._cacheIndex === null ) {
42671
42672                                                 ++ binding.referenceCount;
42673                                                 this._addInactiveBinding( binding, rootUuid, trackName );
42674
42675                                         }
42676
42677                                         continue;
42678
42679                                 }
42680
42681                                 const path = prototypeAction && prototypeAction.
42682                                         _propertyBindings[ i ].binding.parsedPath;
42683
42684                                 binding = new PropertyMixer(
42685                                         PropertyBinding.create( root, trackName, path ),
42686                                         track.ValueTypeName, track.getValueSize() );
42687
42688                                 ++ binding.referenceCount;
42689                                 this._addInactiveBinding( binding, rootUuid, trackName );
42690
42691                                 bindings[ i ] = binding;
42692
42693                         }
42694
42695                         interpolants[ i ].resultBuffer = binding.buffer;
42696
42697                 }
42698
42699         }
42700
42701         _activateAction( action ) {
42702
42703                 if ( ! this._isActiveAction( action ) ) {
42704
42705                         if ( action._cacheIndex === null ) {
42706
42707                                 // this action has been forgotten by the cache, but the user
42708                                 // appears to be still using it -> rebind
42709
42710                                 const rootUuid = ( action._localRoot || this._root ).uuid,
42711                                         clipUuid = action._clip.uuid,
42712                                         actionsForClip = this._actionsByClip[ clipUuid ];
42713
42714                                 this._bindAction( action,
42715                                         actionsForClip && actionsForClip.knownActions[ 0 ] );
42716
42717                                 this._addInactiveAction( action, clipUuid, rootUuid );
42718
42719                         }
42720
42721                         const bindings = action._propertyBindings;
42722
42723                         // increment reference counts / sort out state
42724                         for ( let i = 0, n = bindings.length; i !== n; ++ i ) {
42725
42726                                 const binding = bindings[ i ];
42727
42728                                 if ( binding.useCount ++ === 0 ) {
42729
42730                                         this._lendBinding( binding );
42731                                         binding.saveOriginalState();
42732
42733                                 }
42734
42735                         }
42736
42737                         this._lendAction( action );
42738
42739                 }
42740
42741         }
42742
42743         _deactivateAction( action ) {
42744
42745                 if ( this._isActiveAction( action ) ) {
42746
42747                         const bindings = action._propertyBindings;
42748
42749                         // decrement reference counts / sort out state
42750                         for ( let i = 0, n = bindings.length; i !== n; ++ i ) {
42751
42752                                 const binding = bindings[ i ];
42753
42754                                 if ( -- binding.useCount === 0 ) {
42755
42756                                         binding.restoreOriginalState();
42757                                         this._takeBackBinding( binding );
42758
42759                                 }
42760
42761                         }
42762
42763                         this._takeBackAction( action );
42764
42765                 }
42766
42767         }
42768
42769         // Memory manager
42770
42771         _initMemoryManager() {
42772
42773                 this._actions = []; // 'nActiveActions' followed by inactive ones
42774                 this._nActiveActions = 0;
42775
42776                 this._actionsByClip = {};
42777                 // inside:
42778                 // {
42779                 //      knownActions: Array< AnimationAction > - used as prototypes
42780                 //      actionByRoot: AnimationAction - lookup
42781                 // }
42782
42783
42784                 this._bindings = []; // 'nActiveBindings' followed by inactive ones
42785                 this._nActiveBindings = 0;
42786
42787                 this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer >
42788
42789
42790                 this._controlInterpolants = []; // same game as above
42791                 this._nActiveControlInterpolants = 0;
42792
42793                 const scope = this;
42794
42795                 this.stats = {
42796
42797                         actions: {
42798                                 get total() {
42799
42800                                         return scope._actions.length;
42801
42802                                 },
42803                                 get inUse() {
42804
42805                                         return scope._nActiveActions;
42806
42807                                 }
42808                         },
42809                         bindings: {
42810                                 get total() {
42811
42812                                         return scope._bindings.length;
42813
42814                                 },
42815                                 get inUse() {
42816
42817                                         return scope._nActiveBindings;
42818
42819                                 }
42820                         },
42821                         controlInterpolants: {
42822                                 get total() {
42823
42824                                         return scope._controlInterpolants.length;
42825
42826                                 },
42827                                 get inUse() {
42828
42829                                         return scope._nActiveControlInterpolants;
42830
42831                                 }
42832                         }
42833
42834                 };
42835
42836         }
42837
42838         // Memory management for AnimationAction objects
42839
42840         _isActiveAction( action ) {
42841
42842                 const index = action._cacheIndex;
42843                 return index !== null && index < this._nActiveActions;
42844
42845         }
42846
42847         _addInactiveAction( action, clipUuid, rootUuid ) {
42848
42849                 const actions = this._actions,
42850                         actionsByClip = this._actionsByClip;
42851
42852                 let actionsForClip = actionsByClip[ clipUuid ];
42853
42854                 if ( actionsForClip === undefined ) {
42855
42856                         actionsForClip = {
42857
42858                                 knownActions: [ action ],
42859                                 actionByRoot: {}
42860
42861                         };
42862
42863                         action._byClipCacheIndex = 0;
42864
42865                         actionsByClip[ clipUuid ] = actionsForClip;
42866
42867                 } else {
42868
42869                         const knownActions = actionsForClip.knownActions;
42870
42871                         action._byClipCacheIndex = knownActions.length;
42872                         knownActions.push( action );
42873
42874                 }
42875
42876                 action._cacheIndex = actions.length;
42877                 actions.push( action );
42878
42879                 actionsForClip.actionByRoot[ rootUuid ] = action;
42880
42881         }
42882
42883         _removeInactiveAction( action ) {
42884
42885                 const actions = this._actions,
42886                         lastInactiveAction = actions[ actions.length - 1 ],
42887                         cacheIndex = action._cacheIndex;
42888
42889                 lastInactiveAction._cacheIndex = cacheIndex;
42890                 actions[ cacheIndex ] = lastInactiveAction;
42891                 actions.pop();
42892
42893                 action._cacheIndex = null;
42894
42895
42896                 const clipUuid = action._clip.uuid,
42897                         actionsByClip = this._actionsByClip,
42898                         actionsForClip = actionsByClip[ clipUuid ],
42899                         knownActionsForClip = actionsForClip.knownActions,
42900
42901                         lastKnownAction =
42902                                 knownActionsForClip[ knownActionsForClip.length - 1 ],
42903
42904                         byClipCacheIndex = action._byClipCacheIndex;
42905
42906                 lastKnownAction._byClipCacheIndex = byClipCacheIndex;
42907                 knownActionsForClip[ byClipCacheIndex ] = lastKnownAction;
42908                 knownActionsForClip.pop();
42909
42910                 action._byClipCacheIndex = null;
42911
42912
42913                 const actionByRoot = actionsForClip.actionByRoot,
42914                         rootUuid = ( action._localRoot || this._root ).uuid;
42915
42916                 delete actionByRoot[ rootUuid ];
42917
42918                 if ( knownActionsForClip.length === 0 ) {
42919
42920                         delete actionsByClip[ clipUuid ];
42921
42922                 }
42923
42924                 this._removeInactiveBindingsForAction( action );
42925
42926         }
42927
42928         _removeInactiveBindingsForAction( action ) {
42929
42930                 const bindings = action._propertyBindings;
42931
42932                 for ( let i = 0, n = bindings.length; i !== n; ++ i ) {
42933
42934                         const binding = bindings[ i ];
42935
42936                         if ( -- binding.referenceCount === 0 ) {
42937
42938                                 this._removeInactiveBinding( binding );
42939
42940                         }
42941
42942                 }
42943
42944         }
42945
42946         _lendAction( action ) {
42947
42948                 // [ active actions |  inactive actions  ]
42949                 // [  active actions >| inactive actions ]
42950                 //                 s        a
42951                 //                  <-swap->
42952                 //                 a        s
42953
42954                 const actions = this._actions,
42955                         prevIndex = action._cacheIndex,
42956
42957                         lastActiveIndex = this._nActiveActions ++,
42958
42959                         firstInactiveAction = actions[ lastActiveIndex ];
42960
42961                 action._cacheIndex = lastActiveIndex;
42962                 actions[ lastActiveIndex ] = action;
42963
42964                 firstInactiveAction._cacheIndex = prevIndex;
42965                 actions[ prevIndex ] = firstInactiveAction;
42966
42967         }
42968
42969         _takeBackAction( action ) {
42970
42971                 // [  active actions  | inactive actions ]
42972                 // [ active actions |< inactive actions  ]
42973                 //        a        s
42974                 //         <-swap->
42975                 //        s        a
42976
42977                 const actions = this._actions,
42978                         prevIndex = action._cacheIndex,
42979
42980                         firstInactiveIndex = -- this._nActiveActions,
42981
42982                         lastActiveAction = actions[ firstInactiveIndex ];
42983
42984                 action._cacheIndex = firstInactiveIndex;
42985                 actions[ firstInactiveIndex ] = action;
42986
42987                 lastActiveAction._cacheIndex = prevIndex;
42988                 actions[ prevIndex ] = lastActiveAction;
42989
42990         }
42991
42992         // Memory management for PropertyMixer objects
42993
42994         _addInactiveBinding( binding, rootUuid, trackName ) {
42995
42996                 const bindingsByRoot = this._bindingsByRootAndName,
42997                         bindings = this._bindings;
42998
42999                 let bindingByName = bindingsByRoot[ rootUuid ];
43000
43001                 if ( bindingByName === undefined ) {
43002
43003                         bindingByName = {};
43004                         bindingsByRoot[ rootUuid ] = bindingByName;
43005
43006                 }
43007
43008                 bindingByName[ trackName ] = binding;
43009
43010                 binding._cacheIndex = bindings.length;
43011                 bindings.push( binding );
43012
43013         }
43014
43015         _removeInactiveBinding( binding ) {
43016
43017                 const bindings = this._bindings,
43018                         propBinding = binding.binding,
43019                         rootUuid = propBinding.rootNode.uuid,
43020                         trackName = propBinding.path,
43021                         bindingsByRoot = this._bindingsByRootAndName,
43022                         bindingByName = bindingsByRoot[ rootUuid ],
43023
43024                         lastInactiveBinding = bindings[ bindings.length - 1 ],
43025                         cacheIndex = binding._cacheIndex;
43026
43027                 lastInactiveBinding._cacheIndex = cacheIndex;
43028                 bindings[ cacheIndex ] = lastInactiveBinding;
43029                 bindings.pop();
43030
43031                 delete bindingByName[ trackName ];
43032
43033                 if ( Object.keys( bindingByName ).length === 0 ) {
43034
43035                         delete bindingsByRoot[ rootUuid ];
43036
43037                 }
43038
43039         }
43040
43041         _lendBinding( binding ) {
43042
43043                 const bindings = this._bindings,
43044                         prevIndex = binding._cacheIndex,
43045
43046                         lastActiveIndex = this._nActiveBindings ++,
43047
43048                         firstInactiveBinding = bindings[ lastActiveIndex ];
43049
43050                 binding._cacheIndex = lastActiveIndex;
43051                 bindings[ lastActiveIndex ] = binding;
43052
43053                 firstInactiveBinding._cacheIndex = prevIndex;
43054                 bindings[ prevIndex ] = firstInactiveBinding;
43055
43056         }
43057
43058         _takeBackBinding( binding ) {
43059
43060                 const bindings = this._bindings,
43061                         prevIndex = binding._cacheIndex,
43062
43063                         firstInactiveIndex = -- this._nActiveBindings,
43064
43065                         lastActiveBinding = bindings[ firstInactiveIndex ];
43066
43067                 binding._cacheIndex = firstInactiveIndex;
43068                 bindings[ firstInactiveIndex ] = binding;
43069
43070                 lastActiveBinding._cacheIndex = prevIndex;
43071                 bindings[ prevIndex ] = lastActiveBinding;
43072
43073         }
43074
43075
43076         // Memory management of Interpolants for weight and time scale
43077
43078         _lendControlInterpolant() {
43079
43080                 const interpolants = this._controlInterpolants,
43081                         lastActiveIndex = this._nActiveControlInterpolants ++;
43082
43083                 let interpolant = interpolants[ lastActiveIndex ];
43084
43085                 if ( interpolant === undefined ) {
43086
43087                         interpolant = new LinearInterpolant(
43088                                 new Float32Array( 2 ), new Float32Array( 2 ),
43089                                 1, this._controlInterpolantsResultBuffer );
43090
43091                         interpolant.__cacheIndex = lastActiveIndex;
43092                         interpolants[ lastActiveIndex ] = interpolant;
43093
43094                 }
43095
43096                 return interpolant;
43097
43098         }
43099
43100         _takeBackControlInterpolant( interpolant ) {
43101
43102                 const interpolants = this._controlInterpolants,
43103                         prevIndex = interpolant.__cacheIndex,
43104
43105                         firstInactiveIndex = -- this._nActiveControlInterpolants,
43106
43107                         lastActiveInterpolant = interpolants[ firstInactiveIndex ];
43108
43109                 interpolant.__cacheIndex = firstInactiveIndex;
43110                 interpolants[ firstInactiveIndex ] = interpolant;
43111
43112                 lastActiveInterpolant.__cacheIndex = prevIndex;
43113                 interpolants[ prevIndex ] = lastActiveInterpolant;
43114
43115         }
43116
43117         // return an action for a clip optionally using a custom root target
43118         // object (this method allocates a lot of dynamic memory in case a
43119         // previously unknown clip/root combination is specified)
43120         clipAction( clip, optionalRoot, blendMode ) {
43121
43122                 const root = optionalRoot || this._root,
43123                         rootUuid = root.uuid;
43124
43125                 let clipObject = typeof clip === 'string' ? AnimationClip.findByName( root, clip ) : clip;
43126
43127                 const clipUuid = clipObject !== null ? clipObject.uuid : clip;
43128
43129                 const actionsForClip = this._actionsByClip[ clipUuid ];
43130                 let prototypeAction = null;
43131
43132                 if ( blendMode === undefined ) {
43133
43134                         if ( clipObject !== null ) {
43135
43136                                 blendMode = clipObject.blendMode;
43137
43138                         } else {
43139
43140                                 blendMode = NormalAnimationBlendMode;
43141
43142                         }
43143
43144                 }
43145
43146                 if ( actionsForClip !== undefined ) {
43147
43148                         const existingAction = actionsForClip.actionByRoot[ rootUuid ];
43149
43150                         if ( existingAction !== undefined && existingAction.blendMode === blendMode ) {
43151
43152                                 return existingAction;
43153
43154                         }
43155
43156                         // we know the clip, so we don't have to parse all
43157                         // the bindings again but can just copy
43158                         prototypeAction = actionsForClip.knownActions[ 0 ];
43159
43160                         // also, take the clip from the prototype action
43161                         if ( clipObject === null )
43162                                 clipObject = prototypeAction._clip;
43163
43164                 }
43165
43166                 // clip must be known when specified via string
43167                 if ( clipObject === null ) return null;
43168
43169                 // allocate all resources required to run it
43170                 const newAction = new AnimationAction( this, clipObject, optionalRoot, blendMode );
43171
43172                 this._bindAction( newAction, prototypeAction );
43173
43174                 // and make the action known to the memory manager
43175                 this._addInactiveAction( newAction, clipUuid, rootUuid );
43176
43177                 return newAction;
43178
43179         }
43180
43181         // get an existing action
43182         existingAction( clip, optionalRoot ) {
43183
43184                 const root = optionalRoot || this._root,
43185                         rootUuid = root.uuid,
43186
43187                         clipObject = typeof clip === 'string' ?
43188                                 AnimationClip.findByName( root, clip ) : clip,
43189
43190                         clipUuid = clipObject ? clipObject.uuid : clip,
43191
43192                         actionsForClip = this._actionsByClip[ clipUuid ];
43193
43194                 if ( actionsForClip !== undefined ) {
43195
43196                         return actionsForClip.actionByRoot[ rootUuid ] || null;
43197
43198                 }
43199
43200                 return null;
43201
43202         }
43203
43204         // deactivates all previously scheduled actions
43205         stopAllAction() {
43206
43207                 const actions = this._actions,
43208                         nActions = this._nActiveActions;
43209
43210                 for ( let i = nActions - 1; i >= 0; -- i ) {
43211
43212                         actions[ i ].stop();
43213
43214                 }
43215
43216                 return this;
43217
43218         }
43219
43220         // advance the time and update apply the animation
43221         update( deltaTime ) {
43222
43223                 deltaTime *= this.timeScale;
43224
43225                 const actions = this._actions,
43226                         nActions = this._nActiveActions,
43227
43228                         time = this.time += deltaTime,
43229                         timeDirection = Math.sign( deltaTime ),
43230
43231                         accuIndex = this._accuIndex ^= 1;
43232
43233                 // run active actions
43234
43235                 for ( let i = 0; i !== nActions; ++ i ) {
43236
43237                         const action = actions[ i ];
43238
43239                         action._update( time, deltaTime, timeDirection, accuIndex );
43240
43241                 }
43242
43243                 // update scene graph
43244
43245                 const bindings = this._bindings,
43246                         nBindings = this._nActiveBindings;
43247
43248                 for ( let i = 0; i !== nBindings; ++ i ) {
43249
43250                         bindings[ i ].apply( accuIndex );
43251
43252                 }
43253
43254                 return this;
43255
43256         }
43257
43258         // Allows you to seek to a specific time in an animation.
43259         setTime( timeInSeconds ) {
43260
43261                 this.time = 0; // Zero out time attribute for AnimationMixer object;
43262                 for ( let i = 0; i < this._actions.length; i ++ ) {
43263
43264                         this._actions[ i ].time = 0; // Zero out time attribute for all associated AnimationAction objects.
43265
43266                 }
43267
43268                 return this.update( timeInSeconds ); // Update used to set exact time. Returns "this" AnimationMixer object.
43269
43270         }
43271
43272         // return this mixer's root target object
43273         getRoot() {
43274
43275                 return this._root;
43276
43277         }
43278
43279         // free all resources specific to a particular clip
43280         uncacheClip( clip ) {
43281
43282                 const actions = this._actions,
43283                         clipUuid = clip.uuid,
43284                         actionsByClip = this._actionsByClip,
43285                         actionsForClip = actionsByClip[ clipUuid ];
43286
43287                 if ( actionsForClip !== undefined ) {
43288
43289                         // note: just calling _removeInactiveAction would mess up the
43290                         // iteration state and also require updating the state we can
43291                         // just throw away
43292
43293                         const actionsToRemove = actionsForClip.knownActions;
43294
43295                         for ( let i = 0, n = actionsToRemove.length; i !== n; ++ i ) {
43296
43297                                 const action = actionsToRemove[ i ];
43298
43299                                 this._deactivateAction( action );
43300
43301                                 const cacheIndex = action._cacheIndex,
43302                                         lastInactiveAction = actions[ actions.length - 1 ];
43303
43304                                 action._cacheIndex = null;
43305                                 action._byClipCacheIndex = null;
43306
43307                                 lastInactiveAction._cacheIndex = cacheIndex;
43308                                 actions[ cacheIndex ] = lastInactiveAction;
43309                                 actions.pop();
43310
43311                                 this._removeInactiveBindingsForAction( action );
43312
43313                         }
43314
43315                         delete actionsByClip[ clipUuid ];
43316
43317                 }
43318
43319         }
43320
43321         // free all resources specific to a particular root target object
43322         uncacheRoot( root ) {
43323
43324                 const rootUuid = root.uuid,
43325                         actionsByClip = this._actionsByClip;
43326
43327                 for ( const clipUuid in actionsByClip ) {
43328
43329                         const actionByRoot = actionsByClip[ clipUuid ].actionByRoot,
43330                                 action = actionByRoot[ rootUuid ];
43331
43332                         if ( action !== undefined ) {
43333
43334                                 this._deactivateAction( action );
43335                                 this._removeInactiveAction( action );
43336
43337                         }
43338
43339                 }
43340
43341                 const bindingsByRoot = this._bindingsByRootAndName,
43342                         bindingByName = bindingsByRoot[ rootUuid ];
43343
43344                 if ( bindingByName !== undefined ) {
43345
43346                         for ( const trackName in bindingByName ) {
43347
43348                                 const binding = bindingByName[ trackName ];
43349                                 binding.restoreOriginalState();
43350                                 this._removeInactiveBinding( binding );
43351
43352                         }
43353
43354                 }
43355
43356         }
43357
43358         // remove a targeted clip from the cache
43359         uncacheAction( clip, optionalRoot ) {
43360
43361                 const action = this.existingAction( clip, optionalRoot );
43362
43363                 if ( action !== null ) {
43364
43365                         this._deactivateAction( action );
43366                         this._removeInactiveAction( action );
43367
43368                 }
43369
43370         }
43371
43372 }
43373
43374 AnimationMixer.prototype._controlInterpolantsResultBuffer = new Float32Array( 1 );
43375
43376 class InstancedInterleavedBuffer extends InterleavedBuffer {
43377
43378         constructor( array, stride, meshPerAttribute = 1 ) {
43379
43380                 super( array, stride );
43381
43382                 this.meshPerAttribute = meshPerAttribute;
43383
43384         }
43385
43386         copy( source ) {
43387
43388                 super.copy( source );
43389
43390                 this.meshPerAttribute = source.meshPerAttribute;
43391
43392                 return this;
43393
43394         }
43395
43396         clone( data ) {
43397
43398                 const ib = super.clone( data );
43399
43400                 ib.meshPerAttribute = this.meshPerAttribute;
43401
43402                 return ib;
43403
43404         }
43405
43406         toJSON( data ) {
43407
43408                 const json = super.toJSON( data );
43409
43410                 json.isInstancedInterleavedBuffer = true;
43411                 json.meshPerAttribute = this.meshPerAttribute;
43412
43413                 return json;
43414
43415         }
43416
43417 }
43418
43419 InstancedInterleavedBuffer.prototype.isInstancedInterleavedBuffer = true;
43420
43421 class Raycaster {
43422
43423         constructor( origin, direction, near = 0, far = Infinity ) {
43424
43425                 this.ray = new Ray( origin, direction );
43426                 // direction is assumed to be normalized (for accurate distance calculations)
43427
43428                 this.near = near;
43429                 this.far = far;
43430                 this.camera = null;
43431                 this.layers = new Layers();
43432
43433                 this.params = {
43434                         Mesh: {},
43435                         Line: { threshold: 1 },
43436                         LOD: {},
43437                         Points: { threshold: 1 },
43438                         Sprite: {}
43439                 };
43440
43441         }
43442
43443         set( origin, direction ) {
43444
43445                 // direction is assumed to be normalized (for accurate distance calculations)
43446
43447                 this.ray.set( origin, direction );
43448
43449         }
43450
43451         setFromCamera( coords, camera ) {
43452
43453                 if ( camera && camera.isPerspectiveCamera ) {
43454
43455                         this.ray.origin.setFromMatrixPosition( camera.matrixWorld );
43456                         this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize();
43457                         this.camera = camera;
43458
43459                 } else if ( camera && camera.isOrthographicCamera ) {
43460
43461                         this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera
43462                         this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );
43463                         this.camera = camera;
43464
43465                 } else {
43466
43467                         console.error( 'THREE.Raycaster: Unsupported camera type: ' + camera.type );
43468
43469                 }
43470
43471         }
43472
43473         intersectObject( object, recursive = true, intersects = [] ) {
43474
43475                 intersectObject( object, this, intersects, recursive );
43476
43477                 intersects.sort( ascSort );
43478
43479                 return intersects;
43480
43481         }
43482
43483         intersectObjects( objects, recursive = true, intersects = [] ) {
43484
43485                 for ( let i = 0, l = objects.length; i < l; i ++ ) {
43486
43487                         intersectObject( objects[ i ], this, intersects, recursive );
43488
43489                 }
43490
43491                 intersects.sort( ascSort );
43492
43493                 return intersects;
43494
43495         }
43496
43497 }
43498
43499 function ascSort( a, b ) {
43500
43501         return a.distance - b.distance;
43502
43503 }
43504
43505 function intersectObject( object, raycaster, intersects, recursive ) {
43506
43507         if ( object.layers.test( raycaster.layers ) ) {
43508
43509                 object.raycast( raycaster, intersects );
43510
43511         }
43512
43513         if ( recursive === true ) {
43514
43515                 const children = object.children;
43516
43517                 for ( let i = 0, l = children.length; i < l; i ++ ) {
43518
43519                         intersectObject( children[ i ], raycaster, intersects, true );
43520
43521                 }
43522
43523         }
43524
43525 }
43526
43527 const _vector$2 = /*@__PURE__*/ new Vector3();
43528 const _boneMatrix = /*@__PURE__*/ new Matrix4();
43529 const _matrixWorldInv = /*@__PURE__*/ new Matrix4();
43530
43531
43532 class SkeletonHelper extends LineSegments {
43533
43534         constructor( object ) {
43535
43536                 const bones = getBoneList( object );
43537
43538                 const geometry = new BufferGeometry();
43539
43540                 const vertices = [];
43541                 const colors = [];
43542
43543                 const color1 = new Color( 0, 0, 1 );
43544                 const color2 = new Color( 0, 1, 0 );
43545
43546                 for ( let i = 0; i < bones.length; i ++ ) {
43547
43548                         const bone = bones[ i ];
43549
43550                         if ( bone.parent && bone.parent.isBone ) {
43551
43552                                 vertices.push( 0, 0, 0 );
43553                                 vertices.push( 0, 0, 0 );
43554                                 colors.push( color1.r, color1.g, color1.b );
43555                                 colors.push( color2.r, color2.g, color2.b );
43556
43557                         }
43558
43559                 }
43560
43561                 geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
43562                 geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
43563
43564                 const material = new LineBasicMaterial( { vertexColors: true, depthTest: false, depthWrite: false, toneMapped: false, transparent: true } );
43565
43566                 super( geometry, material );
43567
43568                 this.type = 'SkeletonHelper';
43569                 this.isSkeletonHelper = true;
43570
43571                 this.root = object;
43572                 this.bones = bones;
43573
43574                 this.matrix = object.matrixWorld;
43575                 this.matrixAutoUpdate = false;
43576
43577         }
43578
43579         updateMatrixWorld( force ) {
43580
43581                 const bones = this.bones;
43582
43583                 const geometry = this.geometry;
43584                 const position = geometry.getAttribute( 'position' );
43585
43586                 _matrixWorldInv.copy( this.root.matrixWorld ).invert();
43587
43588                 for ( let i = 0, j = 0; i < bones.length; i ++ ) {
43589
43590                         const bone = bones[ i ];
43591
43592                         if ( bone.parent && bone.parent.isBone ) {
43593
43594                                 _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.matrixWorld );
43595                                 _vector$2.setFromMatrixPosition( _boneMatrix );
43596                                 position.setXYZ( j, _vector$2.x, _vector$2.y, _vector$2.z );
43597
43598                                 _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.parent.matrixWorld );
43599                                 _vector$2.setFromMatrixPosition( _boneMatrix );
43600                                 position.setXYZ( j + 1, _vector$2.x, _vector$2.y, _vector$2.z );
43601
43602                                 j += 2;
43603
43604                         }
43605
43606                 }
43607
43608                 geometry.getAttribute( 'position' ).needsUpdate = true;
43609
43610                 super.updateMatrixWorld( force );
43611
43612         }
43613
43614 }
43615
43616
43617 function getBoneList( object ) {
43618
43619         const boneList = [];
43620
43621         if ( object && object.isBone ) {
43622
43623                 boneList.push( object );
43624
43625         }
43626
43627         for ( let i = 0; i < object.children.length; i ++ ) {
43628
43629                 boneList.push.apply( boneList, getBoneList( object.children[ i ] ) );
43630
43631         }
43632
43633         return boneList;
43634
43635 }
43636
43637 class GridHelper extends LineSegments {
43638
43639         constructor( size = 10, divisions = 10, color1 = 0x444444, color2 = 0x888888 ) {
43640
43641                 color1 = new Color( color1 );
43642                 color2 = new Color( color2 );
43643
43644                 const center = divisions / 2;
43645                 const step = size / divisions;
43646                 const halfSize = size / 2;
43647
43648                 const vertices = [], colors = [];
43649
43650                 for ( let i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) {
43651
43652                         vertices.push( - halfSize, 0, k, halfSize, 0, k );
43653                         vertices.push( k, 0, - halfSize, k, 0, halfSize );
43654
43655                         const color = i === center ? color1 : color2;
43656
43657                         color.toArray( colors, j ); j += 3;
43658                         color.toArray( colors, j ); j += 3;
43659                         color.toArray( colors, j ); j += 3;
43660                         color.toArray( colors, j ); j += 3;
43661
43662                 }
43663
43664                 const geometry = new BufferGeometry();
43665                 geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
43666                 geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
43667
43668                 const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );
43669
43670                 super( geometry, material );
43671
43672                 this.type = 'GridHelper';
43673
43674         }
43675
43676 }
43677
43678 const _floatView = new Float32Array( 1 );
43679 new Int32Array( _floatView.buffer );
43680
43681 //
43682
43683 Curve.create = function ( construct, getPoint ) {
43684
43685         console.log( 'THREE.Curve.create() has been deprecated' );
43686
43687         construct.prototype = Object.create( Curve.prototype );
43688         construct.prototype.constructor = construct;
43689         construct.prototype.getPoint = getPoint;
43690
43691         return construct;
43692
43693 };
43694
43695 //
43696
43697 Path.prototype.fromPoints = function ( points ) {
43698
43699         console.warn( 'THREE.Path: .fromPoints() has been renamed to .setFromPoints().' );
43700         return this.setFromPoints( points );
43701
43702 };
43703
43704 GridHelper.prototype.setColors = function () {
43705
43706         console.error( 'THREE.GridHelper: setColors() has been deprecated, pass them in the constructor instead.' );
43707
43708 };
43709
43710 SkeletonHelper.prototype.update = function () {
43711
43712         console.error( 'THREE.SkeletonHelper: update() no longer needs to be called.' );
43713
43714 };
43715
43716 //
43717
43718 Loader.prototype.extractUrlBase = function ( url ) {
43719
43720         console.warn( 'THREE.Loader: .extractUrlBase() has been deprecated. Use THREE.LoaderUtils.extractUrlBase() instead.' );
43721         return LoaderUtils.extractUrlBase( url );
43722
43723 };
43724
43725 Loader.Handlers = {
43726
43727         add: function ( /* regex, loader */ ) {
43728
43729                 console.error( 'THREE.Loader: Handlers.add() has been removed. Use LoadingManager.addHandler() instead.' );
43730
43731         },
43732
43733         get: function ( /* file */ ) {
43734
43735                 console.error( 'THREE.Loader: Handlers.get() has been removed. Use LoadingManager.getHandler() instead.' );
43736
43737         }
43738
43739 };
43740
43741 //
43742
43743 Box3.prototype.center = function ( optionalTarget ) {
43744
43745         console.warn( 'THREE.Box3: .center() has been renamed to .getCenter().' );
43746         return this.getCenter( optionalTarget );
43747
43748 };
43749
43750 Box3.prototype.empty = function () {
43751
43752         console.warn( 'THREE.Box3: .empty() has been renamed to .isEmpty().' );
43753         return this.isEmpty();
43754
43755 };
43756
43757 Box3.prototype.isIntersectionBox = function ( box ) {
43758
43759         console.warn( 'THREE.Box3: .isIntersectionBox() has been renamed to .intersectsBox().' );
43760         return this.intersectsBox( box );
43761
43762 };
43763
43764 Box3.prototype.isIntersectionSphere = function ( sphere ) {
43765
43766         console.warn( 'THREE.Box3: .isIntersectionSphere() has been renamed to .intersectsSphere().' );
43767         return this.intersectsSphere( sphere );
43768
43769 };
43770
43771 Box3.prototype.size = function ( optionalTarget ) {
43772
43773         console.warn( 'THREE.Box3: .size() has been renamed to .getSize().' );
43774         return this.getSize( optionalTarget );
43775
43776 };
43777
43778 //
43779
43780 Sphere.prototype.empty = function () {
43781
43782         console.warn( 'THREE.Sphere: .empty() has been renamed to .isEmpty().' );
43783         return this.isEmpty();
43784
43785 };
43786
43787 //
43788
43789 Frustum.prototype.setFromMatrix = function ( m ) {
43790
43791         console.warn( 'THREE.Frustum: .setFromMatrix() has been renamed to .setFromProjectionMatrix().' );
43792         return this.setFromProjectionMatrix( m );
43793
43794 };
43795
43796 //
43797
43798 Matrix3.prototype.flattenToArrayOffset = function ( array, offset ) {
43799
43800         console.warn( 'THREE.Matrix3: .flattenToArrayOffset() has been deprecated. Use .toArray() instead.' );
43801         return this.toArray( array, offset );
43802
43803 };
43804
43805 Matrix3.prototype.multiplyVector3 = function ( vector ) {
43806
43807         console.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' );
43808         return vector.applyMatrix3( this );
43809
43810 };
43811
43812 Matrix3.prototype.multiplyVector3Array = function ( /* a */ ) {
43813
43814         console.error( 'THREE.Matrix3: .multiplyVector3Array() has been removed.' );
43815
43816 };
43817
43818 Matrix3.prototype.applyToBufferAttribute = function ( attribute ) {
43819
43820         console.warn( 'THREE.Matrix3: .applyToBufferAttribute() has been removed. Use attribute.applyMatrix3( matrix ) instead.' );
43821         return attribute.applyMatrix3( this );
43822
43823 };
43824
43825 Matrix3.prototype.applyToVector3Array = function ( /* array, offset, length */ ) {
43826
43827         console.error( 'THREE.Matrix3: .applyToVector3Array() has been removed.' );
43828
43829 };
43830
43831 Matrix3.prototype.getInverse = function ( matrix ) {
43832
43833         console.warn( 'THREE.Matrix3: .getInverse() has been removed. Use matrixInv.copy( matrix ).invert(); instead.' );
43834         return this.copy( matrix ).invert();
43835
43836 };
43837
43838 //
43839
43840 Matrix4.prototype.extractPosition = function ( m ) {
43841
43842         console.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' );
43843         return this.copyPosition( m );
43844
43845 };
43846
43847 Matrix4.prototype.flattenToArrayOffset = function ( array, offset ) {
43848
43849         console.warn( 'THREE.Matrix4: .flattenToArrayOffset() has been deprecated. Use .toArray() instead.' );
43850         return this.toArray( array, offset );
43851
43852 };
43853
43854 Matrix4.prototype.getPosition = function () {
43855
43856         console.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' );
43857         return new Vector3().setFromMatrixColumn( this, 3 );
43858
43859 };
43860
43861 Matrix4.prototype.setRotationFromQuaternion = function ( q ) {
43862
43863         console.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' );
43864         return this.makeRotationFromQuaternion( q );
43865
43866 };
43867
43868 Matrix4.prototype.multiplyToArray = function () {
43869
43870         console.warn( 'THREE.Matrix4: .multiplyToArray() has been removed.' );
43871
43872 };
43873
43874 Matrix4.prototype.multiplyVector3 = function ( vector ) {
43875
43876         console.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
43877         return vector.applyMatrix4( this );
43878
43879 };
43880
43881 Matrix4.prototype.multiplyVector4 = function ( vector ) {
43882
43883         console.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
43884         return vector.applyMatrix4( this );
43885
43886 };
43887
43888 Matrix4.prototype.multiplyVector3Array = function ( /* a */ ) {
43889
43890         console.error( 'THREE.Matrix4: .multiplyVector3Array() has been removed.' );
43891
43892 };
43893
43894 Matrix4.prototype.rotateAxis = function ( v ) {
43895
43896         console.warn( 'THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' );
43897         v.transformDirection( this );
43898
43899 };
43900
43901 Matrix4.prototype.crossVector = function ( vector ) {
43902
43903         console.warn( 'THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
43904         return vector.applyMatrix4( this );
43905
43906 };
43907
43908 Matrix4.prototype.translate = function () {
43909
43910         console.error( 'THREE.Matrix4: .translate() has been removed.' );
43911
43912 };
43913
43914 Matrix4.prototype.rotateX = function () {
43915
43916         console.error( 'THREE.Matrix4: .rotateX() has been removed.' );
43917
43918 };
43919
43920 Matrix4.prototype.rotateY = function () {
43921
43922         console.error( 'THREE.Matrix4: .rotateY() has been removed.' );
43923
43924 };
43925
43926 Matrix4.prototype.rotateZ = function () {
43927
43928         console.error( 'THREE.Matrix4: .rotateZ() has been removed.' );
43929
43930 };
43931
43932 Matrix4.prototype.rotateByAxis = function () {
43933
43934         console.error( 'THREE.Matrix4: .rotateByAxis() has been removed.' );
43935
43936 };
43937
43938 Matrix4.prototype.applyToBufferAttribute = function ( attribute ) {
43939
43940         console.warn( 'THREE.Matrix4: .applyToBufferAttribute() has been removed. Use attribute.applyMatrix4( matrix ) instead.' );
43941         return attribute.applyMatrix4( this );
43942
43943 };
43944
43945 Matrix4.prototype.applyToVector3Array = function ( /* array, offset, length */ ) {
43946
43947         console.error( 'THREE.Matrix4: .applyToVector3Array() has been removed.' );
43948
43949 };
43950
43951 Matrix4.prototype.makeFrustum = function ( left, right, bottom, top, near, far ) {
43952
43953         console.warn( 'THREE.Matrix4: .makeFrustum() has been removed. Use .makePerspective( left, right, top, bottom, near, far ) instead.' );
43954         return this.makePerspective( left, right, top, bottom, near, far );
43955
43956 };
43957
43958 Matrix4.prototype.getInverse = function ( matrix ) {
43959
43960         console.warn( 'THREE.Matrix4: .getInverse() has been removed. Use matrixInv.copy( matrix ).invert(); instead.' );
43961         return this.copy( matrix ).invert();
43962
43963 };
43964
43965 //
43966
43967 Plane.prototype.isIntersectionLine = function ( line ) {
43968
43969         console.warn( 'THREE.Plane: .isIntersectionLine() has been renamed to .intersectsLine().' );
43970         return this.intersectsLine( line );
43971
43972 };
43973
43974 //
43975
43976 Quaternion.prototype.multiplyVector3 = function ( vector ) {
43977
43978         console.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' );
43979         return vector.applyQuaternion( this );
43980
43981 };
43982
43983 Quaternion.prototype.inverse = function ( ) {
43984
43985         console.warn( 'THREE.Quaternion: .inverse() has been renamed to invert().' );
43986         return this.invert();
43987
43988 };
43989
43990 //
43991
43992 Ray.prototype.isIntersectionBox = function ( box ) {
43993
43994         console.warn( 'THREE.Ray: .isIntersectionBox() has been renamed to .intersectsBox().' );
43995         return this.intersectsBox( box );
43996
43997 };
43998
43999 Ray.prototype.isIntersectionPlane = function ( plane ) {
44000
44001         console.warn( 'THREE.Ray: .isIntersectionPlane() has been renamed to .intersectsPlane().' );
44002         return this.intersectsPlane( plane );
44003
44004 };
44005
44006 Ray.prototype.isIntersectionSphere = function ( sphere ) {
44007
44008         console.warn( 'THREE.Ray: .isIntersectionSphere() has been renamed to .intersectsSphere().' );
44009         return this.intersectsSphere( sphere );
44010
44011 };
44012
44013 //
44014
44015 Triangle.prototype.area = function () {
44016
44017         console.warn( 'THREE.Triangle: .area() has been renamed to .getArea().' );
44018         return this.getArea();
44019
44020 };
44021
44022 Triangle.prototype.barycoordFromPoint = function ( point, target ) {
44023
44024         console.warn( 'THREE.Triangle: .barycoordFromPoint() has been renamed to .getBarycoord().' );
44025         return this.getBarycoord( point, target );
44026
44027 };
44028
44029 Triangle.prototype.midpoint = function ( target ) {
44030
44031         console.warn( 'THREE.Triangle: .midpoint() has been renamed to .getMidpoint().' );
44032         return this.getMidpoint( target );
44033
44034 };
44035
44036 Triangle.prototypenormal = function ( target ) {
44037
44038         console.warn( 'THREE.Triangle: .normal() has been renamed to .getNormal().' );
44039         return this.getNormal( target );
44040
44041 };
44042
44043 Triangle.prototype.plane = function ( target ) {
44044
44045         console.warn( 'THREE.Triangle: .plane() has been renamed to .getPlane().' );
44046         return this.getPlane( target );
44047
44048 };
44049
44050 Triangle.barycoordFromPoint = function ( point, a, b, c, target ) {
44051
44052         console.warn( 'THREE.Triangle: .barycoordFromPoint() has been renamed to .getBarycoord().' );
44053         return Triangle.getBarycoord( point, a, b, c, target );
44054
44055 };
44056
44057 Triangle.normal = function ( a, b, c, target ) {
44058
44059         console.warn( 'THREE.Triangle: .normal() has been renamed to .getNormal().' );
44060         return Triangle.getNormal( a, b, c, target );
44061
44062 };
44063
44064 //
44065
44066 Shape.prototype.extractAllPoints = function ( divisions ) {
44067
44068         console.warn( 'THREE.Shape: .extractAllPoints() has been removed. Use .extractPoints() instead.' );
44069         return this.extractPoints( divisions );
44070
44071 };
44072
44073 Shape.prototype.extrude = function ( options ) {
44074
44075         console.warn( 'THREE.Shape: .extrude() has been removed. Use ExtrudeGeometry() instead.' );
44076         return new ExtrudeGeometry( this, options );
44077
44078 };
44079
44080 Shape.prototype.makeGeometry = function ( options ) {
44081
44082         console.warn( 'THREE.Shape: .makeGeometry() has been removed. Use ShapeGeometry() instead.' );
44083         return new ShapeGeometry( this, options );
44084
44085 };
44086
44087 //
44088
44089 Vector2.prototype.fromAttribute = function ( attribute, index, offset ) {
44090
44091         console.warn( 'THREE.Vector2: .fromAttribute() has been renamed to .fromBufferAttribute().' );
44092         return this.fromBufferAttribute( attribute, index, offset );
44093
44094 };
44095
44096 Vector2.prototype.distanceToManhattan = function ( v ) {
44097
44098         console.warn( 'THREE.Vector2: .distanceToManhattan() has been renamed to .manhattanDistanceTo().' );
44099         return this.manhattanDistanceTo( v );
44100
44101 };
44102
44103 Vector2.prototype.lengthManhattan = function () {
44104
44105         console.warn( 'THREE.Vector2: .lengthManhattan() has been renamed to .manhattanLength().' );
44106         return this.manhattanLength();
44107
44108 };
44109
44110 //
44111
44112 Vector3.prototype.setEulerFromRotationMatrix = function () {
44113
44114         console.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' );
44115
44116 };
44117
44118 Vector3.prototype.setEulerFromQuaternion = function () {
44119
44120         console.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' );
44121
44122 };
44123
44124 Vector3.prototype.getPositionFromMatrix = function ( m ) {
44125
44126         console.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' );
44127         return this.setFromMatrixPosition( m );
44128
44129 };
44130
44131 Vector3.prototype.getScaleFromMatrix = function ( m ) {
44132
44133         console.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' );
44134         return this.setFromMatrixScale( m );
44135
44136 };
44137
44138 Vector3.prototype.getColumnFromMatrix = function ( index, matrix ) {
44139
44140         console.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' );
44141         return this.setFromMatrixColumn( matrix, index );
44142
44143 };
44144
44145 Vector3.prototype.applyProjection = function ( m ) {
44146
44147         console.warn( 'THREE.Vector3: .applyProjection() has been removed. Use .applyMatrix4( m ) instead.' );
44148         return this.applyMatrix4( m );
44149
44150 };
44151
44152 Vector3.prototype.fromAttribute = function ( attribute, index, offset ) {
44153
44154         console.warn( 'THREE.Vector3: .fromAttribute() has been renamed to .fromBufferAttribute().' );
44155         return this.fromBufferAttribute( attribute, index, offset );
44156
44157 };
44158
44159 Vector3.prototype.distanceToManhattan = function ( v ) {
44160
44161         console.warn( 'THREE.Vector3: .distanceToManhattan() has been renamed to .manhattanDistanceTo().' );
44162         return this.manhattanDistanceTo( v );
44163
44164 };
44165
44166 Vector3.prototype.lengthManhattan = function () {
44167
44168         console.warn( 'THREE.Vector3: .lengthManhattan() has been renamed to .manhattanLength().' );
44169         return this.manhattanLength();
44170
44171 };
44172
44173 //
44174
44175 Vector4.prototype.fromAttribute = function ( attribute, index, offset ) {
44176
44177         console.warn( 'THREE.Vector4: .fromAttribute() has been renamed to .fromBufferAttribute().' );
44178         return this.fromBufferAttribute( attribute, index, offset );
44179
44180 };
44181
44182 Vector4.prototype.lengthManhattan = function () {
44183
44184         console.warn( 'THREE.Vector4: .lengthManhattan() has been renamed to .manhattanLength().' );
44185         return this.manhattanLength();
44186
44187 };
44188
44189 //
44190
44191 Object3D.prototype.getChildByName = function ( name ) {
44192
44193         console.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' );
44194         return this.getObjectByName( name );
44195
44196 };
44197
44198 Object3D.prototype.renderDepth = function () {
44199
44200         console.warn( 'THREE.Object3D: .renderDepth has been removed. Use .renderOrder, instead.' );
44201
44202 };
44203
44204 Object3D.prototype.translate = function ( distance, axis ) {
44205
44206         console.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' );
44207         return this.translateOnAxis( axis, distance );
44208
44209 };
44210
44211 Object3D.prototype.getWorldRotation = function () {
44212
44213         console.error( 'THREE.Object3D: .getWorldRotation() has been removed. Use THREE.Object3D.getWorldQuaternion( target ) instead.' );
44214
44215 };
44216
44217 Object3D.prototype.applyMatrix = function ( matrix ) {
44218
44219         console.warn( 'THREE.Object3D: .applyMatrix() has been renamed to .applyMatrix4().' );
44220         return this.applyMatrix4( matrix );
44221
44222 };
44223
44224 Object.defineProperties( Object3D.prototype, {
44225
44226         eulerOrder: {
44227                 get: function () {
44228
44229                         console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' );
44230                         return this.rotation.order;
44231
44232                 },
44233                 set: function ( value ) {
44234
44235                         console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' );
44236                         this.rotation.order = value;
44237
44238                 }
44239         },
44240         useQuaternion: {
44241                 get: function () {
44242
44243                         console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' );
44244
44245                 },
44246                 set: function () {
44247
44248                         console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' );
44249
44250                 }
44251         }
44252
44253 } );
44254
44255 Mesh.prototype.setDrawMode = function () {
44256
44257         console.error( 'THREE.Mesh: .setDrawMode() has been removed. The renderer now always assumes THREE.TrianglesDrawMode. Transform your geometry via BufferGeometryUtils.toTrianglesDrawMode() if necessary.' );
44258
44259 };
44260
44261 Object.defineProperties( Mesh.prototype, {
44262
44263         drawMode: {
44264                 get: function () {
44265
44266                         console.error( 'THREE.Mesh: .drawMode has been removed. The renderer now always assumes THREE.TrianglesDrawMode.' );
44267                         return TrianglesDrawMode;
44268
44269                 },
44270                 set: function () {
44271
44272                         console.error( 'THREE.Mesh: .drawMode has been removed. The renderer now always assumes THREE.TrianglesDrawMode. Transform your geometry via BufferGeometryUtils.toTrianglesDrawMode() if necessary.' );
44273
44274                 }
44275         }
44276
44277 } );
44278
44279 SkinnedMesh.prototype.initBones = function () {
44280
44281         console.error( 'THREE.SkinnedMesh: initBones() has been removed.' );
44282
44283 };
44284
44285 //
44286
44287 PerspectiveCamera.prototype.setLens = function ( focalLength, filmGauge ) {
44288
44289         console.warn( 'THREE.PerspectiveCamera.setLens is deprecated. ' +
44290                         'Use .setFocalLength and .filmGauge for a photographic setup.' );
44291
44292         if ( filmGauge !== undefined ) this.filmGauge = filmGauge;
44293         this.setFocalLength( focalLength );
44294
44295 };
44296
44297 //
44298
44299 Object.defineProperties( Light.prototype, {
44300         onlyShadow: {
44301                 set: function () {
44302
44303                         console.warn( 'THREE.Light: .onlyShadow has been removed.' );
44304
44305                 }
44306         },
44307         shadowCameraFov: {
44308                 set: function ( value ) {
44309
44310                         console.warn( 'THREE.Light: .shadowCameraFov is now .shadow.camera.fov.' );
44311                         this.shadow.camera.fov = value;
44312
44313                 }
44314         },
44315         shadowCameraLeft: {
44316                 set: function ( value ) {
44317
44318                         console.warn( 'THREE.Light: .shadowCameraLeft is now .shadow.camera.left.' );
44319                         this.shadow.camera.left = value;
44320
44321                 }
44322         },
44323         shadowCameraRight: {
44324                 set: function ( value ) {
44325
44326                         console.warn( 'THREE.Light: .shadowCameraRight is now .shadow.camera.right.' );
44327                         this.shadow.camera.right = value;
44328
44329                 }
44330         },
44331         shadowCameraTop: {
44332                 set: function ( value ) {
44333
44334                         console.warn( 'THREE.Light: .shadowCameraTop is now .shadow.camera.top.' );
44335                         this.shadow.camera.top = value;
44336
44337                 }
44338         },
44339         shadowCameraBottom: {
44340                 set: function ( value ) {
44341
44342                         console.warn( 'THREE.Light: .shadowCameraBottom is now .shadow.camera.bottom.' );
44343                         this.shadow.camera.bottom = value;
44344
44345                 }
44346         },
44347         shadowCameraNear: {
44348                 set: function ( value ) {
44349
44350                         console.warn( 'THREE.Light: .shadowCameraNear is now .shadow.camera.near.' );
44351                         this.shadow.camera.near = value;
44352
44353                 }
44354         },
44355         shadowCameraFar: {
44356                 set: function ( value ) {
44357
44358                         console.warn( 'THREE.Light: .shadowCameraFar is now .shadow.camera.far.' );
44359                         this.shadow.camera.far = value;
44360
44361                 }
44362         },
44363         shadowCameraVisible: {
44364                 set: function () {
44365
44366                         console.warn( 'THREE.Light: .shadowCameraVisible has been removed. Use new THREE.CameraHelper( light.shadow.camera ) instead.' );
44367
44368                 }
44369         },
44370         shadowBias: {
44371                 set: function ( value ) {
44372
44373                         console.warn( 'THREE.Light: .shadowBias is now .shadow.bias.' );
44374                         this.shadow.bias = value;
44375
44376                 }
44377         },
44378         shadowDarkness: {
44379                 set: function () {
44380
44381                         console.warn( 'THREE.Light: .shadowDarkness has been removed.' );
44382
44383                 }
44384         },
44385         shadowMapWidth: {
44386                 set: function ( value ) {
44387
44388                         console.warn( 'THREE.Light: .shadowMapWidth is now .shadow.mapSize.width.' );
44389                         this.shadow.mapSize.width = value;
44390
44391                 }
44392         },
44393         shadowMapHeight: {
44394                 set: function ( value ) {
44395
44396                         console.warn( 'THREE.Light: .shadowMapHeight is now .shadow.mapSize.height.' );
44397                         this.shadow.mapSize.height = value;
44398
44399                 }
44400         }
44401 } );
44402
44403 //
44404
44405 Object.defineProperties( BufferAttribute.prototype, {
44406
44407         length: {
44408                 get: function () {
44409
44410                         console.warn( 'THREE.BufferAttribute: .length has been deprecated. Use .count instead.' );
44411                         return this.array.length;
44412
44413                 }
44414         },
44415         dynamic: {
44416                 get: function () {
44417
44418                         console.warn( 'THREE.BufferAttribute: .dynamic has been deprecated. Use .usage instead.' );
44419                         return this.usage === DynamicDrawUsage;
44420
44421                 },
44422                 set: function ( /* value */ ) {
44423
44424                         console.warn( 'THREE.BufferAttribute: .dynamic has been deprecated. Use .usage instead.' );
44425                         this.setUsage( DynamicDrawUsage );
44426
44427                 }
44428         }
44429
44430 } );
44431
44432 BufferAttribute.prototype.setDynamic = function ( value ) {
44433
44434         console.warn( 'THREE.BufferAttribute: .setDynamic() has been deprecated. Use .setUsage() instead.' );
44435         this.setUsage( value === true ? DynamicDrawUsage : StaticDrawUsage );
44436         return this;
44437
44438 };
44439
44440 BufferAttribute.prototype.copyIndicesArray = function ( /* indices */ ) {
44441
44442         console.error( 'THREE.BufferAttribute: .copyIndicesArray() has been removed.' );
44443
44444 },
44445
44446 BufferAttribute.prototype.setArray = function ( /* array */ ) {
44447
44448         console.error( 'THREE.BufferAttribute: .setArray has been removed. Use BufferGeometry .setAttribute to replace/resize attribute buffers' );
44449
44450 };
44451
44452 //
44453
44454 BufferGeometry.prototype.addIndex = function ( index ) {
44455
44456         console.warn( 'THREE.BufferGeometry: .addIndex() has been renamed to .setIndex().' );
44457         this.setIndex( index );
44458
44459 };
44460
44461 BufferGeometry.prototype.addAttribute = function ( name, attribute ) {
44462
44463         console.warn( 'THREE.BufferGeometry: .addAttribute() has been renamed to .setAttribute().' );
44464
44465         if ( ! ( attribute && attribute.isBufferAttribute ) && ! ( attribute && attribute.isInterleavedBufferAttribute ) ) {
44466
44467                 console.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' );
44468
44469                 return this.setAttribute( name, new BufferAttribute( arguments[ 1 ], arguments[ 2 ] ) );
44470
44471         }
44472
44473         if ( name === 'index' ) {
44474
44475                 console.warn( 'THREE.BufferGeometry.addAttribute: Use .setIndex() for index attribute.' );
44476                 this.setIndex( attribute );
44477
44478                 return this;
44479
44480         }
44481
44482         return this.setAttribute( name, attribute );
44483
44484 };
44485
44486 BufferGeometry.prototype.addDrawCall = function ( start, count, indexOffset ) {
44487
44488         if ( indexOffset !== undefined ) {
44489
44490                 console.warn( 'THREE.BufferGeometry: .addDrawCall() no longer supports indexOffset.' );
44491
44492         }
44493
44494         console.warn( 'THREE.BufferGeometry: .addDrawCall() is now .addGroup().' );
44495         this.addGroup( start, count );
44496
44497 };
44498
44499 BufferGeometry.prototype.clearDrawCalls = function () {
44500
44501         console.warn( 'THREE.BufferGeometry: .clearDrawCalls() is now .clearGroups().' );
44502         this.clearGroups();
44503
44504 };
44505
44506 BufferGeometry.prototype.computeOffsets = function () {
44507
44508         console.warn( 'THREE.BufferGeometry: .computeOffsets() has been removed.' );
44509
44510 };
44511
44512 BufferGeometry.prototype.removeAttribute = function ( name ) {
44513
44514         console.warn( 'THREE.BufferGeometry: .removeAttribute() has been renamed to .deleteAttribute().' );
44515
44516         return this.deleteAttribute( name );
44517
44518 };
44519
44520 BufferGeometry.prototype.applyMatrix = function ( matrix ) {
44521
44522         console.warn( 'THREE.BufferGeometry: .applyMatrix() has been renamed to .applyMatrix4().' );
44523         return this.applyMatrix4( matrix );
44524
44525 };
44526
44527 Object.defineProperties( BufferGeometry.prototype, {
44528
44529         drawcalls: {
44530                 get: function () {
44531
44532                         console.error( 'THREE.BufferGeometry: .drawcalls has been renamed to .groups.' );
44533                         return this.groups;
44534
44535                 }
44536         },
44537         offsets: {
44538                 get: function () {
44539
44540                         console.warn( 'THREE.BufferGeometry: .offsets has been renamed to .groups.' );
44541                         return this.groups;
44542
44543                 }
44544         }
44545
44546 } );
44547
44548 InterleavedBuffer.prototype.setDynamic = function ( value ) {
44549
44550         console.warn( 'THREE.InterleavedBuffer: .setDynamic() has been deprecated. Use .setUsage() instead.' );
44551         this.setUsage( value === true ? DynamicDrawUsage : StaticDrawUsage );
44552         return this;
44553
44554 };
44555
44556 InterleavedBuffer.prototype.setArray = function ( /* array */ ) {
44557
44558         console.error( 'THREE.InterleavedBuffer: .setArray has been removed. Use BufferGeometry .setAttribute to replace/resize attribute buffers' );
44559
44560 };
44561
44562 //
44563
44564 ExtrudeGeometry.prototype.getArrays = function () {
44565
44566         console.error( 'THREE.ExtrudeGeometry: .getArrays() has been removed.' );
44567
44568 };
44569
44570 ExtrudeGeometry.prototype.addShapeList = function () {
44571
44572         console.error( 'THREE.ExtrudeGeometry: .addShapeList() has been removed.' );
44573
44574 };
44575
44576 ExtrudeGeometry.prototype.addShape = function () {
44577
44578         console.error( 'THREE.ExtrudeGeometry: .addShape() has been removed.' );
44579
44580 };
44581
44582 //
44583
44584 Scene.prototype.dispose = function () {
44585
44586         console.error( 'THREE.Scene: .dispose() has been removed.' );
44587
44588 };
44589
44590 //
44591
44592 Object.defineProperties( Material.prototype, {
44593
44594         wrapAround: {
44595                 get: function () {
44596
44597                         console.warn( 'THREE.Material: .wrapAround has been removed.' );
44598
44599                 },
44600                 set: function () {
44601
44602                         console.warn( 'THREE.Material: .wrapAround has been removed.' );
44603
44604                 }
44605         },
44606
44607         overdraw: {
44608                 get: function () {
44609
44610                         console.warn( 'THREE.Material: .overdraw has been removed.' );
44611
44612                 },
44613                 set: function () {
44614
44615                         console.warn( 'THREE.Material: .overdraw has been removed.' );
44616
44617                 }
44618         },
44619
44620         wrapRGB: {
44621                 get: function () {
44622
44623                         console.warn( 'THREE.Material: .wrapRGB has been removed.' );
44624                         return new Color();
44625
44626                 }
44627         },
44628
44629         shading: {
44630                 get: function () {
44631
44632                         console.error( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' );
44633
44634                 },
44635                 set: function ( value ) {
44636
44637                         console.warn( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' );
44638                         this.flatShading = ( value === FlatShading );
44639
44640                 }
44641         },
44642
44643         stencilMask: {
44644                 get: function () {
44645
44646                         console.warn( 'THREE.' + this.type + ': .stencilMask has been removed. Use .stencilFuncMask instead.' );
44647                         return this.stencilFuncMask;
44648
44649                 },
44650                 set: function ( value ) {
44651
44652                         console.warn( 'THREE.' + this.type + ': .stencilMask has been removed. Use .stencilFuncMask instead.' );
44653                         this.stencilFuncMask = value;
44654
44655                 }
44656         },
44657
44658         vertexTangents: {
44659                 get: function () {
44660
44661                         console.warn( 'THREE.' + this.type + ': .vertexTangents has been removed.' );
44662
44663                 },
44664                 set: function () {
44665
44666                         console.warn( 'THREE.' + this.type + ': .vertexTangents has been removed.' );
44667
44668                 }
44669         },
44670
44671 } );
44672
44673 Object.defineProperties( ShaderMaterial.prototype, {
44674
44675         derivatives: {
44676                 get: function () {
44677
44678                         console.warn( 'THREE.ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' );
44679                         return this.extensions.derivatives;
44680
44681                 },
44682                 set: function ( value ) {
44683
44684                         console.warn( 'THREE. ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' );
44685                         this.extensions.derivatives = value;
44686
44687                 }
44688         }
44689
44690 } );
44691
44692 //
44693
44694 WebGLRenderer.prototype.clearTarget = function ( renderTarget, color, depth, stencil ) {
44695
44696         console.warn( 'THREE.WebGLRenderer: .clearTarget() has been deprecated. Use .setRenderTarget() and .clear() instead.' );
44697         this.setRenderTarget( renderTarget );
44698         this.clear( color, depth, stencil );
44699
44700 };
44701
44702 WebGLRenderer.prototype.animate = function ( callback ) {
44703
44704         console.warn( 'THREE.WebGLRenderer: .animate() is now .setAnimationLoop().' );
44705         this.setAnimationLoop( callback );
44706
44707 };
44708
44709 WebGLRenderer.prototype.getCurrentRenderTarget = function () {
44710
44711         console.warn( 'THREE.WebGLRenderer: .getCurrentRenderTarget() is now .getRenderTarget().' );
44712         return this.getRenderTarget();
44713
44714 };
44715
44716 WebGLRenderer.prototype.getMaxAnisotropy = function () {
44717
44718         console.warn( 'THREE.WebGLRenderer: .getMaxAnisotropy() is now .capabilities.getMaxAnisotropy().' );
44719         return this.capabilities.getMaxAnisotropy();
44720
44721 };
44722
44723 WebGLRenderer.prototype.getPrecision = function () {
44724
44725         console.warn( 'THREE.WebGLRenderer: .getPrecision() is now .capabilities.precision.' );
44726         return this.capabilities.precision;
44727
44728 };
44729
44730 WebGLRenderer.prototype.resetGLState = function () {
44731
44732         console.warn( 'THREE.WebGLRenderer: .resetGLState() is now .state.reset().' );
44733         return this.state.reset();
44734
44735 };
44736
44737 WebGLRenderer.prototype.supportsFloatTextures = function () {
44738
44739         console.warn( 'THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( \'OES_texture_float\' ).' );
44740         return this.extensions.get( 'OES_texture_float' );
44741
44742 };
44743
44744 WebGLRenderer.prototype.supportsHalfFloatTextures = function () {
44745
44746         console.warn( 'THREE.WebGLRenderer: .supportsHalfFloatTextures() is now .extensions.get( \'OES_texture_half_float\' ).' );
44747         return this.extensions.get( 'OES_texture_half_float' );
44748
44749 };
44750
44751 WebGLRenderer.prototype.supportsStandardDerivatives = function () {
44752
44753         console.warn( 'THREE.WebGLRenderer: .supportsStandardDerivatives() is now .extensions.get( \'OES_standard_derivatives\' ).' );
44754         return this.extensions.get( 'OES_standard_derivatives' );
44755
44756 };
44757
44758 WebGLRenderer.prototype.supportsCompressedTextureS3TC = function () {
44759
44760         console.warn( 'THREE.WebGLRenderer: .supportsCompressedTextureS3TC() is now .extensions.get( \'WEBGL_compressed_texture_s3tc\' ).' );
44761         return this.extensions.get( 'WEBGL_compressed_texture_s3tc' );
44762
44763 };
44764
44765 WebGLRenderer.prototype.supportsCompressedTexturePVRTC = function () {
44766
44767         console.warn( 'THREE.WebGLRenderer: .supportsCompressedTexturePVRTC() is now .extensions.get( \'WEBGL_compressed_texture_pvrtc\' ).' );
44768         return this.extensions.get( 'WEBGL_compressed_texture_pvrtc' );
44769
44770 };
44771
44772 WebGLRenderer.prototype.supportsBlendMinMax = function () {
44773
44774         console.warn( 'THREE.WebGLRenderer: .supportsBlendMinMax() is now .extensions.get( \'EXT_blend_minmax\' ).' );
44775         return this.extensions.get( 'EXT_blend_minmax' );
44776
44777 };
44778
44779 WebGLRenderer.prototype.supportsVertexTextures = function () {
44780
44781         console.warn( 'THREE.WebGLRenderer: .supportsVertexTextures() is now .capabilities.vertexTextures.' );
44782         return this.capabilities.vertexTextures;
44783
44784 };
44785
44786 WebGLRenderer.prototype.supportsInstancedArrays = function () {
44787
44788         console.warn( 'THREE.WebGLRenderer: .supportsInstancedArrays() is now .extensions.get( \'ANGLE_instanced_arrays\' ).' );
44789         return this.extensions.get( 'ANGLE_instanced_arrays' );
44790
44791 };
44792
44793 WebGLRenderer.prototype.enableScissorTest = function ( boolean ) {
44794
44795         console.warn( 'THREE.WebGLRenderer: .enableScissorTest() is now .setScissorTest().' );
44796         this.setScissorTest( boolean );
44797
44798 };
44799
44800 WebGLRenderer.prototype.initMaterial = function () {
44801
44802         console.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' );
44803
44804 };
44805
44806 WebGLRenderer.prototype.addPrePlugin = function () {
44807
44808         console.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' );
44809
44810 };
44811
44812 WebGLRenderer.prototype.addPostPlugin = function () {
44813
44814         console.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' );
44815
44816 };
44817
44818 WebGLRenderer.prototype.updateShadowMap = function () {
44819
44820         console.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' );
44821
44822 };
44823
44824 WebGLRenderer.prototype.setFaceCulling = function () {
44825
44826         console.warn( 'THREE.WebGLRenderer: .setFaceCulling() has been removed.' );
44827
44828 };
44829
44830 WebGLRenderer.prototype.allocTextureUnit = function () {
44831
44832         console.warn( 'THREE.WebGLRenderer: .allocTextureUnit() has been removed.' );
44833
44834 };
44835
44836 WebGLRenderer.prototype.setTexture = function () {
44837
44838         console.warn( 'THREE.WebGLRenderer: .setTexture() has been removed.' );
44839
44840 };
44841
44842 WebGLRenderer.prototype.setTexture2D = function () {
44843
44844         console.warn( 'THREE.WebGLRenderer: .setTexture2D() has been removed.' );
44845
44846 };
44847
44848 WebGLRenderer.prototype.setTextureCube = function () {
44849
44850         console.warn( 'THREE.WebGLRenderer: .setTextureCube() has been removed.' );
44851
44852 };
44853
44854 WebGLRenderer.prototype.getActiveMipMapLevel = function () {
44855
44856         console.warn( 'THREE.WebGLRenderer: .getActiveMipMapLevel() is now .getActiveMipmapLevel().' );
44857         return this.getActiveMipmapLevel();
44858
44859 };
44860
44861 Object.defineProperties( WebGLRenderer.prototype, {
44862
44863         shadowMapEnabled: {
44864                 get: function () {
44865
44866                         return this.shadowMap.enabled;
44867
44868                 },
44869                 set: function ( value ) {
44870
44871                         console.warn( 'THREE.WebGLRenderer: .shadowMapEnabled is now .shadowMap.enabled.' );
44872                         this.shadowMap.enabled = value;
44873
44874                 }
44875         },
44876         shadowMapType: {
44877                 get: function () {
44878
44879                         return this.shadowMap.type;
44880
44881                 },
44882                 set: function ( value ) {
44883
44884                         console.warn( 'THREE.WebGLRenderer: .shadowMapType is now .shadowMap.type.' );
44885                         this.shadowMap.type = value;
44886
44887                 }
44888         },
44889         shadowMapCullFace: {
44890                 get: function () {
44891
44892                         console.warn( 'THREE.WebGLRenderer: .shadowMapCullFace has been removed. Set Material.shadowSide instead.' );
44893                         return undefined;
44894
44895                 },
44896                 set: function ( /* value */ ) {
44897
44898                         console.warn( 'THREE.WebGLRenderer: .shadowMapCullFace has been removed. Set Material.shadowSide instead.' );
44899
44900                 }
44901         },
44902         context: {
44903                 get: function () {
44904
44905                         console.warn( 'THREE.WebGLRenderer: .context has been removed. Use .getContext() instead.' );
44906                         return this.getContext();
44907
44908                 }
44909         },
44910         vr: {
44911                 get: function () {
44912
44913                         console.warn( 'THREE.WebGLRenderer: .vr has been renamed to .xr' );
44914                         return this.xr;
44915
44916                 }
44917         },
44918         gammaInput: {
44919                 get: function () {
44920
44921                         console.warn( 'THREE.WebGLRenderer: .gammaInput has been removed. Set the encoding for textures via Texture.encoding instead.' );
44922                         return false;
44923
44924                 },
44925                 set: function () {
44926
44927                         console.warn( 'THREE.WebGLRenderer: .gammaInput has been removed. Set the encoding for textures via Texture.encoding instead.' );
44928
44929                 }
44930         },
44931         gammaOutput: {
44932                 get: function () {
44933
44934                         console.warn( 'THREE.WebGLRenderer: .gammaOutput has been removed. Set WebGLRenderer.outputEncoding instead.' );
44935                         return false;
44936
44937                 },
44938                 set: function ( value ) {
44939
44940                         console.warn( 'THREE.WebGLRenderer: .gammaOutput has been removed. Set WebGLRenderer.outputEncoding instead.' );
44941                         this.outputEncoding = ( value === true ) ? sRGBEncoding : LinearEncoding;
44942
44943                 }
44944         },
44945         toneMappingWhitePoint: {
44946                 get: function () {
44947
44948                         console.warn( 'THREE.WebGLRenderer: .toneMappingWhitePoint has been removed.' );
44949                         return 1.0;
44950
44951                 },
44952                 set: function () {
44953
44954                         console.warn( 'THREE.WebGLRenderer: .toneMappingWhitePoint has been removed.' );
44955
44956                 }
44957         },
44958
44959 } );
44960
44961 Object.defineProperties( WebGLShadowMap.prototype, {
44962
44963         cullFace: {
44964                 get: function () {
44965
44966                         console.warn( 'THREE.WebGLRenderer: .shadowMap.cullFace has been removed. Set Material.shadowSide instead.' );
44967                         return undefined;
44968
44969                 },
44970                 set: function ( /* cullFace */ ) {
44971
44972                         console.warn( 'THREE.WebGLRenderer: .shadowMap.cullFace has been removed. Set Material.shadowSide instead.' );
44973
44974                 }
44975         },
44976         renderReverseSided: {
44977                 get: function () {
44978
44979                         console.warn( 'THREE.WebGLRenderer: .shadowMap.renderReverseSided has been removed. Set Material.shadowSide instead.' );
44980                         return undefined;
44981
44982                 },
44983                 set: function () {
44984
44985                         console.warn( 'THREE.WebGLRenderer: .shadowMap.renderReverseSided has been removed. Set Material.shadowSide instead.' );
44986
44987                 }
44988         },
44989         renderSingleSided: {
44990                 get: function () {
44991
44992                         console.warn( 'THREE.WebGLRenderer: .shadowMap.renderSingleSided has been removed. Set Material.shadowSide instead.' );
44993                         return undefined;
44994
44995                 },
44996                 set: function () {
44997
44998                         console.warn( 'THREE.WebGLRenderer: .shadowMap.renderSingleSided has been removed. Set Material.shadowSide instead.' );
44999
45000                 }
45001         }
45002
45003 } );
45004
45005 //
45006
45007 Object.defineProperties( WebGLRenderTarget.prototype, {
45008
45009         wrapS: {
45010                 get: function () {
45011
45012                         console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' );
45013                         return this.texture.wrapS;
45014
45015                 },
45016                 set: function ( value ) {
45017
45018                         console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' );
45019                         this.texture.wrapS = value;
45020
45021                 }
45022         },
45023         wrapT: {
45024                 get: function () {
45025
45026                         console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' );
45027                         return this.texture.wrapT;
45028
45029                 },
45030                 set: function ( value ) {
45031
45032                         console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' );
45033                         this.texture.wrapT = value;
45034
45035                 }
45036         },
45037         magFilter: {
45038                 get: function () {
45039
45040                         console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' );
45041                         return this.texture.magFilter;
45042
45043                 },
45044                 set: function ( value ) {
45045
45046                         console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' );
45047                         this.texture.magFilter = value;
45048
45049                 }
45050         },
45051         minFilter: {
45052                 get: function () {
45053
45054                         console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' );
45055                         return this.texture.minFilter;
45056
45057                 },
45058                 set: function ( value ) {
45059
45060                         console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' );
45061                         this.texture.minFilter = value;
45062
45063                 }
45064         },
45065         anisotropy: {
45066                 get: function () {
45067
45068                         console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' );
45069                         return this.texture.anisotropy;
45070
45071                 },
45072                 set: function ( value ) {
45073
45074                         console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' );
45075                         this.texture.anisotropy = value;
45076
45077                 }
45078         },
45079         offset: {
45080                 get: function () {
45081
45082                         console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' );
45083                         return this.texture.offset;
45084
45085                 },
45086                 set: function ( value ) {
45087
45088                         console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' );
45089                         this.texture.offset = value;
45090
45091                 }
45092         },
45093         repeat: {
45094                 get: function () {
45095
45096                         console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' );
45097                         return this.texture.repeat;
45098
45099                 },
45100                 set: function ( value ) {
45101
45102                         console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' );
45103                         this.texture.repeat = value;
45104
45105                 }
45106         },
45107         format: {
45108                 get: function () {
45109
45110                         console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' );
45111                         return this.texture.format;
45112
45113                 },
45114                 set: function ( value ) {
45115
45116                         console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' );
45117                         this.texture.format = value;
45118
45119                 }
45120         },
45121         type: {
45122                 get: function () {
45123
45124                         console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' );
45125                         return this.texture.type;
45126
45127                 },
45128                 set: function ( value ) {
45129
45130                         console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' );
45131                         this.texture.type = value;
45132
45133                 }
45134         },
45135         generateMipmaps: {
45136                 get: function () {
45137
45138                         console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' );
45139                         return this.texture.generateMipmaps;
45140
45141                 },
45142                 set: function ( value ) {
45143
45144                         console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' );
45145                         this.texture.generateMipmaps = value;
45146
45147                 }
45148         }
45149
45150 } );
45151
45152 //
45153
45154 Audio.prototype.load = function ( file ) {
45155
45156         console.warn( 'THREE.Audio: .load has been deprecated. Use THREE.AudioLoader instead.' );
45157         const scope = this;
45158         const audioLoader = new AudioLoader();
45159         audioLoader.load( file, function ( buffer ) {
45160
45161                 scope.setBuffer( buffer );
45162
45163         } );
45164         return this;
45165
45166 };
45167
45168 //
45169
45170 CubeCamera.prototype.updateCubeMap = function ( renderer, scene ) {
45171
45172         console.warn( 'THREE.CubeCamera: .updateCubeMap() is now .update().' );
45173         return this.update( renderer, scene );
45174
45175 };
45176
45177 CubeCamera.prototype.clear = function ( renderer, color, depth, stencil ) {
45178
45179         console.warn( 'THREE.CubeCamera: .clear() is now .renderTarget.clear().' );
45180         return this.renderTarget.clear( renderer, color, depth, stencil );
45181
45182 };
45183
45184 ImageUtils.crossOrigin = undefined;
45185
45186 ImageUtils.loadTexture = function ( url, mapping, onLoad, onError ) {
45187
45188         console.warn( 'THREE.ImageUtils.loadTexture has been deprecated. Use THREE.TextureLoader() instead.' );
45189
45190         const loader = new TextureLoader();
45191         loader.setCrossOrigin( this.crossOrigin );
45192
45193         const texture = loader.load( url, onLoad, undefined, onError );
45194
45195         if ( mapping ) texture.mapping = mapping;
45196
45197         return texture;
45198
45199 };
45200
45201 ImageUtils.loadTextureCube = function ( urls, mapping, onLoad, onError ) {
45202
45203         console.warn( 'THREE.ImageUtils.loadTextureCube has been deprecated. Use THREE.CubeTextureLoader() instead.' );
45204
45205         const loader = new CubeTextureLoader();
45206         loader.setCrossOrigin( this.crossOrigin );
45207
45208         const texture = loader.load( urls, onLoad, undefined, onError );
45209
45210         if ( mapping ) texture.mapping = mapping;
45211
45212         return texture;
45213
45214 };
45215
45216 ImageUtils.loadCompressedTexture = function () {
45217
45218         console.error( 'THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.' );
45219
45220 };
45221
45222 ImageUtils.loadCompressedTextureCube = function () {
45223
45224         console.error( 'THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.' );
45225
45226 };
45227
45228 if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {
45229
45230         /* eslint-disable no-undef */
45231         __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'register', { detail: {
45232                 revision: REVISION,
45233         } } ) );
45234         /* eslint-enable no-undef */
45235
45236 }
45237
45238 if ( typeof window !== 'undefined' ) {
45239
45240         if ( window.__THREE__ ) {
45241
45242                 console.warn( 'WARNING: Multiple instances of Three.js being imported.' );
45243
45244         } else {
45245
45246                 window.__THREE__ = REVISION;
45247
45248         }
45249
45250 }
45251
45252 const DEG2RAD = Math.PI / 180;
45253 const RAD2DEG = 180 / Math.PI;
45254 const WGS84A = 6378137.0;
45255 const WGS84B = 6356752.31424518;
45256 /**
45257  * Convert coordinates from geodetic (WGS84) reference to local topocentric
45258  * (ENU) reference.
45259  *
45260  * @param {number} lng Longitude in degrees.
45261  * @param {number} lat Latitude in degrees.
45262  * @param {number} alt Altitude in meters.
45263  * @param {number} refLng Reference longitude in degrees.
45264  * @param {number} refLat Reference latitude in degrees.
45265  * @param {number} refAlt Reference altitude in meters.
45266  * @returns {Array<number>} The x, y, z local topocentric ENU coordinates.
45267  */
45268 function geodeticToEnu(lng, lat, alt, refLng, refLat, refAlt) {
45269     const ecef = geodeticToEcef(lng, lat, alt);
45270     return ecefToEnu(ecef[0], ecef[1], ecef[2], refLng, refLat, refAlt);
45271 }
45272 /**
45273  * Convert coordinates from local topocentric (ENU) reference to
45274  * geodetic (WGS84) reference.
45275  *
45276  * @param {number} x Topocentric ENU coordinate in East direction.
45277  * @param {number} y Topocentric ENU coordinate in North direction.
45278  * @param {number} z Topocentric ENU coordinate in Up direction.
45279  * @param {number} refLng Reference longitude in degrees.
45280  * @param {number} refLat Reference latitude in degrees.
45281  * @param {number} refAlt Reference altitude in meters.
45282  * @returns {Array<number>} The longitude, latitude in degrees
45283  * and altitude in meters.
45284  */
45285 function enuToGeodetic(x, y, z, refLng, refLat, refAlt) {
45286     const ecef = enuToEcef(x, y, z, refLng, refLat, refAlt);
45287     return ecefToGeodetic(ecef[0], ecef[1], ecef[2]);
45288 }
45289 /**
45290  * Convert coordinates from Earth-Centered, Earth-Fixed (ECEF) reference
45291  * to local topocentric (ENU) reference.
45292  *
45293  * @param {number} X ECEF X-value.
45294  * @param {number} Y ECEF Y-value.
45295  * @param {number} Z ECEF Z-value.
45296  * @param {number} refLng Reference longitude in degrees.
45297  * @param {number} refLat Reference latitude in degrees.
45298  * @param {number} refAlt Reference altitude in meters.
45299  * @returns {Array<number>} The x, y, z topocentric ENU coordinates in East, North
45300  * and Up directions respectively.
45301  */
45302 function ecefToEnu(X, Y, Z, refLng, refLat, refAlt) {
45303     const refEcef = geodeticToEcef(refLng, refLat, refAlt);
45304     const V = [
45305         X - refEcef[0],
45306         Y - refEcef[1],
45307         Z - refEcef[2],
45308     ];
45309     refLng = refLng * DEG2RAD;
45310     refLat = refLat * DEG2RAD;
45311     const cosLng = Math.cos(refLng);
45312     const sinLng = Math.sin(refLng);
45313     const cosLat = Math.cos(refLat);
45314     const sinLat = Math.sin(refLat);
45315     const x = -sinLng * V[0] + cosLng * V[1];
45316     const y = -sinLat * cosLng * V[0] - sinLat * sinLng * V[1] + cosLat * V[2];
45317     const z = cosLat * cosLng * V[0] + cosLat * sinLng * V[1] + sinLat * V[2];
45318     return [x, y, z];
45319 }
45320 /**
45321  * Convert coordinates from local topocentric (ENU) reference
45322  * to Earth-Centered, Earth-Fixed (ECEF) reference.
45323  *
45324  * @param {number} x Topocentric ENU coordinate in East direction.
45325  * @param {number} y Topocentric ENU coordinate in North direction.
45326  * @param {number} z Topocentric ENU coordinate in Up direction.
45327  * @param {number} refLng Reference longitude in degrees.
45328  * @param {number} refLat Reference latitude in degrees.
45329  * @param {number} refAlt Reference altitude in meters.
45330  * @returns {Array<number>} The X, Y, Z ECEF coordinates.
45331  */
45332 function enuToEcef(x, y, z, refLng, refLat, refAlt) {
45333     const refEcef = geodeticToEcef(refLng, refLat, refAlt);
45334     refLng = refLng * DEG2RAD;
45335     refLat = refLat * DEG2RAD;
45336     const cosLng = Math.cos(refLng);
45337     const sinLng = Math.sin(refLng);
45338     const cosLat = Math.cos(refLat);
45339     const sinLat = Math.sin(refLat);
45340     const X = -sinLng * x
45341         - sinLat * cosLng * y
45342         + cosLat * cosLng * z
45343         + refEcef[0];
45344     const Y = cosLng * x
45345         - sinLat * sinLng * y
45346         + cosLat * sinLng * z
45347         + refEcef[1];
45348     const Z = cosLat * y +
45349         sinLat * z +
45350         refEcef[2];
45351     return [X, Y, Z];
45352 }
45353 /**
45354  * Convert coordinates from geodetic reference (WGS84) to Earth-Centered,
45355  * Earth-Fixed (ECEF) reference.
45356  *
45357  * @param {number} lng Longitude in degrees.
45358  * @param {number} lat Latitude in degrees.
45359  * @param {number} alt Altitude in meters.
45360  * @returns {Array<number>} The X, Y, Z ECEF coordinates.
45361  */
45362 function geodeticToEcef(lng, lat, alt) {
45363     const a = WGS84A;
45364     const b = WGS84B;
45365     lng = lng * DEG2RAD;
45366     lat = lat * DEG2RAD;
45367     const cosLng = Math.cos(lng);
45368     const sinLng = Math.sin(lng);
45369     const cosLat = Math.cos(lat);
45370     const sinLat = Math.sin(lat);
45371     const a2 = a * a;
45372     const b2 = b * b;
45373     const L = 1.0 / Math.sqrt(a2 * cosLat * cosLat + b2 * sinLat * sinLat);
45374     const nhcl = (a2 * L + alt) * cosLat;
45375     const X = nhcl * cosLng;
45376     const Y = nhcl * sinLng;
45377     const Z = (b2 * L + alt) * sinLat;
45378     return [X, Y, Z];
45379 }
45380 /**
45381  * Convert coordinates from Earth-Centered, Earth-Fixed (ECEF) reference
45382  * to geodetic reference (WGS84).
45383  *
45384  * @param {number} X ECEF X-value.
45385  * @param {number} Y ECEF Y-value.
45386  * @param {number} Z ECEF Z-value.
45387  * @returns {Array<number>} The longitude, latitude in degrees
45388  * and altitude in meters.
45389  */
45390 function ecefToGeodetic(X, Y, Z) {
45391     const a = WGS84A;
45392     const b = WGS84B;
45393     const a2 = a * a;
45394     const b2 = b * b;
45395     const a2mb2 = a2 - b2;
45396     const ea = Math.sqrt(a2mb2 / a2);
45397     const eb = Math.sqrt(a2mb2 / b2);
45398     const p = Math.sqrt(X * X + Y * Y);
45399     const theta = Math.atan2(Z * a, p * b);
45400     const sinTheta = Math.sin(theta);
45401     const cosTheta = Math.cos(theta);
45402     const lng = Math.atan2(Y, X);
45403     const lat = Math.atan2(Z + eb * eb * b * sinTheta * sinTheta * sinTheta, p - ea * ea * a * cosTheta * cosTheta * cosTheta);
45404     const sinLat = Math.sin(lat);
45405     const cosLat = Math.cos(lat);
45406     const N = a / Math.sqrt(1 - ea * ea * sinLat * sinLat);
45407     const alt = p / cosLat - N;
45408     return [
45409         lng * RAD2DEG,
45410         lat * RAD2DEG,
45411         alt
45412     ];
45413 }
45414
45415 /**
45416  * @class GraphCalculator
45417  *
45418  * @classdesc Represents a calculator for graph entities.
45419  */
45420 class GraphCalculator {
45421     /**
45422      * Get the bounding box corners for a circle with radius of a threshold
45423      * with center in a geodetic position.
45424      *
45425      * @param {LngLat} lngLat - Longitude, latitude to encode.
45426      * @param {number} threshold - Threshold distance from the position in meters.
45427      *
45428      * @returns {Array<LngLat>} The south west and north east corners of the
45429      * bounding box.
45430      */
45431     boundingBoxCorners(lngLat, threshold) {
45432         const sw = enuToGeodetic(-threshold, -threshold, 0, lngLat.lng, lngLat.lat, 0);
45433         const ne = enuToGeodetic(threshold, threshold, 0, lngLat.lng, lngLat.lat, 0);
45434         return [
45435             { lat: sw[1], lng: sw[0] },
45436             { lat: ne[1], lng: ne[0] },
45437         ];
45438     }
45439     /**
45440      * Convert a compass angle to an angle axis rotation vector.
45441      *
45442      * @param {number} compassAngle - The compass angle in degrees.
45443      * @param {number} orientation - The orientation of the original image.
45444      *
45445      * @returns {Array<number>} Angle axis rotation vector.
45446      */
45447     rotationFromCompass(compassAngle, orientation) {
45448         let x = 0;
45449         let y = 0;
45450         let z = 0;
45451         switch (orientation) {
45452             case 1:
45453                 x = Math.PI / 2;
45454                 break;
45455             case 3:
45456                 x = -Math.PI / 2;
45457                 z = Math.PI;
45458                 break;
45459             case 6:
45460                 y = -Math.PI / 2;
45461                 z = -Math.PI / 2;
45462                 break;
45463             case 8:
45464                 y = Math.PI / 2;
45465                 z = Math.PI / 2;
45466                 break;
45467         }
45468         const rz = new Matrix4()
45469             .makeRotationZ(z);
45470         const euler = new Euler(x, y, compassAngle * Math.PI / 180, "XYZ");
45471         const re = new Matrix4()
45472             .makeRotationFromEuler(euler);
45473         const rotation = new Vector4()
45474             .setAxisAngleFromRotationMatrix(re.multiply(rz));
45475         return rotation
45476             .multiplyScalar(rotation.w)
45477             .toArray()
45478             .slice(0, 3);
45479     }
45480 }
45481
45482 /**
45483  * @class Image
45484  *
45485  * @classdesc Represents a image in the navigation graph.
45486  *
45487  * Explanation of position and bearing properties:
45488  *
45489  * When images are uploaded they will have GPS information in the EXIF, this is what
45490  * is called `originalLngLat` {@link Image.originalLngLat}.
45491  *
45492  * When Structure from Motions has been run for a image a `computedLngLat` that
45493  * differs from the `originalLngLat` will be created. It is different because
45494  * GPS positions are not very exact and SfM aligns the camera positions according
45495  * to the 3D reconstruction {@link Image.computedLngLat}.
45496  *
45497  * At last there exist a `lngLat` property which evaluates to
45498  * the `computedLngLat` from SfM if it exists but falls back
45499  * to the `originalLngLat` from the EXIF GPS otherwise {@link Image.lngLat}.
45500  *
45501  * Everything that is done in in the Viewer is based on the SfM positions,
45502  * i.e. `computedLngLat`. That is why the smooth transitions go in the right
45503  * direction (nd not in strange directions because of bad GPS).
45504  *
45505  * E.g. when placing a marker in the Viewer it is relative to the SfM
45506  * position i.e. the `computedLngLat`.
45507  *
45508  * The same concept as above also applies to the compass angle (or bearing) properties
45509  * `originalCa`, `computedCa` and `ca`.
45510  */
45511 class Image$1 {
45512     /**
45513      * Create a new image instance.
45514      *
45515      * @description Images are always created internally by the library.
45516      * Images can not be added to the library through any API method.
45517      *
45518      * @param {CoreImageEnt} core- Raw core image data.
45519      * @ignore
45520      */
45521     constructor(core) {
45522         if (!core) {
45523             throw new Error(`Incorrect core image data ${core}`);
45524         }
45525         this._cache = null;
45526         this._core = core;
45527         this._spatial = null;
45528     }
45529     /**
45530      * Get assets cached.
45531      *
45532      * @description The assets that need to be cached for this property
45533      * to report true are the following: fill properties, image and mesh.
45534      * The library ensures that the current image will always have the
45535      * assets cached.
45536      *
45537      * @returns {boolean} Value indicating whether all assets have been
45538      * cached.
45539      *
45540      * @ignore
45541      */
45542     get assetsCached() {
45543         return this._core != null &&
45544             this._spatial != null &&
45545             this._cache != null &&
45546             this._cache.image != null &&
45547             this._cache.mesh != null;
45548     }
45549     /**
45550      * Get cameraParameters.
45551      *
45552      * @description Will be undefined if SfM has
45553      * not been run.
45554      *
45555      * Camera type dependent parameters.
45556      *
45557      * For perspective and fisheye camera types,
45558      * the camera parameters array should be
45559      * constructed according to
45560      *
45561      * `[focal, k1, k2]`
45562      *
45563      * where focal is the camera focal length,
45564      * and k1, k2 are radial distortion parameters.
45565      *
45566      * For spherical camera type the camera
45567      * parameters are unset or emtpy array.
45568      *
45569      * @returns {Array<number>} The parameters
45570      * related to the camera type.
45571      */
45572     get cameraParameters() {
45573         return this._spatial.camera_parameters;
45574     }
45575     /**
45576      * Get cameraType.
45577      *
45578      * @description Will be undefined if SfM has not been run.
45579      *
45580      * @returns {string} The camera type that captured the image.
45581      */
45582     get cameraType() {
45583         return this._spatial.camera_type;
45584     }
45585     /**
45586      * Get capturedAt.
45587      *
45588      * @description Timestamp of the image capture date
45589      * and time represented as a Unix epoch timestamp in milliseconds.
45590      *
45591      * @returns {number} Timestamp when the image was captured.
45592      */
45593     get capturedAt() {
45594         return this._spatial.captured_at;
45595     }
45596     /**
45597      * Get clusterId.
45598      *
45599      * @returns {string} Globally unique id of the SfM cluster to which
45600      * the image belongs.
45601      */
45602     get clusterId() {
45603         return !!this._spatial.cluster ?
45604             this._spatial.cluster.id :
45605             null;
45606     }
45607     /**
45608      * Get clusterUrl.
45609      *
45610      * @returns {string} Url to the cluster reconstruction file.
45611      *
45612      * @ignore
45613      */
45614     get clusterUrl() {
45615         return !!this._spatial.cluster ?
45616             this._spatial.cluster.url :
45617             null;
45618     }
45619     /**
45620      * Get compassAngle.
45621      *
45622      * @description If the SfM computed compass angle exists it will
45623      * be returned, otherwise the original EXIF compass angle.
45624      *
45625      * @returns {number} Compass angle, measured in degrees
45626      * clockwise with respect to north.
45627      */
45628     get compassAngle() {
45629         return this._spatial.computed_compass_angle != null ?
45630             this._spatial.computed_compass_angle :
45631             this._spatial.compass_angle;
45632     }
45633     /**
45634      * Get complete.
45635      *
45636      * @description The library ensures that the current image will
45637      * always be full.
45638      *
45639      * @returns {boolean} Value indicating whether the image has all
45640      * properties filled.
45641      *
45642      * @ignore
45643      */
45644     get complete() {
45645         return this._spatial != null;
45646     }
45647     /**
45648      * Get computedAltitude.
45649      *
45650      * @description If SfM has not been run the computed altitude is
45651      * set to a default value of two meters.
45652      *
45653      * @returns {number} Altitude, in meters.
45654      */
45655     get computedAltitude() {
45656         return this._spatial.computed_altitude;
45657     }
45658     /**
45659      * Get computedCompassAngle.
45660      *
45661      * @description Will not be set if SfM has not been run.
45662      *
45663      * @returns {number} SfM computed compass angle, measured
45664      * in degrees clockwise with respect to north.
45665      */
45666     get computedCompassAngle() {
45667         return this._spatial.computed_compass_angle;
45668     }
45669     /**
45670      * Get computedLngLat.
45671      *
45672      * @description Will not be set if SfM has not been run.
45673      *
45674      * @returns {LngLat} SfM computed longitude, latitude in WGS84 datum,
45675      * measured in degrees.
45676      */
45677     get computedLngLat() {
45678         return this._core.computed_geometry;
45679     }
45680     /**
45681      * Get creatorId.
45682      *
45683      * @description Note that the creator ID will not be set when using
45684      * the Mapillary API.
45685      *
45686      * @returns {string} Globally unique id of the user who uploaded
45687      * the image.
45688      */
45689     get creatorId() {
45690         return this._spatial.creator.id;
45691     }
45692     /**
45693      * Get creatorUsername.
45694      *
45695      * @description Note that the creator username will not be set when
45696      * using the Mapillary API.
45697      *
45698      * @returns {string} Username of the creator who uploaded
45699      * the image.
45700      */
45701     get creatorUsername() {
45702         return this._spatial.creator.username;
45703     }
45704     /**
45705      * Get exifOrientation.
45706      *
45707      * @returns {number} EXIF orientation of original image.
45708      */
45709     get exifOrientation() {
45710         return this._spatial.exif_orientation;
45711     }
45712     /**
45713      * Get height.
45714      *
45715      * @returns {number} Height of original image, not adjusted
45716      * for orientation.
45717      */
45718     get height() {
45719         return this._spatial.height;
45720     }
45721     /**
45722      * Get image.
45723      *
45724      * @description The image will always be set on the current image.
45725      *
45726      * @returns {HTMLImageElement} Cached image element of the image.
45727      */
45728     get image() {
45729         return this._cache.image;
45730     }
45731     /**
45732      * Get image$.
45733      *
45734      * @returns {Observable<HTMLImageElement>} Observable emitting
45735      * the cached image when it is updated.
45736      *
45737      * @ignore
45738      */
45739     get image$() {
45740         return this._cache.image$;
45741     }
45742     /**
45743      * Get id.
45744      *
45745      * @returns {string} Globally unique id of the image.
45746      */
45747     get id() {
45748         return this._core.id;
45749     }
45750     /**
45751      * Get lngLat.
45752      *
45753      * @description If the SfM computed longitude, latitude exist
45754      * it will be returned, otherwise the original EXIF latitude
45755      * longitude.
45756      *
45757      * @returns {LngLat} Longitude, latitude in WGS84 datum,
45758      * measured in degrees.
45759      */
45760     get lngLat() {
45761         return this._core.computed_geometry != null ?
45762             this._core.computed_geometry :
45763             this._core.geometry;
45764     }
45765     /**
45766      * Get merged.
45767      *
45768      * @returns {boolean} Value indicating whether SfM has been
45769      * run on the image and the image has been merged into a
45770      * connected component.
45771      */
45772     get merged() {
45773         return this._spatial != null &&
45774             this._spatial.merge_id != null;
45775     }
45776     /**
45777      * Get mergeId.
45778      *
45779      * @description Will not be set if SfM has not yet been run on
45780      * image.
45781      *
45782      * @returns {stirng} Id of connected component to which image
45783      * belongs after the aligning merge.
45784      */
45785     get mergeId() {
45786         return this._spatial.merge_id;
45787     }
45788     /**
45789      * Get mesh.
45790      *
45791      * @description The mesh will always be set on the current image.
45792      *
45793      * @returns {MeshContract} SfM triangulated mesh of reconstructed
45794      * atomic 3D points.
45795      */
45796     get mesh() {
45797         return this._cache.mesh;
45798     }
45799     /**
45800      * Get originalAltitude.
45801      *
45802      * @returns {number} EXIF altitude, in meters, if available.
45803      */
45804     get originalAltitude() {
45805         return this._spatial.altitude;
45806     }
45807     /**
45808      * Get originalCompassAngle.
45809      *
45810      * @returns {number} Original EXIF compass angle, measured in
45811      * degrees.
45812      */
45813     get originalCompassAngle() {
45814         return this._spatial.compass_angle;
45815     }
45816     /**
45817      * Get originalLngLat.
45818      *
45819      * @returns {LngLat} Original EXIF longitude, latitude in
45820      * WGS84 datum, measured in degrees.
45821      */
45822     get originalLngLat() {
45823         return this._core.geometry;
45824     }
45825     /**
45826      * Get ownerId.
45827      *
45828      * @returns {string} Globally unique id of the owner to which
45829      * the image belongs. If the image does not belong to an
45830      * owner the owner id will be undefined.
45831      */
45832     get ownerId() {
45833         return !!this._spatial.owner ?
45834             this._spatial.owner.id :
45835             null;
45836     }
45837     /**
45838      * Get private.
45839      *
45840      * @returns {boolean} Value specifying if image is accessible to
45841      * organization members only or to everyone.
45842      */
45843     get private() {
45844         return this._spatial.private;
45845     }
45846     /**
45847      * Get qualityScore.
45848      *
45849      * @returns {number} A number between zero and one
45850      * determining the quality of the image. Blurriness
45851      * (motion blur / out-of-focus), occlusion (camera
45852      * mount, ego vehicle, water-drops), windshield
45853      * reflections, bad illumination (exposure, glare),
45854      * and bad weather condition (fog, rain, snow)
45855      * affect the quality score.
45856      *
45857      * @description Value should be on the interval [0, 1].
45858      */
45859     get qualityScore() {
45860         return this._spatial.quality_score;
45861     }
45862     /**
45863      * Get rotation.
45864      *
45865      * @description Will not be set if SfM has not been run.
45866      *
45867      * @returns {Array<number>} Rotation vector in angle axis representation.
45868      */
45869     get rotation() {
45870         return this._spatial.computed_rotation;
45871     }
45872     /**
45873      * Get scale.
45874      *
45875      * @description Will not be set if SfM has not been run.
45876      *
45877      * @returns {number} Scale of reconstruction the image
45878      * belongs to.
45879      */
45880     get scale() {
45881         return this._spatial.atomic_scale;
45882     }
45883     /**
45884      * Get sequenceId.
45885      *
45886      * @returns {string} Globally unique id of the sequence
45887      * to which the image belongs.
45888      */
45889     get sequenceId() {
45890         return !!this._core.sequence ?
45891             this._core.sequence.id :
45892             null;
45893     }
45894     /**
45895      * Get sequenceEdges.
45896      *
45897      * @returns {NavigationEdgeStatus} Value describing the status of the
45898      * sequence edges.
45899      *
45900      * @ignore
45901      */
45902     get sequenceEdges() {
45903         return this._cache.sequenceEdges;
45904     }
45905     /**
45906      * Get sequenceEdges$.
45907      *
45908      * @description Internal observable, should not be used as an API.
45909      *
45910      * @returns {Observable<NavigationEdgeStatus>} Observable emitting
45911      * values describing the status of the sequence edges.
45912      *
45913      * @ignore
45914      */
45915     get sequenceEdges$() {
45916         return this._cache.sequenceEdges$;
45917     }
45918     /**
45919      * Get spatialEdges.
45920      *
45921      * @returns {NavigationEdgeStatus} Value describing the status of the
45922      * spatial edges.
45923      *
45924      * @ignore
45925      */
45926     get spatialEdges() {
45927         return this._cache.spatialEdges;
45928     }
45929     /**
45930      * Get spatialEdges$.
45931      *
45932      * @description Internal observable, should not be used as an API.
45933      *
45934      * @returns {Observable<NavigationEdgeStatus>} Observable emitting
45935      * values describing the status of the spatial edges.
45936      *
45937      * @ignore
45938      */
45939     get spatialEdges$() {
45940         return this._cache.spatialEdges$;
45941     }
45942     /**
45943      * Get width.
45944      *
45945      * @returns {number} Width of original image, not
45946      * adjusted for orientation.
45947      */
45948     get width() {
45949         return this._spatial.width;
45950     }
45951     /**
45952      * Cache the image and mesh assets.
45953      *
45954      * @description The assets are always cached internally by the
45955      * library prior to setting a image as the current image.
45956      *
45957      * @returns {Observable<Image>} Observable emitting this image whenever the
45958      * load status has changed and when the mesh or image has been fully loaded.
45959      *
45960      * @ignore
45961      */
45962     cacheAssets$() {
45963         return this._cache
45964             .cacheAssets$(this._spatial, this.merged)
45965             .pipe(map(() => { return this; }));
45966     }
45967     /**
45968      * Cache the image asset.
45969      *
45970      * @description Use for caching a differently sized image than
45971      * the one currently held by the image.
45972      *
45973      * @returns {Observable<Image>} Observable emitting this image whenever the
45974      * load status has changed and when the mesh or image has been fully loaded.
45975      *
45976      * @ignore
45977      */
45978     cacheImage$() {
45979         return this._cache
45980             .cacheImage$(this._spatial)
45981             .pipe(map(() => { return this; }));
45982     }
45983     /**
45984      * Cache the sequence edges.
45985      *
45986      * @description The sequence edges are cached asynchronously
45987      * internally by the library.
45988      *
45989      * @param {Array<NavigationEdge>} edges - Sequence edges to cache.
45990      * @ignore
45991      */
45992     cacheSequenceEdges(edges) {
45993         this._cache.cacheSequenceEdges(edges);
45994     }
45995     /**
45996      * Cache the spatial edges.
45997      *
45998      * @description The spatial edges are cached asynchronously
45999      * internally by the library.
46000      *
46001      * @param {Array<NavigationEdge>} edges - Spatial edges to cache.
46002      * @ignore
46003      */
46004     cacheSpatialEdges(edges) {
46005         this._cache.cacheSpatialEdges(edges);
46006     }
46007     /**
46008      * Dispose the image.
46009      *
46010      * @description Disposes all cached assets.
46011      * @ignore
46012      */
46013     dispose() {
46014         if (this._cache != null) {
46015             this._cache.dispose();
46016             this._cache = null;
46017         }
46018         this._core = null;
46019         this._spatial = null;
46020     }
46021     /**
46022      * Initialize the image cache.
46023      *
46024      * @description The image cache is initialized internally by
46025      * the library.
46026      *
46027      * @param {ImageCache} cache - The image cache to set as cache.
46028      * @ignore
46029      */
46030     initializeCache(cache) {
46031         if (this._cache != null) {
46032             throw new Error(`Image cache already initialized (${this.id}).`);
46033         }
46034         this._cache = cache;
46035     }
46036     /**
46037      * Complete an image with spatial properties.
46038      *
46039      * @description The image is completed internally by
46040      * the library.
46041      *
46042      * @param {SpatialImageEnt} fill - The spatial image struct.
46043      * @ignore
46044      */
46045     makeComplete(fill) {
46046         if (fill == null) {
46047             throw new Error("Fill can not be null.");
46048         }
46049         this._spatial = fill;
46050     }
46051     /**
46052      * Reset the sequence edges.
46053      *
46054      * @ignore
46055      */
46056     resetSequenceEdges() {
46057         this._cache.resetSequenceEdges();
46058     }
46059     /**
46060      * Reset the spatial edges.
46061      *
46062      * @ignore
46063      */
46064     resetSpatialEdges() {
46065         this._cache.resetSpatialEdges();
46066     }
46067     /**
46068      * Clears the image and mesh assets, aborts
46069      * any outstanding requests and resets edges.
46070      *
46071      * @ignore
46072      */
46073     uncache() {
46074         if (this._cache == null) {
46075             return;
46076         }
46077         this._cache.dispose();
46078         this._cache = null;
46079     }
46080 }
46081
46082 /**
46083  * @class ImageCache
46084  *
46085  * @classdesc Represents the cached properties of a image.
46086  */
46087 class ImageCache {
46088     /**
46089      * Create a new image cache instance.
46090      */
46091     constructor(provider) {
46092         this._disposed = false;
46093         this._provider = provider;
46094         this._image = null;
46095         this._mesh = null;
46096         this._sequenceEdges = { cached: false, edges: [] };
46097         this._spatialEdges = { cached: false, edges: [] };
46098         this._imageChanged$ = new Subject();
46099         this._image$ = this._imageChanged$.pipe(startWith(null), publishReplay(1), refCount());
46100         this._iamgeSubscription = this._image$.subscribe();
46101         this._sequenceEdgesChanged$ = new Subject();
46102         this._sequenceEdges$ = this._sequenceEdgesChanged$.pipe(startWith(this._sequenceEdges), publishReplay(1), refCount());
46103         this._sequenceEdgesSubscription = this._sequenceEdges$.subscribe(() => { });
46104         this._spatialEdgesChanged$ = new Subject();
46105         this._spatialEdges$ = this._spatialEdgesChanged$.pipe(startWith(this._spatialEdges), publishReplay(1), refCount());
46106         this._spatialEdgesSubscription = this._spatialEdges$.subscribe(() => { });
46107         this._cachingAssets$ = null;
46108     }
46109     /**
46110      * Get image.
46111      *
46112      * @description Will not be set when assets have not been cached
46113      * or when the object has been disposed.
46114      *
46115      * @returns {HTMLImageElement} Cached image element of the image.
46116      */
46117     get image() {
46118         return this._image;
46119     }
46120     /**
46121      * Get image$.
46122      *
46123      * @returns {Observable<HTMLImageElement>} Observable emitting
46124      * the cached image when it is updated.
46125      */
46126     get image$() {
46127         return this._image$;
46128     }
46129     /**
46130      * Get mesh.
46131      *
46132      * @description Will not be set when assets have not been cached
46133      * or when the object has been disposed.
46134      *
46135      * @returns {MeshContract} SfM triangulated mesh of reconstructed
46136      * atomic 3D points.
46137      */
46138     get mesh() {
46139         return this._mesh;
46140     }
46141     /**
46142      * Get sequenceEdges.
46143      *
46144      * @returns {NavigationEdgeStatus} Value describing the status of the
46145      * sequence edges.
46146      */
46147     get sequenceEdges() {
46148         return this._sequenceEdges;
46149     }
46150     /**
46151      * Get sequenceEdges$.
46152      *
46153      * @returns {Observable<NavigationEdgeStatus>} Observable emitting
46154      * values describing the status of the sequence edges.
46155      */
46156     get sequenceEdges$() {
46157         return this._sequenceEdges$;
46158     }
46159     /**
46160      * Get spatialEdges.
46161      *
46162      * @returns {NavigationEdgeStatus} Value describing the status of the
46163      * spatial edges.
46164      */
46165     get spatialEdges() {
46166         return this._spatialEdges;
46167     }
46168     /**
46169      * Get spatialEdges$.
46170      *
46171      * @returns {Observable<NavigationEdgeStatus>} Observable emitting
46172      * values describing the status of the spatial edges.
46173      */
46174     get spatialEdges$() {
46175         return this._spatialEdges$;
46176     }
46177     /**
46178      * Cache the image and mesh assets.
46179      *
46180      * @param {SpatialImageEnt} spatial - Spatial props of the image to cache.
46181      * @param {boolean} spherical - Value indicating whether image is a spherical.
46182      * @param {boolean} merged - Value indicating whether image is merged.
46183      * @returns {Observable<ImageCache>} Observable emitting this image
46184      * cache whenever the load status has changed and when the mesh or image
46185      * has been fully loaded.
46186      */
46187     cacheAssets$(spatial, merged) {
46188         if (this._cachingAssets$ != null) {
46189             return this._cachingAssets$;
46190         }
46191         this._cachingAssets$ = combineLatest(this._cacheImage$(spatial), this._cacheMesh$(spatial, merged)).pipe(map(([image, mesh]) => {
46192             this._image = image;
46193             this._mesh = mesh;
46194             return this;
46195         }), finalize(() => {
46196             this._cachingAssets$ = null;
46197         }), publishReplay(1), refCount());
46198         this._cachingAssets$.pipe(first((imageCache) => {
46199             return !!imageCache._image;
46200         }))
46201             .subscribe(() => {
46202             this._imageChanged$.next(this._image);
46203         }, () => { });
46204         return this._cachingAssets$;
46205     }
46206     /**
46207      * Cache an image with a higher resolution than the current one.
46208      *
46209      * @param {SpatialImageEnt} spatial - Spatial props.
46210      * @returns {Observable<ImageCache>} Observable emitting a single item,
46211      * the image cache, when the image has been cached. If supplied image
46212      * size is not larger than the current image size the image cache is
46213      * returned immediately.
46214      */
46215     cacheImage$(spatial) {
46216         if (this._image != null) {
46217             return of(this);
46218         }
46219         const cacheImage$ = this._cacheImage$(spatial)
46220             .pipe(first((image) => {
46221             return !!image;
46222         }), tap((image) => {
46223             this._disposeImage();
46224             this._image = image;
46225         }), map(() => {
46226             return this;
46227         }), publishReplay(1), refCount());
46228         cacheImage$
46229             .subscribe(() => {
46230             this._imageChanged$.next(this._image);
46231         }, () => { });
46232         return cacheImage$;
46233     }
46234     /**
46235      * Cache the sequence edges.
46236      *
46237      * @param {Array<NavigationEdge>} edges - Sequence edges to cache.
46238      */
46239     cacheSequenceEdges(edges) {
46240         this._sequenceEdges = { cached: true, edges: edges };
46241         this._sequenceEdgesChanged$.next(this._sequenceEdges);
46242     }
46243     /**
46244      * Cache the spatial edges.
46245      *
46246      * @param {Array<NavigationEdge>} edges - Spatial edges to cache.
46247      */
46248     cacheSpatialEdges(edges) {
46249         this._spatialEdges = { cached: true, edges: edges };
46250         this._spatialEdgesChanged$.next(this._spatialEdges);
46251     }
46252     /**
46253      * Dispose the image cache.
46254      *
46255      * @description Disposes all cached assets and unsubscribes to
46256      * all streams.
46257      */
46258     dispose() {
46259         this._iamgeSubscription.unsubscribe();
46260         this._sequenceEdgesSubscription.unsubscribe();
46261         this._spatialEdgesSubscription.unsubscribe();
46262         this._disposeImage();
46263         this._mesh = null;
46264         this._sequenceEdges = { cached: false, edges: [] };
46265         this._spatialEdges = { cached: false, edges: [] };
46266         this._imageChanged$.next(null);
46267         this._sequenceEdgesChanged$.next(this._sequenceEdges);
46268         this._spatialEdgesChanged$.next(this._spatialEdges);
46269         this._disposed = true;
46270         if (this._imageAborter != null) {
46271             this._imageAborter();
46272             this._imageAborter = null;
46273         }
46274         if (this._meshAborter != null) {
46275             this._meshAborter();
46276             this._meshAborter = null;
46277         }
46278     }
46279     /**
46280      * Reset the sequence edges.
46281      */
46282     resetSequenceEdges() {
46283         this._sequenceEdges = { cached: false, edges: [] };
46284         this._sequenceEdgesChanged$.next(this._sequenceEdges);
46285     }
46286     /**
46287      * Reset the spatial edges.
46288      */
46289     resetSpatialEdges() {
46290         this._spatialEdges = { cached: false, edges: [] };
46291         this._spatialEdgesChanged$.next(this._spatialEdges);
46292     }
46293     /**
46294      * Cache the image.
46295      *
46296      * @param {SpatialImageEnt} spatial - Spatial image.
46297      * @param {boolean} spherical - Value indicating whether image is a spherical.
46298      * @returns {Observable<ILoadStatusObject<HTMLImageElement>>} Observable
46299      * emitting a load status object every time the load status changes
46300      * and completes when the image is fully loaded.
46301      */
46302     _cacheImage$(spatial) {
46303         return Observable.create((subscriber) => {
46304             const abort = new Promise((_, reject) => {
46305                 this._imageAborter = reject;
46306             });
46307             const url = spatial.thumb.url;
46308             if (!url) {
46309                 const thumbId = spatial.thumb.id;
46310                 const message = `Incorrect thumb URL for ${spatial.id} ` +
46311                     `(${thumbId}, ${url})`;
46312                 subscriber.error(new Error(message));
46313                 return;
46314             }
46315             this._provider.getImageBuffer(url, abort)
46316                 .then((buffer) => {
46317                 this._imageAborter = null;
46318                 const image = new Image();
46319                 image.crossOrigin = "Anonymous";
46320                 image.onload = () => {
46321                     if (this._disposed) {
46322                         window.URL.revokeObjectURL(image.src);
46323                         const message = `Image load was aborted (${url})`;
46324                         subscriber.error(new Error(message));
46325                         return;
46326                     }
46327                     subscriber.next(image);
46328                     subscriber.complete();
46329                 };
46330                 image.onerror = () => {
46331                     this._imageAborter = null;
46332                     subscriber.error(new Error(`Failed to load image (${url})`));
46333                 };
46334                 const blob = new Blob([buffer]);
46335                 image.src = window.URL.createObjectURL(blob);
46336             }, (error) => {
46337                 this._imageAborter = null;
46338                 subscriber.error(error);
46339             });
46340         });
46341     }
46342     /**
46343      * Cache the mesh.
46344      *
46345      * @param {SpatialImageEnt} spatial - Spatial props.
46346      * @param {boolean} merged - Value indicating whether image is merged.
46347      * @returns {Observable<ILoadStatusObject<MeshContract>>} Observable emitting
46348      * a load status object every time the load status changes and completes
46349      * when the mesh is fully loaded.
46350      */
46351     _cacheMesh$(spatial, merged) {
46352         return Observable.create((subscriber) => {
46353             if (!merged) {
46354                 subscriber.next(this._createEmptyMesh());
46355                 subscriber.complete();
46356                 return;
46357             }
46358             const url = spatial.mesh.url;
46359             if (!url) {
46360                 const meshId = spatial.mesh.id;
46361                 const message = `Incorrect mesh URL for ${spatial.id} ` +
46362                     `(${meshId}, ${url})`;
46363                 console.warn(message);
46364                 subscriber.next(this._createEmptyMesh());
46365                 subscriber.complete();
46366                 return;
46367             }
46368             const abort = new Promise((_, reject) => {
46369                 this._meshAborter = reject;
46370             });
46371             this._provider.getMesh(url, abort)
46372                 .then((mesh) => {
46373                 this._meshAborter = null;
46374                 if (this._disposed) {
46375                     return;
46376                 }
46377                 subscriber.next(mesh);
46378                 subscriber.complete();
46379             }, (error) => {
46380                 this._meshAborter = null;
46381                 console.error(error);
46382                 subscriber.next(this._createEmptyMesh());
46383                 subscriber.complete();
46384             });
46385         });
46386     }
46387     /**
46388      * Create a load status object with an empty mesh.
46389      *
46390      * @returns {ILoadStatusObject<MeshContract>} Load status object
46391      * with empty mesh.
46392      */
46393     _createEmptyMesh() {
46394         return { faces: [], vertices: [] };
46395     }
46396     _disposeImage() {
46397         if (this._image != null) {
46398             window.URL.revokeObjectURL(this._image.src);
46399         }
46400         this._image = null;
46401     }
46402 }
46403
46404 /**
46405  * @class Sequence
46406  *
46407  * @classdesc Represents a sequence of ordered images.
46408  */
46409 class Sequence {
46410     /**
46411      * Create a new sequene instance.
46412      *
46413      * @param {SequenceEnt} sequence - Raw sequence data.
46414      */
46415     constructor(sequence) {
46416         this._id = sequence.id;
46417         this._imageIds = sequence.image_ids;
46418     }
46419     /**
46420      * Get id.
46421      *
46422      * @returns {string} Unique sequence id.
46423      */
46424     get id() {
46425         return this._id;
46426     }
46427     /**
46428      * Get ids.
46429      *
46430      * @returns {Array<string>} Array of ordered image ids in the sequence.
46431      */
46432     get imageIds() {
46433         return this._imageIds;
46434     }
46435     /**
46436      * Dispose the sequence.
46437      *
46438      * @description Disposes all cached assets.
46439      */
46440     dispose() {
46441         this._id = null;
46442         this._imageIds = null;
46443     }
46444     /**
46445      * Find the next image id in the sequence with respect to
46446      * the provided image id.
46447      *
46448      * @param {string} id - Reference image id.
46449      * @returns {string} Next id in sequence if it exists, null otherwise.
46450      */
46451     findNext(id) {
46452         let i = this._imageIds.indexOf(id);
46453         if ((i + 1) >= this._imageIds.length || i === -1) {
46454             return null;
46455         }
46456         else {
46457             return this._imageIds[i + 1];
46458         }
46459     }
46460     /**
46461      * Find the previous image id in the sequence with respect to
46462      * the provided image id.
46463      *
46464      * @param {string} id - Reference image id.
46465      * @returns {string} Previous id in sequence if it exists, null otherwise.
46466      */
46467     findPrev(id) {
46468         let i = this._imageIds.indexOf(id);
46469         if (i === 0 || i === -1) {
46470             return null;
46471         }
46472         else {
46473             return this._imageIds[i - 1];
46474         }
46475     }
46476 }
46477
46478 class EdgeCalculatorCoefficients {
46479     constructor() {
46480         this.sphericalPreferredDistance = 2;
46481         this.sphericalMotion = 2;
46482         this.sphericalSequencePenalty = 1;
46483         this.sphericalMergeCCPenalty = 4;
46484         this.stepPreferredDistance = 4;
46485         this.stepMotion = 3;
46486         this.stepRotation = 4;
46487         this.stepSequencePenalty = 2;
46488         this.stepMergeCCPenalty = 6;
46489         this.similarDistance = 2;
46490         this.similarRotation = 3;
46491         this.turnDistance = 4;
46492         this.turnMotion = 2;
46493         this.turnSequencePenalty = 1;
46494         this.turnMergeCCPenalty = 4;
46495     }
46496 }
46497
46498 /**
46499  * Enumeration for edge directions
46500  * @enum {number}
46501  * @readonly
46502  * @description Directions for edges in image graph describing
46503  * sequence, spatial and image type relations between nodes.
46504  */
46505 var NavigationDirection;
46506 (function (NavigationDirection) {
46507     /**
46508      * Next image in the sequence.
46509      */
46510     NavigationDirection[NavigationDirection["Next"] = 0] = "Next";
46511     /**
46512      * Previous image in the sequence.
46513      */
46514     NavigationDirection[NavigationDirection["Prev"] = 1] = "Prev";
46515     /**
46516      * Step to the left keeping viewing direction.
46517      */
46518     NavigationDirection[NavigationDirection["StepLeft"] = 2] = "StepLeft";
46519     /**
46520      * Step to the right keeping viewing direction.
46521      */
46522     NavigationDirection[NavigationDirection["StepRight"] = 3] = "StepRight";
46523     /**
46524      * Step forward keeping viewing direction.
46525      */
46526     NavigationDirection[NavigationDirection["StepForward"] = 4] = "StepForward";
46527     /**
46528      * Step backward keeping viewing direction.
46529      */
46530     NavigationDirection[NavigationDirection["StepBackward"] = 5] = "StepBackward";
46531     /**
46532      * Turn 90 degrees counter clockwise.
46533      */
46534     NavigationDirection[NavigationDirection["TurnLeft"] = 6] = "TurnLeft";
46535     /**
46536      * Turn 90 degrees clockwise.
46537      */
46538     NavigationDirection[NavigationDirection["TurnRight"] = 7] = "TurnRight";
46539     /**
46540      * Turn 180 degrees.
46541      */
46542     NavigationDirection[NavigationDirection["TurnU"] = 8] = "TurnU";
46543     /**
46544      * Spherical in general direction.
46545      */
46546     NavigationDirection[NavigationDirection["Spherical"] = 9] = "Spherical";
46547     /**
46548      * Looking in roughly the same direction at rougly the same position.
46549      */
46550     NavigationDirection[NavigationDirection["Similar"] = 10] = "Similar";
46551 })(NavigationDirection || (NavigationDirection = {}));
46552
46553 class EdgeCalculatorDirections {
46554     constructor() {
46555         this.steps = {};
46556         this.turns = {};
46557         this.spherical = {};
46558         this.steps[NavigationDirection.StepForward] = {
46559             direction: NavigationDirection.StepForward,
46560             motionChange: 0,
46561             useFallback: true,
46562         };
46563         this.steps[NavigationDirection.StepBackward] = {
46564             direction: NavigationDirection.StepBackward,
46565             motionChange: Math.PI,
46566             useFallback: true,
46567         };
46568         this.steps[NavigationDirection.StepLeft] = {
46569             direction: NavigationDirection.StepLeft,
46570             motionChange: Math.PI / 2,
46571             useFallback: false,
46572         };
46573         this.steps[NavigationDirection.StepRight] = {
46574             direction: NavigationDirection.StepRight,
46575             motionChange: -Math.PI / 2,
46576             useFallback: false,
46577         };
46578         this.turns[NavigationDirection.TurnLeft] = {
46579             direction: NavigationDirection.TurnLeft,
46580             directionChange: Math.PI / 2,
46581             motionChange: Math.PI / 4,
46582         };
46583         this.turns[NavigationDirection.TurnRight] = {
46584             direction: NavigationDirection.TurnRight,
46585             directionChange: -Math.PI / 2,
46586             motionChange: -Math.PI / 4,
46587         };
46588         this.turns[NavigationDirection.TurnU] = {
46589             direction: NavigationDirection.TurnU,
46590             directionChange: Math.PI,
46591             motionChange: null,
46592         };
46593         this.spherical[NavigationDirection.StepForward] = {
46594             direction: NavigationDirection.StepForward,
46595             directionChange: 0,
46596             next: NavigationDirection.StepLeft,
46597             prev: NavigationDirection.StepRight,
46598         };
46599         this.spherical[NavigationDirection.StepBackward] = {
46600             direction: NavigationDirection.StepBackward,
46601             directionChange: Math.PI,
46602             next: NavigationDirection.StepRight,
46603             prev: NavigationDirection.StepLeft,
46604         };
46605         this.spherical[NavigationDirection.StepLeft] = {
46606             direction: NavigationDirection.StepLeft,
46607             directionChange: Math.PI / 2,
46608             next: NavigationDirection.StepBackward,
46609             prev: NavigationDirection.StepForward,
46610         };
46611         this.spherical[NavigationDirection.StepRight] = {
46612             direction: NavigationDirection.StepRight,
46613             directionChange: -Math.PI / 2,
46614             next: NavigationDirection.StepForward,
46615             prev: NavigationDirection.StepBackward,
46616         };
46617     }
46618 }
46619
46620 class EdgeCalculatorSettings {
46621     constructor() {
46622         this.sphericalMinDistance = 0.1;
46623         this.sphericalMaxDistance = 20;
46624         this.sphericalPreferredDistance = 5;
46625         this.sphericalMaxItems = 4;
46626         this.sphericalMaxStepTurnChange = Math.PI / 8;
46627         this.rotationMaxDistance = this.turnMaxRigDistance;
46628         this.rotationMaxDirectionChange = Math.PI / 6;
46629         this.rotationMaxVerticalDirectionChange = Math.PI / 8;
46630         this.similarMaxDirectionChange = Math.PI / 8;
46631         this.similarMaxDistance = 12;
46632         this.similarMinTimeDifference = 12 * 3600 * 1000;
46633         this.stepMaxDistance = 20;
46634         this.stepMaxDirectionChange = Math.PI / 6;
46635         this.stepMaxDrift = Math.PI / 6;
46636         this.stepPreferredDistance = 4;
46637         this.turnMaxDistance = 15;
46638         this.turnMaxDirectionChange = 2 * Math.PI / 9;
46639         this.turnMaxRigDistance = 0.65;
46640         this.turnMinRigDirectionChange = Math.PI / 6;
46641     }
46642     get maxDistance() {
46643         return Math.max(this.sphericalMaxDistance, this.similarMaxDistance, this.stepMaxDistance, this.turnMaxDistance);
46644     }
46645 }
46646
46647 /**
46648  * @class MapillaryError
46649  *
46650  * @classdesc Generic Mapillary error.
46651  */
46652 class MapillaryError extends Error {
46653     constructor(message) {
46654         super(message);
46655         Object.setPrototypeOf(this, MapillaryError.prototype);
46656         this.name = "MapillaryError";
46657     }
46658 }
46659
46660 class ArgumentMapillaryError extends MapillaryError {
46661     constructor(message) {
46662         super(message != null ? message : "The argument is not valid.");
46663         Object.setPrototypeOf(this, ArgumentMapillaryError.prototype);
46664         this.name = "ArgumentMapillaryError";
46665     }
46666 }
46667
46668 /**
46669  * @class Spatial
46670  *
46671  * @classdesc Provides methods for scalar, vector and matrix calculations.
46672  */
46673 class Spatial {
46674     constructor() {
46675         this._epsilon = 1e-9;
46676     }
46677     /**
46678      * Converts azimuthal phi rotation (counter-clockwise with origin on X-axis) to
46679      * bearing (clockwise with origin at north or Y-axis).
46680      *
46681      * @param {number} phi - Azimuthal phi angle in radians.
46682      * @returns {number} Bearing in radians.
46683      */
46684     azimuthalToBearing(phi) {
46685         return -phi + Math.PI / 2;
46686     }
46687     /**
46688      * Converts degrees to radians.
46689      *
46690      * @param {number} deg - Degrees.
46691      * @returns {number} Radians.
46692      */
46693     degToRad(deg) {
46694         return Math.PI * deg / 180;
46695     }
46696     /**
46697      * Converts radians to degrees.
46698      *
46699      * @param {number} rad - Radians.
46700      * @returns {number} Degrees.
46701      */
46702     radToDeg(rad) {
46703         return 180 * rad / Math.PI;
46704     }
46705     /**
46706      * Creates a rotation matrix from an angle-axis vector.
46707      *
46708      * @param {Array<number>} angleAxis - Angle-axis representation of a rotation.
46709      * @returns {THREE.Matrix4} Rotation matrix.
46710      */
46711     rotationMatrix(angleAxis) {
46712         let axis = new Vector3(angleAxis[0], angleAxis[1], angleAxis[2]);
46713         let angle = axis.length();
46714         if (angle > 0) {
46715             axis.normalize();
46716         }
46717         return new Matrix4().makeRotationAxis(axis, angle);
46718     }
46719     /**
46720      * Rotates a vector according to a angle-axis rotation vector.
46721      *
46722      * @param {Array<number>} vector - Vector to rotate.
46723      * @param {Array<number>} angleAxis - Angle-axis representation of a rotation.
46724      * @returns {THREE.Vector3} Rotated vector.
46725      */
46726     rotate(vector, angleAxis) {
46727         let v = new Vector3(vector[0], vector[1], vector[2]);
46728         let rotationMatrix = this.rotationMatrix(angleAxis);
46729         v.applyMatrix4(rotationMatrix);
46730         return v;
46731     }
46732     /**
46733      * Calculates the optical center from a rotation vector
46734      * on the angle-axis representation and a translation vector
46735      * according to C = -R^T t.
46736      *
46737      * @param {Array<number>} rotation - Angle-axis representation of a rotation.
46738      * @param {Array<number>} translation - Translation vector.
46739      * @returns {THREE.Vector3} Optical center.
46740      */
46741     opticalCenter(rotation, translation) {
46742         let angleAxis = [-rotation[0], -rotation[1], -rotation[2]];
46743         let vector = [-translation[0], -translation[1], -translation[2]];
46744         return this.rotate(vector, angleAxis);
46745     }
46746     /**
46747      * Calculates the viewing direction from a rotation vector
46748      * on the angle-axis representation.
46749      *
46750      * @param {number[]} rotation - Angle-axis representation of a rotation.
46751      * @returns {THREE.Vector3} Viewing direction.
46752      */
46753     viewingDirection(rotation) {
46754         let angleAxis = [-rotation[0], -rotation[1], -rotation[2]];
46755         return this.rotate([0, 0, 1], angleAxis);
46756     }
46757     /**
46758      * Wrap a number on the interval [min, max].
46759      *
46760      * @param {number} value - Value to wrap.
46761      * @param {number} min - Lower endpoint of interval.
46762      * @param {number} max - Upper endpoint of interval.
46763      * @returns {number} The wrapped number.
46764      */
46765     wrap(value, min, max) {
46766         if (max < min) {
46767             throw new Error("Invalid arguments: max must be larger than min.");
46768         }
46769         let interval = (max - min);
46770         while (value > max || value < min) {
46771             if (value > max) {
46772                 value = value - interval;
46773             }
46774             else if (value < min) {
46775                 value = value + interval;
46776             }
46777         }
46778         return value;
46779     }
46780     /**
46781      * Wrap an angle on the interval [-Pi, Pi].
46782      *
46783      * @param {number} angle - Value to wrap.
46784      * @returns {number} Wrapped angle.
46785      */
46786     wrapAngle(angle) {
46787         return this.wrap(angle, -Math.PI, Math.PI);
46788     }
46789     /**
46790      * Limit the value to the interval [min, max] by changing the value to
46791      * the nearest available one when it is outside the interval.
46792      *
46793      * @param {number} value - Value to clamp.
46794      * @param {number} min - Minimum of the interval.
46795      * @param {number} max - Maximum of the interval.
46796      * @returns {number} Clamped value.
46797      */
46798     clamp(value, min, max) {
46799         if (value < min) {
46800             return min;
46801         }
46802         if (value > max) {
46803             return max;
46804         }
46805         return value;
46806     }
46807     /**
46808      * Calculates the counter-clockwise angle from the first
46809      * vector (x1, y1)^T to the second (x2, y2)^T.
46810      *
46811      * @param {number} x1 - X coordinate of first vector.
46812      * @param {number} y1 - Y coordinate of first vector.
46813      * @param {number} x2 - X coordinate of second vector.
46814      * @param {number} y2 - Y coordinate of second vector.
46815      * @returns {number} Counter clockwise angle between the vectors.
46816      */
46817     angleBetweenVector2(x1, y1, x2, y2) {
46818         let angle = Math.atan2(y2, x2) - Math.atan2(y1, x1);
46819         return this.wrapAngle(angle);
46820     }
46821     /**
46822      * Calculates the minimum (absolute) angle change for rotation
46823      * from one angle to another on the [-Pi, Pi] interval.
46824      *
46825      * @param {number} angle1 - Start angle.
46826      * @param {number} angle2 - Destination angle.
46827      * @returns {number} Absolute angle change between angles.
46828      */
46829     angleDifference(angle1, angle2) {
46830         let angle = angle2 - angle1;
46831         return this.wrapAngle(angle);
46832     }
46833     /**
46834      * Calculates the relative rotation angle between two
46835      * angle-axis vectors.
46836      *
46837      * @param {number} rotation1 - First angle-axis vector.
46838      * @param {number} rotation2 - Second angle-axis vector.
46839      * @returns {number} Relative rotation angle.
46840      */
46841     relativeRotationAngle(rotation1, rotation2) {
46842         let R1T = this.rotationMatrix([-rotation1[0], -rotation1[1], -rotation1[2]]);
46843         let R2 = this.rotationMatrix(rotation2);
46844         let R = R1T.multiply(R2);
46845         let elements = R.elements;
46846         // from Tr(R) = 1 + 2 * cos(theta)
46847         let tr = elements[0] + elements[5] + elements[10];
46848         let theta = Math.acos(Math.max(Math.min((tr - 1) / 2, 1), -1));
46849         return theta;
46850     }
46851     /**
46852      * Calculates the angle from a vector to a plane.
46853      *
46854      * @param {Array<number>} vector - The vector.
46855      * @param {Array<number>} planeNormal - Normal of the plane.
46856      * @returns {number} Angle from between plane and vector.
46857      */
46858     angleToPlane(vector, planeNormal) {
46859         let v = new Vector3().fromArray(vector);
46860         let norm = v.length();
46861         if (norm < this._epsilon) {
46862             return 0;
46863         }
46864         let projection = v.dot(new Vector3().fromArray(planeNormal));
46865         return Math.asin(projection / norm);
46866     }
46867     azimuthal(direction, up) {
46868         const directionVector = new Vector3().fromArray(direction);
46869         const upVector = new Vector3().fromArray(up);
46870         const upProjection = directionVector.clone().dot(upVector);
46871         const planeProjection = directionVector.clone().sub(upVector.clone().multiplyScalar(upProjection));
46872         return Math.atan2(planeProjection.y, planeProjection.x);
46873     }
46874     /**
46875      * Calculates the distance between two coordinates
46876      * (longitude, latitude pairs) in meters according to
46877      * the haversine formula.
46878      *
46879      * @param {number} lat1 - Latitude of the first coordinate in degrees.
46880      * @param {number} lng1 - Longitude of the first coordinate in degrees.
46881      * @param {number} lat2 - Latitude of the second coordinate in degrees.
46882      * @param {number} lng2 - Longitude of the second coordinate in degrees.
46883      * @returns {number} Distance between lat lon positions in meters.
46884      */
46885     distanceFromLngLat(lng1, lat1, lng2, lat2) {
46886         let r = 6371000;
46887         let dLat = this.degToRad(lat2 - lat1);
46888         let dLng = this.degToRad(lng2 - lng1);
46889         let hav = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
46890             Math.cos(this.degToRad(lat1)) * Math.cos(this.degToRad(lat2)) *
46891                 Math.sin(dLng / 2) * Math.sin(dLng / 2);
46892         let d = 2 * r * Math.atan2(Math.sqrt(hav), Math.sqrt(1 - hav));
46893         return d;
46894     }
46895 }
46896
46897 const spatial = new Spatial();
46898 function isSpherical(cameraType) {
46899     return cameraType === "spherical";
46900 }
46901 function isFisheye(cameraType) {
46902     return cameraType === "fisheye";
46903 }
46904 function computeTranslation(position, rotation, reference) {
46905     const C = geodeticToEnu(position.lng, position.lat, position.alt, reference.lng, reference.lat, reference.alt);
46906     const RC = spatial.rotate(C, rotation);
46907     const translation = [-RC.x, -RC.y, -RC.z];
46908     return translation;
46909 }
46910 function computeProjectedPoints(transform, basicVertices, basicDirections, pointsPerLine, viewportCoords) {
46911     const basicPoints = [];
46912     for (let side = 0; side < basicVertices.length; ++side) {
46913         const v = basicVertices[side];
46914         const d = basicDirections[side];
46915         for (let i = 0; i <= pointsPerLine; ++i) {
46916             basicPoints.push([v[0] + d[0] * i / pointsPerLine,
46917                 v[1] + d[1] * i / pointsPerLine]);
46918         }
46919     }
46920     const camera = new Camera$1();
46921     camera.up.copy(transform.upVector());
46922     camera.position.copy(new Vector3().fromArray(transform.unprojectSfM([0, 0], 0)));
46923     camera.lookAt(new Vector3().fromArray(transform.unprojectSfM([0, 0], 10)));
46924     camera.updateMatrix();
46925     camera.updateMatrixWorld(true);
46926     const projectedPoints = basicPoints
46927         .map((basicPoint) => {
46928         const worldPoint = transform.unprojectBasic(basicPoint, 10000);
46929         const cameraPoint = viewportCoords.worldToCamera(worldPoint, camera);
46930         return [
46931             Math.abs(cameraPoint[0] / cameraPoint[2]),
46932             Math.abs(cameraPoint[1] / cameraPoint[2]),
46933         ];
46934     });
46935     return projectedPoints;
46936 }
46937
46938 /**
46939  * @class EdgeCalculator
46940  *
46941  * @classdesc Represents a class for calculating node edges.
46942  */
46943 class EdgeCalculator {
46944     /**
46945      * Create a new edge calculator instance.
46946      *
46947      * @param {EdgeCalculatorSettings} settings - Settings struct.
46948      * @param {EdgeCalculatorDirections} directions - Directions struct.
46949      * @param {EdgeCalculatorCoefficients} coefficients - Coefficients struct.
46950      */
46951     constructor(settings, directions, coefficients) {
46952         this._spatial = new Spatial();
46953         this._settings = settings != null ? settings : new EdgeCalculatorSettings();
46954         this._directions = directions != null ? directions : new EdgeCalculatorDirections();
46955         this._coefficients = coefficients != null ? coefficients : new EdgeCalculatorCoefficients();
46956     }
46957     /**
46958      * Returns the potential edges to destination nodes for a set
46959      * of nodes with respect to a source node.
46960      *
46961      * @param {Image} node - Source node.
46962      * @param {Array<Image>} nodes - Potential destination nodes.
46963      * @param {Array<string>} fallbackIds - Ids for destination nodes
46964      * that should be returned even if they do not meet the
46965      * criteria for a potential edge.
46966      * @throws {ArgumentMapillaryError} If node is not full.
46967      */
46968     getPotentialEdges(node, potentialImages, fallbackIds) {
46969         if (!node.complete) {
46970             throw new ArgumentMapillaryError("Image has to be full.");
46971         }
46972         if (!node.merged) {
46973             return [];
46974         }
46975         let currentDirection = this._spatial.viewingDirection(node.rotation);
46976         let currentVerticalDirection = this._spatial.angleToPlane(currentDirection.toArray(), [0, 0, 1]);
46977         let potentialEdges = [];
46978         for (let potential of potentialImages) {
46979             if (!potential.merged ||
46980                 potential.id === node.id) {
46981                 continue;
46982             }
46983             let enu = geodeticToEnu(potential.lngLat.lng, potential.lngLat.lat, potential.computedAltitude, node.lngLat.lng, node.lngLat.lat, node.computedAltitude);
46984             let motion = new Vector3(enu[0], enu[1], enu[2]);
46985             let distance = motion.length();
46986             if (distance > this._settings.maxDistance &&
46987                 fallbackIds.indexOf(potential.id) < 0) {
46988                 continue;
46989             }
46990             let motionChange = this._spatial.angleBetweenVector2(currentDirection.x, currentDirection.y, motion.x, motion.y);
46991             let verticalMotion = this._spatial.angleToPlane(motion.toArray(), [0, 0, 1]);
46992             let direction = this._spatial.viewingDirection(potential.rotation);
46993             let directionChange = this._spatial.angleBetweenVector2(currentDirection.x, currentDirection.y, direction.x, direction.y);
46994             let verticalDirection = this._spatial.angleToPlane(direction.toArray(), [0, 0, 1]);
46995             let verticalDirectionChange = verticalDirection - currentVerticalDirection;
46996             let rotation = this._spatial.relativeRotationAngle(node.rotation, potential.rotation);
46997             let worldMotionAzimuth = this._spatial.angleBetweenVector2(1, 0, motion.x, motion.y);
46998             let sameSequence = potential.sequenceId != null &&
46999                 node.sequenceId != null &&
47000                 potential.sequenceId === node.sequenceId;
47001             let sameMergeCC = potential.mergeId === node.mergeId;
47002             let sameUser = potential.creatorId === node.creatorId;
47003             let potentialEdge = {
47004                 capturedAt: potential.capturedAt,
47005                 directionChange: directionChange,
47006                 distance: distance,
47007                 spherical: isSpherical(potential.cameraType),
47008                 id: potential.id,
47009                 motionChange: motionChange,
47010                 rotation: rotation,
47011                 sameMergeCC: sameMergeCC,
47012                 sameSequence: sameSequence,
47013                 sameUser: sameUser,
47014                 sequenceId: potential.sequenceId,
47015                 verticalDirectionChange: verticalDirectionChange,
47016                 verticalMotion: verticalMotion,
47017                 worldMotionAzimuth: worldMotionAzimuth,
47018             };
47019             potentialEdges.push(potentialEdge);
47020         }
47021         return potentialEdges;
47022     }
47023     /**
47024      * Computes the sequence edges for a node.
47025      *
47026      * @param {Image} node - Source node.
47027      * @throws {ArgumentMapillaryError} If node is not full.
47028      */
47029     computeSequenceEdges(node, sequence) {
47030         if (!node.complete) {
47031             throw new ArgumentMapillaryError("Image has to be full.");
47032         }
47033         if (node.sequenceId !== sequence.id) {
47034             throw new ArgumentMapillaryError("Image and sequence does not correspond.");
47035         }
47036         let edges = [];
47037         let nextId = sequence.findNext(node.id);
47038         if (nextId != null) {
47039             edges.push({
47040                 data: {
47041                     direction: NavigationDirection.Next,
47042                     worldMotionAzimuth: Number.NaN,
47043                 },
47044                 source: node.id,
47045                 target: nextId,
47046             });
47047         }
47048         let prevId = sequence.findPrev(node.id);
47049         if (prevId != null) {
47050             edges.push({
47051                 data: {
47052                     direction: NavigationDirection.Prev,
47053                     worldMotionAzimuth: Number.NaN,
47054                 },
47055                 source: node.id,
47056                 target: prevId,
47057             });
47058         }
47059         return edges;
47060     }
47061     /**
47062      * Computes the similar edges for a node.
47063      *
47064      * @description Similar edges for perspective images
47065      * look roughly in the same direction and are positioned closed to the node.
47066      * Similar edges for spherical only target other spherical.
47067      *
47068      * @param {Image} node - Source node.
47069      * @param {Array<PotentialEdge>} potentialEdges - Potential edges.
47070      * @throws {ArgumentMapillaryError} If node is not full.
47071      */
47072     computeSimilarEdges(node, potentialEdges) {
47073         if (!node.complete) {
47074             throw new ArgumentMapillaryError("Image has to be full.");
47075         }
47076         let nodeSpherical = isSpherical(node.cameraType);
47077         let sequenceGroups = {};
47078         for (let potentialEdge of potentialEdges) {
47079             if (potentialEdge.sequenceId == null) {
47080                 continue;
47081             }
47082             if (potentialEdge.sameSequence) {
47083                 continue;
47084             }
47085             if (nodeSpherical) {
47086                 if (!potentialEdge.spherical) {
47087                     continue;
47088                 }
47089             }
47090             else {
47091                 if (!potentialEdge.spherical &&
47092                     Math.abs(potentialEdge.directionChange) > this._settings.similarMaxDirectionChange) {
47093                     continue;
47094                 }
47095             }
47096             if (potentialEdge.distance > this._settings.similarMaxDistance) {
47097                 continue;
47098             }
47099             if (potentialEdge.sameUser &&
47100                 Math.abs(potentialEdge.capturedAt - node.capturedAt) <
47101                     this._settings.similarMinTimeDifference) {
47102                 continue;
47103             }
47104             if (sequenceGroups[potentialEdge.sequenceId] == null) {
47105                 sequenceGroups[potentialEdge.sequenceId] = [];
47106             }
47107             sequenceGroups[potentialEdge.sequenceId].push(potentialEdge);
47108         }
47109         let similarEdges = [];
47110         let calculateScore = isSpherical(node.cameraType) ?
47111             (potentialEdge) => {
47112                 return potentialEdge.distance;
47113             } :
47114             (potentialEdge) => {
47115                 return this._coefficients.similarDistance * potentialEdge.distance +
47116                     this._coefficients.similarRotation * potentialEdge.rotation;
47117             };
47118         for (let sequenceId in sequenceGroups) {
47119             if (!sequenceGroups.hasOwnProperty(sequenceId)) {
47120                 continue;
47121             }
47122             let lowestScore = Number.MAX_VALUE;
47123             let similarEdge = null;
47124             for (let potentialEdge of sequenceGroups[sequenceId]) {
47125                 let score = calculateScore(potentialEdge);
47126                 if (score < lowestScore) {
47127                     lowestScore = score;
47128                     similarEdge = potentialEdge;
47129                 }
47130             }
47131             if (similarEdge == null) {
47132                 continue;
47133             }
47134             similarEdges.push(similarEdge);
47135         }
47136         return similarEdges
47137             .map((potentialEdge) => {
47138             return {
47139                 data: {
47140                     direction: NavigationDirection.Similar,
47141                     worldMotionAzimuth: potentialEdge.worldMotionAzimuth,
47142                 },
47143                 source: node.id,
47144                 target: potentialEdge.id,
47145             };
47146         });
47147     }
47148     /**
47149      * Computes the step edges for a perspective node.
47150      *
47151      * @description Step edge targets can only be other perspective nodes.
47152      * Returns an empty array for spherical.
47153      *
47154      * @param {Image} node - Source node.
47155      * @param {Array<PotentialEdge>} potentialEdges - Potential edges.
47156      * @param {string} prevId - Id of previous node in sequence.
47157      * @param {string} nextId - Id of next node in sequence.
47158      * @throws {ArgumentMapillaryError} If node is not full.
47159      */
47160     computeStepEdges(node, potentialEdges, prevId, nextId) {
47161         if (!node.complete) {
47162             throw new ArgumentMapillaryError("Image has to be full.");
47163         }
47164         let edges = [];
47165         if (isSpherical(node.cameraType)) {
47166             return edges;
47167         }
47168         for (let k in this._directions.steps) {
47169             if (!this._directions.steps.hasOwnProperty(k)) {
47170                 continue;
47171             }
47172             let step = this._directions.steps[k];
47173             let lowestScore = Number.MAX_VALUE;
47174             let edge = null;
47175             let fallback = null;
47176             for (let potential of potentialEdges) {
47177                 if (potential.spherical) {
47178                     continue;
47179                 }
47180                 if (Math.abs(potential.directionChange) > this._settings.stepMaxDirectionChange) {
47181                     continue;
47182                 }
47183                 let motionDifference = this._spatial.angleDifference(step.motionChange, potential.motionChange);
47184                 let directionMotionDifference = this._spatial.angleDifference(potential.directionChange, motionDifference);
47185                 let drift = Math.max(Math.abs(motionDifference), Math.abs(directionMotionDifference));
47186                 if (Math.abs(drift) > this._settings.stepMaxDrift) {
47187                     continue;
47188                 }
47189                 let potentialId = potential.id;
47190                 if (step.useFallback && (potentialId === prevId || potentialId === nextId)) {
47191                     fallback = potential;
47192                 }
47193                 if (potential.distance > this._settings.stepMaxDistance) {
47194                     continue;
47195                 }
47196                 motionDifference = Math.sqrt(motionDifference * motionDifference +
47197                     potential.verticalMotion * potential.verticalMotion);
47198                 let score = this._coefficients.stepPreferredDistance *
47199                     Math.abs(potential.distance - this._settings.stepPreferredDistance) /
47200                     this._settings.stepMaxDistance +
47201                     this._coefficients.stepMotion * motionDifference / this._settings.stepMaxDrift +
47202                     this._coefficients.stepRotation * potential.rotation / this._settings.stepMaxDirectionChange +
47203                     this._coefficients.stepSequencePenalty * (potential.sameSequence ? 0 : 1) +
47204                     this._coefficients.stepMergeCCPenalty * (potential.sameMergeCC ? 0 : 1);
47205                 if (score < lowestScore) {
47206                     lowestScore = score;
47207                     edge = potential;
47208                 }
47209             }
47210             edge = edge == null ? fallback : edge;
47211             if (edge != null) {
47212                 edges.push({
47213                     data: {
47214                         direction: step.direction,
47215                         worldMotionAzimuth: edge.worldMotionAzimuth,
47216                     },
47217                     source: node.id,
47218                     target: edge.id,
47219                 });
47220             }
47221         }
47222         return edges;
47223     }
47224     /**
47225      * Computes the turn edges for a perspective node.
47226      *
47227      * @description Turn edge targets can only be other perspective images.
47228      * Returns an empty array for spherical.
47229      *
47230      * @param {Image} node - Source node.
47231      * @param {Array<PotentialEdge>} potentialEdges - Potential edges.
47232      * @throws {ArgumentMapillaryError} If node is not full.
47233      */
47234     computeTurnEdges(node, potentialEdges) {
47235         if (!node.complete) {
47236             throw new ArgumentMapillaryError("Image has to be full.");
47237         }
47238         let edges = [];
47239         if (isSpherical(node.cameraType)) {
47240             return edges;
47241         }
47242         for (let k in this._directions.turns) {
47243             if (!this._directions.turns.hasOwnProperty(k)) {
47244                 continue;
47245             }
47246             let turn = this._directions.turns[k];
47247             let lowestScore = Number.MAX_VALUE;
47248             let edge = null;
47249             for (let potential of potentialEdges) {
47250                 if (potential.spherical) {
47251                     continue;
47252                 }
47253                 if (potential.distance > this._settings.turnMaxDistance) {
47254                     continue;
47255                 }
47256                 let rig = turn.direction !== NavigationDirection.TurnU &&
47257                     potential.distance < this._settings.turnMaxRigDistance &&
47258                     Math.abs(potential.directionChange) > this._settings.turnMinRigDirectionChange;
47259                 let directionDifference = this._spatial.angleDifference(turn.directionChange, potential.directionChange);
47260                 let score;
47261                 if (rig &&
47262                     potential.directionChange * turn.directionChange > 0 &&
47263                     Math.abs(potential.directionChange) < Math.abs(turn.directionChange)) {
47264                     score = -Math.PI / 2 + Math.abs(potential.directionChange);
47265                 }
47266                 else {
47267                     if (Math.abs(directionDifference) > this._settings.turnMaxDirectionChange) {
47268                         continue;
47269                     }
47270                     let motionDifference = turn.motionChange ?
47271                         this._spatial.angleDifference(turn.motionChange, potential.motionChange) : 0;
47272                     motionDifference = Math.sqrt(motionDifference * motionDifference +
47273                         potential.verticalMotion * potential.verticalMotion);
47274                     score =
47275                         this._coefficients.turnDistance * potential.distance /
47276                             this._settings.turnMaxDistance +
47277                             this._coefficients.turnMotion * motionDifference / Math.PI +
47278                             this._coefficients.turnSequencePenalty * (potential.sameSequence ? 0 : 1) +
47279                             this._coefficients.turnMergeCCPenalty * (potential.sameMergeCC ? 0 : 1);
47280                 }
47281                 if (score < lowestScore) {
47282                     lowestScore = score;
47283                     edge = potential;
47284                 }
47285             }
47286             if (edge != null) {
47287                 edges.push({
47288                     data: {
47289                         direction: turn.direction,
47290                         worldMotionAzimuth: edge.worldMotionAzimuth,
47291                     },
47292                     source: node.id,
47293                     target: edge.id,
47294                 });
47295             }
47296         }
47297         return edges;
47298     }
47299     /**
47300      * Computes the spherical edges for a perspective node.
47301      *
47302      * @description Perspective to spherical edge targets can only be
47303      * spherical nodes. Returns an empty array for spherical.
47304      *
47305      * @param {Image} node - Source node.
47306      * @param {Array<PotentialEdge>} potentialEdges - Potential edges.
47307      * @throws {ArgumentMapillaryError} If node is not full.
47308      */
47309     computePerspectiveToSphericalEdges(node, potentialEdges) {
47310         if (!node.complete) {
47311             throw new ArgumentMapillaryError("Image has to be full.");
47312         }
47313         if (isSpherical(node.cameraType)) {
47314             return [];
47315         }
47316         let lowestScore = Number.MAX_VALUE;
47317         let edge = null;
47318         for (let potential of potentialEdges) {
47319             if (!potential.spherical) {
47320                 continue;
47321             }
47322             let score = this._coefficients.sphericalPreferredDistance *
47323                 Math.abs(potential.distance - this._settings.sphericalPreferredDistance) /
47324                 this._settings.sphericalMaxDistance +
47325                 this._coefficients.sphericalMotion * Math.abs(potential.motionChange) / Math.PI +
47326                 this._coefficients.sphericalMergeCCPenalty * (potential.sameMergeCC ? 0 : 1);
47327             if (score < lowestScore) {
47328                 lowestScore = score;
47329                 edge = potential;
47330             }
47331         }
47332         if (edge == null) {
47333             return [];
47334         }
47335         return [
47336             {
47337                 data: {
47338                     direction: NavigationDirection.Spherical,
47339                     worldMotionAzimuth: edge.worldMotionAzimuth,
47340                 },
47341                 source: node.id,
47342                 target: edge.id,
47343             },
47344         ];
47345     }
47346     /**
47347      * Computes the spherical and step edges for a spherical node.
47348      *
47349      * @description Spherical to spherical edge targets can only be
47350      * spherical nodes. spherical to step edge targets can only be perspective
47351      * nodes.
47352      *
47353      * @param {Image} node - Source node.
47354      * @param {Array<PotentialEdge>} potentialEdges - Potential edges.
47355      * @throws {ArgumentMapillaryError} If node is not full.
47356      */
47357     computeSphericalEdges(node, potentialEdges) {
47358         if (!node.complete) {
47359             throw new ArgumentMapillaryError("Image has to be full.");
47360         }
47361         if (!isSpherical(node.cameraType)) {
47362             return [];
47363         }
47364         let sphericalEdges = [];
47365         let potentialSpherical = [];
47366         let potentialSteps = [];
47367         for (let potential of potentialEdges) {
47368             if (potential.distance > this._settings.sphericalMaxDistance) {
47369                 continue;
47370             }
47371             if (potential.spherical) {
47372                 if (potential.distance < this._settings.sphericalMinDistance) {
47373                     continue;
47374                 }
47375                 potentialSpherical.push(potential);
47376             }
47377             else {
47378                 for (let k in this._directions.spherical) {
47379                     if (!this._directions.spherical.hasOwnProperty(k)) {
47380                         continue;
47381                     }
47382                     let spherical = this._directions.spherical[k];
47383                     let turn = this._spatial.angleDifference(potential.directionChange, potential.motionChange);
47384                     let turnChange = this._spatial.angleDifference(spherical.directionChange, turn);
47385                     if (Math.abs(turnChange) > this._settings.sphericalMaxStepTurnChange) {
47386                         continue;
47387                     }
47388                     potentialSteps.push([spherical.direction, potential]);
47389                     // break if step direction found
47390                     break;
47391                 }
47392             }
47393         }
47394         let maxRotationDifference = Math.PI / this._settings.sphericalMaxItems;
47395         let occupiedAngles = [];
47396         let stepAngles = [];
47397         for (let index = 0; index < this._settings.sphericalMaxItems; index++) {
47398             let rotation = index / this._settings.sphericalMaxItems * 2 * Math.PI;
47399             let lowestScore = Number.MAX_VALUE;
47400             let edge = null;
47401             for (let potential of potentialSpherical) {
47402                 let motionDifference = this._spatial.angleDifference(rotation, potential.motionChange);
47403                 if (Math.abs(motionDifference) > maxRotationDifference) {
47404                     continue;
47405                 }
47406                 let occupiedDifference = Number.MAX_VALUE;
47407                 for (let occupiedAngle of occupiedAngles) {
47408                     let difference = Math.abs(this._spatial.angleDifference(occupiedAngle, potential.motionChange));
47409                     if (difference < occupiedDifference) {
47410                         occupiedDifference = difference;
47411                     }
47412                 }
47413                 if (occupiedDifference <= maxRotationDifference) {
47414                     continue;
47415                 }
47416                 let score = this._coefficients.sphericalPreferredDistance *
47417                     Math.abs(potential.distance - this._settings.sphericalPreferredDistance) /
47418                     this._settings.sphericalMaxDistance +
47419                     this._coefficients.sphericalMotion * Math.abs(motionDifference) / maxRotationDifference +
47420                     this._coefficients.sphericalSequencePenalty * (potential.sameSequence ? 0 : 1) +
47421                     this._coefficients.sphericalMergeCCPenalty * (potential.sameMergeCC ? 0 : 1);
47422                 if (score < lowestScore) {
47423                     lowestScore = score;
47424                     edge = potential;
47425                 }
47426             }
47427             if (edge != null) {
47428                 occupiedAngles.push(edge.motionChange);
47429                 sphericalEdges.push({
47430                     data: {
47431                         direction: NavigationDirection.Spherical,
47432                         worldMotionAzimuth: edge.worldMotionAzimuth,
47433                     },
47434                     source: node.id,
47435                     target: edge.id,
47436                 });
47437             }
47438             else {
47439                 stepAngles.push(rotation);
47440             }
47441         }
47442         let occupiedStepAngles = {};
47443         occupiedStepAngles[NavigationDirection.Spherical] = occupiedAngles;
47444         occupiedStepAngles[NavigationDirection.StepForward] = [];
47445         occupiedStepAngles[NavigationDirection.StepLeft] = [];
47446         occupiedStepAngles[NavigationDirection.StepBackward] = [];
47447         occupiedStepAngles[NavigationDirection.StepRight] = [];
47448         for (let stepAngle of stepAngles) {
47449             let occupations = [];
47450             for (let k in this._directions.spherical) {
47451                 if (!this._directions.spherical.hasOwnProperty(k)) {
47452                     continue;
47453                 }
47454                 let spherical = this._directions.spherical[k];
47455                 let allOccupiedAngles = occupiedStepAngles[NavigationDirection.Spherical]
47456                     .concat(occupiedStepAngles[spherical.direction])
47457                     .concat(occupiedStepAngles[spherical.prev])
47458                     .concat(occupiedStepAngles[spherical.next]);
47459                 let lowestScore = Number.MAX_VALUE;
47460                 let edge = null;
47461                 for (let potential of potentialSteps) {
47462                     if (potential[0] !== spherical.direction) {
47463                         continue;
47464                     }
47465                     let motionChange = this._spatial.angleDifference(stepAngle, potential[1].motionChange);
47466                     if (Math.abs(motionChange) > maxRotationDifference) {
47467                         continue;
47468                     }
47469                     let minOccupiedDifference = Number.MAX_VALUE;
47470                     for (let occupiedAngle of allOccupiedAngles) {
47471                         let occupiedDifference = Math.abs(this._spatial.angleDifference(occupiedAngle, potential[1].motionChange));
47472                         if (occupiedDifference < minOccupiedDifference) {
47473                             minOccupiedDifference = occupiedDifference;
47474                         }
47475                     }
47476                     if (minOccupiedDifference <= maxRotationDifference) {
47477                         continue;
47478                     }
47479                     let score = this._coefficients.sphericalPreferredDistance *
47480                         Math.abs(potential[1].distance - this._settings.sphericalPreferredDistance) /
47481                         this._settings.sphericalMaxDistance +
47482                         this._coefficients.sphericalMotion * Math.abs(motionChange) / maxRotationDifference +
47483                         this._coefficients.sphericalMergeCCPenalty * (potential[1].sameMergeCC ? 0 : 1);
47484                     if (score < lowestScore) {
47485                         lowestScore = score;
47486                         edge = potential;
47487                     }
47488                 }
47489                 if (edge != null) {
47490                     occupations.push(edge);
47491                     sphericalEdges.push({
47492                         data: {
47493                             direction: edge[0],
47494                             worldMotionAzimuth: edge[1].worldMotionAzimuth,
47495                         },
47496                         source: node.id,
47497                         target: edge[1].id,
47498                     });
47499                 }
47500             }
47501             for (let occupation of occupations) {
47502                 occupiedStepAngles[occupation[0]].push(occupation[1].motionChange);
47503             }
47504         }
47505         return sphericalEdges;
47506     }
47507 }
47508
47509 class GraphMapillaryError extends MapillaryError {
47510     constructor(message) {
47511         super(message);
47512         Object.setPrototypeOf(this, GraphMapillaryError.prototype);
47513         this.name = "GraphMapillaryError";
47514     }
47515 }
47516
47517 /**
47518  * @class Graph
47519  *
47520  * @classdesc Represents a graph of nodes with edges.
47521  */
47522 class Graph {
47523     /**
47524      * Create a new graph instance.
47525      *
47526      * @param {APIWrapper} [api] - API instance for retrieving data.
47527      * @param {rbush.RBush<NodeIndexItem>} [nodeIndex] - Node index for fast spatial retreival.
47528      * @param {GraphCalculator} [graphCalculator] - Instance for graph calculations.
47529      * @param {EdgeCalculator} [edgeCalculator] - Instance for edge calculations.
47530      * @param {FilterCreator} [filterCreator] - Instance for  filter creation.
47531      * @param {GraphConfiguration} [configuration] - Configuration struct.
47532      */
47533     constructor(api, nodeIndex, graphCalculator, edgeCalculator, filterCreator, configuration) {
47534         this._api = api;
47535         this._cachedNodes = {};
47536         this._cachedNodeTiles = {};
47537         this._cachedSequenceNodes = {};
47538         this._cachedSpatialEdges = {};
47539         this._cachedTiles = {};
47540         this._cachingFill$ = {};
47541         this._cachingFull$ = {};
47542         this._cachingSequenceNodes$ = {};
47543         this._cachingSequences$ = {};
47544         this._cachingSpatialArea$ = {};
47545         this._cachingTiles$ = {};
47546         this._changed$ = new Subject();
47547         this._filterCreator = filterCreator !== null && filterCreator !== void 0 ? filterCreator : new FilterCreator();
47548         this._filter = this._filterCreator.createFilter(undefined);
47549         this._filterSubject$ = new Subject();
47550         this._filter$ =
47551             concat(of(this._filter), this._filterSubject$).pipe(publishReplay(1), refCount());
47552         this._filterSubscription = this._filter$.subscribe(() => { });
47553         this._defaultAlt = 2;
47554         this._edgeCalculator = edgeCalculator !== null && edgeCalculator !== void 0 ? edgeCalculator : new EdgeCalculator();
47555         this._graphCalculator = graphCalculator !== null && graphCalculator !== void 0 ? graphCalculator : new GraphCalculator();
47556         this._configuration = configuration !== null && configuration !== void 0 ? configuration : {
47557             maxSequences: 50,
47558             maxUnusedImages: 100,
47559             maxUnusedPreStoredImages: 30,
47560             maxUnusedTiles: 20,
47561         };
47562         this._nodes = {};
47563         this._nodeIndex = nodeIndex !== null && nodeIndex !== void 0 ? nodeIndex : new Graph._spatialIndex(16);
47564         this._nodeIndexTiles = {};
47565         this._nodeToTile = {};
47566         this._preStored = {};
47567         this._requiredNodeTiles = {};
47568         this._requiredSpatialArea = {};
47569         this._sequences = {};
47570         this._tileThreshold = 20;
47571     }
47572     static register(spatialIndex) {
47573         Graph._spatialIndex = spatialIndex;
47574     }
47575     /**
47576      * Get api.
47577      *
47578      * @returns {APIWrapper} The API instance used by
47579      * the graph.
47580      */
47581     get api() {
47582         return this._api;
47583     }
47584     /**
47585      * Get changed$.
47586      *
47587      * @returns {Observable<Graph>} Observable emitting
47588      * the graph every time it has changed.
47589      */
47590     get changed$() {
47591         return this._changed$;
47592     }
47593     /**
47594      * Get filter$.
47595      *
47596      * @returns {Observable<FilterFunction>} Observable emitting
47597      * the filter every time it has changed.
47598      */
47599     get filter$() {
47600         return this._filter$;
47601     }
47602     /**
47603      * Caches the full node data for all images within a bounding
47604      * box.
47605      *
47606      * @description The node assets are not cached.
47607      *
47608      * @param {LngLat} sw - South west corner of bounding box.
47609      * @param {LngLat} ne - North east corner of bounding box.
47610      * @returns {Observable<Array<Image>>} Observable emitting
47611      * the full nodes in the bounding box.
47612      */
47613     cacheBoundingBox$(sw, ne) {
47614         const cacheTiles$ = this._api.data.geometry.bboxToCellIds(sw, ne)
47615             .filter((h) => {
47616             return !(h in this._cachedTiles);
47617         })
47618             .map((h) => {
47619             return h in this._cachingTiles$ ?
47620                 this._cachingTiles$[h] :
47621                 this._cacheTile$(h);
47622         });
47623         if (cacheTiles$.length === 0) {
47624             cacheTiles$.push(of(this));
47625         }
47626         return from(cacheTiles$).pipe(mergeAll(), last(), mergeMap(() => {
47627             const nodes = this._nodeIndex
47628                 .search({
47629                 maxX: ne.lng,
47630                 maxY: ne.lat,
47631                 minX: sw.lng,
47632                 minY: sw.lat,
47633             })
47634                 .map((item) => {
47635                 return item.node;
47636             });
47637             const fullNodes = [];
47638             const coreNodes = [];
47639             for (const node of nodes) {
47640                 if (node.complete) {
47641                     fullNodes.push(node);
47642                 }
47643                 else {
47644                     coreNodes.push(node.id);
47645                 }
47646             }
47647             const coreNodeBatches = [];
47648             const batchSize = 200;
47649             while (coreNodes.length > 0) {
47650                 coreNodeBatches.push(coreNodes.splice(0, batchSize));
47651             }
47652             const fullNodes$ = of(fullNodes);
47653             const fillNodes$ = coreNodeBatches
47654                 .map((batch) => {
47655                 return this._api
47656                     .getSpatialImages$(batch)
47657                     .pipe(map((items) => {
47658                     const result = [];
47659                     for (const item of items) {
47660                         const exists = this
47661                             .hasNode(item.node_id);
47662                         if (!exists) {
47663                             continue;
47664                         }
47665                         const node = this
47666                             .getNode(item.node_id);
47667                         if (!node.complete) {
47668                             this._makeFull(node, item.node);
47669                         }
47670                         result.push(node);
47671                     }
47672                     return result;
47673                 }));
47674             });
47675             return merge(fullNodes$, from(fillNodes$).pipe(mergeAll()));
47676         }), reduce((acc, value) => {
47677             return acc.concat(value);
47678         }));
47679     }
47680     /**
47681      * Caches the full node data for all images of a cell.
47682      *
47683      * @description The node assets are not cached.
47684      *
47685      * @param {string} cellId - Cell id.
47686      * @returns {Observable<Array<Image>>} Observable
47687      * emitting the full nodes of the cell.
47688      */
47689     cacheCell$(cellId) {
47690         const cacheCell$ = cellId in this._cachedTiles ?
47691             of(this) :
47692             cellId in this._cachingTiles$ ?
47693                 this._cachingTiles$[cellId] :
47694                 this._cacheTile$(cellId);
47695         return cacheCell$.pipe(mergeMap(() => {
47696             const cachedCell = this._cachedTiles[cellId];
47697             cachedCell.accessed = new Date().getTime();
47698             const cellNodes = cachedCell.nodes;
47699             const fullNodes = [];
47700             const coreNodes = [];
47701             for (const node of cellNodes) {
47702                 if (node.complete) {
47703                     fullNodes.push(node);
47704                 }
47705                 else {
47706                     coreNodes.push(node.id);
47707                 }
47708             }
47709             const coreNodeBatches = [];
47710             const batchSize = 200;
47711             while (coreNodes.length > 0) {
47712                 coreNodeBatches.push(coreNodes.splice(0, batchSize));
47713             }
47714             const fullNodes$ = of(fullNodes);
47715             const fillNodes$ = coreNodeBatches
47716                 .map((batch) => {
47717                 return this._api.getSpatialImages$(batch).pipe(map((items) => {
47718                     const filled = [];
47719                     for (const item of items) {
47720                         if (!item.node) {
47721                             console.warn(`Image is empty (${item.node})`);
47722                             continue;
47723                         }
47724                         const id = item.node_id;
47725                         if (!this.hasNode(id)) {
47726                             continue;
47727                         }
47728                         const node = this.getNode(id);
47729                         if (!node.complete) {
47730                             this._makeFull(node, item.node);
47731                         }
47732                         filled.push(node);
47733                     }
47734                     return filled;
47735                 }));
47736             });
47737             return merge(fullNodes$, from(fillNodes$).pipe(mergeAll()));
47738         }), reduce((acc, value) => {
47739             return acc.concat(value);
47740         }));
47741     }
47742     /**
47743      * Retrieve and cache node fill properties.
47744      *
47745      * @param {string} key - Key of node to fill.
47746      * @returns {Observable<Graph>} Observable emitting the graph
47747      * when the node has been updated.
47748      * @throws {GraphMapillaryError} When the operation is not valid on the
47749      * current graph.
47750      */
47751     cacheFill$(key) {
47752         if (key in this._cachingFull$) {
47753             throw new GraphMapillaryError(`Cannot fill node while caching full (${key}).`);
47754         }
47755         if (!this.hasNode(key)) {
47756             throw new GraphMapillaryError(`Cannot fill node that does not exist in graph (${key}).`);
47757         }
47758         if (key in this._cachingFill$) {
47759             return this._cachingFill$[key];
47760         }
47761         const node = this.getNode(key);
47762         if (node.complete) {
47763             throw new GraphMapillaryError(`Cannot fill node that is already full (${key}).`);
47764         }
47765         this._cachingFill$[key] = this._api.getSpatialImages$([key]).pipe(tap((items) => {
47766             for (const item of items) {
47767                 if (!item.node) {
47768                     console.warn(`Image is empty ${item.node_id}`);
47769                 }
47770                 if (!node.complete) {
47771                     this._makeFull(node, item.node);
47772                 }
47773                 delete this._cachingFill$[item.node_id];
47774             }
47775         }), map(() => { return this; }), finalize(() => {
47776             if (key in this._cachingFill$) {
47777                 delete this._cachingFill$[key];
47778             }
47779             this._changed$.next(this);
47780         }), publish(), refCount());
47781         return this._cachingFill$[key];
47782     }
47783     /**
47784      * Retrieve and cache full node properties.
47785      *
47786      * @param {string} key - Key of node to fill.
47787      * @returns {Observable<Graph>} Observable emitting the graph
47788      * when the node has been updated.
47789      * @throws {GraphMapillaryError} When the operation is not valid on the
47790      * current graph.
47791      */
47792     cacheFull$(key) {
47793         if (key in this._cachingFull$) {
47794             return this._cachingFull$[key];
47795         }
47796         if (this.hasNode(key)) {
47797             throw new GraphMapillaryError(`Cannot cache full node that already exist in graph (${key}).`);
47798         }
47799         this._cachingFull$[key] = this._api.getImages$([key]).pipe(tap((items) => {
47800             for (const item of items) {
47801                 if (!item.node) {
47802                     throw new GraphMapillaryError(`Image does not exist (${key}, ${item.node}).`);
47803                 }
47804                 const id = item.node_id;
47805                 if (this.hasNode(id)) {
47806                     const node = this.getNode(key);
47807                     if (!node.complete) {
47808                         this._makeFull(node, item.node);
47809                     }
47810                 }
47811                 else {
47812                     if (item.node.sequence.id == null) {
47813                         throw new GraphMapillaryError(`Image has no sequence key (${key}).`);
47814                     }
47815                     const node = new Image$1(item.node);
47816                     this._makeFull(node, item.node);
47817                     const cellId = this._api.data.geometry
47818                         .lngLatToCellId(node.originalLngLat);
47819                     this._preStore(cellId, node);
47820                     this._setNode(node);
47821                     delete this._cachingFull$[id];
47822                 }
47823             }
47824         }), map(() => this), finalize(() => {
47825             if (key in this._cachingFull$) {
47826                 delete this._cachingFull$[key];
47827             }
47828             this._changed$.next(this);
47829         }), publish(), refCount());
47830         return this._cachingFull$[key];
47831     }
47832     /**
47833      * Retrieve and cache a node sequence.
47834      *
47835      * @param {string} key - Key of node for which to retrieve sequence.
47836      * @returns {Observable<Graph>} Observable emitting the graph
47837      * when the sequence has been retrieved.
47838      * @throws {GraphMapillaryError} When the operation is not valid on the
47839      * current graph.
47840      */
47841     cacheNodeSequence$(key) {
47842         if (!this.hasNode(key)) {
47843             throw new GraphMapillaryError(`Cannot cache sequence edges of node that does not exist in graph (${key}).`);
47844         }
47845         let node = this.getNode(key);
47846         if (node.sequenceId in this._sequences) {
47847             throw new GraphMapillaryError(`Sequence already cached (${key}), (${node.sequenceId}).`);
47848         }
47849         return this._cacheSequence$(node.sequenceId);
47850     }
47851     /**
47852      * Retrieve and cache a sequence.
47853      *
47854      * @param {string} sequenceKey - Key of sequence to cache.
47855      * @returns {Observable<Graph>} Observable emitting the graph
47856      * when the sequence has been retrieved.
47857      * @throws {GraphMapillaryError} When the operation is not valid on the
47858      * current graph.
47859      */
47860     cacheSequence$(sequenceKey) {
47861         if (sequenceKey in this._sequences) {
47862             throw new GraphMapillaryError(`Sequence already cached (${sequenceKey})`);
47863         }
47864         return this._cacheSequence$(sequenceKey);
47865     }
47866     /**
47867      * Cache sequence edges for a node.
47868      *
47869      * @param {string} key - Key of node.
47870      * @throws {GraphMapillaryError} When the operation is not valid on the
47871      * current graph.
47872      */
47873     cacheSequenceEdges(key) {
47874         let node = this.getNode(key);
47875         if (!(node.sequenceId in this._sequences)) {
47876             throw new GraphMapillaryError(`Sequence is not cached (${key}), (${node.sequenceId})`);
47877         }
47878         let sequence = this._sequences[node.sequenceId].sequence;
47879         let edges = this._edgeCalculator.computeSequenceEdges(node, sequence);
47880         node.cacheSequenceEdges(edges);
47881     }
47882     /**
47883      * Retrieve and cache full nodes for all keys in a sequence.
47884      *
47885      * @param {string} sequenceKey - Key of sequence.
47886      * @param {string} referenceNodeKey - Key of node to use as reference
47887      * for optimized caching.
47888      * @returns {Observable<Graph>} Observable emitting the graph
47889      * when the nodes of the sequence has been cached.
47890      */
47891     cacheSequenceNodes$(sequenceKey, referenceNodeKey) {
47892         if (!this.hasSequence(sequenceKey)) {
47893             throw new GraphMapillaryError(`Cannot cache sequence nodes of sequence that does not exist in graph (${sequenceKey}).`);
47894         }
47895         if (this.hasSequenceNodes(sequenceKey)) {
47896             throw new GraphMapillaryError(`Sequence nodes already cached (${sequenceKey}).`);
47897         }
47898         const sequence = this.getSequence(sequenceKey);
47899         if (sequence.id in this._cachingSequenceNodes$) {
47900             return this._cachingSequenceNodes$[sequence.id];
47901         }
47902         const batches = [];
47903         const keys = sequence.imageIds.slice();
47904         const referenceBatchSize = 50;
47905         if (!!referenceNodeKey && keys.length > referenceBatchSize) {
47906             const referenceIndex = keys.indexOf(referenceNodeKey);
47907             const startIndex = Math.max(0, Math.min(referenceIndex - referenceBatchSize / 2, keys.length - referenceBatchSize));
47908             batches.push(keys.splice(startIndex, referenceBatchSize));
47909         }
47910         const batchSize = 200;
47911         while (keys.length > 0) {
47912             batches.push(keys.splice(0, batchSize));
47913         }
47914         let batchesToCache = batches.length;
47915         const sequenceNodes$ = from(batches).pipe(mergeMap((batch) => {
47916             return this._api.getImages$(batch).pipe(tap((items) => {
47917                 for (const item of items) {
47918                     if (!item.node) {
47919                         console.warn(`Image empty (${item.node_id})`);
47920                         continue;
47921                     }
47922                     const id = item.node_id;
47923                     if (this.hasNode(id)) {
47924                         const node = this.getNode(id);
47925                         if (!node.complete) {
47926                             this._makeFull(node, item.node);
47927                         }
47928                     }
47929                     else {
47930                         if (item.node.sequence.id == null) {
47931                             console.warn(`Sequence missing, discarding node (${item.node_id})`);
47932                         }
47933                         const node = new Image$1(item.node);
47934                         this._makeFull(node, item.node);
47935                         const cellId = this._api.data.geometry
47936                             .lngLatToCellId(node.originalLngLat);
47937                         this._preStore(cellId, node);
47938                         this._setNode(node);
47939                     }
47940                 }
47941                 batchesToCache--;
47942             }), map(() => this));
47943         }, 6), last(), finalize(() => {
47944             delete this._cachingSequenceNodes$[sequence.id];
47945             if (batchesToCache === 0) {
47946                 this._cachedSequenceNodes[sequence.id] = true;
47947             }
47948         }), publish(), refCount());
47949         this._cachingSequenceNodes$[sequence.id] = sequenceNodes$;
47950         return sequenceNodes$;
47951     }
47952     /**
47953      * Retrieve and cache full nodes for a node spatial area.
47954      *
47955      * @param {string} key - Key of node for which to retrieve sequence.
47956      * @returns {Observable<Graph>} Observable emitting the graph
47957      * when the nodes in the spatial area has been made full.
47958      * @throws {GraphMapillaryError} When the operation is not valid on the
47959      * current graph.
47960      */
47961     cacheSpatialArea$(key) {
47962         if (!this.hasNode(key)) {
47963             throw new GraphMapillaryError(`Cannot cache spatial area of node that does not exist in graph (${key}).`);
47964         }
47965         if (key in this._cachedSpatialEdges) {
47966             throw new GraphMapillaryError(`Image already spatially cached (${key}).`);
47967         }
47968         if (!(key in this._requiredSpatialArea)) {
47969             throw new GraphMapillaryError(`Spatial area not determined (${key}).`);
47970         }
47971         let spatialArea = this._requiredSpatialArea[key];
47972         if (Object.keys(spatialArea.cacheNodes).length === 0) {
47973             throw new GraphMapillaryError(`Spatial nodes already cached (${key}).`);
47974         }
47975         if (key in this._cachingSpatialArea$) {
47976             return this._cachingSpatialArea$[key];
47977         }
47978         let batches = [];
47979         while (spatialArea.cacheKeys.length > 0) {
47980             batches.push(spatialArea.cacheKeys.splice(0, 200));
47981         }
47982         let batchesToCache = batches.length;
47983         let spatialNodes$ = [];
47984         for (let batch of batches) {
47985             let spatialNodeBatch$ = this._api.getSpatialImages$(batch).pipe(tap((items) => {
47986                 for (const item of items) {
47987                     if (!item.node) {
47988                         console.warn(`Image is empty (${item.node_id})`);
47989                         continue;
47990                     }
47991                     const id = item.node_id;
47992                     const spatialNode = spatialArea.cacheNodes[id];
47993                     if (spatialNode.complete) {
47994                         delete spatialArea.cacheNodes[id];
47995                         continue;
47996                     }
47997                     this._makeFull(spatialNode, item.node);
47998                     delete spatialArea.cacheNodes[id];
47999                 }
48000                 if (--batchesToCache === 0) {
48001                     delete this._cachingSpatialArea$[key];
48002                 }
48003             }), map(() => { return this; }), catchError((error) => {
48004                 for (let batchKey of batch) {
48005                     if (batchKey in spatialArea.all) {
48006                         delete spatialArea.all[batchKey];
48007                     }
48008                     if (batchKey in spatialArea.cacheNodes) {
48009                         delete spatialArea.cacheNodes[batchKey];
48010                     }
48011                 }
48012                 if (--batchesToCache === 0) {
48013                     delete this._cachingSpatialArea$[key];
48014                 }
48015                 throw error;
48016             }), finalize(() => {
48017                 if (Object.keys(spatialArea.cacheNodes).length === 0) {
48018                     this._changed$.next(this);
48019                 }
48020             }), publish(), refCount());
48021             spatialNodes$.push(spatialNodeBatch$);
48022         }
48023         this._cachingSpatialArea$[key] = spatialNodes$;
48024         return spatialNodes$;
48025     }
48026     /**
48027      * Cache spatial edges for a node.
48028      *
48029      * @param {string} key - Key of node.
48030      * @throws {GraphMapillaryError} When the operation is not valid on the
48031      * current graph.
48032      */
48033     cacheSpatialEdges(key) {
48034         if (key in this._cachedSpatialEdges) {
48035             throw new GraphMapillaryError(`Spatial edges already cached (${key}).`);
48036         }
48037         let node = this.getNode(key);
48038         let sequence = this._sequences[node.sequenceId].sequence;
48039         let fallbackKeys = [];
48040         let prevKey = sequence.findPrev(node.id);
48041         if (prevKey != null) {
48042             fallbackKeys.push(prevKey);
48043         }
48044         let nextKey = sequence.findNext(node.id);
48045         if (nextKey != null) {
48046             fallbackKeys.push(nextKey);
48047         }
48048         let allSpatialNodes = this._requiredSpatialArea[key].all;
48049         let potentialNodes = [];
48050         let filter = this._filter;
48051         for (let spatialNodeKey in allSpatialNodes) {
48052             if (!allSpatialNodes.hasOwnProperty(spatialNodeKey)) {
48053                 continue;
48054             }
48055             let spatialNode = allSpatialNodes[spatialNodeKey];
48056             if (filter(spatialNode)) {
48057                 potentialNodes.push(spatialNode);
48058             }
48059         }
48060         let potentialEdges = this._edgeCalculator.getPotentialEdges(node, potentialNodes, fallbackKeys);
48061         let edges = this._edgeCalculator.computeStepEdges(node, potentialEdges, prevKey, nextKey);
48062         edges = edges.concat(this._edgeCalculator.computeTurnEdges(node, potentialEdges));
48063         edges = edges.concat(this._edgeCalculator.computeSphericalEdges(node, potentialEdges));
48064         edges = edges.concat(this._edgeCalculator.computePerspectiveToSphericalEdges(node, potentialEdges));
48065         edges = edges.concat(this._edgeCalculator.computeSimilarEdges(node, potentialEdges));
48066         node.cacheSpatialEdges(edges);
48067         this._cachedSpatialEdges[key] = node;
48068         delete this._requiredSpatialArea[key];
48069         delete this._cachedNodeTiles[key];
48070     }
48071     /**
48072      * Retrieve and cache tiles for a node.
48073      *
48074      * @param {string} key - Key of node for which to retrieve tiles.
48075      * @returns {Array<Observable<Graph>>} Array of observables emitting
48076      * the graph for each tile required for the node has been cached.
48077      * @throws {GraphMapillaryError} When the operation is not valid on the
48078      * current graph.
48079      */
48080     cacheTiles$(key) {
48081         if (key in this._cachedNodeTiles) {
48082             throw new GraphMapillaryError(`Tiles already cached (${key}).`);
48083         }
48084         if (key in this._cachedSpatialEdges) {
48085             throw new GraphMapillaryError(`Spatial edges already cached so tiles considered cached (${key}).`);
48086         }
48087         if (!(key in this._requiredNodeTiles)) {
48088             throw new GraphMapillaryError(`Tiles have not been determined (${key}).`);
48089         }
48090         let nodeTiles = this._requiredNodeTiles[key];
48091         if (nodeTiles.cache.length === 0 &&
48092             nodeTiles.caching.length === 0) {
48093             throw new GraphMapillaryError(`Tiles already cached (${key}).`);
48094         }
48095         if (!this.hasNode(key)) {
48096             throw new GraphMapillaryError(`Cannot cache tiles of node that does not exist in graph (${key}).`);
48097         }
48098         let hs = nodeTiles.cache.slice();
48099         nodeTiles.caching = this._requiredNodeTiles[key].caching.concat(hs);
48100         nodeTiles.cache = [];
48101         let cacheTiles$ = [];
48102         for (let h of nodeTiles.caching) {
48103             const cacheTile$ = h in this._cachingTiles$ ?
48104                 this._cachingTiles$[h] :
48105                 this._cacheTile$(h);
48106             cacheTiles$.push(cacheTile$.pipe(tap((graph) => {
48107                 let index = nodeTiles.caching.indexOf(h);
48108                 if (index > -1) {
48109                     nodeTiles.caching.splice(index, 1);
48110                 }
48111                 if (nodeTiles.caching.length === 0 &&
48112                     nodeTiles.cache.length === 0) {
48113                     delete this._requiredNodeTiles[key];
48114                     this._cachedNodeTiles[key] = true;
48115                 }
48116             }), catchError((error) => {
48117                 let index = nodeTiles.caching.indexOf(h);
48118                 if (index > -1) {
48119                     nodeTiles.caching.splice(index, 1);
48120                 }
48121                 if (nodeTiles.caching.length === 0 &&
48122                     nodeTiles.cache.length === 0) {
48123                     delete this._requiredNodeTiles[key];
48124                     this._cachedNodeTiles[key] = true;
48125                 }
48126                 throw error;
48127             }), finalize(() => {
48128                 this._changed$.next(this);
48129             }), publish(), refCount()));
48130         }
48131         return cacheTiles$;
48132     }
48133     /**
48134      * Initialize the cache for a node.
48135      *
48136      * @param {string} key - Key of node.
48137      * @throws {GraphMapillaryError} When the operation is not valid on the
48138      * current graph.
48139      */
48140     initializeCache(key) {
48141         if (key in this._cachedNodes) {
48142             throw new GraphMapillaryError(`Image already in cache (${key}).`);
48143         }
48144         const node = this.getNode(key);
48145         const provider = this._api.data;
48146         node.initializeCache(new ImageCache(provider));
48147         const accessed = new Date().getTime();
48148         this._cachedNodes[key] = { accessed: accessed, node: node };
48149         this._updateCachedTileAccess(key, accessed);
48150     }
48151     /**
48152      * Get a value indicating if the graph is fill caching a node.
48153      *
48154      * @param {string} key - Key of node.
48155      * @returns {boolean} Value indicating if the node is being fill cached.
48156      */
48157     isCachingFill(key) {
48158         return key in this._cachingFill$;
48159     }
48160     /**
48161      * Get a value indicating if the graph is fully caching a node.
48162      *
48163      * @param {string} key - Key of node.
48164      * @returns {boolean} Value indicating if the node is being fully cached.
48165      */
48166     isCachingFull(key) {
48167         return key in this._cachingFull$;
48168     }
48169     /**
48170      * Get a value indicating if the graph is caching a sequence of a node.
48171      *
48172      * @param {string} key - Key of node.
48173      * @returns {boolean} Value indicating if the sequence of a node is
48174      * being cached.
48175      */
48176     isCachingNodeSequence(key) {
48177         let node = this.getNode(key);
48178         return node.sequenceId in this._cachingSequences$;
48179     }
48180     /**
48181      * Get a value indicating if the graph is caching a sequence.
48182      *
48183      * @param {string} sequenceKey - Key of sequence.
48184      * @returns {boolean} Value indicating if the sequence is
48185      * being cached.
48186      */
48187     isCachingSequence(sequenceKey) {
48188         return sequenceKey in this._cachingSequences$;
48189     }
48190     /**
48191      * Get a value indicating if the graph is caching sequence nodes.
48192      *
48193      * @param {string} sequenceKey - Key of sequence.
48194      * @returns {boolean} Value indicating if the sequence nodes are
48195      * being cached.
48196      */
48197     isCachingSequenceNodes(sequenceKey) {
48198         return sequenceKey in this._cachingSequenceNodes$;
48199     }
48200     /**
48201      * Get a value indicating if the graph is caching the tiles
48202      * required for calculating spatial edges of a node.
48203      *
48204      * @param {string} key - Key of node.
48205      * @returns {boolean} Value indicating if the tiles of
48206      * a node are being cached.
48207      */
48208     isCachingTiles(key) {
48209         return key in this._requiredNodeTiles &&
48210             this._requiredNodeTiles[key].cache.length === 0 &&
48211             this._requiredNodeTiles[key].caching.length > 0;
48212     }
48213     /**
48214      * Get a value indicating if the cache has been initialized
48215      * for a node.
48216      *
48217      * @param {string} key - Key of node.
48218      * @returns {boolean} Value indicating if the cache has been
48219      * initialized for a node.
48220      */
48221     hasInitializedCache(key) {
48222         return key in this._cachedNodes;
48223     }
48224     /**
48225      * Get a value indicating if a node exist in the graph.
48226      *
48227      * @param {string} key - Key of node.
48228      * @returns {boolean} Value indicating if a node exist in the graph.
48229      */
48230     hasNode(key) {
48231         let accessed = new Date().getTime();
48232         this._updateCachedNodeAccess(key, accessed);
48233         this._updateCachedTileAccess(key, accessed);
48234         return key in this._nodes;
48235     }
48236     /**
48237      * Get a value indicating if a node sequence exist in the graph.
48238      *
48239      * @param {string} key - Key of node.
48240      * @returns {boolean} Value indicating if a node sequence exist
48241      * in the graph.
48242      */
48243     hasNodeSequence(key) {
48244         let node = this.getNode(key);
48245         let sequenceKey = node.sequenceId;
48246         let hasNodeSequence = sequenceKey in this._sequences;
48247         if (hasNodeSequence) {
48248             this._sequences[sequenceKey].accessed = new Date().getTime();
48249         }
48250         return hasNodeSequence;
48251     }
48252     /**
48253      * Get a value indicating if a sequence exist in the graph.
48254      *
48255      * @param {string} sequenceKey - Key of sequence.
48256      * @returns {boolean} Value indicating if a sequence exist
48257      * in the graph.
48258      */
48259     hasSequence(sequenceKey) {
48260         let hasSequence = sequenceKey in this._sequences;
48261         if (hasSequence) {
48262             this._sequences[sequenceKey].accessed = new Date().getTime();
48263         }
48264         return hasSequence;
48265     }
48266     /**
48267      * Get a value indicating if sequence nodes has been cached in the graph.
48268      *
48269      * @param {string} sequenceKey - Key of sequence.
48270      * @returns {boolean} Value indicating if a sequence nodes has been
48271      * cached in the graph.
48272      */
48273     hasSequenceNodes(sequenceKey) {
48274         return sequenceKey in this._cachedSequenceNodes;
48275     }
48276     /**
48277      * Get a value indicating if the graph has fully cached
48278      * all nodes in the spatial area of a node.
48279      *
48280      * @param {string} key - Key of node.
48281      * @returns {boolean} Value indicating if the spatial area
48282      * of a node has been cached.
48283      */
48284     hasSpatialArea(key) {
48285         if (!this.hasNode(key)) {
48286             throw new GraphMapillaryError(`Spatial area nodes cannot be determined if node not in graph (${key}).`);
48287         }
48288         if (key in this._cachedSpatialEdges) {
48289             return true;
48290         }
48291         if (key in this._requiredSpatialArea) {
48292             return Object
48293                 .keys(this._requiredSpatialArea[key].cacheNodes)
48294                 .length === 0;
48295         }
48296         let node = this.getNode(key);
48297         let bbox = this._graphCalculator
48298             .boundingBoxCorners(node.lngLat, this._tileThreshold);
48299         let spatialItems = this._nodeIndex
48300             .search({
48301             maxX: bbox[1].lng,
48302             maxY: bbox[1].lat,
48303             minX: bbox[0].lng,
48304             minY: bbox[0].lat,
48305         });
48306         let spatialNodes = {
48307             all: {},
48308             cacheKeys: [],
48309             cacheNodes: {},
48310         };
48311         for (let spatialItem of spatialItems) {
48312             spatialNodes.all[spatialItem.node.id] = spatialItem.node;
48313             if (!spatialItem.node.complete) {
48314                 spatialNodes.cacheKeys.push(spatialItem.node.id);
48315                 spatialNodes.cacheNodes[spatialItem.node.id] = spatialItem.node;
48316             }
48317         }
48318         this._requiredSpatialArea[key] = spatialNodes;
48319         return spatialNodes.cacheKeys.length === 0;
48320     }
48321     /**
48322      * Get a value indicating if the graph has a tiles required
48323      * for a node.
48324      *
48325      * @param {string} key - Key of node.
48326      * @returns {boolean} Value indicating if the the tiles required
48327      * by a node has been cached.
48328      */
48329     hasTiles(key) {
48330         if (key in this._cachedNodeTiles) {
48331             return true;
48332         }
48333         if (key in this._cachedSpatialEdges) {
48334             return true;
48335         }
48336         if (!this.hasNode(key)) {
48337             throw new GraphMapillaryError(`Image does not exist in graph (${key}).`);
48338         }
48339         let nodeTiles = { cache: [], caching: [] };
48340         if (!(key in this._requiredNodeTiles)) {
48341             const node = this.getNode(key);
48342             const [sw, ne] = this._graphCalculator
48343                 .boundingBoxCorners(node.lngLat, this._tileThreshold);
48344             nodeTiles.cache = this._api.data.geometry
48345                 .bboxToCellIds(sw, ne)
48346                 .filter((h) => {
48347                 return !(h in this._cachedTiles);
48348             });
48349             if (nodeTiles.cache.length > 0) {
48350                 this._requiredNodeTiles[key] = nodeTiles;
48351             }
48352         }
48353         else {
48354             nodeTiles = this._requiredNodeTiles[key];
48355         }
48356         return nodeTiles.cache.length === 0 && nodeTiles.caching.length === 0;
48357     }
48358     /**
48359      * Get a node.
48360      *
48361      * @param {string} key - Key of node.
48362      * @returns {Image} Retrieved node.
48363      */
48364     getNode(key) {
48365         let accessed = new Date().getTime();
48366         this._updateCachedNodeAccess(key, accessed);
48367         this._updateCachedTileAccess(key, accessed);
48368         return this._nodes[key];
48369     }
48370     /**
48371      * Get a sequence.
48372      *
48373      * @param {string} sequenceKey - Key of sequence.
48374      * @returns {Image} Retrieved sequence.
48375      */
48376     getSequence(sequenceKey) {
48377         let sequenceAccess = this._sequences[sequenceKey];
48378         sequenceAccess.accessed = new Date().getTime();
48379         return sequenceAccess.sequence;
48380     }
48381     /**
48382      * Reset all spatial edges of the graph nodes.
48383      */
48384     resetSpatialEdges() {
48385         let cachedKeys = Object.keys(this._cachedSpatialEdges);
48386         for (let cachedKey of cachedKeys) {
48387             let node = this._cachedSpatialEdges[cachedKey];
48388             node.resetSpatialEdges();
48389             delete this._cachedSpatialEdges[cachedKey];
48390         }
48391     }
48392     /**
48393      * Reset the complete graph but keep the nodes corresponding
48394      * to the supplied keys. All other nodes will be disposed.
48395      *
48396      * @param {Array<string>} keepKeys - Keys for nodes to keep
48397      * in graph after reset.
48398      */
48399     reset(keepKeys) {
48400         const nodes = [];
48401         for (const key of keepKeys) {
48402             if (!this.hasNode(key)) {
48403                 throw new Error(`Image does not exist ${key}`);
48404             }
48405             const node = this.getNode(key);
48406             node.resetSequenceEdges();
48407             node.resetSpatialEdges();
48408             nodes.push(node);
48409         }
48410         for (let cachedKey of Object.keys(this._cachedNodes)) {
48411             if (keepKeys.indexOf(cachedKey) !== -1) {
48412                 continue;
48413             }
48414             this._cachedNodes[cachedKey].node.dispose();
48415             delete this._cachedNodes[cachedKey];
48416         }
48417         this._cachedNodeTiles = {};
48418         this._cachedSpatialEdges = {};
48419         this._cachedTiles = {};
48420         this._cachingFill$ = {};
48421         this._cachingFull$ = {};
48422         this._cachingSequences$ = {};
48423         this._cachingSpatialArea$ = {};
48424         this._cachingTiles$ = {};
48425         this._nodes = {};
48426         this._nodeToTile = {};
48427         this._preStored = {};
48428         for (const node of nodes) {
48429             this._nodes[node.id] = node;
48430             const h = this._api.data.geometry.lngLatToCellId(node.originalLngLat);
48431             this._preStore(h, node);
48432         }
48433         this._requiredNodeTiles = {};
48434         this._requiredSpatialArea = {};
48435         this._sequences = {};
48436         this._nodeIndexTiles = {};
48437         this._nodeIndex.clear();
48438     }
48439     /**
48440      * Set the spatial node filter.
48441      *
48442      * @emits FilterFunction The filter function to the {@link Graph.filter$}
48443      * observable.
48444      *
48445      * @param {FilterExpression} filter - Filter expression to be applied
48446      * when calculating spatial edges.
48447      */
48448     setFilter(filter) {
48449         this._filter = this._filterCreator.createFilter(filter);
48450         this._filterSubject$.next(this._filter);
48451     }
48452     /**
48453      * Uncache the graph according to the graph configuration.
48454      *
48455      * @description Uncaches unused tiles, unused nodes and
48456      * sequences according to the numbers specified in the
48457      * graph configuration. Sequences does not have a direct
48458      * reference to either tiles or nodes and may be uncached
48459      * even if they are related to the nodes that should be kept.
48460      *
48461      * @param {Array<string>} keepIds - Ids of nodes to keep in
48462      * graph unrelated to last access. Tiles related to those keys
48463      * will also be kept in graph.
48464      * @param {Array<string>} keepCellIds - Ids of cells to keep in
48465      * graph unrelated to last access. The nodes of the cells may
48466      * still be uncached if not specified in the keep ids param
48467      * but are guaranteed to not be disposed.
48468      * @param {string} keepSequenceId - Optional id of sequence
48469      * for which the belonging nodes should not be disposed or
48470      * removed from the graph. These nodes may still be uncached if
48471      * not specified in keep ids param but are guaranteed to not
48472      * be disposed.
48473      */
48474     uncache(keepIds, keepCellIds, keepSequenceId) {
48475         const idsInUse = {};
48476         this._addNewKeys(idsInUse, this._cachingFull$);
48477         this._addNewKeys(idsInUse, this._cachingFill$);
48478         this._addNewKeys(idsInUse, this._cachingSpatialArea$);
48479         this._addNewKeys(idsInUse, this._requiredNodeTiles);
48480         this._addNewKeys(idsInUse, this._requiredSpatialArea);
48481         for (const key of keepIds) {
48482             if (key in idsInUse) {
48483                 continue;
48484             }
48485             idsInUse[key] = true;
48486         }
48487         const tileThreshold = this._tileThreshold;
48488         const calculator = this._graphCalculator;
48489         const geometry = this._api.data.geometry;
48490         const keepCells = new Set(keepCellIds);
48491         for (let id in idsInUse) {
48492             if (!idsInUse.hasOwnProperty(id)) {
48493                 continue;
48494             }
48495             const node = this._nodes[id];
48496             const [sw, ne] = calculator
48497                 .boundingBoxCorners(node.lngLat, tileThreshold);
48498             const nodeCellIds = geometry.bboxToCellIds(sw, ne);
48499             for (const nodeCellId of nodeCellIds) {
48500                 if (!keepCells.has(nodeCellId)) {
48501                     keepCells.add(nodeCellId);
48502                 }
48503             }
48504         }
48505         const potentialCells = [];
48506         for (let cellId in this._cachedTiles) {
48507             if (!this._cachedTiles.hasOwnProperty(cellId) ||
48508                 keepCells.has(cellId)) {
48509                 continue;
48510             }
48511             potentialCells.push([cellId, this._cachedTiles[cellId]]);
48512         }
48513         const uncacheCells = potentialCells
48514             .sort((h1, h2) => {
48515             return h2[1].accessed - h1[1].accessed;
48516         })
48517             .slice(this._configuration.maxUnusedTiles)
48518             .map((h) => {
48519             return h[0];
48520         });
48521         for (let uncacheCell of uncacheCells) {
48522             this._uncacheTile(uncacheCell, keepSequenceId);
48523         }
48524         const potentialPreStored = [];
48525         const nonCachedPreStored = [];
48526         for (let cellId in this._preStored) {
48527             if (!this._preStored.hasOwnProperty(cellId) ||
48528                 cellId in this._cachingTiles$) {
48529                 continue;
48530             }
48531             const prestoredNodes = this._preStored[cellId];
48532             for (let id in prestoredNodes) {
48533                 if (!prestoredNodes.hasOwnProperty(id) || id in idsInUse) {
48534                     continue;
48535                 }
48536                 if (prestoredNodes[id].sequenceId === keepSequenceId) {
48537                     continue;
48538                 }
48539                 if (id in this._cachedNodes) {
48540                     potentialPreStored.push([this._cachedNodes[id], cellId]);
48541                 }
48542                 else {
48543                     nonCachedPreStored.push([id, cellId]);
48544                 }
48545             }
48546         }
48547         const uncachePreStored = potentialPreStored
48548             .sort(([na1], [na2]) => {
48549             return na2.accessed - na1.accessed;
48550         })
48551             .slice(this._configuration.maxUnusedPreStoredImages)
48552             .map(([na, h]) => {
48553             return [na.node.id, h];
48554         });
48555         this._uncachePreStored(nonCachedPreStored);
48556         this._uncachePreStored(uncachePreStored);
48557         const potentialNodes = [];
48558         for (let id in this._cachedNodes) {
48559             if (!this._cachedNodes.hasOwnProperty(id) || id in idsInUse) {
48560                 continue;
48561             }
48562             potentialNodes.push(this._cachedNodes[id]);
48563         }
48564         const uncacheNodes = potentialNodes
48565             .sort((n1, n2) => {
48566             return n2.accessed - n1.accessed;
48567         })
48568             .slice(this._configuration.maxUnusedImages);
48569         for (const nodeAccess of uncacheNodes) {
48570             nodeAccess.node.uncache();
48571             const id = nodeAccess.node.id;
48572             delete this._cachedNodes[id];
48573             if (id in this._cachedNodeTiles) {
48574                 delete this._cachedNodeTiles[id];
48575             }
48576             if (id in this._cachedSpatialEdges) {
48577                 delete this._cachedSpatialEdges[id];
48578             }
48579         }
48580         const potentialSequences = [];
48581         for (let sequenceId in this._sequences) {
48582             if (!this._sequences.hasOwnProperty(sequenceId) ||
48583                 sequenceId in this._cachingSequences$ ||
48584                 sequenceId === keepSequenceId) {
48585                 continue;
48586             }
48587             potentialSequences.push(this._sequences[sequenceId]);
48588         }
48589         const uncacheSequences = potentialSequences
48590             .sort((s1, s2) => {
48591             return s2.accessed - s1.accessed;
48592         })
48593             .slice(this._configuration.maxSequences);
48594         for (const sequenceAccess of uncacheSequences) {
48595             const sequenceId = sequenceAccess.sequence.id;
48596             delete this._sequences[sequenceId];
48597             if (sequenceId in this._cachedSequenceNodes) {
48598                 delete this._cachedSequenceNodes[sequenceId];
48599             }
48600             sequenceAccess.sequence.dispose();
48601         }
48602     }
48603     /**
48604      * Updates existing cells with new core nodes.
48605      *
48606      * @description Non-existing cells are discarded
48607      * and not requested at all.
48608      *
48609      * Existing nodes are not changed.
48610      *
48611      * New nodes are not made full or getting assets
48612      * cached.
48613      *
48614      * @param {Array<string>} cellIds - Cell ids.
48615      * @returns {Observable<Array<Image>>} Observable
48616      * emitting the updated cells.
48617      */
48618     updateCells$(cellIds) {
48619         const cachedCells = this._cachedTiles;
48620         const cachingCells = this._cachingTiles$;
48621         return from(cellIds)
48622             .pipe(mergeMap((cellId) => {
48623             if (cellId in cachedCells) {
48624                 return this._updateCell$(cellId);
48625             }
48626             if (cellId in cachingCells) {
48627                 return cachingCells[cellId]
48628                     .pipe(catchError(() => {
48629                     return of(this);
48630                 }), mergeMap(() => this._updateCell$(cellId)));
48631             }
48632             return empty();
48633         }));
48634     }
48635     /**
48636      * Unsubscribes all subscriptions.
48637      *
48638      * @description Afterwards, you must not call any other methods
48639      * on the graph instance.
48640      */
48641     unsubscribe() {
48642         this._filterSubscription.unsubscribe();
48643     }
48644     _addNewKeys(keys, dict) {
48645         for (let key in dict) {
48646             if (!dict.hasOwnProperty(key) || !this.hasNode(key)) {
48647                 continue;
48648             }
48649             if (!(key in keys)) {
48650                 keys[key] = true;
48651             }
48652         }
48653     }
48654     _cacheSequence$(sequenceId) {
48655         if (sequenceId in this._cachingSequences$) {
48656             return this._cachingSequences$[sequenceId];
48657         }
48658         this._cachingSequences$[sequenceId] = this._api
48659             .getSequence$(sequenceId)
48660             .pipe(tap((sequence) => {
48661             if (!sequence) {
48662                 console.warn(`Sequence does not exist ` +
48663                     `(${sequenceId})`);
48664             }
48665             else {
48666                 if (!(sequence.id in this._sequences)) {
48667                     this._sequences[sequence.id] = {
48668                         accessed: new Date().getTime(),
48669                         sequence: new Sequence(sequence),
48670                     };
48671                 }
48672                 delete this._cachingSequences$[sequenceId];
48673             }
48674         }), map(() => { return this; }), finalize(() => {
48675             if (sequenceId in this._cachingSequences$) {
48676                 delete this._cachingSequences$[sequenceId];
48677             }
48678             this._changed$.next(this);
48679         }), publish(), refCount());
48680         return this._cachingSequences$[sequenceId];
48681     }
48682     _cacheTile$(cellId) {
48683         this._cachingTiles$[cellId] = this._api
48684             .getCoreImages$(cellId)
48685             .pipe(tap((contract) => {
48686             if (cellId in this._cachedTiles) {
48687                 return;
48688             }
48689             const cores = contract.images;
48690             this._nodeIndexTiles[cellId] = [];
48691             this._cachedTiles[cellId] = {
48692                 accessed: new Date().getTime(),
48693                 nodes: [],
48694             };
48695             const hCache = this._cachedTiles[cellId].nodes;
48696             const preStored = this._removeFromPreStore(cellId);
48697             for (const core of cores) {
48698                 if (!core) {
48699                     break;
48700                 }
48701                 if (core.sequence.id == null) {
48702                     console.warn(`Sequence missing, discarding ` +
48703                         `node (${core.id})`);
48704                     continue;
48705                 }
48706                 if (preStored != null && core.id in preStored) {
48707                     const preStoredNode = preStored[core.id];
48708                     delete preStored[core.id];
48709                     hCache.push(preStoredNode);
48710                     const preStoredNodeIndexItem = {
48711                         lat: preStoredNode.lngLat.lat,
48712                         lng: preStoredNode.lngLat.lng,
48713                         node: preStoredNode,
48714                     };
48715                     this._nodeIndex.insert(preStoredNodeIndexItem);
48716                     this._nodeIndexTiles[cellId]
48717                         .push(preStoredNodeIndexItem);
48718                     this._nodeToTile[preStoredNode.id] = cellId;
48719                     continue;
48720                 }
48721                 const node = new Image$1(core);
48722                 hCache.push(node);
48723                 const nodeIndexItem = {
48724                     lat: node.lngLat.lat,
48725                     lng: node.lngLat.lng,
48726                     node: node,
48727                 };
48728                 this._nodeIndex.insert(nodeIndexItem);
48729                 this._nodeIndexTiles[cellId].push(nodeIndexItem);
48730                 this._nodeToTile[node.id] = cellId;
48731                 this._setNode(node);
48732             }
48733             delete this._cachingTiles$[cellId];
48734         }), map(() => this), catchError((error) => {
48735             delete this._cachingTiles$[cellId];
48736             throw error;
48737         }), publish(), refCount());
48738         return this._cachingTiles$[cellId];
48739     }
48740     _makeFull(node, fillNode) {
48741         if (fillNode.computed_altitude == null) {
48742             fillNode.computed_altitude = this._defaultAlt;
48743         }
48744         if (fillNode.computed_rotation == null) {
48745             fillNode.computed_rotation = this._graphCalculator.rotationFromCompass(fillNode.compass_angle, fillNode.exif_orientation);
48746         }
48747         node.makeComplete(fillNode);
48748     }
48749     _preStore(h, node) {
48750         if (!(h in this._preStored)) {
48751             this._preStored[h] = {};
48752         }
48753         this._preStored[h][node.id] = node;
48754     }
48755     _removeFromPreStore(h) {
48756         let preStored = null;
48757         if (h in this._preStored) {
48758             preStored = this._preStored[h];
48759             delete this._preStored[h];
48760         }
48761         return preStored;
48762     }
48763     _setNode(node) {
48764         let key = node.id;
48765         if (this.hasNode(key)) {
48766             throw new GraphMapillaryError(`Image already exist (${key}).`);
48767         }
48768         this._nodes[key] = node;
48769     }
48770     _uncacheTile(h, keepSequenceKey) {
48771         for (let node of this._cachedTiles[h].nodes) {
48772             let key = node.id;
48773             delete this._nodeToTile[key];
48774             if (key in this._cachedNodes) {
48775                 delete this._cachedNodes[key];
48776             }
48777             if (key in this._cachedNodeTiles) {
48778                 delete this._cachedNodeTiles[key];
48779             }
48780             if (key in this._cachedSpatialEdges) {
48781                 delete this._cachedSpatialEdges[key];
48782             }
48783             if (node.sequenceId === keepSequenceKey) {
48784                 this._preStore(h, node);
48785                 node.uncache();
48786             }
48787             else {
48788                 delete this._nodes[key];
48789                 if (node.sequenceId in this._cachedSequenceNodes) {
48790                     delete this._cachedSequenceNodes[node.sequenceId];
48791                 }
48792                 node.dispose();
48793             }
48794         }
48795         for (let nodeIndexItem of this._nodeIndexTiles[h]) {
48796             this._nodeIndex.remove(nodeIndexItem);
48797         }
48798         delete this._nodeIndexTiles[h];
48799         delete this._cachedTiles[h];
48800     }
48801     _uncachePreStored(preStored) {
48802         let hs = {};
48803         for (let [key, h] of preStored) {
48804             if (key in this._nodes) {
48805                 delete this._nodes[key];
48806             }
48807             if (key in this._cachedNodes) {
48808                 delete this._cachedNodes[key];
48809             }
48810             let node = this._preStored[h][key];
48811             if (node.sequenceId in this._cachedSequenceNodes) {
48812                 delete this._cachedSequenceNodes[node.sequenceId];
48813             }
48814             delete this._preStored[h][key];
48815             node.dispose();
48816             hs[h] = true;
48817         }
48818         for (let h in hs) {
48819             if (!hs.hasOwnProperty(h)) {
48820                 continue;
48821             }
48822             if (Object.keys(this._preStored[h]).length === 0) {
48823                 delete this._preStored[h];
48824             }
48825         }
48826     }
48827     _updateCachedTileAccess(key, accessed) {
48828         if (key in this._nodeToTile) {
48829             this._cachedTiles[this._nodeToTile[key]].accessed = accessed;
48830         }
48831     }
48832     _updateCachedNodeAccess(key, accessed) {
48833         if (key in this._cachedNodes) {
48834             this._cachedNodes[key].accessed = accessed;
48835         }
48836     }
48837     _updateCell$(cellId) {
48838         return this._api.getCoreImages$(cellId).pipe(mergeMap((contract) => {
48839             if (!(cellId in this._cachedTiles)) {
48840                 return empty();
48841             }
48842             const nodeIndex = this._nodeIndex;
48843             const nodeIndexCell = this._nodeIndexTiles[cellId];
48844             const nodeToCell = this._nodeToTile;
48845             const cell = this._cachedTiles[cellId];
48846             cell.accessed = new Date().getTime();
48847             const cellNodes = cell.nodes;
48848             const cores = contract.images;
48849             for (const core of cores) {
48850                 if (core == null) {
48851                     break;
48852                 }
48853                 if (this.hasNode(core.id)) {
48854                     continue;
48855                 }
48856                 if (core.sequence.id == null) {
48857                     console.warn(`Sequence missing, discarding ` +
48858                         `node (${core.id})`);
48859                     continue;
48860                 }
48861                 const node = new Image$1(core);
48862                 cellNodes.push(node);
48863                 const nodeIndexItem = {
48864                     lat: node.lngLat.lat,
48865                     lng: node.lngLat.lng,
48866                     node: node,
48867                 };
48868                 nodeIndex.insert(nodeIndexItem);
48869                 nodeIndexCell.push(nodeIndexItem);
48870                 nodeToCell[node.id] = cellId;
48871                 this._setNode(node);
48872             }
48873             return of(cellId);
48874         }), catchError((error) => {
48875             console.error(error);
48876             return empty();
48877         }));
48878     }
48879 }
48880
48881 class MarkerSet {
48882     constructor() {
48883         this._hash = {};
48884         this._index = new MarkerSet._spatialIndex(16);
48885         this._indexChanged$ = new Subject();
48886         this._updated$ = new Subject();
48887     }
48888     static register(spatialIndex) {
48889         MarkerSet._spatialIndex = spatialIndex;
48890     }
48891     get changed$() {
48892         return this._indexChanged$;
48893     }
48894     get updated$() {
48895         return this._updated$;
48896     }
48897     add(markers) {
48898         const updated = [];
48899         const hash = this._hash;
48900         const index = this._index;
48901         for (const marker of markers) {
48902             const id = marker.id;
48903             if (id in hash) {
48904                 index.remove(hash[id]);
48905                 updated.push(marker);
48906             }
48907             const item = {
48908                 lat: marker.lngLat.lat,
48909                 lng: marker.lngLat.lng,
48910                 marker: marker,
48911             };
48912             hash[id] = item;
48913             index.insert(item);
48914         }
48915         if (updated.length > 0) {
48916             this._updated$.next(updated);
48917         }
48918         if (markers.length > updated.length) {
48919             this._indexChanged$.next(this);
48920         }
48921     }
48922     has(id) {
48923         return id in this._hash;
48924     }
48925     get(id) {
48926         return this.has(id) ? this._hash[id].marker : undefined;
48927     }
48928     getAll() {
48929         return this._index
48930             .all()
48931             .map((indexItem) => {
48932             return indexItem.marker;
48933         });
48934     }
48935     remove(ids) {
48936         const hash = this._hash;
48937         const index = this._index;
48938         let changed = false;
48939         for (const id of ids) {
48940             if (!(id in hash)) {
48941                 continue;
48942             }
48943             const item = hash[id];
48944             index.remove(item);
48945             delete hash[id];
48946             changed = true;
48947         }
48948         if (changed) {
48949             this._indexChanged$.next(this);
48950         }
48951     }
48952     removeAll() {
48953         this._hash = {};
48954         this._index.clear();
48955         this._indexChanged$.next(this);
48956     }
48957     search([sw, ne]) {
48958         return this._index
48959             .search({
48960             maxX: ne.lng,
48961             maxY: ne.lat,
48962             minX: sw.lng,
48963             minY: sw.lat,
48964         })
48965             .map((indexItem) => {
48966             return indexItem.marker;
48967         });
48968     }
48969     update(marker) {
48970         const hash = this._hash;
48971         const index = this._index;
48972         const id = marker.id;
48973         if (!(id in hash)) {
48974             return;
48975         }
48976         index.remove(hash[id]);
48977         const item = {
48978             lat: marker.lngLat.lat,
48979             lng: marker.lngLat.lng,
48980             marker: marker,
48981         };
48982         hash[id] = item;
48983         index.insert(item);
48984     }
48985 }
48986
48987 function quickselect(arr, k, left, right, compare) {
48988     quickselectStep(arr, k, left || 0, right || (arr.length - 1), compare || defaultCompare$2);
48989 }
48990
48991 function quickselectStep(arr, k, left, right, compare) {
48992
48993     while (right > left) {
48994         if (right - left > 600) {
48995             var n = right - left + 1;
48996             var m = k - left + 1;
48997             var z = Math.log(n);
48998             var s = 0.5 * Math.exp(2 * z / 3);
48999             var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
49000             var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
49001             var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
49002             quickselectStep(arr, k, newLeft, newRight, compare);
49003         }
49004
49005         var t = arr[k];
49006         var i = left;
49007         var j = right;
49008
49009         swap(arr, left, k);
49010         if (compare(arr[right], t) > 0) swap(arr, left, right);
49011
49012         while (i < j) {
49013             swap(arr, i, j);
49014             i++;
49015             j--;
49016             while (compare(arr[i], t) < 0) i++;
49017             while (compare(arr[j], t) > 0) j--;
49018         }
49019
49020         if (compare(arr[left], t) === 0) swap(arr, left, j);
49021         else {
49022             j++;
49023             swap(arr, j, right);
49024         }
49025
49026         if (j <= k) left = j + 1;
49027         if (k <= j) right = j - 1;
49028     }
49029 }
49030
49031 function swap(arr, i, j) {
49032     var tmp = arr[i];
49033     arr[i] = arr[j];
49034     arr[j] = tmp;
49035 }
49036
49037 function defaultCompare$2(a, b) {
49038     return a < b ? -1 : a > b ? 1 : 0;
49039 }
49040
49041 class RBush {
49042     constructor(maxEntries = 9) {
49043         // max entries in a node is 9 by default; min node fill is 40% for best performance
49044         this._maxEntries = Math.max(4, maxEntries);
49045         this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
49046         this.clear();
49047     }
49048
49049     all() {
49050         return this._all(this.data, []);
49051     }
49052
49053     search(bbox) {
49054         let node = this.data;
49055         const result = [];
49056
49057         if (!intersects$1(bbox, node)) return result;
49058
49059         const toBBox = this.toBBox;
49060         const nodesToSearch = [];
49061
49062         while (node) {
49063             for (let i = 0; i < node.children.length; i++) {
49064                 const child = node.children[i];
49065                 const childBBox = node.leaf ? toBBox(child) : child;
49066
49067                 if (intersects$1(bbox, childBBox)) {
49068                     if (node.leaf) result.push(child);
49069                     else if (contains(bbox, childBBox)) this._all(child, result);
49070                     else nodesToSearch.push(child);
49071                 }
49072             }
49073             node = nodesToSearch.pop();
49074         }
49075
49076         return result;
49077     }
49078
49079     collides(bbox) {
49080         let node = this.data;
49081
49082         if (!intersects$1(bbox, node)) return false;
49083
49084         const nodesToSearch = [];
49085         while (node) {
49086             for (let i = 0; i < node.children.length; i++) {
49087                 const child = node.children[i];
49088                 const childBBox = node.leaf ? this.toBBox(child) : child;
49089
49090                 if (intersects$1(bbox, childBBox)) {
49091                     if (node.leaf || contains(bbox, childBBox)) return true;
49092                     nodesToSearch.push(child);
49093                 }
49094             }
49095             node = nodesToSearch.pop();
49096         }
49097
49098         return false;
49099     }
49100
49101     load(data) {
49102         if (!(data && data.length)) return this;
49103
49104         if (data.length < this._minEntries) {
49105             for (let i = 0; i < data.length; i++) {
49106                 this.insert(data[i]);
49107             }
49108             return this;
49109         }
49110
49111         // recursively build the tree with the given data from scratch using OMT algorithm
49112         let node = this._build(data.slice(), 0, data.length - 1, 0);
49113
49114         if (!this.data.children.length) {
49115             // save as is if tree is empty
49116             this.data = node;
49117
49118         } else if (this.data.height === node.height) {
49119             // split root if trees have the same height
49120             this._splitRoot(this.data, node);
49121
49122         } else {
49123             if (this.data.height < node.height) {
49124                 // swap trees if inserted one is bigger
49125                 const tmpNode = this.data;
49126                 this.data = node;
49127                 node = tmpNode;
49128             }
49129
49130             // insert the small tree into the large tree at appropriate level
49131             this._insert(node, this.data.height - node.height - 1, true);
49132         }
49133
49134         return this;
49135     }
49136
49137     insert(item) {
49138         if (item) this._insert(item, this.data.height - 1);
49139         return this;
49140     }
49141
49142     clear() {
49143         this.data = createNode([]);
49144         return this;
49145     }
49146
49147     remove(item, equalsFn) {
49148         if (!item) return this;
49149
49150         let node = this.data;
49151         const bbox = this.toBBox(item);
49152         const path = [];
49153         const indexes = [];
49154         let i, parent, goingUp;
49155
49156         // depth-first iterative tree traversal
49157         while (node || path.length) {
49158
49159             if (!node) { // go up
49160                 node = path.pop();
49161                 parent = path[path.length - 1];
49162                 i = indexes.pop();
49163                 goingUp = true;
49164             }
49165
49166             if (node.leaf) { // check current node
49167                 const index = findItem(item, node.children, equalsFn);
49168
49169                 if (index !== -1) {
49170                     // item found, remove the item and condense tree upwards
49171                     node.children.splice(index, 1);
49172                     path.push(node);
49173                     this._condense(path);
49174                     return this;
49175                 }
49176             }
49177
49178             if (!goingUp && !node.leaf && contains(node, bbox)) { // go down
49179                 path.push(node);
49180                 indexes.push(i);
49181                 i = 0;
49182                 parent = node;
49183                 node = node.children[0];
49184
49185             } else if (parent) { // go right
49186                 i++;
49187                 node = parent.children[i];
49188                 goingUp = false;
49189
49190             } else node = null; // nothing found
49191         }
49192
49193         return this;
49194     }
49195
49196     toBBox(item) { return item; }
49197
49198     compareMinX(a, b) { return a.minX - b.minX; }
49199     compareMinY(a, b) { return a.minY - b.minY; }
49200
49201     toJSON() { return this.data; }
49202
49203     fromJSON(data) {
49204         this.data = data;
49205         return this;
49206     }
49207
49208     _all(node, result) {
49209         const nodesToSearch = [];
49210         while (node) {
49211             if (node.leaf) result.push(...node.children);
49212             else nodesToSearch.push(...node.children);
49213
49214             node = nodesToSearch.pop();
49215         }
49216         return result;
49217     }
49218
49219     _build(items, left, right, height) {
49220
49221         const N = right - left + 1;
49222         let M = this._maxEntries;
49223         let node;
49224
49225         if (N <= M) {
49226             // reached leaf level; return leaf
49227             node = createNode(items.slice(left, right + 1));
49228             calcBBox(node, this.toBBox);
49229             return node;
49230         }
49231
49232         if (!height) {
49233             // target height of the bulk-loaded tree
49234             height = Math.ceil(Math.log(N) / Math.log(M));
49235
49236             // target number of root entries to maximize storage utilization
49237             M = Math.ceil(N / Math.pow(M, height - 1));
49238         }
49239
49240         node = createNode([]);
49241         node.leaf = false;
49242         node.height = height;
49243
49244         // split the items into M mostly square tiles
49245
49246         const N2 = Math.ceil(N / M);
49247         const N1 = N2 * Math.ceil(Math.sqrt(M));
49248
49249         multiSelect(items, left, right, N1, this.compareMinX);
49250
49251         for (let i = left; i <= right; i += N1) {
49252
49253             const right2 = Math.min(i + N1 - 1, right);
49254
49255             multiSelect(items, i, right2, N2, this.compareMinY);
49256
49257             for (let j = i; j <= right2; j += N2) {
49258
49259                 const right3 = Math.min(j + N2 - 1, right2);
49260
49261                 // pack each entry recursively
49262                 node.children.push(this._build(items, j, right3, height - 1));
49263             }
49264         }
49265
49266         calcBBox(node, this.toBBox);
49267
49268         return node;
49269     }
49270
49271     _chooseSubtree(bbox, node, level, path) {
49272         while (true) {
49273             path.push(node);
49274
49275             if (node.leaf || path.length - 1 === level) break;
49276
49277             let minArea = Infinity;
49278             let minEnlargement = Infinity;
49279             let targetNode;
49280
49281             for (let i = 0; i < node.children.length; i++) {
49282                 const child = node.children[i];
49283                 const area = bboxArea(child);
49284                 const enlargement = enlargedArea(bbox, child) - area;
49285
49286                 // choose entry with the least area enlargement
49287                 if (enlargement < minEnlargement) {
49288                     minEnlargement = enlargement;
49289                     minArea = area < minArea ? area : minArea;
49290                     targetNode = child;
49291
49292                 } else if (enlargement === minEnlargement) {
49293                     // otherwise choose one with the smallest area
49294                     if (area < minArea) {
49295                         minArea = area;
49296                         targetNode = child;
49297                     }
49298                 }
49299             }
49300
49301             node = targetNode || node.children[0];
49302         }
49303
49304         return node;
49305     }
49306
49307     _insert(item, level, isNode) {
49308         const bbox = isNode ? item : this.toBBox(item);
49309         const insertPath = [];
49310
49311         // find the best node for accommodating the item, saving all nodes along the path too
49312         const node = this._chooseSubtree(bbox, this.data, level, insertPath);
49313
49314         // put the item into the node
49315         node.children.push(item);
49316         extend(node, bbox);
49317
49318         // split on node overflow; propagate upwards if necessary
49319         while (level >= 0) {
49320             if (insertPath[level].children.length > this._maxEntries) {
49321                 this._split(insertPath, level);
49322                 level--;
49323             } else break;
49324         }
49325
49326         // adjust bboxes along the insertion path
49327         this._adjustParentBBoxes(bbox, insertPath, level);
49328     }
49329
49330     // split overflowed node into two
49331     _split(insertPath, level) {
49332         const node = insertPath[level];
49333         const M = node.children.length;
49334         const m = this._minEntries;
49335
49336         this._chooseSplitAxis(node, m, M);
49337
49338         const splitIndex = this._chooseSplitIndex(node, m, M);
49339
49340         const newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));
49341         newNode.height = node.height;
49342         newNode.leaf = node.leaf;
49343
49344         calcBBox(node, this.toBBox);
49345         calcBBox(newNode, this.toBBox);
49346
49347         if (level) insertPath[level - 1].children.push(newNode);
49348         else this._splitRoot(node, newNode);
49349     }
49350
49351     _splitRoot(node, newNode) {
49352         // split root node
49353         this.data = createNode([node, newNode]);
49354         this.data.height = node.height + 1;
49355         this.data.leaf = false;
49356         calcBBox(this.data, this.toBBox);
49357     }
49358
49359     _chooseSplitIndex(node, m, M) {
49360         let index;
49361         let minOverlap = Infinity;
49362         let minArea = Infinity;
49363
49364         for (let i = m; i <= M - m; i++) {
49365             const bbox1 = distBBox(node, 0, i, this.toBBox);
49366             const bbox2 = distBBox(node, i, M, this.toBBox);
49367
49368             const overlap = intersectionArea(bbox1, bbox2);
49369             const area = bboxArea(bbox1) + bboxArea(bbox2);
49370
49371             // choose distribution with minimum overlap
49372             if (overlap < minOverlap) {
49373                 minOverlap = overlap;
49374                 index = i;
49375
49376                 minArea = area < minArea ? area : minArea;
49377
49378             } else if (overlap === minOverlap) {
49379                 // otherwise choose distribution with minimum area
49380                 if (area < minArea) {
49381                     minArea = area;
49382                     index = i;
49383                 }
49384             }
49385         }
49386
49387         return index || M - m;
49388     }
49389
49390     // sorts node children by the best axis for split
49391     _chooseSplitAxis(node, m, M) {
49392         const compareMinX = node.leaf ? this.compareMinX : compareNodeMinX;
49393         const compareMinY = node.leaf ? this.compareMinY : compareNodeMinY;
49394         const xMargin = this._allDistMargin(node, m, M, compareMinX);
49395         const yMargin = this._allDistMargin(node, m, M, compareMinY);
49396
49397         // if total distributions margin value is minimal for x, sort by minX,
49398         // otherwise it's already sorted by minY
49399         if (xMargin < yMargin) node.children.sort(compareMinX);
49400     }
49401
49402     // total margin of all possible split distributions where each node is at least m full
49403     _allDistMargin(node, m, M, compare) {
49404         node.children.sort(compare);
49405
49406         const toBBox = this.toBBox;
49407         const leftBBox = distBBox(node, 0, m, toBBox);
49408         const rightBBox = distBBox(node, M - m, M, toBBox);
49409         let margin = bboxMargin(leftBBox) + bboxMargin(rightBBox);
49410
49411         for (let i = m; i < M - m; i++) {
49412             const child = node.children[i];
49413             extend(leftBBox, node.leaf ? toBBox(child) : child);
49414             margin += bboxMargin(leftBBox);
49415         }
49416
49417         for (let i = M - m - 1; i >= m; i--) {
49418             const child = node.children[i];
49419             extend(rightBBox, node.leaf ? toBBox(child) : child);
49420             margin += bboxMargin(rightBBox);
49421         }
49422
49423         return margin;
49424     }
49425
49426     _adjustParentBBoxes(bbox, path, level) {
49427         // adjust bboxes along the given tree path
49428         for (let i = level; i >= 0; i--) {
49429             extend(path[i], bbox);
49430         }
49431     }
49432
49433     _condense(path) {
49434         // go through the path, removing empty nodes and updating bboxes
49435         for (let i = path.length - 1, siblings; i >= 0; i--) {
49436             if (path[i].children.length === 0) {
49437                 if (i > 0) {
49438                     siblings = path[i - 1].children;
49439                     siblings.splice(siblings.indexOf(path[i]), 1);
49440
49441                 } else this.clear();
49442
49443             } else calcBBox(path[i], this.toBBox);
49444         }
49445     }
49446 }
49447
49448 function findItem(item, items, equalsFn) {
49449     if (!equalsFn) return items.indexOf(item);
49450
49451     for (let i = 0; i < items.length; i++) {
49452         if (equalsFn(item, items[i])) return i;
49453     }
49454     return -1;
49455 }
49456
49457 // calculate node's bbox from bboxes of its children
49458 function calcBBox(node, toBBox) {
49459     distBBox(node, 0, node.children.length, toBBox, node);
49460 }
49461
49462 // min bounding rectangle of node children from k to p-1
49463 function distBBox(node, k, p, toBBox, destNode) {
49464     if (!destNode) destNode = createNode(null);
49465     destNode.minX = Infinity;
49466     destNode.minY = Infinity;
49467     destNode.maxX = -Infinity;
49468     destNode.maxY = -Infinity;
49469
49470     for (let i = k; i < p; i++) {
49471         const child = node.children[i];
49472         extend(destNode, node.leaf ? toBBox(child) : child);
49473     }
49474
49475     return destNode;
49476 }
49477
49478 function extend(a, b) {
49479     a.minX = Math.min(a.minX, b.minX);
49480     a.minY = Math.min(a.minY, b.minY);
49481     a.maxX = Math.max(a.maxX, b.maxX);
49482     a.maxY = Math.max(a.maxY, b.maxY);
49483     return a;
49484 }
49485
49486 function compareNodeMinX(a, b) { return a.minX - b.minX; }
49487 function compareNodeMinY(a, b) { return a.minY - b.minY; }
49488
49489 function bboxArea(a)   { return (a.maxX - a.minX) * (a.maxY - a.minY); }
49490 function bboxMargin(a) { return (a.maxX - a.minX) + (a.maxY - a.minY); }
49491
49492 function enlargedArea(a, b) {
49493     return (Math.max(b.maxX, a.maxX) - Math.min(b.minX, a.minX)) *
49494            (Math.max(b.maxY, a.maxY) - Math.min(b.minY, a.minY));
49495 }
49496
49497 function intersectionArea(a, b) {
49498     const minX = Math.max(a.minX, b.minX);
49499     const minY = Math.max(a.minY, b.minY);
49500     const maxX = Math.min(a.maxX, b.maxX);
49501     const maxY = Math.min(a.maxY, b.maxY);
49502
49503     return Math.max(0, maxX - minX) *
49504            Math.max(0, maxY - minY);
49505 }
49506
49507 function contains(a, b) {
49508     return a.minX <= b.minX &&
49509            a.minY <= b.minY &&
49510            b.maxX <= a.maxX &&
49511            b.maxY <= a.maxY;
49512 }
49513
49514 function intersects$1(a, b) {
49515     return b.minX <= a.maxX &&
49516            b.minY <= a.maxY &&
49517            b.maxX >= a.minX &&
49518            b.maxY >= a.minY;
49519 }
49520
49521 function createNode(children) {
49522     return {
49523         children,
49524         height: 1,
49525         leaf: true,
49526         minX: Infinity,
49527         minY: Infinity,
49528         maxX: -Infinity,
49529         maxY: -Infinity
49530     };
49531 }
49532
49533 // sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
49534 // combines selection algorithm with binary divide & conquer approach
49535
49536 function multiSelect(arr, left, right, n, compare) {
49537     const stack = [left, right];
49538
49539     while (stack.length) {
49540         right = stack.pop();
49541         left = stack.pop();
49542
49543         if (right - left <= n) continue;
49544
49545         const mid = left + Math.ceil((right - left) / n / 2) * n;
49546         quickselect(arr, mid, left, right, compare);
49547
49548         stack.push(left, mid, mid, right);
49549     }
49550 }
49551
49552 class GeoRBush extends RBush {
49553     compareMinX(a, b) {
49554         return a.lng - b.lng;
49555     }
49556     compareMinY(a, b) {
49557         return a.lat - b.lat;
49558     }
49559     toBBox(item) {
49560         return {
49561             minX: item.lng,
49562             minY: item.lat,
49563             maxX: item.lng,
49564             maxY: item.lat,
49565         };
49566     }
49567 }
49568
49569 class ComponentService {
49570     constructor(container, navigator) {
49571         this._components = {};
49572         for (const componentName in ComponentService.registeredComponents) {
49573             if (!ComponentService.registeredComponents.hasOwnProperty(componentName)) {
49574                 continue;
49575             }
49576             const component = ComponentService.registeredComponents[componentName];
49577             this._components[componentName] = {
49578                 active: false,
49579                 component: new component(componentName, container, navigator),
49580             };
49581         }
49582         this._coverComponent = new ComponentService.registeredCoverComponent("cover", container, navigator);
49583         this._coverComponent.activate();
49584         this._coverActivated = true;
49585     }
49586     static register(component) {
49587         if (ComponentService.registeredComponents[component.componentName] === undefined) {
49588             ComponentService.registeredComponents[component.componentName] = component;
49589         }
49590     }
49591     static registerCover(coverComponent) {
49592         ComponentService.registeredCoverComponent = coverComponent;
49593     }
49594     get coverActivated() {
49595         return this._coverActivated;
49596     }
49597     activateCover() {
49598         if (this._coverActivated) {
49599             return;
49600         }
49601         this._coverActivated = true;
49602         for (const componentName in this._components) {
49603             if (!this._components.hasOwnProperty(componentName)) {
49604                 continue;
49605             }
49606             const component = this._components[componentName];
49607             if (component.active) {
49608                 component.component.deactivate();
49609             }
49610         }
49611     }
49612     deactivateCover() {
49613         if (!this._coverActivated) {
49614             return;
49615         }
49616         this._coverActivated = false;
49617         for (const componentName in this._components) {
49618             if (!this._components.hasOwnProperty(componentName)) {
49619                 continue;
49620             }
49621             const component = this._components[componentName];
49622             if (component.active) {
49623                 component.component.activate();
49624             }
49625         }
49626     }
49627     activate(name) {
49628         this._checkName(name);
49629         this._components[name].active = true;
49630         if (!this._coverActivated) {
49631             this.get(name).activate();
49632         }
49633     }
49634     configure(name, conf) {
49635         this._checkName(name);
49636         this.get(name).configure(conf);
49637     }
49638     deactivate(name) {
49639         this._checkName(name);
49640         this._components[name].active = false;
49641         if (!this._coverActivated) {
49642             this.get(name).deactivate();
49643         }
49644     }
49645     get(name) {
49646         return this._components[name].component;
49647     }
49648     getCover() {
49649         return this._coverComponent;
49650     }
49651     remove() {
49652         this._coverComponent.deactivate();
49653         for (const componentName in this._components) {
49654             if (!this._components.hasOwnProperty(componentName)) {
49655                 continue;
49656             }
49657             this._components[componentName].component.deactivate();
49658         }
49659     }
49660     _checkName(name) {
49661         if (!(name in this._components)) {
49662             throw new ArgumentMapillaryError(`Component does not exist: ${name}`);
49663         }
49664     }
49665 }
49666 ComponentService.registeredComponents = {};
49667
49668 var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
49669
49670 function getAugmentedNamespace(n) {
49671         if (n.__esModule) return n;
49672         var a = Object.defineProperty({}, '__esModule', {value: true});
49673         Object.keys(n).forEach(function (k) {
49674                 var d = Object.getOwnPropertyDescriptor(n, k);
49675                 Object.defineProperty(a, k, d.get ? d : {
49676                         enumerable: true,
49677                         get: function () {
49678                                 return n[k];
49679                         }
49680                 });
49681         });
49682         return a;
49683 }
49684
49685 function commonjsRequire (path) {
49686         throw new Error('Could not dynamically require "' + path + '". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.');
49687 }
49688
49689 var nativeIsArray = Array.isArray;
49690 var toString$2 = Object.prototype.toString;
49691
49692 var xIsArray = nativeIsArray || isArray$3;
49693
49694 function isArray$3(obj) {
49695     return toString$2.call(obj) === "[object Array]"
49696 }
49697
49698 var version$5 = "2";
49699
49700 var version$4 = version$5;
49701
49702 VirtualPatch.NONE = 0;
49703 VirtualPatch.VTEXT = 1;
49704 VirtualPatch.VNODE = 2;
49705 VirtualPatch.WIDGET = 3;
49706 VirtualPatch.PROPS = 4;
49707 VirtualPatch.ORDER = 5;
49708 VirtualPatch.INSERT = 6;
49709 VirtualPatch.REMOVE = 7;
49710 VirtualPatch.THUNK = 8;
49711
49712 var vpatch = VirtualPatch;
49713
49714 function VirtualPatch(type, vNode, patch) {
49715     this.type = Number(type);
49716     this.vNode = vNode;
49717     this.patch = patch;
49718 }
49719
49720 VirtualPatch.prototype.version = version$4;
49721 VirtualPatch.prototype.type = "VirtualPatch";
49722
49723 var version$3 = version$5;
49724
49725 var isVnode = isVirtualNode;
49726
49727 function isVirtualNode(x) {
49728     return x && x.type === "VirtualNode" && x.version === version$3
49729 }
49730
49731 var version$2 = version$5;
49732
49733 var isVtext = isVirtualText;
49734
49735 function isVirtualText(x) {
49736     return x && x.type === "VirtualText" && x.version === version$2
49737 }
49738
49739 var isWidget_1 = isWidget$7;
49740
49741 function isWidget$7(w) {
49742     return w && w.type === "Widget"
49743 }
49744
49745 var isThunk_1 = isThunk$3;
49746
49747 function isThunk$3(t) {
49748     return t && t.type === "Thunk"
49749 }
49750
49751 var isVNode$4 = isVnode;
49752 var isVText$3 = isVtext;
49753 var isWidget$6 = isWidget_1;
49754 var isThunk$2 = isThunk_1;
49755
49756 var handleThunk_1 = handleThunk$2;
49757
49758 function handleThunk$2(a, b) {
49759     var renderedA = a;
49760     var renderedB = b;
49761
49762     if (isThunk$2(b)) {
49763         renderedB = renderThunk(b, a);
49764     }
49765
49766     if (isThunk$2(a)) {
49767         renderedA = renderThunk(a, null);
49768     }
49769
49770     return {
49771         a: renderedA,
49772         b: renderedB
49773     }
49774 }
49775
49776 function renderThunk(thunk, previous) {
49777     var renderedThunk = thunk.vnode;
49778
49779     if (!renderedThunk) {
49780         renderedThunk = thunk.vnode = thunk.render(previous);
49781     }
49782
49783     if (!(isVNode$4(renderedThunk) ||
49784             isVText$3(renderedThunk) ||
49785             isWidget$6(renderedThunk))) {
49786         throw new Error("thunk did not return a valid node");
49787     }
49788
49789     return renderedThunk
49790 }
49791
49792 var isObject$2 = function isObject(x) {
49793         return typeof x === 'object' && x !== null;
49794 };
49795
49796 var isVhook = isHook$3;
49797
49798 function isHook$3(hook) {
49799     return hook &&
49800       (typeof hook.hook === "function" && !hook.hasOwnProperty("hook") ||
49801        typeof hook.unhook === "function" && !hook.hasOwnProperty("unhook"))
49802 }
49803
49804 var isObject$1 = isObject$2;
49805 var isHook$2 = isVhook;
49806
49807 var diffProps_1 = diffProps$1;
49808
49809 function diffProps$1(a, b) {
49810     var diff;
49811
49812     for (var aKey in a) {
49813         if (!(aKey in b)) {
49814             diff = diff || {};
49815             diff[aKey] = undefined;
49816         }
49817
49818         var aValue = a[aKey];
49819         var bValue = b[aKey];
49820
49821         if (aValue === bValue) {
49822             continue
49823         } else if (isObject$1(aValue) && isObject$1(bValue)) {
49824             if (getPrototype$1(bValue) !== getPrototype$1(aValue)) {
49825                 diff = diff || {};
49826                 diff[aKey] = bValue;
49827             } else if (isHook$2(bValue)) {
49828                  diff = diff || {};
49829                  diff[aKey] = bValue;
49830             } else {
49831                 var objectDiff = diffProps$1(aValue, bValue);
49832                 if (objectDiff) {
49833                     diff = diff || {};
49834                     diff[aKey] = objectDiff;
49835                 }
49836             }
49837         } else {
49838             diff = diff || {};
49839             diff[aKey] = bValue;
49840         }
49841     }
49842
49843     for (var bKey in b) {
49844         if (!(bKey in a)) {
49845             diff = diff || {};
49846             diff[bKey] = b[bKey];
49847         }
49848     }
49849
49850     return diff
49851 }
49852
49853 function getPrototype$1(value) {
49854   if (Object.getPrototypeOf) {
49855     return Object.getPrototypeOf(value)
49856   } else if (value.__proto__) {
49857     return value.__proto__
49858   } else if (value.constructor) {
49859     return value.constructor.prototype
49860   }
49861 }
49862
49863 var isArray$2 = xIsArray;
49864
49865 var VPatch$1 = vpatch;
49866 var isVNode$3 = isVnode;
49867 var isVText$2 = isVtext;
49868 var isWidget$5 = isWidget_1;
49869 var isThunk$1 = isThunk_1;
49870 var handleThunk$1 = handleThunk_1;
49871
49872 var diffProps = diffProps_1;
49873
49874 var diff_1$1 = diff$2;
49875
49876 function diff$2(a, b) {
49877     var patch = { a: a };
49878     walk(a, b, patch, 0);
49879     return patch
49880 }
49881
49882 function walk(a, b, patch, index) {
49883     if (a === b) {
49884         return
49885     }
49886
49887     var apply = patch[index];
49888     var applyClear = false;
49889
49890     if (isThunk$1(a) || isThunk$1(b)) {
49891         thunks(a, b, patch, index);
49892     } else if (b == null) {
49893
49894         // If a is a widget we will add a remove patch for it
49895         // Otherwise any child widgets/hooks must be destroyed.
49896         // This prevents adding two remove patches for a widget.
49897         if (!isWidget$5(a)) {
49898             clearState(a, patch, index);
49899             apply = patch[index];
49900         }
49901
49902         apply = appendPatch(apply, new VPatch$1(VPatch$1.REMOVE, a, b));
49903     } else if (isVNode$3(b)) {
49904         if (isVNode$3(a)) {
49905             if (a.tagName === b.tagName &&
49906                 a.namespace === b.namespace &&
49907                 a.key === b.key) {
49908                 var propsPatch = diffProps(a.properties, b.properties);
49909                 if (propsPatch) {
49910                     apply = appendPatch(apply,
49911                         new VPatch$1(VPatch$1.PROPS, a, propsPatch));
49912                 }
49913                 apply = diffChildren(a, b, patch, apply, index);
49914             } else {
49915                 apply = appendPatch(apply, new VPatch$1(VPatch$1.VNODE, a, b));
49916                 applyClear = true;
49917             }
49918         } else {
49919             apply = appendPatch(apply, new VPatch$1(VPatch$1.VNODE, a, b));
49920             applyClear = true;
49921         }
49922     } else if (isVText$2(b)) {
49923         if (!isVText$2(a)) {
49924             apply = appendPatch(apply, new VPatch$1(VPatch$1.VTEXT, a, b));
49925             applyClear = true;
49926         } else if (a.text !== b.text) {
49927             apply = appendPatch(apply, new VPatch$1(VPatch$1.VTEXT, a, b));
49928         }
49929     } else if (isWidget$5(b)) {
49930         if (!isWidget$5(a)) {
49931             applyClear = true;
49932         }
49933
49934         apply = appendPatch(apply, new VPatch$1(VPatch$1.WIDGET, a, b));
49935     }
49936
49937     if (apply) {
49938         patch[index] = apply;
49939     }
49940
49941     if (applyClear) {
49942         clearState(a, patch, index);
49943     }
49944 }
49945
49946 function diffChildren(a, b, patch, apply, index) {
49947     var aChildren = a.children;
49948     var orderedSet = reorder(aChildren, b.children);
49949     var bChildren = orderedSet.children;
49950
49951     var aLen = aChildren.length;
49952     var bLen = bChildren.length;
49953     var len = aLen > bLen ? aLen : bLen;
49954
49955     for (var i = 0; i < len; i++) {
49956         var leftNode = aChildren[i];
49957         var rightNode = bChildren[i];
49958         index += 1;
49959
49960         if (!leftNode) {
49961             if (rightNode) {
49962                 // Excess nodes in b need to be added
49963                 apply = appendPatch(apply,
49964                     new VPatch$1(VPatch$1.INSERT, null, rightNode));
49965             }
49966         } else {
49967             walk(leftNode, rightNode, patch, index);
49968         }
49969
49970         if (isVNode$3(leftNode) && leftNode.count) {
49971             index += leftNode.count;
49972         }
49973     }
49974
49975     if (orderedSet.moves) {
49976         // Reorder nodes last
49977         apply = appendPatch(apply, new VPatch$1(
49978             VPatch$1.ORDER,
49979             a,
49980             orderedSet.moves
49981         ));
49982     }
49983
49984     return apply
49985 }
49986
49987 function clearState(vNode, patch, index) {
49988     // TODO: Make this a single walk, not two
49989     unhook(vNode, patch, index);
49990     destroyWidgets(vNode, patch, index);
49991 }
49992
49993 // Patch records for all destroyed widgets must be added because we need
49994 // a DOM node reference for the destroy function
49995 function destroyWidgets(vNode, patch, index) {
49996     if (isWidget$5(vNode)) {
49997         if (typeof vNode.destroy === "function") {
49998             patch[index] = appendPatch(
49999                 patch[index],
50000                 new VPatch$1(VPatch$1.REMOVE, vNode, null)
50001             );
50002         }
50003     } else if (isVNode$3(vNode) && (vNode.hasWidgets || vNode.hasThunks)) {
50004         var children = vNode.children;
50005         var len = children.length;
50006         for (var i = 0; i < len; i++) {
50007             var child = children[i];
50008             index += 1;
50009
50010             destroyWidgets(child, patch, index);
50011
50012             if (isVNode$3(child) && child.count) {
50013                 index += child.count;
50014             }
50015         }
50016     } else if (isThunk$1(vNode)) {
50017         thunks(vNode, null, patch, index);
50018     }
50019 }
50020
50021 // Create a sub-patch for thunks
50022 function thunks(a, b, patch, index) {
50023     var nodes = handleThunk$1(a, b);
50024     var thunkPatch = diff$2(nodes.a, nodes.b);
50025     if (hasPatches(thunkPatch)) {
50026         patch[index] = new VPatch$1(VPatch$1.THUNK, null, thunkPatch);
50027     }
50028 }
50029
50030 function hasPatches(patch) {
50031     for (var index in patch) {
50032         if (index !== "a") {
50033             return true
50034         }
50035     }
50036
50037     return false
50038 }
50039
50040 // Execute hooks when two nodes are identical
50041 function unhook(vNode, patch, index) {
50042     if (isVNode$3(vNode)) {
50043         if (vNode.hooks) {
50044             patch[index] = appendPatch(
50045                 patch[index],
50046                 new VPatch$1(
50047                     VPatch$1.PROPS,
50048                     vNode,
50049                     undefinedKeys(vNode.hooks)
50050                 )
50051             );
50052         }
50053
50054         if (vNode.descendantHooks || vNode.hasThunks) {
50055             var children = vNode.children;
50056             var len = children.length;
50057             for (var i = 0; i < len; i++) {
50058                 var child = children[i];
50059                 index += 1;
50060
50061                 unhook(child, patch, index);
50062
50063                 if (isVNode$3(child) && child.count) {
50064                     index += child.count;
50065                 }
50066             }
50067         }
50068     } else if (isThunk$1(vNode)) {
50069         thunks(vNode, null, patch, index);
50070     }
50071 }
50072
50073 function undefinedKeys(obj) {
50074     var result = {};
50075
50076     for (var key in obj) {
50077         result[key] = undefined;
50078     }
50079
50080     return result
50081 }
50082
50083 // List diff, naive left to right reordering
50084 function reorder(aChildren, bChildren) {
50085     // O(M) time, O(M) memory
50086     var bChildIndex = keyIndex(bChildren);
50087     var bKeys = bChildIndex.keys;
50088     var bFree = bChildIndex.free;
50089
50090     if (bFree.length === bChildren.length) {
50091         return {
50092             children: bChildren,
50093             moves: null
50094         }
50095     }
50096
50097     // O(N) time, O(N) memory
50098     var aChildIndex = keyIndex(aChildren);
50099     var aKeys = aChildIndex.keys;
50100     var aFree = aChildIndex.free;
50101
50102     if (aFree.length === aChildren.length) {
50103         return {
50104             children: bChildren,
50105             moves: null
50106         }
50107     }
50108
50109     // O(MAX(N, M)) memory
50110     var newChildren = [];
50111
50112     var freeIndex = 0;
50113     var freeCount = bFree.length;
50114     var deletedItems = 0;
50115
50116     // Iterate through a and match a node in b
50117     // O(N) time,
50118     for (var i = 0 ; i < aChildren.length; i++) {
50119         var aItem = aChildren[i];
50120         var itemIndex;
50121
50122         if (aItem.key) {
50123             if (bKeys.hasOwnProperty(aItem.key)) {
50124                 // Match up the old keys
50125                 itemIndex = bKeys[aItem.key];
50126                 newChildren.push(bChildren[itemIndex]);
50127
50128             } else {
50129                 // Remove old keyed items
50130                 itemIndex = i - deletedItems++;
50131                 newChildren.push(null);
50132             }
50133         } else {
50134             // Match the item in a with the next free item in b
50135             if (freeIndex < freeCount) {
50136                 itemIndex = bFree[freeIndex++];
50137                 newChildren.push(bChildren[itemIndex]);
50138             } else {
50139                 // There are no free items in b to match with
50140                 // the free items in a, so the extra free nodes
50141                 // are deleted.
50142                 itemIndex = i - deletedItems++;
50143                 newChildren.push(null);
50144             }
50145         }
50146     }
50147
50148     var lastFreeIndex = freeIndex >= bFree.length ?
50149         bChildren.length :
50150         bFree[freeIndex];
50151
50152     // Iterate through b and append any new keys
50153     // O(M) time
50154     for (var j = 0; j < bChildren.length; j++) {
50155         var newItem = bChildren[j];
50156
50157         if (newItem.key) {
50158             if (!aKeys.hasOwnProperty(newItem.key)) {
50159                 // Add any new keyed items
50160                 // We are adding new items to the end and then sorting them
50161                 // in place. In future we should insert new items in place.
50162                 newChildren.push(newItem);
50163             }
50164         } else if (j >= lastFreeIndex) {
50165             // Add any leftover non-keyed items
50166             newChildren.push(newItem);
50167         }
50168     }
50169
50170     var simulate = newChildren.slice();
50171     var simulateIndex = 0;
50172     var removes = [];
50173     var inserts = [];
50174     var simulateItem;
50175
50176     for (var k = 0; k < bChildren.length;) {
50177         var wantedItem = bChildren[k];
50178         simulateItem = simulate[simulateIndex];
50179
50180         // remove items
50181         while (simulateItem === null && simulate.length) {
50182             removes.push(remove(simulate, simulateIndex, null));
50183             simulateItem = simulate[simulateIndex];
50184         }
50185
50186         if (!simulateItem || simulateItem.key !== wantedItem.key) {
50187             // if we need a key in this position...
50188             if (wantedItem.key) {
50189                 if (simulateItem && simulateItem.key) {
50190                     // if an insert doesn't put this key in place, it needs to move
50191                     if (bKeys[simulateItem.key] !== k + 1) {
50192                         removes.push(remove(simulate, simulateIndex, simulateItem.key));
50193                         simulateItem = simulate[simulateIndex];
50194                         // if the remove didn't put the wanted item in place, we need to insert it
50195                         if (!simulateItem || simulateItem.key !== wantedItem.key) {
50196                             inserts.push({key: wantedItem.key, to: k});
50197                         }
50198                         // items are matching, so skip ahead
50199                         else {
50200                             simulateIndex++;
50201                         }
50202                     }
50203                     else {
50204                         inserts.push({key: wantedItem.key, to: k});
50205                     }
50206                 }
50207                 else {
50208                     inserts.push({key: wantedItem.key, to: k});
50209                 }
50210                 k++;
50211             }
50212             // a key in simulate has no matching wanted key, remove it
50213             else if (simulateItem && simulateItem.key) {
50214                 removes.push(remove(simulate, simulateIndex, simulateItem.key));
50215             }
50216         }
50217         else {
50218             simulateIndex++;
50219             k++;
50220         }
50221     }
50222
50223     // remove all the remaining nodes from simulate
50224     while(simulateIndex < simulate.length) {
50225         simulateItem = simulate[simulateIndex];
50226         removes.push(remove(simulate, simulateIndex, simulateItem && simulateItem.key));
50227     }
50228
50229     // If the only moves we have are deletes then we can just
50230     // let the delete patch remove these items.
50231     if (removes.length === deletedItems && !inserts.length) {
50232         return {
50233             children: newChildren,
50234             moves: null
50235         }
50236     }
50237
50238     return {
50239         children: newChildren,
50240         moves: {
50241             removes: removes,
50242             inserts: inserts
50243         }
50244     }
50245 }
50246
50247 function remove(arr, index, key) {
50248     arr.splice(index, 1);
50249
50250     return {
50251         from: index,
50252         key: key
50253     }
50254 }
50255
50256 function keyIndex(children) {
50257     var keys = {};
50258     var free = [];
50259     var length = children.length;
50260
50261     for (var i = 0; i < length; i++) {
50262         var child = children[i];
50263
50264         if (child.key) {
50265             keys[child.key] = i;
50266         } else {
50267             free.push(i);
50268         }
50269     }
50270
50271     return {
50272         keys: keys,     // A hash of key name to index
50273         free: free      // An array of unkeyed item indices
50274     }
50275 }
50276
50277 function appendPatch(apply, patch) {
50278     if (apply) {
50279         if (isArray$2(apply)) {
50280             apply.push(patch);
50281         } else {
50282             apply = [apply, patch];
50283         }
50284
50285         return apply
50286     } else {
50287         return patch
50288     }
50289 }
50290
50291 var diff$1 = diff_1$1;
50292
50293 var diff_1 = diff$1;
50294
50295 var slice = Array.prototype.slice;
50296
50297 var domWalk$2 = iterativelyWalk;
50298
50299 function iterativelyWalk(nodes, cb) {
50300     if (!('length' in nodes)) {
50301         nodes = [nodes];
50302     }
50303     
50304     nodes = slice.call(nodes);
50305
50306     while(nodes.length) {
50307         var node = nodes.shift(),
50308             ret = cb(node);
50309
50310         if (ret) {
50311             return ret
50312         }
50313
50314         if (node.childNodes && node.childNodes.length) {
50315             nodes = slice.call(node.childNodes).concat(nodes);
50316         }
50317     }
50318 }
50319
50320 var domComment = Comment$1;
50321
50322 function Comment$1(data, owner) {
50323     if (!(this instanceof Comment$1)) {
50324         return new Comment$1(data, owner)
50325     }
50326
50327     this.data = data;
50328     this.nodeValue = data;
50329     this.length = data.length;
50330     this.ownerDocument = owner || null;
50331 }
50332
50333 Comment$1.prototype.nodeType = 8;
50334 Comment$1.prototype.nodeName = "#comment";
50335
50336 Comment$1.prototype.toString = function _Comment_toString() {
50337     return "[object Comment]"
50338 };
50339
50340 var domText = DOMText$1;
50341
50342 function DOMText$1(value, owner) {
50343     if (!(this instanceof DOMText$1)) {
50344         return new DOMText$1(value)
50345     }
50346
50347     this.data = value || "";
50348     this.length = this.data.length;
50349     this.ownerDocument = owner || null;
50350 }
50351
50352 DOMText$1.prototype.type = "DOMTextNode";
50353 DOMText$1.prototype.nodeType = 3;
50354 DOMText$1.prototype.nodeName = "#text";
50355
50356 DOMText$1.prototype.toString = function _Text_toString() {
50357     return this.data
50358 };
50359
50360 DOMText$1.prototype.replaceData = function replaceData(index, length, value) {
50361     var current = this.data;
50362     var left = current.substring(0, index);
50363     var right = current.substring(index + length, current.length);
50364     this.data = left + value + right;
50365     this.length = this.data.length;
50366 };
50367
50368 var dispatchEvent_1 = dispatchEvent$2;
50369
50370 function dispatchEvent$2(ev) {
50371     var elem = this;
50372     var type = ev.type;
50373
50374     if (!ev.target) {
50375         ev.target = elem;
50376     }
50377
50378     if (!elem.listeners) {
50379         elem.listeners = {};
50380     }
50381
50382     var listeners = elem.listeners[type];
50383
50384     if (listeners) {
50385         return listeners.forEach(function (listener) {
50386             ev.currentTarget = elem;
50387             if (typeof listener === 'function') {
50388                 listener(ev);
50389             } else {
50390                 listener.handleEvent(ev);
50391             }
50392         })
50393     }
50394
50395     if (elem.parentNode) {
50396         elem.parentNode.dispatchEvent(ev);
50397     }
50398 }
50399
50400 var addEventListener_1 = addEventListener$2;
50401
50402 function addEventListener$2(type, listener) {
50403     var elem = this;
50404
50405     if (!elem.listeners) {
50406         elem.listeners = {};
50407     }
50408
50409     if (!elem.listeners[type]) {
50410         elem.listeners[type] = [];
50411     }
50412
50413     if (elem.listeners[type].indexOf(listener) === -1) {
50414         elem.listeners[type].push(listener);
50415     }
50416 }
50417
50418 var removeEventListener_1 = removeEventListener$2;
50419
50420 function removeEventListener$2(type, listener) {
50421     var elem = this;
50422
50423     if (!elem.listeners) {
50424         return
50425     }
50426
50427     if (!elem.listeners[type]) {
50428         return
50429     }
50430
50431     var list = elem.listeners[type];
50432     var index = list.indexOf(listener);
50433     if (index !== -1) {
50434         list.splice(index, 1);
50435     }
50436 }
50437
50438 var serialize = serializeNode$1;
50439
50440 var voidElements = ["area","base","br","col","embed","hr","img","input","keygen","link","menuitem","meta","param","source","track","wbr"];
50441
50442 function serializeNode$1(node) {
50443     switch (node.nodeType) {
50444         case 3:
50445             return escapeText(node.data)
50446         case 8:
50447             return "<!--" + node.data + "-->"
50448         default:
50449             return serializeElement(node)
50450     }
50451 }
50452
50453 function serializeElement(elem) {
50454     var strings = [];
50455
50456     var tagname = elem.tagName;
50457
50458     if (elem.namespaceURI === "http://www.w3.org/1999/xhtml") {
50459         tagname = tagname.toLowerCase();
50460     }
50461
50462     strings.push("<" + tagname + properties(elem) + datasetify(elem));
50463
50464     if (voidElements.indexOf(tagname) > -1) {
50465         strings.push(" />");
50466     } else {
50467         strings.push(">");
50468
50469         if (elem.childNodes.length) {
50470             strings.push.apply(strings, elem.childNodes.map(serializeNode$1));
50471         } else if (elem.textContent || elem.innerText) {
50472             strings.push(escapeText(elem.textContent || elem.innerText));
50473         } else if (elem.innerHTML) {
50474             strings.push(elem.innerHTML);
50475         }
50476
50477         strings.push("</" + tagname + ">");
50478     }
50479
50480     return strings.join("")
50481 }
50482
50483 function isProperty(elem, key) {
50484     var type = typeof elem[key];
50485
50486     if (key === "style" && Object.keys(elem.style).length > 0) {
50487       return true
50488     }
50489
50490     return elem.hasOwnProperty(key) &&
50491         (type === "string" || type === "boolean" || type === "number") &&
50492         key !== "nodeName" && key !== "className" && key !== "tagName" &&
50493         key !== "textContent" && key !== "innerText" && key !== "namespaceURI" &&  key !== "innerHTML"
50494 }
50495
50496 function stylify(styles) {
50497     if (typeof styles === 'string') return styles
50498     var attr = "";
50499     Object.keys(styles).forEach(function (key) {
50500         var value = styles[key];
50501         key = key.replace(/[A-Z]/g, function(c) {
50502             return "-" + c.toLowerCase();
50503         });
50504         attr += key + ":" + value + ";";
50505     });
50506     return attr
50507 }
50508
50509 function datasetify(elem) {
50510     var ds = elem.dataset;
50511     var props = [];
50512
50513     for (var key in ds) {
50514         props.push({ name: "data-" + key, value: ds[key] });
50515     }
50516
50517     return props.length ? stringify(props) : ""
50518 }
50519
50520 function stringify(list) {
50521     var attributes = [];
50522     list.forEach(function (tuple) {
50523         var name = tuple.name;
50524         var value = tuple.value;
50525
50526         if (name === "style") {
50527             value = stylify(value);
50528         }
50529
50530         attributes.push(name + "=" + "\"" + escapeAttributeValue(value) + "\"");
50531     });
50532
50533     return attributes.length ? " " + attributes.join(" ") : ""
50534 }
50535
50536 function properties(elem) {
50537     var props = [];
50538     for (var key in elem) {
50539         if (isProperty(elem, key)) {
50540             props.push({ name: key, value: elem[key] });
50541         }
50542     }
50543
50544     for (var ns in elem._attributes) {
50545       for (var attribute in elem._attributes[ns]) {
50546         var prop = elem._attributes[ns][attribute];
50547         var name = (prop.prefix ? prop.prefix + ":" : "") + attribute;
50548         props.push({ name: name, value: prop.value });
50549       }
50550     }
50551
50552     if (elem.className) {
50553         props.push({ name: "class", value: elem.className });
50554     }
50555
50556     return props.length ? stringify(props) : ""
50557 }
50558
50559 function escapeText(s) {
50560     var str = '';
50561
50562     if (typeof(s) === 'string') { 
50563         str = s; 
50564     } else if (s) {
50565         str = s.toString();
50566     }
50567
50568     return str
50569         .replace(/&/g, "&amp;")
50570         .replace(/</g, "&lt;")
50571         .replace(/>/g, "&gt;")
50572 }
50573
50574 function escapeAttributeValue(str) {
50575     return escapeText(str).replace(/"/g, "&quot;")
50576 }
50577
50578 var domWalk$1 = domWalk$2;
50579 var dispatchEvent$1 = dispatchEvent_1;
50580 var addEventListener$1 = addEventListener_1;
50581 var removeEventListener$1 = removeEventListener_1;
50582 var serializeNode = serialize;
50583
50584 var htmlns = "http://www.w3.org/1999/xhtml";
50585
50586 var domElement = DOMElement$2;
50587
50588 function DOMElement$2(tagName, owner, namespace) {
50589     if (!(this instanceof DOMElement$2)) {
50590         return new DOMElement$2(tagName)
50591     }
50592
50593     var ns = namespace === undefined ? htmlns : (namespace || null);
50594
50595     this.tagName = ns === htmlns ? String(tagName).toUpperCase() : tagName;
50596     this.nodeName = this.tagName;
50597     this.className = "";
50598     this.dataset = {};
50599     this.childNodes = [];
50600     this.parentNode = null;
50601     this.style = {};
50602     this.ownerDocument = owner || null;
50603     this.namespaceURI = ns;
50604     this._attributes = {};
50605
50606     if (this.tagName === 'INPUT') {
50607       this.type = 'text';
50608     }
50609 }
50610
50611 DOMElement$2.prototype.type = "DOMElement";
50612 DOMElement$2.prototype.nodeType = 1;
50613
50614 DOMElement$2.prototype.appendChild = function _Element_appendChild(child) {
50615     if (child.parentNode) {
50616         child.parentNode.removeChild(child);
50617     }
50618
50619     this.childNodes.push(child);
50620     child.parentNode = this;
50621
50622     return child
50623 };
50624
50625 DOMElement$2.prototype.replaceChild =
50626     function _Element_replaceChild(elem, needle) {
50627         // TODO: Throw NotFoundError if needle.parentNode !== this
50628
50629         if (elem.parentNode) {
50630             elem.parentNode.removeChild(elem);
50631         }
50632
50633         var index = this.childNodes.indexOf(needle);
50634
50635         needle.parentNode = null;
50636         this.childNodes[index] = elem;
50637         elem.parentNode = this;
50638
50639         return needle
50640     };
50641
50642 DOMElement$2.prototype.removeChild = function _Element_removeChild(elem) {
50643     // TODO: Throw NotFoundError if elem.parentNode !== this
50644
50645     var index = this.childNodes.indexOf(elem);
50646     this.childNodes.splice(index, 1);
50647
50648     elem.parentNode = null;
50649     return elem
50650 };
50651
50652 DOMElement$2.prototype.insertBefore =
50653     function _Element_insertBefore(elem, needle) {
50654         // TODO: Throw NotFoundError if referenceElement is a dom node
50655         // and parentNode !== this
50656
50657         if (elem.parentNode) {
50658             elem.parentNode.removeChild(elem);
50659         }
50660
50661         var index = needle === null || needle === undefined ?
50662             -1 :
50663             this.childNodes.indexOf(needle);
50664
50665         if (index > -1) {
50666             this.childNodes.splice(index, 0, elem);
50667         } else {
50668             this.childNodes.push(elem);
50669         }
50670
50671         elem.parentNode = this;
50672         return elem
50673     };
50674
50675 DOMElement$2.prototype.setAttributeNS =
50676     function _Element_setAttributeNS(namespace, name, value) {
50677         var prefix = null;
50678         var localName = name;
50679         var colonPosition = name.indexOf(":");
50680         if (colonPosition > -1) {
50681             prefix = name.substr(0, colonPosition);
50682             localName = name.substr(colonPosition + 1);
50683         }
50684         if (this.tagName === 'INPUT' && name === 'type') {
50685           this.type = value;
50686         }
50687         else {
50688           var attributes = this._attributes[namespace] || (this._attributes[namespace] = {});
50689           attributes[localName] = {value: value, prefix: prefix};
50690         }
50691     };
50692
50693 DOMElement$2.prototype.getAttributeNS =
50694     function _Element_getAttributeNS(namespace, name) {
50695         var attributes = this._attributes[namespace];
50696         var value = attributes && attributes[name] && attributes[name].value;
50697         if (this.tagName === 'INPUT' && name === 'type') {
50698           return this.type;
50699         }
50700         if (typeof value !== "string") {
50701             return null
50702         }
50703         return value
50704     };
50705
50706 DOMElement$2.prototype.removeAttributeNS =
50707     function _Element_removeAttributeNS(namespace, name) {
50708         var attributes = this._attributes[namespace];
50709         if (attributes) {
50710             delete attributes[name];
50711         }
50712     };
50713
50714 DOMElement$2.prototype.hasAttributeNS =
50715     function _Element_hasAttributeNS(namespace, name) {
50716         var attributes = this._attributes[namespace];
50717         return !!attributes && name in attributes;
50718     };
50719
50720 DOMElement$2.prototype.setAttribute = function _Element_setAttribute(name, value) {
50721     return this.setAttributeNS(null, name, value)
50722 };
50723
50724 DOMElement$2.prototype.getAttribute = function _Element_getAttribute(name) {
50725     return this.getAttributeNS(null, name)
50726 };
50727
50728 DOMElement$2.prototype.removeAttribute = function _Element_removeAttribute(name) {
50729     return this.removeAttributeNS(null, name)
50730 };
50731
50732 DOMElement$2.prototype.hasAttribute = function _Element_hasAttribute(name) {
50733     return this.hasAttributeNS(null, name)
50734 };
50735
50736 DOMElement$2.prototype.removeEventListener = removeEventListener$1;
50737 DOMElement$2.prototype.addEventListener = addEventListener$1;
50738 DOMElement$2.prototype.dispatchEvent = dispatchEvent$1;
50739
50740 // Un-implemented
50741 DOMElement$2.prototype.focus = function _Element_focus() {
50742     return void 0
50743 };
50744
50745 DOMElement$2.prototype.toString = function _Element_toString() {
50746     return serializeNode(this)
50747 };
50748
50749 DOMElement$2.prototype.getElementsByClassName = function _Element_getElementsByClassName(classNames) {
50750     var classes = classNames.split(" ");
50751     var elems = [];
50752
50753     domWalk$1(this, function (node) {
50754         if (node.nodeType === 1) {
50755             var nodeClassName = node.className || "";
50756             var nodeClasses = nodeClassName.split(" ");
50757
50758             if (classes.every(function (item) {
50759                 return nodeClasses.indexOf(item) !== -1
50760             })) {
50761                 elems.push(node);
50762             }
50763         }
50764     });
50765
50766     return elems
50767 };
50768
50769 DOMElement$2.prototype.getElementsByTagName = function _Element_getElementsByTagName(tagName) {
50770     tagName = tagName.toLowerCase();
50771     var elems = [];
50772
50773     domWalk$1(this.childNodes, function (node) {
50774         if (node.nodeType === 1 && (tagName === '*' || node.tagName.toLowerCase() === tagName)) {
50775             elems.push(node);
50776         }
50777     });
50778
50779     return elems
50780 };
50781
50782 DOMElement$2.prototype.contains = function _Element_contains(element) {
50783     return domWalk$1(this, function (node) {
50784         return element === node
50785     }) || false
50786 };
50787
50788 var DOMElement$1 = domElement;
50789
50790 var domFragment = DocumentFragment$1;
50791
50792 function DocumentFragment$1(owner) {
50793     if (!(this instanceof DocumentFragment$1)) {
50794         return new DocumentFragment$1()
50795     }
50796
50797     this.childNodes = [];
50798     this.parentNode = null;
50799     this.ownerDocument = owner || null;
50800 }
50801
50802 DocumentFragment$1.prototype.type = "DocumentFragment";
50803 DocumentFragment$1.prototype.nodeType = 11;
50804 DocumentFragment$1.prototype.nodeName = "#document-fragment";
50805
50806 DocumentFragment$1.prototype.appendChild  = DOMElement$1.prototype.appendChild;
50807 DocumentFragment$1.prototype.replaceChild = DOMElement$1.prototype.replaceChild;
50808 DocumentFragment$1.prototype.removeChild  = DOMElement$1.prototype.removeChild;
50809
50810 DocumentFragment$1.prototype.toString =
50811     function _DocumentFragment_toString() {
50812         return this.childNodes.map(function (node) {
50813             return String(node)
50814         }).join("")
50815     };
50816
50817 var event = Event$1;
50818
50819 function Event$1(family) {}
50820
50821 Event$1.prototype.initEvent = function _Event_initEvent(type, bubbles, cancelable) {
50822     this.type = type;
50823     this.bubbles = bubbles;
50824     this.cancelable = cancelable;
50825 };
50826
50827 Event$1.prototype.preventDefault = function _Event_preventDefault() {
50828     
50829 };
50830
50831 var domWalk = domWalk$2;
50832
50833 var Comment = domComment;
50834 var DOMText = domText;
50835 var DOMElement = domElement;
50836 var DocumentFragment = domFragment;
50837 var Event = event;
50838 var dispatchEvent = dispatchEvent_1;
50839 var addEventListener = addEventListener_1;
50840 var removeEventListener = removeEventListener_1;
50841
50842 var document$3 = Document$1;
50843
50844 function Document$1() {
50845     if (!(this instanceof Document$1)) {
50846         return new Document$1();
50847     }
50848
50849     this.head = this.createElement("head");
50850     this.body = this.createElement("body");
50851     this.documentElement = this.createElement("html");
50852     this.documentElement.appendChild(this.head);
50853     this.documentElement.appendChild(this.body);
50854     this.childNodes = [this.documentElement];
50855     this.nodeType = 9;
50856 }
50857
50858 var proto = Document$1.prototype;
50859 proto.createTextNode = function createTextNode(value) {
50860     return new DOMText(value, this)
50861 };
50862
50863 proto.createElementNS = function createElementNS(namespace, tagName) {
50864     var ns = namespace === null ? null : String(namespace);
50865     return new DOMElement(tagName, this, ns)
50866 };
50867
50868 proto.createElement = function createElement(tagName) {
50869     return new DOMElement(tagName, this)
50870 };
50871
50872 proto.createDocumentFragment = function createDocumentFragment() {
50873     return new DocumentFragment(this)
50874 };
50875
50876 proto.createEvent = function createEvent(family) {
50877     return new Event(family)
50878 };
50879
50880 proto.createComment = function createComment(data) {
50881     return new Comment(data, this)
50882 };
50883
50884 proto.getElementById = function getElementById(id) {
50885     id = String(id);
50886
50887     var result = domWalk(this.childNodes, function (node) {
50888         if (String(node.id) === id) {
50889             return node
50890         }
50891     });
50892
50893     return result || null
50894 };
50895
50896 proto.getElementsByClassName = DOMElement.prototype.getElementsByClassName;
50897 proto.getElementsByTagName = DOMElement.prototype.getElementsByTagName;
50898 proto.contains = DOMElement.prototype.contains;
50899
50900 proto.removeEventListener = removeEventListener;
50901 proto.addEventListener = addEventListener;
50902 proto.dispatchEvent = dispatchEvent;
50903
50904 var Document = document$3;
50905
50906 var minDocument = new Document();
50907
50908 var topLevel = typeof commonjsGlobal !== 'undefined' ? commonjsGlobal :
50909     typeof window !== 'undefined' ? window : {};
50910 var minDoc = minDocument;
50911
50912 var doccy;
50913
50914 if (typeof document !== 'undefined') {
50915     doccy = document;
50916 } else {
50917     doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'];
50918
50919     if (!doccy) {
50920         doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc;
50921     }
50922 }
50923
50924 var document_1 = doccy;
50925
50926 var isObject = isObject$2;
50927 var isHook$1 = isVhook;
50928
50929 var applyProperties_1 = applyProperties$2;
50930
50931 function applyProperties$2(node, props, previous) {
50932     for (var propName in props) {
50933         var propValue = props[propName];
50934
50935         if (propValue === undefined) {
50936             removeProperty(node, propName, propValue, previous);
50937         } else if (isHook$1(propValue)) {
50938             removeProperty(node, propName, propValue, previous);
50939             if (propValue.hook) {
50940                 propValue.hook(node,
50941                     propName,
50942                     previous ? previous[propName] : undefined);
50943             }
50944         } else {
50945             if (isObject(propValue)) {
50946                 patchObject(node, props, previous, propName, propValue);
50947             } else {
50948                 node[propName] = propValue;
50949             }
50950         }
50951     }
50952 }
50953
50954 function removeProperty(node, propName, propValue, previous) {
50955     if (previous) {
50956         var previousValue = previous[propName];
50957
50958         if (!isHook$1(previousValue)) {
50959             if (propName === "attributes") {
50960                 for (var attrName in previousValue) {
50961                     node.removeAttribute(attrName);
50962                 }
50963             } else if (propName === "style") {
50964                 for (var i in previousValue) {
50965                     node.style[i] = "";
50966                 }
50967             } else if (typeof previousValue === "string") {
50968                 node[propName] = "";
50969             } else {
50970                 node[propName] = null;
50971             }
50972         } else if (previousValue.unhook) {
50973             previousValue.unhook(node, propName, propValue);
50974         }
50975     }
50976 }
50977
50978 function patchObject(node, props, previous, propName, propValue) {
50979     var previousValue = previous ? previous[propName] : undefined;
50980
50981     // Set attributes
50982     if (propName === "attributes") {
50983         for (var attrName in propValue) {
50984             var attrValue = propValue[attrName];
50985
50986             if (attrValue === undefined) {
50987                 node.removeAttribute(attrName);
50988             } else {
50989                 node.setAttribute(attrName, attrValue);
50990             }
50991         }
50992
50993         return
50994     }
50995
50996     if(previousValue && isObject(previousValue) &&
50997         getPrototype(previousValue) !== getPrototype(propValue)) {
50998         node[propName] = propValue;
50999         return
51000     }
51001
51002     if (!isObject(node[propName])) {
51003         node[propName] = {};
51004     }
51005
51006     var replacer = propName === "style" ? "" : undefined;
51007
51008     for (var k in propValue) {
51009         var value = propValue[k];
51010         node[propName][k] = (value === undefined) ? replacer : value;
51011     }
51012 }
51013
51014 function getPrototype(value) {
51015     if (Object.getPrototypeOf) {
51016         return Object.getPrototypeOf(value)
51017     } else if (value.__proto__) {
51018         return value.__proto__
51019     } else if (value.constructor) {
51020         return value.constructor.prototype
51021     }
51022 }
51023
51024 var document$2 = document_1;
51025
51026 var applyProperties$1 = applyProperties_1;
51027
51028 var isVNode$2 = isVnode;
51029 var isVText$1 = isVtext;
51030 var isWidget$4 = isWidget_1;
51031 var handleThunk = handleThunk_1;
51032
51033 var createElement_1$1 = createElement$1;
51034
51035 function createElement$1(vnode, opts) {
51036     var doc = opts ? opts.document || document$2 : document$2;
51037     var warn = opts ? opts.warn : null;
51038
51039     vnode = handleThunk(vnode).a;
51040
51041     if (isWidget$4(vnode)) {
51042         return vnode.init()
51043     } else if (isVText$1(vnode)) {
51044         return doc.createTextNode(vnode.text)
51045     } else if (!isVNode$2(vnode)) {
51046         if (warn) {
51047             warn("Item is not a valid virtual dom node", vnode);
51048         }
51049         return null
51050     }
51051
51052     var node = (vnode.namespace === null) ?
51053         doc.createElement(vnode.tagName) :
51054         doc.createElementNS(vnode.namespace, vnode.tagName);
51055
51056     var props = vnode.properties;
51057     applyProperties$1(node, props);
51058
51059     var children = vnode.children;
51060
51061     for (var i = 0; i < children.length; i++) {
51062         var childNode = createElement$1(children[i], opts);
51063         if (childNode) {
51064             node.appendChild(childNode);
51065         }
51066     }
51067
51068     return node
51069 }
51070
51071 // Maps a virtual DOM tree onto a real DOM tree in an efficient manner.
51072 // We don't want to read all of the DOM nodes in the tree so we use
51073 // the in-order tree indexing to eliminate recursion down certain branches.
51074 // We only recurse into a DOM node if we know that it contains a child of
51075 // interest.
51076
51077 var noChild = {};
51078
51079 var domIndex_1 = domIndex$1;
51080
51081 function domIndex$1(rootNode, tree, indices, nodes) {
51082     if (!indices || indices.length === 0) {
51083         return {}
51084     } else {
51085         indices.sort(ascending);
51086         return recurse(rootNode, tree, indices, nodes, 0)
51087     }
51088 }
51089
51090 function recurse(rootNode, tree, indices, nodes, rootIndex) {
51091     nodes = nodes || {};
51092
51093
51094     if (rootNode) {
51095         if (indexInRange(indices, rootIndex, rootIndex)) {
51096             nodes[rootIndex] = rootNode;
51097         }
51098
51099         var vChildren = tree.children;
51100
51101         if (vChildren) {
51102
51103             var childNodes = rootNode.childNodes;
51104
51105             for (var i = 0; i < tree.children.length; i++) {
51106                 rootIndex += 1;
51107
51108                 var vChild = vChildren[i] || noChild;
51109                 var nextIndex = rootIndex + (vChild.count || 0);
51110
51111                 // skip recursion down the tree if there are no nodes down here
51112                 if (indexInRange(indices, rootIndex, nextIndex)) {
51113                     recurse(childNodes[i], vChild, indices, nodes, rootIndex);
51114                 }
51115
51116                 rootIndex = nextIndex;
51117             }
51118         }
51119     }
51120
51121     return nodes
51122 }
51123
51124 // Binary search for an index in the interval [left, right]
51125 function indexInRange(indices, left, right) {
51126     if (indices.length === 0) {
51127         return false
51128     }
51129
51130     var minIndex = 0;
51131     var maxIndex = indices.length - 1;
51132     var currentIndex;
51133     var currentItem;
51134
51135     while (minIndex <= maxIndex) {
51136         currentIndex = ((maxIndex + minIndex) / 2) >> 0;
51137         currentItem = indices[currentIndex];
51138
51139         if (minIndex === maxIndex) {
51140             return currentItem >= left && currentItem <= right
51141         } else if (currentItem < left) {
51142             minIndex = currentIndex + 1;
51143         } else  if (currentItem > right) {
51144             maxIndex = currentIndex - 1;
51145         } else {
51146             return true
51147         }
51148     }
51149
51150     return false;
51151 }
51152
51153 function ascending(a, b) {
51154     return a > b ? 1 : -1
51155 }
51156
51157 var isWidget$3 = isWidget_1;
51158
51159 var updateWidget_1 = updateWidget$1;
51160
51161 function updateWidget$1(a, b) {
51162     if (isWidget$3(a) && isWidget$3(b)) {
51163         if ("name" in a && "name" in b) {
51164             return a.id === b.id
51165         } else {
51166             return a.init === b.init
51167         }
51168     }
51169
51170     return false
51171 }
51172
51173 var applyProperties = applyProperties_1;
51174
51175 var isWidget$2 = isWidget_1;
51176 var VPatch = vpatch;
51177
51178 var updateWidget = updateWidget_1;
51179
51180 var patchOp$1 = applyPatch$1;
51181
51182 function applyPatch$1(vpatch, domNode, renderOptions) {
51183     var type = vpatch.type;
51184     var vNode = vpatch.vNode;
51185     var patch = vpatch.patch;
51186
51187     switch (type) {
51188         case VPatch.REMOVE:
51189             return removeNode$1(domNode, vNode)
51190         case VPatch.INSERT:
51191             return insertNode$1(domNode, patch, renderOptions)
51192         case VPatch.VTEXT:
51193             return stringPatch(domNode, vNode, patch, renderOptions)
51194         case VPatch.WIDGET:
51195             return widgetPatch(domNode, vNode, patch, renderOptions)
51196         case VPatch.VNODE:
51197             return vNodePatch(domNode, vNode, patch, renderOptions)
51198         case VPatch.ORDER:
51199             reorderChildren(domNode, patch);
51200             return domNode
51201         case VPatch.PROPS:
51202             applyProperties(domNode, patch, vNode.properties);
51203             return domNode
51204         case VPatch.THUNK:
51205             return replaceRoot(domNode,
51206                 renderOptions.patch(domNode, patch, renderOptions))
51207         default:
51208             return domNode
51209     }
51210 }
51211
51212 function removeNode$1(domNode, vNode) {
51213     var parentNode = domNode.parentNode;
51214
51215     if (parentNode) {
51216         parentNode.removeChild(domNode);
51217     }
51218
51219     destroyWidget(domNode, vNode);
51220
51221     return null
51222 }
51223
51224 function insertNode$1(parentNode, vNode, renderOptions) {
51225     var newNode = renderOptions.render(vNode, renderOptions);
51226
51227     if (parentNode) {
51228         parentNode.appendChild(newNode);
51229     }
51230
51231     return parentNode
51232 }
51233
51234 function stringPatch(domNode, leftVNode, vText, renderOptions) {
51235     var newNode;
51236
51237     if (domNode.nodeType === 3) {
51238         domNode.replaceData(0, domNode.length, vText.text);
51239         newNode = domNode;
51240     } else {
51241         var parentNode = domNode.parentNode;
51242         newNode = renderOptions.render(vText, renderOptions);
51243
51244         if (parentNode && newNode !== domNode) {
51245             parentNode.replaceChild(newNode, domNode);
51246         }
51247     }
51248
51249     return newNode
51250 }
51251
51252 function widgetPatch(domNode, leftVNode, widget, renderOptions) {
51253     var updating = updateWidget(leftVNode, widget);
51254     var newNode;
51255
51256     if (updating) {
51257         newNode = widget.update(leftVNode, domNode) || domNode;
51258     } else {
51259         newNode = renderOptions.render(widget, renderOptions);
51260     }
51261
51262     var parentNode = domNode.parentNode;
51263
51264     if (parentNode && newNode !== domNode) {
51265         parentNode.replaceChild(newNode, domNode);
51266     }
51267
51268     if (!updating) {
51269         destroyWidget(domNode, leftVNode);
51270     }
51271
51272     return newNode
51273 }
51274
51275 function vNodePatch(domNode, leftVNode, vNode, renderOptions) {
51276     var parentNode = domNode.parentNode;
51277     var newNode = renderOptions.render(vNode, renderOptions);
51278
51279     if (parentNode && newNode !== domNode) {
51280         parentNode.replaceChild(newNode, domNode);
51281     }
51282
51283     return newNode
51284 }
51285
51286 function destroyWidget(domNode, w) {
51287     if (typeof w.destroy === "function" && isWidget$2(w)) {
51288         w.destroy(domNode);
51289     }
51290 }
51291
51292 function reorderChildren(domNode, moves) {
51293     var childNodes = domNode.childNodes;
51294     var keyMap = {};
51295     var node;
51296     var remove;
51297     var insert;
51298
51299     for (var i = 0; i < moves.removes.length; i++) {
51300         remove = moves.removes[i];
51301         node = childNodes[remove.from];
51302         if (remove.key) {
51303             keyMap[remove.key] = node;
51304         }
51305         domNode.removeChild(node);
51306     }
51307
51308     var length = childNodes.length;
51309     for (var j = 0; j < moves.inserts.length; j++) {
51310         insert = moves.inserts[j];
51311         node = keyMap[insert.key];
51312         // this is the weirdest bug i've ever seen in webkit
51313         domNode.insertBefore(node, insert.to >= length++ ? null : childNodes[insert.to]);
51314     }
51315 }
51316
51317 function replaceRoot(oldRoot, newRoot) {
51318     if (oldRoot && newRoot && oldRoot !== newRoot && oldRoot.parentNode) {
51319         oldRoot.parentNode.replaceChild(newRoot, oldRoot);
51320     }
51321
51322     return newRoot;
51323 }
51324
51325 var document$1 = document_1;
51326 var isArray$1 = xIsArray;
51327
51328 var render = createElement_1$1;
51329 var domIndex = domIndex_1;
51330 var patchOp = patchOp$1;
51331 var patch_1$1 = patch$2;
51332
51333 function patch$2(rootNode, patches, renderOptions) {
51334     renderOptions = renderOptions || {};
51335     renderOptions.patch = renderOptions.patch && renderOptions.patch !== patch$2
51336         ? renderOptions.patch
51337         : patchRecursive;
51338     renderOptions.render = renderOptions.render || render;
51339
51340     return renderOptions.patch(rootNode, patches, renderOptions)
51341 }
51342
51343 function patchRecursive(rootNode, patches, renderOptions) {
51344     var indices = patchIndices(patches);
51345
51346     if (indices.length === 0) {
51347         return rootNode
51348     }
51349
51350     var index = domIndex(rootNode, patches.a, indices);
51351     var ownerDocument = rootNode.ownerDocument;
51352
51353     if (!renderOptions.document && ownerDocument !== document$1) {
51354         renderOptions.document = ownerDocument;
51355     }
51356
51357     for (var i = 0; i < indices.length; i++) {
51358         var nodeIndex = indices[i];
51359         rootNode = applyPatch(rootNode,
51360             index[nodeIndex],
51361             patches[nodeIndex],
51362             renderOptions);
51363     }
51364
51365     return rootNode
51366 }
51367
51368 function applyPatch(rootNode, domNode, patchList, renderOptions) {
51369     if (!domNode) {
51370         return rootNode
51371     }
51372
51373     var newNode;
51374
51375     if (isArray$1(patchList)) {
51376         for (var i = 0; i < patchList.length; i++) {
51377             newNode = patchOp(patchList[i], domNode, renderOptions);
51378
51379             if (domNode === rootNode) {
51380                 rootNode = newNode;
51381             }
51382         }
51383     } else {
51384         newNode = patchOp(patchList, domNode, renderOptions);
51385
51386         if (domNode === rootNode) {
51387             rootNode = newNode;
51388         }
51389     }
51390
51391     return rootNode
51392 }
51393
51394 function patchIndices(patches) {
51395     var indices = [];
51396
51397     for (var key in patches) {
51398         if (key !== "a") {
51399             indices.push(Number(key));
51400         }
51401     }
51402
51403     return indices
51404 }
51405
51406 var patch$1 = patch_1$1;
51407
51408 var patch_1 = patch$1;
51409
51410 var version$1 = version$5;
51411 var isVNode$1 = isVnode;
51412 var isWidget$1 = isWidget_1;
51413 var isThunk = isThunk_1;
51414 var isVHook = isVhook;
51415
51416 var vnode = VirtualNode;
51417
51418 var noProperties = {};
51419 var noChildren = [];
51420
51421 function VirtualNode(tagName, properties, children, key, namespace) {
51422     this.tagName = tagName;
51423     this.properties = properties || noProperties;
51424     this.children = children || noChildren;
51425     this.key = key != null ? String(key) : undefined;
51426     this.namespace = (typeof namespace === "string") ? namespace : null;
51427
51428     var count = (children && children.length) || 0;
51429     var descendants = 0;
51430     var hasWidgets = false;
51431     var hasThunks = false;
51432     var descendantHooks = false;
51433     var hooks;
51434
51435     for (var propName in properties) {
51436         if (properties.hasOwnProperty(propName)) {
51437             var property = properties[propName];
51438             if (isVHook(property) && property.unhook) {
51439                 if (!hooks) {
51440                     hooks = {};
51441                 }
51442
51443                 hooks[propName] = property;
51444             }
51445         }
51446     }
51447
51448     for (var i = 0; i < count; i++) {
51449         var child = children[i];
51450         if (isVNode$1(child)) {
51451             descendants += child.count || 0;
51452
51453             if (!hasWidgets && child.hasWidgets) {
51454                 hasWidgets = true;
51455             }
51456
51457             if (!hasThunks && child.hasThunks) {
51458                 hasThunks = true;
51459             }
51460
51461             if (!descendantHooks && (child.hooks || child.descendantHooks)) {
51462                 descendantHooks = true;
51463             }
51464         } else if (!hasWidgets && isWidget$1(child)) {
51465             if (typeof child.destroy === "function") {
51466                 hasWidgets = true;
51467             }
51468         } else if (!hasThunks && isThunk(child)) {
51469             hasThunks = true;
51470         }
51471     }
51472
51473     this.count = count + descendants;
51474     this.hasWidgets = hasWidgets;
51475     this.hasThunks = hasThunks;
51476     this.hooks = hooks;
51477     this.descendantHooks = descendantHooks;
51478 }
51479
51480 VirtualNode.prototype.version = version$1;
51481 VirtualNode.prototype.type = "VirtualNode";
51482
51483 var version = version$5;
51484
51485 var vtext = VirtualText;
51486
51487 function VirtualText(text) {
51488     this.text = String(text);
51489 }
51490
51491 VirtualText.prototype.version = version;
51492 VirtualText.prototype.type = "VirtualText";
51493
51494 /*!
51495  * Cross-Browser Split 1.1.1
51496  * Copyright 2007-2012 Steven Levithan <stevenlevithan.com>
51497  * Available under the MIT License
51498  * ECMAScript compliant, uniform cross-browser split method
51499  */
51500
51501 /**
51502  * Splits a string into an array of strings using a regex or string separator. Matches of the
51503  * separator are not included in the result array. However, if `separator` is a regex that contains
51504  * capturing groups, backreferences are spliced into the result each time `separator` is matched.
51505  * Fixes browser bugs compared to the native `String.prototype.split` and can be used reliably
51506  * cross-browser.
51507  * @param {String} str String to split.
51508  * @param {RegExp|String} separator Regex or string to use for separating the string.
51509  * @param {Number} [limit] Maximum number of items to include in the result array.
51510  * @returns {Array} Array of substrings.
51511  * @example
51512  *
51513  * // Basic use
51514  * split('a b c d', ' ');
51515  * // -> ['a', 'b', 'c', 'd']
51516  *
51517  * // With limit
51518  * split('a b c d', ' ', 2);
51519  * // -> ['a', 'b']
51520  *
51521  * // Backreferences in result array
51522  * split('..word1 word2..', /([a-z]+)(\d+)/i);
51523  * // -> ['..', 'word', '1', ' ', 'word', '2', '..']
51524  */
51525 var browserSplit = (function split(undef) {
51526
51527   var nativeSplit = String.prototype.split,
51528     compliantExecNpcg = /()??/.exec("")[1] === undef,
51529     // NPCG: nonparticipating capturing group
51530     self;
51531
51532   self = function(str, separator, limit) {
51533     // If `separator` is not a regex, use `nativeSplit`
51534     if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
51535       return nativeSplit.call(str, separator, limit);
51536     }
51537     var output = [],
51538       flags = (separator.ignoreCase ? "i" : "") + (separator.multiline ? "m" : "") + (separator.extended ? "x" : "") + // Proposed for ES6
51539       (separator.sticky ? "y" : ""),
51540       // Firefox 3+
51541       lastLastIndex = 0,
51542       // Make `global` and avoid `lastIndex` issues by working with a copy
51543       separator = new RegExp(separator.source, flags + "g"),
51544       separator2, match, lastIndex, lastLength;
51545     str += ""; // Type-convert
51546     if (!compliantExecNpcg) {
51547       // Doesn't need flags gy, but they don't hurt
51548       separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
51549     }
51550     /* Values for `limit`, per the spec:
51551      * If undefined: 4294967295 // Math.pow(2, 32) - 1
51552      * If 0, Infinity, or NaN: 0
51553      * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
51554      * If negative number: 4294967296 - Math.floor(Math.abs(limit))
51555      * If other: Type-convert, then use the above rules
51556      */
51557     limit = limit === undef ? -1 >>> 0 : // Math.pow(2, 32) - 1
51558     limit >>> 0; // ToUint32(limit)
51559     while (match = separator.exec(str)) {
51560       // `separator.lastIndex` is not reliable cross-browser
51561       lastIndex = match.index + match[0].length;
51562       if (lastIndex > lastLastIndex) {
51563         output.push(str.slice(lastLastIndex, match.index));
51564         // Fix browsers whose `exec` methods don't consistently return `undefined` for
51565         // nonparticipating capturing groups
51566         if (!compliantExecNpcg && match.length > 1) {
51567           match[0].replace(separator2, function() {
51568             for (var i = 1; i < arguments.length - 2; i++) {
51569               if (arguments[i] === undef) {
51570                 match[i] = undef;
51571               }
51572             }
51573           });
51574         }
51575         if (match.length > 1 && match.index < str.length) {
51576           Array.prototype.push.apply(output, match.slice(1));
51577         }
51578         lastLength = match[0].length;
51579         lastLastIndex = lastIndex;
51580         if (output.length >= limit) {
51581           break;
51582         }
51583       }
51584       if (separator.lastIndex === match.index) {
51585         separator.lastIndex++; // Avoid an infinite loop
51586       }
51587     }
51588     if (lastLastIndex === str.length) {
51589       if (lastLength || !separator.test("")) {
51590         output.push("");
51591       }
51592     } else {
51593       output.push(str.slice(lastLastIndex));
51594     }
51595     return output.length > limit ? output.slice(0, limit) : output;
51596   };
51597
51598   return self;
51599 })();
51600
51601 var split = browserSplit;
51602
51603 var classIdSplit = /([\.#]?[a-zA-Z0-9\u007F-\uFFFF_:-]+)/;
51604 var notClassId = /^\.|#/;
51605
51606 var parseTag_1 = parseTag$1;
51607
51608 function parseTag$1(tag, props) {
51609     if (!tag) {
51610         return 'DIV';
51611     }
51612
51613     var noId = !(props.hasOwnProperty('id'));
51614
51615     var tagParts = split(tag, classIdSplit);
51616     var tagName = null;
51617
51618     if (notClassId.test(tagParts[1])) {
51619         tagName = 'DIV';
51620     }
51621
51622     var classes, part, type, i;
51623
51624     for (i = 0; i < tagParts.length; i++) {
51625         part = tagParts[i];
51626
51627         if (!part) {
51628             continue;
51629         }
51630
51631         type = part.charAt(0);
51632
51633         if (!tagName) {
51634             tagName = part;
51635         } else if (type === '.') {
51636             classes = classes || [];
51637             classes.push(part.substring(1, part.length));
51638         } else if (type === '#' && noId) {
51639             props.id = part.substring(1, part.length);
51640         }
51641     }
51642
51643     if (classes) {
51644         if (props.className) {
51645             classes.push(props.className);
51646         }
51647
51648         props.className = classes.join(' ');
51649     }
51650
51651     return props.namespace ? tagName : tagName.toUpperCase();
51652 }
51653
51654 var softSetHook$1 = SoftSetHook;
51655
51656 function SoftSetHook(value) {
51657     if (!(this instanceof SoftSetHook)) {
51658         return new SoftSetHook(value);
51659     }
51660
51661     this.value = value;
51662 }
51663
51664 SoftSetHook.prototype.hook = function (node, propertyName) {
51665     if (node[propertyName] !== this.value) {
51666         node[propertyName] = this.value;
51667     }
51668 };
51669
51670 /*global window, global*/
51671
51672 var root = typeof window !== 'undefined' ?
51673     window : typeof commonjsGlobal !== 'undefined' ?
51674     commonjsGlobal : {};
51675
51676 var individual = Individual$1;
51677
51678 function Individual$1(key, value) {
51679     if (key in root) {
51680         return root[key];
51681     }
51682
51683     root[key] = value;
51684
51685     return value;
51686 }
51687
51688 var Individual = individual;
51689
51690 var oneVersion = OneVersion;
51691
51692 function OneVersion(moduleName, version, defaultValue) {
51693     var key = '__INDIVIDUAL_ONE_VERSION_' + moduleName;
51694     var enforceKey = key + '_ENFORCE_SINGLETON';
51695
51696     var versionValue = Individual(enforceKey, version);
51697
51698     if (versionValue !== version) {
51699         throw new Error('Can only have one copy of ' +
51700             moduleName + '.\n' +
51701             'You already have version ' + versionValue +
51702             ' installed.\n' +
51703             'This means you cannot install version ' + version);
51704     }
51705
51706     return Individual(key, defaultValue);
51707 }
51708
51709 var OneVersionConstraint = oneVersion;
51710
51711 var MY_VERSION = '7';
51712 OneVersionConstraint('ev-store', MY_VERSION);
51713
51714 var hashKey = '__EV_STORE_KEY@' + MY_VERSION;
51715
51716 var evStore = EvStore$1;
51717
51718 function EvStore$1(elem) {
51719     var hash = elem[hashKey];
51720
51721     if (!hash) {
51722         hash = elem[hashKey] = {};
51723     }
51724
51725     return hash;
51726 }
51727
51728 var EvStore = evStore;
51729
51730 var evHook$1 = EvHook;
51731
51732 function EvHook(value) {
51733     if (!(this instanceof EvHook)) {
51734         return new EvHook(value);
51735     }
51736
51737     this.value = value;
51738 }
51739
51740 EvHook.prototype.hook = function (node, propertyName) {
51741     var es = EvStore(node);
51742     var propName = propertyName.substr(3);
51743
51744     es[propName] = this.value;
51745 };
51746
51747 EvHook.prototype.unhook = function(node, propertyName) {
51748     var es = EvStore(node);
51749     var propName = propertyName.substr(3);
51750
51751     es[propName] = undefined;
51752 };
51753
51754 var isArray = xIsArray;
51755
51756 var VNode$1 = vnode;
51757 var VText$1 = vtext;
51758 var isVNode = isVnode;
51759 var isVText = isVtext;
51760 var isWidget = isWidget_1;
51761 var isHook = isVhook;
51762 var isVThunk = isThunk_1;
51763
51764 var parseTag = parseTag_1;
51765 var softSetHook = softSetHook$1;
51766 var evHook = evHook$1;
51767
51768 var virtualHyperscript = h$2;
51769
51770 function h$2(tagName, properties, children) {
51771     var childNodes = [];
51772     var tag, props, key, namespace;
51773
51774     if (!children && isChildren(properties)) {
51775         children = properties;
51776         props = {};
51777     }
51778
51779     props = props || properties || {};
51780     tag = parseTag(tagName, props);
51781
51782     // support keys
51783     if (props.hasOwnProperty('key')) {
51784         key = props.key;
51785         props.key = undefined;
51786     }
51787
51788     // support namespace
51789     if (props.hasOwnProperty('namespace')) {
51790         namespace = props.namespace;
51791         props.namespace = undefined;
51792     }
51793
51794     // fix cursor bug
51795     if (tag === 'INPUT' &&
51796         !namespace &&
51797         props.hasOwnProperty('value') &&
51798         props.value !== undefined &&
51799         !isHook(props.value)
51800     ) {
51801         props.value = softSetHook(props.value);
51802     }
51803
51804     transformProperties(props);
51805
51806     if (children !== undefined && children !== null) {
51807         addChild(children, childNodes, tag, props);
51808     }
51809
51810
51811     return new VNode$1(tag, props, childNodes, key, namespace);
51812 }
51813
51814 function addChild(c, childNodes, tag, props) {
51815     if (typeof c === 'string') {
51816         childNodes.push(new VText$1(c));
51817     } else if (typeof c === 'number') {
51818         childNodes.push(new VText$1(String(c)));
51819     } else if (isChild(c)) {
51820         childNodes.push(c);
51821     } else if (isArray(c)) {
51822         for (var i = 0; i < c.length; i++) {
51823             addChild(c[i], childNodes, tag, props);
51824         }
51825     } else if (c === null || c === undefined) {
51826         return;
51827     } else {
51828         throw UnexpectedVirtualElement({
51829             foreignObject: c,
51830             parentVnode: {
51831                 tagName: tag,
51832                 properties: props
51833             }
51834         });
51835     }
51836 }
51837
51838 function transformProperties(props) {
51839     for (var propName in props) {
51840         if (props.hasOwnProperty(propName)) {
51841             var value = props[propName];
51842
51843             if (isHook(value)) {
51844                 continue;
51845             }
51846
51847             if (propName.substr(0, 3) === 'ev-') {
51848                 // add ev-foo support
51849                 props[propName] = evHook(value);
51850             }
51851         }
51852     }
51853 }
51854
51855 function isChild(x) {
51856     return isVNode(x) || isVText(x) || isWidget(x) || isVThunk(x);
51857 }
51858
51859 function isChildren(x) {
51860     return typeof x === 'string' || isArray(x) || isChild(x);
51861 }
51862
51863 function UnexpectedVirtualElement(data) {
51864     var err = new Error();
51865
51866     err.type = 'virtual-hyperscript.unexpected.virtual-element';
51867     err.message = 'Unexpected virtual child passed to h().\n' +
51868         'Expected a VNode / Vthunk / VWidget / string but:\n' +
51869         'got:\n' +
51870         errorString(data.foreignObject) +
51871         '.\n' +
51872         'The parent vnode is:\n' +
51873         errorString(data.parentVnode);
51874     err.foreignObject = data.foreignObject;
51875     err.parentVnode = data.parentVnode;
51876
51877     return err;
51878 }
51879
51880 function errorString(obj) {
51881     try {
51882         return JSON.stringify(obj, null, '    ');
51883     } catch (e) {
51884         return String(obj);
51885     }
51886 }
51887
51888 var h$1 = virtualHyperscript;
51889
51890 var h_1 = h$1;
51891
51892 var createElement = createElement_1$1;
51893
51894 var createElement_1 = createElement;
51895
51896 var diff = diff_1;
51897 var patch = patch_1;
51898 var h = h_1;
51899 var create = createElement_1;
51900 var VNode = vnode;
51901 var VText = vtext;
51902
51903 var virtualDom = {
51904     diff: diff,
51905     patch: patch,
51906     h: h,
51907     create: create,
51908     VNode: VNode,
51909     VText: VText
51910 };
51911
51912 class EventEmitter {
51913     constructor() { this._events = {}; }
51914     /**
51915      * @ignore
51916      */
51917     fire(type, event) {
51918         if (!this._listens(type)) {
51919             return;
51920         }
51921         for (const handler of this._events[type]) {
51922             handler(event);
51923         }
51924     }
51925     /**
51926      * Unsubscribe from an event by its name.
51927      * @param {string} type - The name of the event
51928      * to unsubscribe from.
51929      * @param {(event: T) => void} handler - The
51930      * handler to remove.
51931      */
51932     off(type, handler) {
51933         if (!type) {
51934             this._events = {};
51935             return;
51936         }
51937         if (this._listens(type)) {
51938             const index = this._events[type].indexOf(handler);
51939             if (index >= 0) {
51940                 this._events[type].splice(index, 1);
51941             }
51942             if (!this._events[type].length) {
51943                 delete this._events[type];
51944             }
51945         }
51946     }
51947     /**
51948      * Subscribe to an event by its name.
51949      * @param {string} type - The name of the event
51950      * to subscribe to.
51951      * @param {(event: T) => void} handler - The
51952      * handler called when the event occurs.
51953      */
51954     on(type, handler) {
51955         this._events[type] = this._events[type] || [];
51956         this._events[type].push(handler);
51957     }
51958     _listens(eventType) {
51959         return eventType in this._events;
51960     }
51961 }
51962
51963 class SubscriptionHolder {
51964     constructor() {
51965         this._subscriptions = [];
51966     }
51967     push(subscription) {
51968         this._subscriptions.push(subscription);
51969     }
51970     unsubscribe() {
51971         for (const sub of this._subscriptions) {
51972             sub.unsubscribe();
51973         }
51974         this._subscriptions = [];
51975     }
51976 }
51977
51978 class Component extends EventEmitter {
51979     constructor(name, container, navigator) {
51980         super();
51981         this._activated$ = new BehaviorSubject(false);
51982         this._configurationSubject$ = new Subject();
51983         this._activated = false;
51984         this._container = container;
51985         this._name = name;
51986         this._navigator = navigator;
51987         this._subscriptions = new SubscriptionHolder();
51988         this._configuration$ =
51989             this._configurationSubject$.pipe(startWith(this.defaultConfiguration), scan((conf, newConf) => {
51990                 for (let key in newConf) {
51991                     if (newConf.hasOwnProperty(key)) {
51992                         conf[key] = newConf[key];
51993                     }
51994                 }
51995                 return conf;
51996             }), publishReplay(1), refCount());
51997         this._configuration$.subscribe(() => { });
51998     }
51999     /**
52000      * Get activated.
52001      *
52002      * @returns {boolean} Value indicating if the component is
52003      * currently active.
52004      */
52005     get activated() {
52006         return this._activated;
52007     }
52008     /** @ignore */
52009     get activated$() {
52010         return this._activated$;
52011     }
52012     /**
52013      * Get default configuration.
52014      *
52015      * @returns {TConfiguration} Default configuration for component.
52016      */
52017     get defaultConfiguration() {
52018         return this._getDefaultConfiguration();
52019     }
52020     /** @ignore */
52021     get configuration$() {
52022         return this._configuration$;
52023     }
52024     /**
52025      * Get name.
52026      *
52027      * @description The name of the component. Used when interacting with the
52028      * component through the Viewer's API.
52029      */
52030     get name() {
52031         return this._name;
52032     }
52033     /** @ignore */
52034     activate(conf) {
52035         if (this._activated) {
52036             return;
52037         }
52038         if (conf !== undefined) {
52039             this._configurationSubject$.next(conf);
52040         }
52041         this._activated = true;
52042         this._activate();
52043         this._activated$.next(true);
52044     }
52045     /**
52046      * Configure the component.
52047      *
52048      * @param configuration Component configuration.
52049      */
52050     configure(configuration) {
52051         this._configurationSubject$.next(configuration);
52052     }
52053     /** @ignore */
52054     deactivate() {
52055         if (!this._activated) {
52056             return;
52057         }
52058         this._activated = false;
52059         this._deactivate();
52060         this._container.domRenderer.clear(this._name);
52061         this._container.glRenderer.clear(this._name);
52062         this._activated$.next(false);
52063     }
52064     /** @inheritdoc */
52065     fire(type, event) {
52066         super.fire(type, event);
52067     }
52068     /** @inheritdoc */
52069     off(type, handler) {
52070         super.off(type, handler);
52071     }
52072     /** @inheritdoc */
52073     on(type, handler) {
52074         super.on(type, handler);
52075     }
52076     /**
52077      * Detect the viewer's new width and height and resize the component's
52078      * rendered elements accordingly if applicable.
52079      *
52080      * @ignore
52081      */
52082     resize() { return; }
52083 }
52084
52085 var CoverState;
52086 (function (CoverState) {
52087     CoverState[CoverState["Hidden"] = 0] = "Hidden";
52088     CoverState[CoverState["Loading"] = 1] = "Loading";
52089     CoverState[CoverState["Visible"] = 2] = "Visible";
52090 })(CoverState || (CoverState = {}));
52091
52092 class CoverComponent extends Component {
52093     constructor(name, container, navigator) {
52094         super(name, container, navigator);
52095     }
52096     _activate() {
52097         const originalSrc$ = this.configuration$.pipe(first((c) => {
52098             return !!c.id;
52099         }), filter((c) => {
52100             return !c.src;
52101         }), switchMap((c) => {
52102             return this._getImageSrc$(c.id).pipe(catchError((error) => {
52103                 console.error(error);
52104                 return empty();
52105             }));
52106         }), publishReplay(1), refCount());
52107         const subs = this._subscriptions;
52108         subs.push(originalSrc$.pipe(map((src) => {
52109             return { src: src };
52110         }))
52111             .subscribe((c) => {
52112             this._configurationSubject$.next(c);
52113         }));
52114         subs.push(combineLatest(this.configuration$, originalSrc$).pipe(filter(([c, src]) => {
52115             return !!c.src && c.src !== src;
52116         }), first())
52117             .subscribe(([, src]) => {
52118             window.URL.revokeObjectURL(src);
52119         }));
52120         subs.push(this._configuration$.pipe(distinctUntilChanged(undefined, (configuration) => {
52121             return configuration.state;
52122         }), switchMap((configuration) => {
52123             return combineLatest(of(configuration.state), this._navigator.stateService.currentImage$);
52124         }), switchMap(([state, image]) => {
52125             const keySrc$ = combineLatest(of(image.id), image.image$.pipe(filter((imageElement) => {
52126                 return !!imageElement;
52127             }), map((imageElement) => {
52128                 return imageElement.src;
52129             })));
52130             return state === CoverState.Visible ? keySrc$.pipe(first()) : keySrc$;
52131         }), distinctUntilChanged(([k1, s1], [k2, s2]) => {
52132             return k1 === k2 && s1 === s2;
52133         }), map(([key, src]) => {
52134             return { id: key, src: src };
52135         }))
52136             .subscribe(this._configurationSubject$));
52137         subs.push(combineLatest(this._configuration$, this._container.configurationService.exploreUrl$, this._container.renderService.size$).pipe(map(([configuration, exploreUrl, size]) => {
52138             if (!configuration.src) {
52139                 return { name: this._name, vNode: virtualDom.h("div", []) };
52140             }
52141             const compactClass = size.width <= 640 || size.height <= 480 ? ".mapillary-cover-compact" : "";
52142             if (configuration.state === CoverState.Hidden) {
52143                 const doneContainer = virtualDom.h("div.mapillary-cover-container.mapillary-cover-done" + compactClass, [this._getCoverBackgroundVNode(configuration)]);
52144                 return { name: this._name, vNode: doneContainer };
52145             }
52146             const container = virtualDom.h("div.mapillary-cover-container" + compactClass, [this._getCoverButtonVNode(configuration, exploreUrl)]);
52147             return { name: this._name, vNode: container };
52148         }))
52149             .subscribe(this._container.domRenderer.render$));
52150     }
52151     _deactivate() {
52152         this._subscriptions.unsubscribe();
52153     }
52154     _getDefaultConfiguration() {
52155         return { state: CoverState.Visible };
52156     }
52157     _getCoverButtonVNode(configuration, exploreUrl) {
52158         const cover = configuration.state === CoverState.Loading ? "div.mapillary-cover.mapillary-cover-loading" : "div.mapillary-cover";
52159         const coverButton = virtualDom.h("div.mapillary-cover-button", [virtualDom.h("div.mapillary-cover-button-icon", [])]);
52160         const coverLogo = virtualDom.h("a.mapillary-cover-logo", { href: exploreUrl, target: "_blank" }, []);
52161         const coverIndicator = virtualDom.h("div.mapillary-cover-indicator", { onclick: () => { this.configure({ state: CoverState.Loading }); } }, []);
52162         return virtualDom.h(cover, [
52163             this._getCoverBackgroundVNode(configuration),
52164             coverIndicator,
52165             coverButton,
52166             coverLogo,
52167         ]);
52168     }
52169     _getCoverBackgroundVNode(conf) {
52170         const properties = {
52171             style: { backgroundImage: `url(${conf.src})` },
52172         };
52173         const children = [];
52174         if (conf.state === CoverState.Loading) {
52175             children.push(virtualDom.h("div.mapillary-cover-spinner", {}, []));
52176         }
52177         return virtualDom.h("div.mapillary-cover-background", properties, children);
52178     }
52179     _getImageSrc$(id) {
52180         return Observable.create((subscriber) => {
52181             this._navigator.api.getImages$([id])
52182                 .subscribe((items) => {
52183                 for (const item of items) {
52184                     const imageId = typeof id === "number" ?
52185                         id.toString() : id;
52186                     if (item.node_id !== imageId) {
52187                         continue;
52188                     }
52189                     this._navigator.api.data
52190                         .getImageBuffer(item.node.thumb.url)
52191                         .then((buffer) => {
52192                         const image = new Image();
52193                         image.crossOrigin = "Anonymous";
52194                         image.onload = () => {
52195                             subscriber.next(image.src);
52196                             subscriber.complete();
52197                         };
52198                         image.onerror = () => {
52199                             subscriber.error(new Error(`Failed to load cover ` +
52200                                 `image (${id})`));
52201                         };
52202                         const blob = new Blob([buffer]);
52203                         image.src = window.URL
52204                             .createObjectURL(blob);
52205                     }, (error) => {
52206                         subscriber.error(error);
52207                     });
52208                     return;
52209                 }
52210                 subscriber.error(new MapillaryError(`Non existent cover key: ${id}`));
52211             }, (error) => {
52212                 subscriber.error(error);
52213             });
52214         });
52215     }
52216 }
52217 CoverComponent.componentName = "cover";
52218
52219 class AttributionComponent extends Component {
52220     _activate() {
52221         this._subscriptions.push(combineLatest(this._container.configurationService.exploreUrl$, this._navigator.stateService.currentImage$, this._container.renderService.size$).pipe(map(([exploreUrl, image, size]) => {
52222             const attribution = this._makeAttribution(image.creatorUsername, exploreUrl, image.id, image.capturedAt, size.width);
52223             return {
52224                 name: this._name,
52225                 vNode: attribution,
52226             };
52227         }))
52228             .subscribe(this._container.domRenderer.render$));
52229     }
52230     _deactivate() {
52231         this._subscriptions.unsubscribe();
52232     }
52233     _getDefaultConfiguration() {
52234         return {};
52235     }
52236     makeImageUrl(exploreUrl, id) {
52237         return `${exploreUrl}/app/?pKey=${id}&focus=photo`;
52238     }
52239     _makeAttribution(creatorUsername, exploreUrl, imageId, capturedAt, viewportWidth) {
52240         const compact = viewportWidth <= 640;
52241         const date = this._makeDate(capturedAt, compact);
52242         const by = this._makeBy(creatorUsername, exploreUrl, imageId, compact);
52243         const compactClass = compact ?
52244             ".mapillary-attribution-compact" : "";
52245         return virtualDom.h("div.mapillary-attribution-container" + compactClass, {}, [...by, date]);
52246     }
52247     _makeBy(creatorUsername, exploreUrl, imageId, compact) {
52248         const icon = virtualDom.h("div.mapillary-attribution-logo", []);
52249         return creatorUsername ?
52250             this._makeCreatorBy(icon, creatorUsername, exploreUrl, imageId, compact) :
52251             this._makeGeneralBy(icon, exploreUrl, imageId, compact);
52252     }
52253     _makeCreatorBy(icon, creatorUsername, exploreUrl, imageId, compact) {
52254         const mapillary = virtualDom.h("a.mapillary-attribution-icon-container", { href: exploreUrl, rel: "noreferrer", target: "_blank" }, [icon]);
52255         const content = compact ?
52256             `${creatorUsername}` : `image by ${creatorUsername}`;
52257         const imageBy = virtualDom.h("div.mapillary-attribution-username", { textContent: content }, []);
52258         const image = virtualDom.h("a.mapillary-attribution-image-container", {
52259             href: this.makeImageUrl(exploreUrl, imageId),
52260             rel: "noreferrer",
52261             target: "_blank",
52262         }, [imageBy]);
52263         return [mapillary, image];
52264     }
52265     _makeGeneralBy(icon, exploreUrl, imageId, compact) {
52266         const imagesBy = virtualDom.h("div.mapillary-attribution-username", { textContent: 'images by' }, []);
52267         const mapillary = virtualDom.h("div.mapillary-attribution-icon-container", {}, [icon]);
52268         const contributors = virtualDom.h("div.mapillary-attribution-username", { textContent: 'contributors' }, []);
52269         const children = [mapillary, contributors];
52270         if (!compact) {
52271             children.unshift(imagesBy);
52272         }
52273         const image = virtualDom.h("a.mapillary-attribution-image-container", {
52274             href: this.makeImageUrl(exploreUrl, imageId),
52275             rel: "noreferrer",
52276             target: "_blank",
52277         }, children);
52278         return [image];
52279     }
52280     _makeDate(capturedAt, compact) {
52281         const date = new Date(capturedAt)
52282             .toDateString()
52283             .split(" ");
52284         const formatted = (date.length > 3 ?
52285             compact ?
52286                 [date[3]] :
52287                 [date[1], date[2] + ",", date[3]] :
52288             date).join(" ");
52289         return virtualDom.h("div.mapillary-attribution-date", { textContent: formatted }, []);
52290     }
52291 }
52292 AttributionComponent.componentName = "attribution";
52293
52294 /**
52295  * @class ViewportCoords
52296  *
52297  * @classdesc Provides methods for calculating 2D coordinate conversions
52298  * as well as 3D projection and unprojection.
52299  *
52300  * Basic coordinates are 2D coordinates on the [0, 1] interval and
52301  * have the origin point, (0, 0), at the top left corner and the
52302  * maximum value, (1, 1), at the bottom right corner of the original
52303  * image.
52304  *
52305  * Viewport coordinates are 2D coordinates on the [-1, 1] interval and
52306  * have the origin point in the center. The bottom left corner point is
52307  * (-1, -1) and the top right corner point is (1, 1).
52308  *
52309  * Canvas coordiantes are 2D pixel coordinates on the [0, canvasWidth] and
52310  * [0, canvasHeight] intervals. The origin point (0, 0) is in the top left
52311  * corner and the maximum value is (canvasWidth, canvasHeight) is in the
52312  * bottom right corner.
52313  *
52314  * 3D coordinates are in the topocentric world reference frame.
52315  */
52316 class ViewportCoords {
52317     constructor() {
52318         this._unprojectDepth = 200;
52319     }
52320     /**
52321      * Convert basic coordinates to canvas coordinates.
52322      *
52323      * @description Transform origin and camera position needs to be the
52324      * equal for reliable return value.
52325      *
52326      * @param {number} basicX - Basic X coordinate.
52327      * @param {number} basicY - Basic Y coordinate.
52328      * @param {HTMLElement} container - The viewer container.
52329      * @param {Transform} transform - Transform of the image to unproject from.
52330      * @param {THREE.Camera} camera - Camera used in rendering.
52331      * @returns {Array<number>} 2D canvas coordinates.
52332      */
52333     basicToCanvas(basicX, basicY, container, transform, camera) {
52334         const point3d = transform.unprojectBasic([basicX, basicY], this._unprojectDepth);
52335         const canvas = this.projectToCanvas(point3d, container, camera);
52336         return canvas;
52337     }
52338     /**
52339      * Convert basic coordinates to canvas coordinates safely. If 3D point is
52340      * behind camera null will be returned.
52341      *
52342      * @description Transform origin and camera position needs to be the
52343      * equal for reliable return value.
52344      *
52345      * @param {number} basicX - Basic X coordinate.
52346      * @param {number} basicY - Basic Y coordinate.
52347      * @param {HTMLElement} container - The viewer container.
52348      * @param {Transform} transform - Transform of the image to unproject from.
52349      * @param {THREE.Camera} camera - Camera used in rendering.
52350      * @returns {Array<number>} 2D canvas coordinates if the basic point represents a 3D point
52351      * in front of the camera, otherwise null.
52352      */
52353     basicToCanvasSafe(basicX, basicY, container, transform, camera) {
52354         const viewport = this.basicToViewportSafe(basicX, basicY, transform, camera);
52355         if (viewport === null) {
52356             return null;
52357         }
52358         const canvas = this.viewportToCanvas(viewport[0], viewport[1], container);
52359         return canvas;
52360     }
52361     /**
52362      * Convert basic coordinates to viewport coordinates.
52363      *
52364      * @description Transform origin and camera position needs to be the
52365      * equal for reliable return value.
52366      *
52367      * @param {number} basicX - Basic X coordinate.
52368      * @param {number} basicY - Basic Y coordinate.
52369      * @param {Transform} transform - Transform of the image to unproject from.
52370      * @param {THREE.Camera} camera - Camera used in rendering.
52371      * @returns {Array<number>} 2D viewport coordinates.
52372      */
52373     basicToViewport(basicX, basicY, transform, camera) {
52374         const point3d = transform.unprojectBasic([basicX, basicY], this._unprojectDepth);
52375         const viewport = this.projectToViewport(point3d, camera);
52376         return viewport;
52377     }
52378     /**
52379      * Convert basic coordinates to viewport coordinates safely. If 3D point is
52380      * behind camera null will be returned.
52381      *
52382      * @description Transform origin and camera position needs to be the
52383      * equal for reliable return value.
52384      *
52385      * @param {number} basicX - Basic X coordinate.
52386      * @param {number} basicY - Basic Y coordinate.
52387      * @param {Transform} transform - Transform of the image to unproject from.
52388      * @param {THREE.Camera} camera - Camera used in rendering.
52389      * @returns {Array<number>} 2D viewport coordinates.
52390      */
52391     basicToViewportSafe(basicX, basicY, transform, camera) {
52392         const point3d = transform.unprojectBasic([basicX, basicY], this._unprojectDepth);
52393         const pointCamera = this.worldToCamera(point3d, camera);
52394         if (pointCamera[2] > 0) {
52395             return null;
52396         }
52397         const viewport = this.projectToViewport(point3d, camera);
52398         return viewport;
52399     }
52400     /**
52401      * Convert camera 3D coordinates to viewport coordinates.
52402      *
52403      * @param {number} pointCamera - 3D point in camera coordinate system.
52404      * @param {THREE.Camera} camera - Camera used in rendering.
52405      * @returns {Array<number>} 2D viewport coordinates.
52406      */
52407     cameraToViewport(pointCamera, camera) {
52408         const viewport = new Vector3().fromArray(pointCamera)
52409             .applyMatrix4(camera.projectionMatrix);
52410         return [viewport.x, viewport.y];
52411     }
52412     /**
52413      * Get canvas pixel position from event.
52414      *
52415      * @param {Event} event - Event containing clientX and clientY properties.
52416      * @param {HTMLElement} element - HTML element.
52417      * @returns {Array<number>} 2D canvas coordinates.
52418      */
52419     canvasPosition(event, element) {
52420         const clientRect = element.getBoundingClientRect();
52421         const canvasX = event.clientX - clientRect.left - element.clientLeft;
52422         const canvasY = event.clientY - clientRect.top - element.clientTop;
52423         return [canvasX, canvasY];
52424     }
52425     /**
52426      * Convert canvas coordinates to basic coordinates.
52427      *
52428      * @description Transform origin and camera position needs to be the
52429      * equal for reliable return value.
52430      *
52431      * @param {number} canvasX - Canvas X coordinate.
52432      * @param {number} canvasY - Canvas Y coordinate.
52433      * @param {HTMLElement} container - The viewer container.
52434      * @param {Transform} transform - Transform of the image to unproject from.
52435      * @param {THREE.Camera} camera - Camera used in rendering.
52436      * @returns {Array<number>} 2D basic coordinates.
52437      */
52438     canvasToBasic(canvasX, canvasY, container, transform, camera) {
52439         const point3d = this.unprojectFromCanvas(canvasX, canvasY, container, camera)
52440             .toArray();
52441         const basic = transform.projectBasic(point3d);
52442         return basic;
52443     }
52444     /**
52445      * Convert canvas coordinates to viewport coordinates.
52446      *
52447      * @param {number} canvasX - Canvas X coordinate.
52448      * @param {number} canvasY - Canvas Y coordinate.
52449      * @param {HTMLElement} container - The viewer container.
52450      * @returns {Array<number>} 2D viewport coordinates.
52451      */
52452     canvasToViewport(canvasX, canvasY, container) {
52453         const [canvasWidth, canvasHeight] = this.containerToCanvas(container);
52454         const viewportX = 2 * canvasX / canvasWidth - 1;
52455         const viewportY = 1 - 2 * canvasY / canvasHeight;
52456         return [viewportX, viewportY];
52457     }
52458     /**
52459      * Determines the width and height of the container in canvas coordinates.
52460      *
52461      * @param {HTMLElement} container - The viewer container.
52462      * @returns {Array<number>} 2D canvas coordinates.
52463      */
52464     containerToCanvas(container) {
52465         return [container.offsetWidth, container.offsetHeight];
52466     }
52467     /**
52468      * Determine basic distances from image to canvas corners.
52469      *
52470      * @description Transform origin and camera position needs to be the
52471      * equal for reliable return value.
52472      *
52473      * Determines the smallest basic distance for every side of the canvas.
52474      *
52475      * @param {Transform} transform - Transform of the image to unproject from.
52476      * @param {THREE.Camera} camera - Camera used in rendering.
52477      * @returns {Array<number>} Array of basic distances as [top, right, bottom, left].
52478      */
52479     getBasicDistances(transform, camera) {
52480         const topLeftBasic = this.viewportToBasic(-1, 1, transform, camera);
52481         const topRightBasic = this.viewportToBasic(1, 1, transform, camera);
52482         const bottomRightBasic = this.viewportToBasic(1, -1, transform, camera);
52483         const bottomLeftBasic = this.viewportToBasic(-1, -1, transform, camera);
52484         let topBasicDistance = 0;
52485         let rightBasicDistance = 0;
52486         let bottomBasicDistance = 0;
52487         let leftBasicDistance = 0;
52488         if (topLeftBasic[1] < 0 && topRightBasic[1] < 0) {
52489             topBasicDistance = topLeftBasic[1] > topRightBasic[1] ?
52490                 -topLeftBasic[1] :
52491                 -topRightBasic[1];
52492         }
52493         if (topRightBasic[0] > 1 && bottomRightBasic[0] > 1) {
52494             rightBasicDistance = topRightBasic[0] < bottomRightBasic[0] ?
52495                 topRightBasic[0] - 1 :
52496                 bottomRightBasic[0] - 1;
52497         }
52498         if (bottomRightBasic[1] > 1 && bottomLeftBasic[1] > 1) {
52499             bottomBasicDistance = bottomRightBasic[1] < bottomLeftBasic[1] ?
52500                 bottomRightBasic[1] - 1 :
52501                 bottomLeftBasic[1] - 1;
52502         }
52503         if (bottomLeftBasic[0] < 0 && topLeftBasic[0] < 0) {
52504             leftBasicDistance = bottomLeftBasic[0] > topLeftBasic[0] ?
52505                 -bottomLeftBasic[0] :
52506                 -topLeftBasic[0];
52507         }
52508         return [topBasicDistance, rightBasicDistance, bottomBasicDistance, leftBasicDistance];
52509     }
52510     /**
52511      * Determine pixel distances from image to canvas corners.
52512      *
52513      * @description Transform origin and camera position needs to be the
52514      * equal for reliable return value.
52515      *
52516      * Determines the smallest pixel distance for every side of the canvas.
52517      *
52518      * @param {HTMLElement} container - The viewer container.
52519      * @param {Transform} transform - Transform of the image to unproject from.
52520      * @param {THREE.Camera} camera - Camera used in rendering.
52521      * @returns {Array<number>} Array of pixel distances as [top, right, bottom, left].
52522      */
52523     getPixelDistances(container, transform, camera) {
52524         const topLeftBasic = this.viewportToBasic(-1, 1, transform, camera);
52525         const topRightBasic = this.viewportToBasic(1, 1, transform, camera);
52526         const bottomRightBasic = this.viewportToBasic(1, -1, transform, camera);
52527         const bottomLeftBasic = this.viewportToBasic(-1, -1, transform, camera);
52528         let topPixelDistance = 0;
52529         let rightPixelDistance = 0;
52530         let bottomPixelDistance = 0;
52531         let leftPixelDistance = 0;
52532         const [canvasWidth, canvasHeight] = this.containerToCanvas(container);
52533         if (topLeftBasic[1] < 0 && topRightBasic[1] < 0) {
52534             const basicX = topLeftBasic[1] > topRightBasic[1] ?
52535                 topLeftBasic[0] :
52536                 topRightBasic[0];
52537             const canvas = this.basicToCanvas(basicX, 0, container, transform, camera);
52538             topPixelDistance = canvas[1] > 0 ? canvas[1] : 0;
52539         }
52540         if (topRightBasic[0] > 1 && bottomRightBasic[0] > 1) {
52541             const basicY = topRightBasic[0] < bottomRightBasic[0] ?
52542                 topRightBasic[1] :
52543                 bottomRightBasic[1];
52544             const canvas = this.basicToCanvas(1, basicY, container, transform, camera);
52545             rightPixelDistance = canvas[0] < canvasWidth ? canvasWidth - canvas[0] : 0;
52546         }
52547         if (bottomRightBasic[1] > 1 && bottomLeftBasic[1] > 1) {
52548             const basicX = bottomRightBasic[1] < bottomLeftBasic[1] ?
52549                 bottomRightBasic[0] :
52550                 bottomLeftBasic[0];
52551             const canvas = this.basicToCanvas(basicX, 1, container, transform, camera);
52552             bottomPixelDistance = canvas[1] < canvasHeight ? canvasHeight - canvas[1] : 0;
52553         }
52554         if (bottomLeftBasic[0] < 0 && topLeftBasic[0] < 0) {
52555             const basicY = bottomLeftBasic[0] > topLeftBasic[0] ?
52556                 bottomLeftBasic[1] :
52557                 topLeftBasic[1];
52558             const canvas = this.basicToCanvas(0, basicY, container, transform, camera);
52559             leftPixelDistance = canvas[0] > 0 ? canvas[0] : 0;
52560         }
52561         return [topPixelDistance, rightPixelDistance, bottomPixelDistance, leftPixelDistance];
52562     }
52563     /**
52564      * Determine if an event occured inside an element.
52565      *
52566      * @param {Event} event - Event containing clientX and clientY properties.
52567      * @param {HTMLElement} element - HTML element.
52568      * @returns {boolean} Value indicating if the event occured inside the element or not.
52569      */
52570     insideElement(event, element) {
52571         const clientRect = element.getBoundingClientRect();
52572         const minX = clientRect.left + element.clientLeft;
52573         const maxX = minX + element.clientWidth;
52574         const minY = clientRect.top + element.clientTop;
52575         const maxY = minY + element.clientHeight;
52576         return event.clientX > minX &&
52577             event.clientX < maxX &&
52578             event.clientY > minY &&
52579             event.clientY < maxY;
52580     }
52581     /**
52582      * Project 3D world coordinates to canvas coordinates.
52583      *
52584      * @param {Array<number>} point3D - 3D world coordinates.
52585      * @param {HTMLElement} container - The viewer container.
52586      * @param {THREE.Camera} camera - Camera used in rendering.
52587      * @returns {Array<number>} 2D canvas coordinates.
52588      */
52589     projectToCanvas(point3d, container, camera) {
52590         const viewport = this.projectToViewport(point3d, camera);
52591         const canvas = this.viewportToCanvas(viewport[0], viewport[1], container);
52592         return canvas;
52593     }
52594     /**
52595      * Project 3D world coordinates to canvas coordinates safely. If 3D
52596      * point is behind camera null will be returned.
52597      *
52598      * @param {Array<number>} point3D - 3D world coordinates.
52599      * @param {HTMLElement} container - The viewer container.
52600      * @param {THREE.Camera} camera - Camera used in rendering.
52601      * @returns {Array<number>} 2D canvas coordinates.
52602      */
52603     projectToCanvasSafe(point3d, container, camera) {
52604         const pointCamera = this.worldToCamera(point3d, camera);
52605         if (pointCamera[2] > 0) {
52606             return null;
52607         }
52608         const viewport = this.projectToViewport(point3d, camera);
52609         const canvas = this.viewportToCanvas(viewport[0], viewport[1], container);
52610         return canvas;
52611     }
52612     /**
52613      * Project 3D world coordinates to viewport coordinates.
52614      *
52615      * @param {Array<number>} point3D - 3D world coordinates.
52616      * @param {THREE.Camera} camera - Camera used in rendering.
52617      * @returns {Array<number>} 2D viewport coordinates.
52618      */
52619     projectToViewport(point3d, camera) {
52620         const viewport = new Vector3(point3d[0], point3d[1], point3d[2])
52621             .project(camera);
52622         return [viewport.x, viewport.y];
52623     }
52624     /**
52625      * Uproject canvas coordinates to 3D world coordinates.
52626      *
52627      * @param {number} canvasX - Canvas X coordinate.
52628      * @param {number} canvasY - Canvas Y coordinate.
52629      * @param {HTMLElement} container - The viewer container.
52630      * @param {THREE.Camera} camera - Camera used in rendering.
52631      * @returns {Array<number>} 3D world coordinates.
52632      */
52633     unprojectFromCanvas(canvasX, canvasY, container, camera) {
52634         const viewport = this.canvasToViewport(canvasX, canvasY, container);
52635         const point3d = this.unprojectFromViewport(viewport[0], viewport[1], camera);
52636         return point3d;
52637     }
52638     /**
52639      * Unproject viewport coordinates to 3D world coordinates.
52640      *
52641      * @param {number} viewportX - Viewport X coordinate.
52642      * @param {number} viewportY - Viewport Y coordinate.
52643      * @param {THREE.Camera} camera - Camera used in rendering.
52644      * @returns {Array<number>} 3D world coordinates.
52645      */
52646     unprojectFromViewport(viewportX, viewportY, camera) {
52647         const point3d = new Vector3(viewportX, viewportY, 1)
52648             .unproject(camera);
52649         return point3d;
52650     }
52651     /**
52652      * Convert viewport coordinates to basic coordinates.
52653      *
52654      * @description Transform origin and camera position needs to be the
52655      * equal for reliable return value.
52656      *
52657      * @param {number} viewportX - Viewport X coordinate.
52658      * @param {number} viewportY - Viewport Y coordinate.
52659      * @param {Transform} transform - Transform of the image to unproject from.
52660      * @param {THREE.Camera} camera - Camera used in rendering.
52661      * @returns {Array<number>} 2D basic coordinates.
52662      */
52663     viewportToBasic(viewportX, viewportY, transform, camera) {
52664         const point3d = new Vector3(viewportX, viewportY, 1)
52665             .unproject(camera)
52666             .toArray();
52667         const basic = transform.projectBasic(point3d);
52668         return basic;
52669     }
52670     /**
52671      * Convert viewport coordinates to canvas coordinates.
52672      *
52673      * @param {number} viewportX - Viewport X coordinate.
52674      * @param {number} viewportY - Viewport Y coordinate.
52675      * @param {HTMLElement} container - The viewer container.
52676      * @returns {Array<number>} 2D canvas coordinates.
52677      */
52678     viewportToCanvas(viewportX, viewportY, container) {
52679         const [canvasWidth, canvasHeight] = this.containerToCanvas(container);
52680         const canvasX = canvasWidth * (viewportX + 1) / 2;
52681         const canvasY = -canvasHeight * (viewportY - 1) / 2;
52682         return [canvasX, canvasY];
52683     }
52684     /**
52685      * Convert 3D world coordinates to 3D camera coordinates.
52686      *
52687      * @param {number} point3D - 3D point in world coordinate system.
52688      * @param {THREE.Camera} camera - Camera used in rendering.
52689      * @returns {Array<number>} 3D camera coordinates.
52690      */
52691     worldToCamera(point3d, camera) {
52692         const pointCamera = new Vector3(point3d[0], point3d[1], point3d[2])
52693             .applyMatrix4(camera.matrixWorldInverse);
52694         return pointCamera.toArray();
52695     }
52696 }
52697
52698 /**
52699  * Enumeration for component size.
52700  * @enum {number}
52701  * @readonly
52702  * @description May be used by a component to allow for resizing
52703  * of the UI elements rendered by the component.
52704  */
52705 var ComponentSize;
52706 (function (ComponentSize) {
52707     /**
52708      * Automatic size. The size of the elements will automatically
52709      * change at a predefined threshold.
52710      */
52711     ComponentSize[ComponentSize["Automatic"] = 0] = "Automatic";
52712     /**
52713      * Large size. The size of the elements will be fixed until another
52714      * component size is configured.
52715      */
52716     ComponentSize[ComponentSize["Large"] = 1] = "Large";
52717     /**
52718      * Small size. The size of the elements will be fixed until another
52719      * component size is configured.
52720      */
52721     ComponentSize[ComponentSize["Small"] = 2] = "Small";
52722 })(ComponentSize || (ComponentSize = {}));
52723
52724 /**
52725  * @class BearingComponent
52726  *
52727  * @classdesc Component for indicating bearing and field of view.
52728  *
52729  * @example
52730  * ```js
52731  * var viewer = new Viewer({ ... });
52732  * var bearingComponent = viewer.getComponent("bearing");
52733  * bearingComponent.configure({ size: ComponentSize.Small });
52734  * ```
52735  */
52736 class BearingComponent extends Component {
52737     /** @ignore */
52738     constructor(name, container, navigator) {
52739         super(name, container, navigator);
52740         this._spatial = new Spatial();
52741         this._viewportCoords = new ViewportCoords();
52742         this._svgNamespace = "http://www.w3.org/2000/svg";
52743         this._distinctThreshold = Math.PI / 360;
52744         this._animationSpeed = 0.075;
52745     }
52746     _activate() {
52747         const subs = this._subscriptions;
52748         const cameraBearingFov$ = this._container.renderService.renderCamera$.pipe(map((rc) => {
52749             let vFov = this._spatial.degToRad(rc.perspective.fov);
52750             let hFov = rc.perspective.aspect === Number.POSITIVE_INFINITY ?
52751                 Math.PI :
52752                 Math.atan(rc.perspective.aspect * Math.tan(0.5 * vFov)) * 2;
52753             return [this._spatial.azimuthalToBearing(rc.rotation.phi), hFov];
52754         }), distinctUntilChanged((a1, a2) => {
52755             return Math.abs(a2[0] - a1[0]) < this._distinctThreshold &&
52756                 Math.abs(a2[1] - a1[1]) < this._distinctThreshold;
52757         }));
52758         const imageFov$ = combineLatest(this._navigator.stateService.currentState$.pipe(distinctUntilChanged(undefined, (frame) => {
52759             return frame.state.currentImage.id;
52760         })), this._navigator.panService.panImages$).pipe(map(([frame, panImages]) => {
52761             const image = frame.state.currentImage;
52762             const transform = frame.state.currentTransform;
52763             if (isSpherical(image.cameraType)) {
52764                 return [Math.PI, Math.PI];
52765             }
52766             const currentProjectedPoints = this._computeProjectedPoints(transform);
52767             const hFov = this._spatial
52768                 .degToRad(this._computeHorizontalFov(currentProjectedPoints));
52769             let hFovLeft = hFov / 2;
52770             let hFovRight = hFov / 2;
52771             for (const [n, , f] of panImages) {
52772                 const diff = this._spatial.wrap(n.compassAngle - image.compassAngle, -180, 180);
52773                 if (diff < 0) {
52774                     hFovLeft = this._spatial.degToRad(Math.abs(diff)) + f / 2;
52775                 }
52776                 else {
52777                     hFovRight = this._spatial.degToRad(Math.abs(diff)) + f / 2;
52778                 }
52779             }
52780             return [hFovLeft, hFovRight];
52781         }), distinctUntilChanged(([hFovLeft1, hFovRight1], [hFovLeft2, hFovRight2]) => {
52782             return Math.abs(hFovLeft2 - hFovLeft1) < this._distinctThreshold &&
52783                 Math.abs(hFovRight2 - hFovRight1) < this._distinctThreshold;
52784         }));
52785         const offset$ = combineLatest(this._navigator.stateService.currentState$.pipe(distinctUntilChanged(undefined, (frame) => {
52786             return frame.state.currentImage.id;
52787         })), this._container.renderService.bearing$).pipe(map(([frame, bearing]) => {
52788             const offset = this._spatial.degToRad(frame.state.currentImage.compassAngle - bearing);
52789             return offset;
52790         }));
52791         const imageFovOperation$ = new Subject();
52792         const smoothImageFov$ = imageFovOperation$.pipe(scan((state, operation) => {
52793             return operation(state);
52794         }, { alpha: 0, curr: [0, 0, 0], prev: [0, 0, 0] }), map((state) => {
52795             const alpha = MathUtils.smootherstep(state.alpha, 0, 1);
52796             const curr = state.curr;
52797             const prev = state.prev;
52798             return [
52799                 this._interpolate(prev[0], curr[0], alpha),
52800                 this._interpolate(prev[1], curr[1], alpha),
52801             ];
52802         }));
52803         subs.push(imageFov$.pipe(map((nbf) => {
52804             return (state) => {
52805                 const a = MathUtils.smootherstep(state.alpha, 0, 1);
52806                 const c = state.curr;
52807                 const p = state.prev;
52808                 const prev = [
52809                     this._interpolate(p[0], c[0], a),
52810                     this._interpolate(p[1], c[1], a),
52811                 ];
52812                 const curr = nbf.slice();
52813                 return {
52814                     alpha: 0,
52815                     curr: curr,
52816                     prev: prev,
52817                 };
52818             };
52819         }))
52820             .subscribe(imageFovOperation$));
52821         subs.push(imageFov$.pipe(switchMap(() => {
52822             return this._container.renderService.renderCameraFrame$.pipe(skip(1), scan((alpha) => {
52823                 return alpha + this._animationSpeed;
52824             }, 0), takeWhile((alpha) => {
52825                 return alpha <= 1 + this._animationSpeed;
52826             }), map((alpha) => {
52827                 return Math.min(alpha, 1);
52828             }));
52829         }), map((alpha) => {
52830             return (nbfState) => {
52831                 return {
52832                     alpha: alpha,
52833                     curr: nbfState.curr.slice(),
52834                     prev: nbfState.prev.slice(),
52835                 };
52836             };
52837         }))
52838             .subscribe(imageFovOperation$));
52839         const imageBearingFov$ = combineLatest(offset$, smoothImageFov$).pipe(map(([offset, fov]) => {
52840             return [offset, fov[0], fov[1]];
52841         }));
52842         subs.push(combineLatest(cameraBearingFov$, imageBearingFov$, this._configuration$, this._container.renderService.size$).pipe(map(([[cb, cf], [no, nfl, nfr], configuration, size]) => {
52843             const background = this._createBackground(cb);
52844             const fovIndicator = this._createFovIndicator(nfl, nfr, no);
52845             const north = this._createNorth(cb);
52846             const cameraSector = this._createCircleSectorCompass(this._createCircleSector(Math.max(Math.PI / 20, cf), "#FFF"));
52847             const compact = configuration.size === ComponentSize.Small ||
52848                 configuration.size === ComponentSize.Automatic && size.width < 640 ?
52849                 ".mapillary-bearing-compact" : "";
52850             return {
52851                 name: this._name,
52852                 vNode: virtualDom.h("div.mapillary-bearing-indicator-container" + compact, { oncontextmenu: (event) => { event.preventDefault(); } }, [
52853                     background,
52854                     fovIndicator,
52855                     north,
52856                     cameraSector,
52857                 ]),
52858             };
52859         }))
52860             .subscribe(this._container.domRenderer.render$));
52861     }
52862     _deactivate() {
52863         this._subscriptions.unsubscribe();
52864     }
52865     _getDefaultConfiguration() {
52866         return { size: ComponentSize.Automatic };
52867     }
52868     _createFovIndicator(fovLeft, fovRigth, offset) {
52869         const arc = this._createFovArc(fovLeft, fovRigth);
52870         const group = virtualDom.h("g", {
52871             attributes: { transform: "translate(18,18)" },
52872             namespace: this._svgNamespace,
52873         }, [arc]);
52874         const svg = virtualDom.h("svg", {
52875             attributes: { viewBox: "0 0 36 36" },
52876             namespace: this._svgNamespace,
52877             style: {
52878                 height: "36px",
52879                 left: "2px",
52880                 position: "absolute",
52881                 top: "2px",
52882                 transform: `rotateZ(${this._spatial.radToDeg(offset)}deg)`,
52883                 width: "36px",
52884             },
52885         }, [group]);
52886         return svg;
52887     }
52888     _createFovArc(fovLeft, fovRigth) {
52889         const radius = 16.75;
52890         const strokeWidth = 2.5;
52891         const fov = fovLeft + fovRigth;
52892         if (fov > 2 * Math.PI - Math.PI / 90) {
52893             return virtualDom.h("circle", {
52894                 attributes: {
52895                     cx: "0",
52896                     cy: "0",
52897                     "fill-opacity": "0",
52898                     r: `${radius}`,
52899                     stroke: "#FFF",
52900                     "stroke-width": `${strokeWidth}`,
52901                 },
52902                 namespace: this._svgNamespace,
52903             }, []);
52904         }
52905         let arcStart = -Math.PI / 2 - fovLeft;
52906         let arcEnd = arcStart + fov;
52907         let startX = radius * Math.cos(arcStart);
52908         let startY = radius * Math.sin(arcStart);
52909         let endX = radius * Math.cos(arcEnd);
52910         let endY = radius * Math.sin(arcEnd);
52911         let largeArc = fov >= Math.PI ? 1 : 0;
52912         let description = `M ${startX} ${startY} A ${radius} ${radius} 0 ${largeArc} 1 ${endX} ${endY}`;
52913         return virtualDom.h("path", {
52914             attributes: {
52915                 d: description,
52916                 "fill-opacity": "0",
52917                 stroke: "#FFF",
52918                 "stroke-width": `${strokeWidth}`,
52919             },
52920             namespace: this._svgNamespace,
52921         }, []);
52922     }
52923     _createCircleSectorCompass(cameraSector) {
52924         let group = virtualDom.h("g", {
52925             attributes: { transform: "translate(1,1)" },
52926             namespace: this._svgNamespace,
52927         }, [cameraSector]);
52928         let svg = virtualDom.h("svg", {
52929             attributes: { viewBox: "0 0 2 2" },
52930             namespace: this._svgNamespace,
52931             style: {
52932                 height: "26px",
52933                 left: "7px",
52934                 position: "absolute",
52935                 top: "7px",
52936                 width: "26px",
52937             },
52938         }, [group]);
52939         return svg;
52940     }
52941     _createCircleSector(fov, fill) {
52942         if (fov > 2 * Math.PI - Math.PI / 90) {
52943             return virtualDom.h("circle", {
52944                 attributes: { cx: "0", cy: "0", fill: fill, r: "1" },
52945                 namespace: this._svgNamespace,
52946             }, []);
52947         }
52948         let arcStart = -Math.PI / 2 - fov / 2;
52949         let arcEnd = arcStart + fov;
52950         let startX = Math.cos(arcStart);
52951         let startY = Math.sin(arcStart);
52952         let endX = Math.cos(arcEnd);
52953         let endY = Math.sin(arcEnd);
52954         let largeArc = fov >= Math.PI ? 1 : 0;
52955         let description = `M 0 0 ${startX} ${startY} A 1 1 0 ${largeArc} 1 ${endX} ${endY}`;
52956         return virtualDom.h("path", {
52957             attributes: { d: description, fill: fill },
52958             namespace: this._svgNamespace,
52959         }, []);
52960     }
52961     _createNorth(bearing) {
52962         const north = virtualDom.h("div.mapillary-bearing-north", []);
52963         const container = virtualDom.h("div.mapillary-bearing-north-container", { style: { transform: `rotateZ(${this._spatial.radToDeg(-bearing)}deg)` } }, [north]);
52964         return container;
52965     }
52966     _createBackground(bearing) {
52967         return virtualDom.h("div.mapillary-bearing-indicator-background", { style: { transform: `rotateZ(${this._spatial.radToDeg(-bearing)}deg)` } }, [
52968             virtualDom.h("div.mapillary-bearing-indicator-background-circle", []),
52969             virtualDom.h("div.mapillary-bearing-indicator-background-arrow-container", [
52970                 virtualDom.h("div.mapillary-bearing-indicator-background-arrow", []),
52971             ]),
52972         ]);
52973     }
52974     _computeProjectedPoints(transform) {
52975         const vertices = [[1, 0]];
52976         const directions = [[0, 0.5]];
52977         const pointsPerLine = 12;
52978         return computeProjectedPoints(transform, vertices, directions, pointsPerLine, this._viewportCoords);
52979     }
52980     _computeHorizontalFov(projectedPoints) {
52981         const fovs = projectedPoints
52982             .map((projectedPoint) => {
52983             return this._coordToFov(projectedPoint[0]);
52984         });
52985         const fov = Math.min(...fovs);
52986         return fov;
52987     }
52988     _coordToFov(x) {
52989         return this._spatial.radToDeg(2 * Math.atan(x));
52990     }
52991     _interpolate(x1, x2, alpha) {
52992         return (1 - alpha) * x1 + alpha * x2;
52993     }
52994 }
52995 BearingComponent.componentName = "bearing";
52996
52997 class CacheComponent extends Component {
52998     /** @ignore */
52999     constructor(name, container, navigator) {
53000         super(name, container, navigator);
53001     }
53002     _activate() {
53003         const subs = this._subscriptions;
53004         subs.push(combineLatest(this._navigator.stateService.currentImage$.pipe(switchMap((image) => {
53005             return image.sequenceEdges$;
53006         }), filter((status) => {
53007             return status.cached;
53008         })), this._configuration$).pipe(switchMap((nc) => {
53009             let status = nc[0];
53010             let configuration = nc[1];
53011             let sequenceDepth = Math.max(0, Math.min(4, configuration.depth.sequence));
53012             let next$ = this._cache$(status.edges, NavigationDirection.Next, sequenceDepth);
53013             let prev$ = this._cache$(status.edges, NavigationDirection.Prev, sequenceDepth);
53014             return merge(next$, prev$).pipe(catchError((error) => {
53015                 console.error("Failed to cache sequence edges.", error);
53016                 return empty();
53017             }));
53018         }))
53019             .subscribe(() => { }));
53020         subs.push(combineLatest(this._navigator.stateService.currentImage$.pipe(switchMap((image) => {
53021             return combineLatest(of(image), image.spatialEdges$.pipe(filter((status) => {
53022                 return status.cached;
53023             })));
53024         })), this._configuration$).pipe(switchMap(([[image, edgeStatus], configuration]) => {
53025             let edges = edgeStatus.edges;
53026             let depth = configuration.depth;
53027             let sphericalDepth = Math.max(0, Math.min(2, depth.spherical));
53028             let stepDepth = isSpherical(image.cameraType) ?
53029                 0 : Math.max(0, Math.min(3, depth.step));
53030             let turnDepth = isSpherical(image.cameraType) ?
53031                 0 : Math.max(0, Math.min(1, depth.turn));
53032             let spherical$ = this._cache$(edges, NavigationDirection.Spherical, sphericalDepth);
53033             let forward$ = this._cache$(edges, NavigationDirection.StepForward, stepDepth);
53034             let backward$ = this._cache$(edges, NavigationDirection.StepBackward, stepDepth);
53035             let left$ = this._cache$(edges, NavigationDirection.StepLeft, stepDepth);
53036             let right$ = this._cache$(edges, NavigationDirection.StepRight, stepDepth);
53037             let turnLeft$ = this._cache$(edges, NavigationDirection.TurnLeft, turnDepth);
53038             let turnRight$ = this._cache$(edges, NavigationDirection.TurnRight, turnDepth);
53039             let turnU$ = this._cache$(edges, NavigationDirection.TurnU, turnDepth);
53040             return merge(forward$, backward$, left$, right$, spherical$, turnLeft$, turnRight$, turnU$).pipe(catchError((error) => {
53041                 console.error("Failed to cache spatial edges.", error);
53042                 return empty();
53043             }));
53044         }))
53045             .subscribe(() => { }));
53046     }
53047     _deactivate() {
53048         this._subscriptions.unsubscribe();
53049     }
53050     _getDefaultConfiguration() {
53051         return { depth: { spherical: 1, sequence: 2, step: 1, turn: 0 } };
53052     }
53053     _cache$(edges, direction, depth) {
53054         return zip(of(edges), of(depth)).pipe(expand((ed) => {
53055             let es = ed[0];
53056             let d = ed[1];
53057             let edgesDepths$ = [];
53058             if (d > 0) {
53059                 for (let edge of es) {
53060                     if (edge.data.direction === direction) {
53061                         edgesDepths$.push(zip(this._navigator.graphService.cacheImage$(edge.target).pipe(mergeMap((n) => {
53062                             return this._imageToEdges$(n, direction);
53063                         })), of(d - 1)));
53064                     }
53065                 }
53066             }
53067             return from(edgesDepths$).pipe(mergeAll());
53068         }), skip(1));
53069     }
53070     _imageToEdges$(image, direction) {
53071         return ([NavigationDirection.Next, NavigationDirection.Prev].indexOf(direction) > -1 ?
53072             image.sequenceEdges$ :
53073             image.spatialEdges$).pipe(first((status) => {
53074             return status.cached;
53075         }), map((status) => {
53076             return status.edges;
53077         }));
53078     }
53079 }
53080 CacheComponent.componentName = "cache";
53081
53082 /**
53083  * @class CancelMapillaryError
53084  *
53085  * @classdesc Error thrown when a move to request has been
53086  * cancelled before completing because of a subsequent request.
53087  */
53088 class CancelMapillaryError extends MapillaryError {
53089     constructor(message) {
53090         super(message != null ? message : "The request was cancelled.");
53091         Object.setPrototypeOf(this, CancelMapillaryError.prototype);
53092         this.name = "CancelMapillaryError";
53093     }
53094 }
53095
53096 /**
53097  * @class DirectionDOMCalculator
53098  * @classdesc Helper class for calculating DOM CSS properties.
53099  */
53100 class DirectionDOMCalculator {
53101     constructor(configuration, size) {
53102         this._spatial = new Spatial();
53103         this._minThresholdWidth = 320;
53104         this._maxThresholdWidth = 1480;
53105         this._minThresholdHeight = 240;
53106         this._maxThresholdHeight = 820;
53107         this._configure(configuration);
53108         this._resize(size);
53109         this._reset();
53110     }
53111     get minWidth() {
53112         return this._minWidth;
53113     }
53114     get maxWidth() {
53115         return this._maxWidth;
53116     }
53117     get containerWidth() {
53118         return this._containerWidth;
53119     }
53120     get containerWidthCss() {
53121         return this._containerWidthCss;
53122     }
53123     get containerMarginCss() {
53124         return this._containerMarginCss;
53125     }
53126     get containerLeftCss() {
53127         return this._containerLeftCss;
53128     }
53129     get containerHeight() {
53130         return this._containerHeight;
53131     }
53132     get containerHeightCss() {
53133         return this._containerHeightCss;
53134     }
53135     get containerBottomCss() {
53136         return this._containerBottomCss;
53137     }
53138     get stepCircleSize() {
53139         return this._stepCircleSize;
53140     }
53141     get stepCircleSizeCss() {
53142         return this._stepCircleSizeCss;
53143     }
53144     get stepCircleMarginCss() {
53145         return this._stepCircleMarginCss;
53146     }
53147     get turnCircleSize() {
53148         return this._turnCircleSize;
53149     }
53150     get turnCircleSizeCss() {
53151         return this._turnCircleSizeCss;
53152     }
53153     get outerRadius() {
53154         return this._outerRadius;
53155     }
53156     get innerRadius() {
53157         return this._innerRadius;
53158     }
53159     get shadowOffset() {
53160         return this._shadowOffset;
53161     }
53162     /**
53163      * Configures the min and max width values.
53164      *
53165      * @param {DirectionConfiguration} configuration Configuration
53166      * with min and max width values.
53167      */
53168     configure(configuration) {
53169         this._configure(configuration);
53170         this._reset();
53171     }
53172     /**
53173      * Resizes all properties according to the width and height
53174      * of the size object.
53175      *
53176      * @param {ViewportSize} size The size of the container element.
53177      */
53178     resize(size) {
53179         this._resize(size);
53180         this._reset();
53181     }
53182     /**
53183      * Calculates the coordinates on the unit circle for an angle.
53184      *
53185      * @param {number} angle Angle in radians.
53186      * @returns {Array<number>} The x and y coordinates on the unit circle.
53187      */
53188     angleToCoordinates(angle) {
53189         return [Math.cos(angle), Math.sin(angle)];
53190     }
53191     /**
53192      * Calculates the coordinates on the unit circle for the
53193      * relative angle between the first and second angle.
53194      *
53195      * @param {number} first Angle in radians.
53196      * @param {number} second Angle in radians.
53197      * @returns {Array<number>} The x and y coordinates on the unit circle
53198      * for the relative angle between the first and second angle.
53199      */
53200     relativeAngleToCoordiantes(first, second) {
53201         let relativeAngle = this._spatial.wrapAngle(first - second);
53202         return this.angleToCoordinates(relativeAngle);
53203     }
53204     _configure(configuration) {
53205         this._minWidth = configuration.minWidth;
53206         this._maxWidth = this._getMaxWidth(configuration.minWidth, configuration.maxWidth);
53207     }
53208     _resize(size) {
53209         this._elementWidth = size.width;
53210         this._elementHeight = size.height;
53211     }
53212     _reset() {
53213         this._containerWidth = this._getContainerWidth(this._elementWidth, this._elementHeight);
53214         this._containerHeight = this._getContainerHeight(this.containerWidth);
53215         this._stepCircleSize = this._getStepCircleDiameter(this._containerHeight);
53216         this._turnCircleSize = this._getTurnCircleDiameter(this.containerHeight);
53217         this._outerRadius = this._getOuterRadius(this._containerHeight);
53218         this._innerRadius = this._getInnerRadius(this._containerHeight);
53219         this._shadowOffset = 3;
53220         this._containerWidthCss = this._numberToCssPixels(this._containerWidth);
53221         this._containerMarginCss = this._numberToCssPixels(-0.5 * this._containerWidth);
53222         this._containerLeftCss = this._numberToCssPixels(Math.floor(0.5 * this._elementWidth));
53223         this._containerHeightCss = this._numberToCssPixels(this._containerHeight);
53224         this._containerBottomCss = this._numberToCssPixels(Math.floor(-0.08 * this._containerHeight));
53225         this._stepCircleSizeCss = this._numberToCssPixels(this._stepCircleSize);
53226         this._stepCircleMarginCss = this._numberToCssPixels(-0.5 * this._stepCircleSize);
53227         this._turnCircleSizeCss = this._numberToCssPixels(this._turnCircleSize);
53228     }
53229     _getContainerWidth(elementWidth, elementHeight) {
53230         let relativeWidth = (elementWidth - this._minThresholdWidth) / (this._maxThresholdWidth - this._minThresholdWidth);
53231         let relativeHeight = (elementHeight - this._minThresholdHeight) / (this._maxThresholdHeight - this._minThresholdHeight);
53232         let coeff = Math.max(0, Math.min(1, Math.min(relativeWidth, relativeHeight)));
53233         coeff = 0.04 * Math.round(25 * coeff);
53234         return this._minWidth + coeff * (this._maxWidth - this._minWidth);
53235     }
53236     _getContainerHeight(containerWidth) {
53237         return 0.77 * containerWidth;
53238     }
53239     _getStepCircleDiameter(containerHeight) {
53240         return 0.34 * containerHeight;
53241     }
53242     _getTurnCircleDiameter(containerHeight) {
53243         return 0.3 * containerHeight;
53244     }
53245     _getOuterRadius(containerHeight) {
53246         return 0.31 * containerHeight;
53247     }
53248     _getInnerRadius(containerHeight) {
53249         return 0.125 * containerHeight;
53250     }
53251     _numberToCssPixels(value) {
53252         return value + "px";
53253     }
53254     _getMaxWidth(value, minWidth) {
53255         return value > minWidth ? value : minWidth;
53256     }
53257 }
53258
53259 /**
53260  * @class DirectionDOMRenderer
53261  * @classdesc DOM renderer for direction arrows.
53262  */
53263 class DirectionDOMRenderer {
53264     constructor(configuration, size) {
53265         this._isEdge = false;
53266         this._spatial = new Spatial();
53267         this._calculator = new DirectionDOMCalculator(configuration, size);
53268         this._image = null;
53269         this._rotation = { phi: 0, theta: 0 };
53270         this._epsilon = 0.5 * Math.PI / 180;
53271         this._highlightKey = null;
53272         this._distinguishSequence = false;
53273         this._needsRender = false;
53274         this._stepEdges = [];
53275         this._turnEdges = [];
53276         this._sphericalEdges = [];
53277         this._sequenceEdgeKeys = [];
53278         this._stepDirections = [
53279             NavigationDirection.StepForward,
53280             NavigationDirection.StepBackward,
53281             NavigationDirection.StepLeft,
53282             NavigationDirection.StepRight,
53283         ];
53284         this._turnDirections = [
53285             NavigationDirection.TurnLeft,
53286             NavigationDirection.TurnRight,
53287             NavigationDirection.TurnU,
53288         ];
53289         this._turnNames = {};
53290         this._turnNames[NavigationDirection.TurnLeft] = "mapillary-direction-turn-left";
53291         this._turnNames[NavigationDirection.TurnRight] = "mapillary-direction-turn-right";
53292         this._turnNames[NavigationDirection.TurnU] = "mapillary-direction-turn-around";
53293         // detects IE 8-11, then Edge 20+.
53294         let isIE = !!document.documentMode;
53295         this._isEdge = !isIE && !!window.StyleMedia;
53296     }
53297     /**
53298      * Get needs render.
53299      *
53300      * @returns {boolean} Value indicating whether render should be called.
53301      */
53302     get needsRender() {
53303         return this._needsRender;
53304     }
53305     /**
53306      * Renders virtual DOM elements.
53307      *
53308      * @description Calling render resets the needs render property.
53309      */
53310     render(navigator) {
53311         this._needsRender = false;
53312         let rotation = this._rotation;
53313         let steps = [];
53314         let turns = [];
53315         if (isSpherical(this._image.cameraType)) {
53316             steps = steps.concat(this._createSphericalArrows(navigator, rotation));
53317         }
53318         else {
53319             steps = steps.concat(this._createPerspectiveToSphericalArrows(navigator, rotation));
53320             steps = steps.concat(this._createStepArrows(navigator, rotation));
53321             turns = turns.concat(this._createTurnArrows(navigator));
53322         }
53323         return this._getContainer(steps, turns, rotation);
53324     }
53325     setEdges(edgeStatus, sequence) {
53326         this._setEdges(edgeStatus, sequence);
53327         this._setNeedsRender();
53328     }
53329     /**
53330      * Set image for which to show edges.
53331      *
53332      * @param {Image} image
53333      */
53334     setImage(image) {
53335         this._image = image;
53336         this._clearEdges();
53337         this._setNeedsRender();
53338     }
53339     /**
53340      * Set the render camera to use for calculating rotations.
53341      *
53342      * @param {RenderCamera} renderCamera
53343      */
53344     setRenderCamera(renderCamera) {
53345         let rotation = renderCamera.rotation;
53346         if (Math.abs(rotation.phi - this._rotation.phi) < this._epsilon) {
53347             return;
53348         }
53349         this._rotation = rotation;
53350         this._setNeedsRender();
53351     }
53352     /**
53353      * Set configuration values.
53354      *
53355      * @param {DirectionConfiguration} configuration
53356      */
53357     setConfiguration(configuration) {
53358         let needsRender = false;
53359         if (this._highlightKey !== configuration.highlightId ||
53360             this._distinguishSequence !== configuration.distinguishSequence) {
53361             this._highlightKey = configuration.highlightId;
53362             this._distinguishSequence = configuration.distinguishSequence;
53363             needsRender = true;
53364         }
53365         if (this._calculator.minWidth !== configuration.minWidth ||
53366             this._calculator.maxWidth !== configuration.maxWidth) {
53367             this._calculator.configure(configuration);
53368             needsRender = true;
53369         }
53370         if (needsRender) {
53371             this._setNeedsRender();
53372         }
53373     }
53374     /**
53375      * Detect the element's width and height and resize
53376      * elements accordingly.
53377      *
53378      * @param {ViewportSize} size Size of vßiewer container element.
53379      */
53380     resize(size) {
53381         this._calculator.resize(size);
53382         this._setNeedsRender();
53383     }
53384     _setNeedsRender() {
53385         if (this._image != null) {
53386             this._needsRender = true;
53387         }
53388     }
53389     _clearEdges() {
53390         this._stepEdges = [];
53391         this._turnEdges = [];
53392         this._sphericalEdges = [];
53393         this._sequenceEdgeKeys = [];
53394     }
53395     _setEdges(edgeStatus, sequence) {
53396         this._stepEdges = [];
53397         this._turnEdges = [];
53398         this._sphericalEdges = [];
53399         this._sequenceEdgeKeys = [];
53400         for (let edge of edgeStatus.edges) {
53401             let direction = edge.data.direction;
53402             if (this._stepDirections.indexOf(direction) > -1) {
53403                 this._stepEdges.push(edge);
53404                 continue;
53405             }
53406             if (this._turnDirections.indexOf(direction) > -1) {
53407                 this._turnEdges.push(edge);
53408                 continue;
53409             }
53410             if (edge.data.direction === NavigationDirection.Spherical) {
53411                 this._sphericalEdges.push(edge);
53412             }
53413         }
53414         if (this._distinguishSequence && sequence != null) {
53415             let edges = this._sphericalEdges
53416                 .concat(this._stepEdges)
53417                 .concat(this._turnEdges);
53418             for (let edge of edges) {
53419                 let edgeKey = edge.target;
53420                 for (let sequenceKey of sequence.imageIds) {
53421                     if (sequenceKey === edgeKey) {
53422                         this._sequenceEdgeKeys.push(edgeKey);
53423                         break;
53424                     }
53425                 }
53426             }
53427         }
53428     }
53429     _createSphericalArrows(navigator, rotation) {
53430         let arrows = [];
53431         for (let sphericalEdge of this._sphericalEdges) {
53432             arrows.push(this._createVNodeByKey(navigator, sphericalEdge.target, sphericalEdge.data.worldMotionAzimuth, rotation, this._calculator.outerRadius, "mapillary-direction-arrow-spherical"));
53433         }
53434         for (let stepEdge of this._stepEdges) {
53435             arrows.push(this._createSphericalToPerspectiveArrow(navigator, stepEdge.target, stepEdge.data.worldMotionAzimuth, rotation, stepEdge.data.direction));
53436         }
53437         return arrows;
53438     }
53439     _createSphericalToPerspectiveArrow(navigator, key, azimuth, rotation, direction) {
53440         let threshold = Math.PI / 8;
53441         let relativePhi = rotation.phi;
53442         switch (direction) {
53443             case NavigationDirection.StepBackward:
53444                 relativePhi = rotation.phi - Math.PI;
53445                 break;
53446             case NavigationDirection.StepLeft:
53447                 relativePhi = rotation.phi + Math.PI / 2;
53448                 break;
53449             case NavigationDirection.StepRight:
53450                 relativePhi = rotation.phi - Math.PI / 2;
53451                 break;
53452         }
53453         if (Math.abs(this._spatial.wrapAngle(azimuth - relativePhi)) < threshold) {
53454             return this._createVNodeByKey(navigator, key, azimuth, rotation, this._calculator.outerRadius, "mapillary-direction-arrow-step");
53455         }
53456         return this._createVNodeInactive(key, azimuth, rotation);
53457     }
53458     _createPerspectiveToSphericalArrows(navigator, rotation) {
53459         let arrows = [];
53460         for (let sphericalEdge of this._sphericalEdges) {
53461             arrows.push(this._createVNodeByKey(navigator, sphericalEdge.target, sphericalEdge.data.worldMotionAzimuth, rotation, this._calculator.innerRadius, "mapillary-direction-arrow-spherical", true));
53462         }
53463         return arrows;
53464     }
53465     _createStepArrows(navigator, rotation) {
53466         let arrows = [];
53467         for (let stepEdge of this._stepEdges) {
53468             arrows.push(this._createVNodeByDirection(navigator, stepEdge.target, stepEdge.data.worldMotionAzimuth, rotation, stepEdge.data.direction));
53469         }
53470         return arrows;
53471     }
53472     _createTurnArrows(navigator) {
53473         let turns = [];
53474         for (let turnEdge of this._turnEdges) {
53475             let direction = turnEdge.data.direction;
53476             let name = this._turnNames[direction];
53477             turns.push(this._createVNodeByTurn(navigator, turnEdge.target, name, direction));
53478         }
53479         return turns;
53480     }
53481     _createVNodeByKey(navigator, key, azimuth, rotation, offset, className, shiftVertically) {
53482         let onClick = (e) => {
53483             navigator.moveTo$(key)
53484                 .subscribe(undefined, (error) => {
53485                 if (!(error instanceof CancelMapillaryError)) {
53486                     console.error(error);
53487                 }
53488             });
53489         };
53490         return this._createVNode(key, azimuth, rotation, offset, className, "mapillary-direction-circle", onClick, shiftVertically);
53491     }
53492     _createVNodeByDirection(navigator, key, azimuth, rotation, direction) {
53493         let onClick = (e) => {
53494             navigator.moveDir$(direction)
53495                 .subscribe(undefined, (error) => {
53496                 if (!(error instanceof CancelMapillaryError)) {
53497                     console.error(error);
53498                 }
53499             });
53500         };
53501         return this._createVNode(key, azimuth, rotation, this._calculator.outerRadius, "mapillary-direction-arrow-step", "mapillary-direction-circle", onClick);
53502     }
53503     _createVNodeByTurn(navigator, key, className, direction) {
53504         let onClick = (e) => {
53505             navigator.moveDir$(direction)
53506                 .subscribe(undefined, (error) => {
53507                 if (!(error instanceof CancelMapillaryError)) {
53508                     console.error(error);
53509                 }
53510             });
53511         };
53512         let style = {
53513             height: this._calculator.turnCircleSizeCss,
53514             transform: "rotate(0)",
53515             width: this._calculator.turnCircleSizeCss,
53516         };
53517         switch (direction) {
53518             case NavigationDirection.TurnLeft:
53519                 style.left = "5px";
53520                 style.top = "5px";
53521                 break;
53522             case NavigationDirection.TurnRight:
53523                 style.right = "5px";
53524                 style.top = "5px";
53525                 break;
53526             case NavigationDirection.TurnU:
53527                 style.left = "5px";
53528                 style.bottom = "5px";
53529                 break;
53530         }
53531         let circleProperties = {
53532             attributes: {
53533                 "data-id": key,
53534             },
53535             onclick: onClick,
53536             style: style,
53537         };
53538         let circleClassName = "mapillary-direction-turn-circle";
53539         if (this._sequenceEdgeKeys.indexOf(key) > -1) {
53540             circleClassName += "-sequence";
53541         }
53542         if (this._highlightKey === key) {
53543             circleClassName += "-highlight";
53544         }
53545         let turn = virtualDom.h(`div.${className}`, {}, []);
53546         return virtualDom.h("div." + circleClassName, circleProperties, [turn]);
53547     }
53548     _createVNodeInactive(key, azimuth, rotation) {
53549         return this._createVNode(key, azimuth, rotation, this._calculator.outerRadius, "mapillary-direction-arrow-inactive", "mapillary-direction-circle-inactive");
53550     }
53551     _createVNode(key, azimuth, rotation, radius, className, circleClassName, onClick, shiftVertically) {
53552         let translation = this._calculator.angleToCoordinates(azimuth - rotation.phi);
53553         // rotate 90 degrees clockwise and flip over X-axis
53554         let translationX = Math.round(-radius * translation[1] + 0.5 * this._calculator.containerWidth);
53555         let translationY = Math.round(-radius * translation[0] + 0.5 * this._calculator.containerHeight);
53556         let shadowTranslation = this._calculator.relativeAngleToCoordiantes(azimuth, rotation.phi);
53557         let shadowOffset = this._calculator.shadowOffset;
53558         let shadowTranslationX = -shadowOffset * shadowTranslation[1];
53559         let shadowTranslationY = shadowOffset * shadowTranslation[0];
53560         let filter = `drop-shadow(${shadowTranslationX}px ${shadowTranslationY}px 1px rgba(0,0,0,0.8))`;
53561         let properties = {
53562             style: {
53563                 "-webkit-filter": filter,
53564                 filter: filter,
53565             },
53566         };
53567         let chevron = virtualDom.h("div." + className, properties, []);
53568         let azimuthDeg = -this._spatial.radToDeg(azimuth - rotation.phi);
53569         let circleTransform = shiftVertically ?
53570             `translate(${translationX}px, ${translationY}px) rotate(${azimuthDeg}deg) translateZ(-0.01px)` :
53571             `translate(${translationX}px, ${translationY}px) rotate(${azimuthDeg}deg)`;
53572         let circleProperties = {
53573             attributes: { "data-id": key },
53574             onclick: onClick,
53575             style: {
53576                 height: this._calculator.stepCircleSizeCss,
53577                 marginLeft: this._calculator.stepCircleMarginCss,
53578                 marginTop: this._calculator.stepCircleMarginCss,
53579                 transform: circleTransform,
53580                 width: this._calculator.stepCircleSizeCss,
53581             },
53582         };
53583         if (this._sequenceEdgeKeys.indexOf(key) > -1) {
53584             circleClassName += "-sequence";
53585         }
53586         if (this._highlightKey === key) {
53587             circleClassName += "-highlight";
53588         }
53589         return virtualDom.h("div." + circleClassName, circleProperties, [chevron]);
53590     }
53591     _getContainer(steps, turns, rotation) {
53592         // edge does not handle hover on perspective transforms.
53593         let transform = this._isEdge ?
53594             "rotateX(60deg)" :
53595             `perspective(${this._calculator.containerWidthCss}) rotateX(60deg)`;
53596         let properties = {
53597             oncontextmenu: (event) => { event.preventDefault(); },
53598             style: {
53599                 bottom: this._calculator.containerBottomCss,
53600                 height: this._calculator.containerHeightCss,
53601                 left: this._calculator.containerLeftCss,
53602                 marginLeft: this._calculator.containerMarginCss,
53603                 transform: transform,
53604                 width: this._calculator.containerWidthCss,
53605             },
53606         };
53607         return virtualDom.h("div.mapillary-direction-perspective", properties, turns.concat(steps));
53608     }
53609 }
53610
53611 /**
53612  * @class DirectionComponent
53613  * @classdesc Component showing navigation arrows for steps and turns.
53614  */
53615 class DirectionComponent extends Component {
53616     /** @ignore */
53617     constructor(name, container, navigator, directionDOMRenderer) {
53618         super(name, container, navigator);
53619         this._renderer = !!directionDOMRenderer ?
53620             directionDOMRenderer :
53621             new DirectionDOMRenderer(this.defaultConfiguration, { height: container.container.offsetHeight, width: container.container.offsetWidth });
53622         this._hoveredIdSubject$ = new Subject();
53623         this._hoveredId$ = this._hoveredIdSubject$.pipe(share());
53624     }
53625     fire(type, event) {
53626         super.fire(type, event);
53627     }
53628     off(type, handler) {
53629         super.off(type, handler);
53630     }
53631     on(type, handler) {
53632         super.on(type, handler);
53633     }
53634     _activate() {
53635         const subs = this._subscriptions;
53636         subs.push(this._configuration$
53637             .subscribe((configuration) => {
53638             this._renderer.setConfiguration(configuration);
53639         }));
53640         subs.push(this._container.renderService.size$
53641             .subscribe((size) => {
53642             this._renderer.resize(size);
53643         }));
53644         subs.push(this._navigator.stateService.currentImage$.pipe(tap((image) => {
53645             this._container.domRenderer.render$.next({ name: this._name, vNode: virtualDom.h("div", {}, []) });
53646             this._renderer.setImage(image);
53647         }), withLatestFrom(this._configuration$), switchMap(([image, configuration]) => {
53648             return combineLatest(image.spatialEdges$, configuration.distinguishSequence ?
53649                 this._navigator.graphService
53650                     .cacheSequence$(image.sequenceId).pipe(catchError((error) => {
53651                     console.error(`Failed to cache sequence (${image.sequenceId})`, error);
53652                     return of(null);
53653                 })) :
53654                 of(null));
53655         }))
53656             .subscribe(([edgeStatus, sequence]) => {
53657             this._renderer.setEdges(edgeStatus, sequence);
53658         }));
53659         subs.push(this._container.renderService.renderCameraFrame$.pipe(tap((renderCamera) => {
53660             this._renderer.setRenderCamera(renderCamera);
53661         }), map(() => {
53662             return this._renderer;
53663         }), filter((renderer) => {
53664             return renderer.needsRender;
53665         }), map((renderer) => {
53666             return { name: this._name, vNode: renderer.render(this._navigator) };
53667         }))
53668             .subscribe(this._container.domRenderer.render$));
53669         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]) => {
53670             let elements = element.getElementsByClassName("mapillary-direction-perspective");
53671             for (let i = 0; i < elements.length; i++) {
53672                 let hovered = elements.item(i).querySelector(":hover");
53673                 if (hovered != null && hovered.hasAttribute("data-id")) {
53674                     return hovered.getAttribute("data-id");
53675                 }
53676             }
53677             return null;
53678         }), distinctUntilChanged())
53679             .subscribe(this._hoveredIdSubject$));
53680         subs.push(this._hoveredId$
53681             .subscribe((id) => {
53682             const type = "hover";
53683             const event = {
53684                 id,
53685                 target: this,
53686                 type,
53687             };
53688             this.fire(type, event);
53689         }));
53690     }
53691     _deactivate() {
53692         this._subscriptions.unsubscribe();
53693     }
53694     _getDefaultConfiguration() {
53695         return {
53696             distinguishSequence: false,
53697             maxWidth: 460,
53698             minWidth: 260,
53699         };
53700     }
53701 }
53702 /** @inheritdoc */
53703 DirectionComponent.componentName = "direction";
53704
53705 const sphericalFrag = `
53706 #ifdef GL_FRAGMENT_PRECISION_HIGH
53707 precision highp float;
53708 #else
53709 precision mediump float;
53710 #endif
53711
53712 #define tau 6.28318530718
53713
53714 uniform sampler2D projectorTex;
53715 uniform float opacity;
53716
53717 varying vec4 vRstq;
53718
53719 void main()
53720 {
53721     vec3 b = normalize(vRstq.xyz);
53722     float lat = -asin(b.y);
53723     float lng = atan(b.x, b.z);
53724     float x = lng / tau + 0.5;
53725     float y = lat / tau * 2.0 + 0.5;
53726     vec4 baseColor = texture2D(projectorTex, vec2(x, y));
53727     baseColor.a = opacity;
53728     gl_FragColor = baseColor;
53729 }
53730 `;
53731
53732 const sphericalVert = `
53733 #ifdef GL_ES
53734 precision highp float;
53735 #endif
53736
53737 uniform mat4 projectorMat;
53738
53739 varying vec4 vRstq;
53740
53741 void main()
53742 {
53743     vRstq = projectorMat * vec4(position, 1.0);
53744     gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
53745 }
53746 `;
53747
53748 const sphericalCurtainFrag = `
53749 #ifdef GL_FRAGMENT_PRECISION_HIGH
53750 precision highp float;
53751 #else
53752 precision mediump float;
53753 #endif
53754
53755 #define tau 6.28318530718
53756
53757 uniform sampler2D projectorTex;
53758 uniform float curtain;
53759 uniform float opacity;
53760
53761 varying vec4 vRstq;
53762
53763 void main()
53764 {
53765     vec3 b = normalize(vRstq.xyz);
53766     float lat = -asin(b.y);
53767     float lng = atan(b.x, b.z);
53768     float x = lng / tau + 0.5;
53769     float y = lat / tau * 2.0 + 0.5;
53770
53771     bool inverted = curtain < 0.5;
53772
53773     float curtainMin = inverted ? curtain + 0.5 : curtain - 0.5;
53774     float curtainMax = curtain;
53775
53776     bool insideCurtain = inverted ?
53777         x > curtainMin || x < curtainMax :
53778         x > curtainMin && x < curtainMax;
53779
53780     vec4 baseColor;
53781     if (insideCurtain) {
53782         baseColor = texture2D(projectorTex, vec2(x, y));
53783         baseColor.a = opacity;
53784     } else {
53785         baseColor = vec4(0.0, 0.0, 0.0, 0.0);
53786     }
53787
53788     gl_FragColor = baseColor;
53789 }
53790 `;
53791
53792 const sphericalCurtainVert = `
53793 #ifdef GL_ES
53794 precision highp float;
53795 #endif
53796
53797 uniform mat4 projectorMat;
53798
53799 varying vec4 vRstq;
53800
53801 void main()
53802 {
53803     vRstq = projectorMat * vec4(position, 1.0);
53804     gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
53805 }
53806 `;
53807
53808 const fisheyeFrag = `
53809 #ifdef GL_FRAGMENT_PRECISION_HIGH
53810 precision highp float;
53811 #else
53812 precision mediump float;
53813 #endif
53814
53815 uniform sampler2D projectorTex;
53816 uniform float opacity;
53817 uniform float focal;
53818 uniform float k1;
53819 uniform float k2;
53820 uniform float scale_x;
53821 uniform float scale_y;
53822 uniform float radial_peak;
53823
53824 varying vec4 vRstq;
53825
53826 void main()
53827 {
53828     float x = vRstq.x;
53829     float y = vRstq.y;
53830     float z = vRstq.z;
53831
53832     float r = sqrt(x * x + y * y);
53833     float theta = atan(r, z);
53834
53835     if (radial_peak > 0. && theta > radial_peak) {
53836         theta = radial_peak;
53837     }
53838
53839     float theta2 = theta * theta;
53840     float theta_d = theta * (1.0 + theta2 * (k1 + theta2 * k2));
53841     float s = focal * theta_d / r;
53842
53843     float u = scale_x * s * x + 0.5;
53844     float v = -scale_y * s * y + 0.5;
53845
53846     vec4 baseColor;
53847     if (u >= 0. && u <= 1. && v >= 0. && v <= 1.) {
53848         baseColor = texture2D(projectorTex, vec2(u, v));
53849         baseColor.a = opacity;
53850     } else {
53851         baseColor = vec4(0.0, 0.0, 0.0, 0.0);
53852     }
53853
53854     gl_FragColor = baseColor;
53855 }
53856 `;
53857
53858 const fisheyeVert = `
53859 #ifdef GL_ES
53860 precision highp float;
53861 #endif
53862
53863 uniform mat4 projectorMat;
53864
53865 varying vec4 vRstq;
53866
53867 void main()
53868 {
53869     vRstq = projectorMat * vec4(position, 1.0);
53870     gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
53871 }
53872 `;
53873
53874 const fisheyeCurtainFrag = `
53875 #ifdef GL_FRAGMENT_PRECISION_HIGH
53876 precision highp float;
53877 #else
53878 precision mediump float;
53879 #endif
53880
53881 uniform sampler2D projectorTex;
53882 uniform float opacity;
53883 uniform float focal;
53884 uniform float k1;
53885 uniform float k2;
53886 uniform float scale_x;
53887 uniform float scale_y;
53888 uniform float radial_peak;
53889 uniform float curtain;
53890
53891 varying vec4 vRstq;
53892
53893 void main()
53894 {
53895     float x = vRstq.x;
53896     float y = vRstq.y;
53897     float z = vRstq.z;
53898
53899     float r2 = sqrt(x * x + y * y);
53900     float theta = atan(r2, z);
53901
53902     if (radial_peak > 0. && theta > radial_peak) {
53903         theta = radial_peak;
53904     }
53905
53906     float theta2 = theta * theta;
53907     float theta_d = theta * (1.0 + theta2 * (k1 + theta2 * k2));
53908     float s = focal * theta_d / r2;
53909
53910     float u = scale_x * s * x + 0.5;
53911     float v = -scale_y * s * y + 0.5;
53912
53913     vec4 baseColor;
53914     if ((u < curtain || curtain >= 1.0) && u >= 0. && u <= 1. && v >= 0. && v <= 1.) {
53915         baseColor = texture2D(projectorTex, vec2(u, v));
53916         baseColor.a = opacity;
53917     } else {
53918         baseColor = vec4(0.0, 0.0, 0.0, 0.0);
53919     }
53920
53921     gl_FragColor = baseColor;
53922 }
53923 `;
53924
53925 const fisheyeCurtainVert = `
53926 #ifdef GL_ES
53927 precision highp float;
53928 #endif
53929
53930 uniform mat4 projectorMat;
53931
53932 varying vec4 vRstq;
53933
53934 void main()
53935 {
53936     vRstq = projectorMat * vec4(position, 1.0);
53937     gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
53938 }
53939 `;
53940
53941 const perspectiveFrag = `
53942 #ifdef GL_FRAGMENT_PRECISION_HIGH
53943 precision highp float;
53944 #else
53945 precision mediump float;
53946 #endif
53947
53948 uniform sampler2D projectorTex;
53949 uniform float opacity;
53950 uniform float focal;
53951 uniform float k1;
53952 uniform float k2;
53953 uniform float scale_x;
53954 uniform float scale_y;
53955 uniform float radial_peak;
53956
53957 varying vec4 vRstq;
53958
53959 void main()
53960 {
53961     float x = vRstq.x / vRstq.z;
53962     float y = vRstq.y / vRstq.z;
53963     float r2 = x * x + y * y;
53964
53965     if (radial_peak > 0. && r2 > radial_peak * sqrt(r2)) {
53966         r2 = radial_peak * radial_peak;
53967     }
53968
53969     float d = 1.0 + k1 * r2 + k2 * r2 * r2;
53970     float u = scale_x * focal * d * x + 0.5;
53971     float v = - scale_y * focal * d * y + 0.5;
53972
53973     vec4 baseColor;
53974     if (u >= 0. && u <= 1. && v >= 0. && v <= 1.) {
53975         baseColor = texture2D(projectorTex, vec2(u, v));
53976         baseColor.a = opacity;
53977     } else {
53978         baseColor = vec4(0.0, 0.0, 0.0, 0.0);
53979     }
53980
53981     gl_FragColor = baseColor;
53982 }
53983 `;
53984
53985 const perspectiveVert = `
53986 #ifdef GL_ES
53987 precision highp float;
53988 #endif
53989
53990 uniform mat4 projectorMat;
53991
53992 varying vec4 vRstq;
53993
53994 void main()
53995 {
53996     vRstq = projectorMat * vec4(position, 1.0);
53997     gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
53998 }
53999 `;
54000
54001 const perspectiveCurtainFrag = `
54002 #ifdef GL_FRAGMENT_PRECISION_HIGH
54003 precision highp float;
54004 #else
54005 precision mediump float;
54006 #endif
54007
54008 uniform sampler2D projectorTex;
54009 uniform float opacity;
54010 uniform float focal;
54011 uniform float k1;
54012 uniform float k2;
54013 uniform float scale_x;
54014 uniform float scale_y;
54015 uniform float radial_peak;
54016 uniform float curtain;
54017
54018 varying vec4 vRstq;
54019
54020 void main()
54021 {
54022     float x = vRstq.x / vRstq.z;
54023     float y = vRstq.y / vRstq.z;
54024     float r2 = x * x + y * y;
54025
54026     if (radial_peak > 0. && r2 > radial_peak * sqrt(r2)) {
54027         r2 = radial_peak * radial_peak;
54028     }
54029
54030     float d = 1.0 + k1 * r2 + k2 * r2 * r2;
54031     float u = scale_x * focal * d * x + 0.5;
54032     float v = - scale_y * focal * d * y + 0.5;
54033
54034     vec4 baseColor;
54035     if ((u < curtain || curtain >= 1.0) && u >= 0. && u <= 1. && v >= 0. && v <= 1.) {
54036         baseColor = texture2D(projectorTex, vec2(u, v));
54037         baseColor.a = opacity;
54038     } else {
54039         baseColor = vec4(0.0, 0.0, 0.0, 0.0);
54040     }
54041
54042     gl_FragColor = baseColor;
54043 }
54044 `;
54045
54046 const perspectiveCurtainVert = `
54047 #ifdef GL_ES
54048 precision highp float;
54049 #endif
54050
54051 uniform mat4 projectorMat;
54052
54053 varying vec4 vRstq;
54054
54055 void main()
54056 {
54057     vRstq = projectorMat * vec4(position, 1.0);
54058     gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
54059 }
54060 `;
54061
54062 const perspectiveDistortedFrag = `
54063 #ifdef GL_FRAGMENT_PRECISION_HIGH
54064 precision highp float;
54065 #else
54066 precision mediump float;
54067 #endif
54068
54069 uniform sampler2D projectorTex;
54070 uniform float opacity;
54071
54072 varying vec4 vRstq;
54073
54074 void main()
54075 {
54076     float u = vRstq.x / vRstq.w;
54077     float v = vRstq.y / vRstq.w;
54078
54079     vec4 baseColor;
54080     if (u >= 0. && u <= 1. && v >= 0. && v <= 1.) {
54081         baseColor = texture2D(projectorTex, vec2(u, v));
54082         baseColor.a = opacity;
54083     } else {
54084         baseColor = vec4(0.0, 0.0, 0.0, 0.0);
54085     }
54086
54087     gl_FragColor = baseColor;
54088 }
54089 `;
54090
54091 const perspectiveDistortedVert = `
54092 #ifdef GL_ES
54093 precision highp float;
54094 #endif
54095
54096 uniform mat4 projectorMat;
54097
54098 varying vec4 vRstq;
54099
54100 void main()
54101 {
54102     vRstq = projectorMat * vec4(position, 1.0);
54103     gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
54104 }
54105 `;
54106
54107 const perspectiveDistortedCurtainFrag = `
54108 #ifdef GL_FRAGMENT_PRECISION_HIGH
54109 precision highp float;
54110 #else
54111 precision mediump float;
54112 #endif
54113
54114 uniform sampler2D projectorTex;
54115 uniform float opacity;
54116 uniform float curtain;
54117
54118 varying vec4 vRstq;
54119
54120 void main()
54121 {
54122     float u = vRstq.x / vRstq.w;
54123     float v = vRstq.y / vRstq.w;
54124
54125     vec4 baseColor;
54126     if ((u < curtain || curtain >= 1.0) && u >= 0. && u <= 1. && v >= 0. && v <= 1.) {
54127         baseColor = texture2D(projectorTex, vec2(u, v));
54128         baseColor.a = opacity;
54129     } else {
54130         baseColor = vec4(0.0, 0.0, 0.0, 0.0);
54131     }
54132
54133     gl_FragColor = baseColor;
54134 }
54135 `;
54136
54137 const perspectiveDistortedCurtainVert = `
54138 #ifdef GL_ES
54139 precision highp float;
54140 #endif
54141
54142 uniform mat4 projectorMat;
54143
54144 varying vec4 vRstq;
54145
54146 void main()
54147 {
54148     vRstq = projectorMat * vec4(position, 1.0);
54149     gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
54150 }
54151 `;
54152
54153 class Shaders {
54154 }
54155 Shaders.fisheye = {
54156     fragment: fisheyeFrag,
54157     vertex: fisheyeVert,
54158 };
54159 Shaders.fisheyeCurtain = {
54160     fragment: fisheyeCurtainFrag,
54161     vertex: fisheyeCurtainVert,
54162 };
54163 Shaders.perspective = {
54164     fragment: perspectiveFrag,
54165     vertex: perspectiveVert,
54166 };
54167 Shaders.perspectiveCurtain = {
54168     fragment: perspectiveCurtainFrag,
54169     vertex: perspectiveCurtainVert,
54170 };
54171 Shaders.perspectiveDistorted = {
54172     fragment: perspectiveDistortedFrag,
54173     vertex: perspectiveDistortedVert,
54174 };
54175 Shaders.perspectiveDistortedCurtain = {
54176     fragment: perspectiveDistortedCurtainFrag,
54177     vertex: perspectiveDistortedCurtainVert,
54178 };
54179 Shaders.spherical = {
54180     fragment: sphericalFrag,
54181     vertex: sphericalVert,
54182 };
54183 Shaders.sphericalCurtain = {
54184     fragment: sphericalCurtainFrag,
54185     vertex: sphericalCurtainVert,
54186 };
54187
54188 class MeshFactory {
54189     constructor(imagePlaneDepth, imageSphereRadius) {
54190         this._imagePlaneDepth = imagePlaneDepth != null ? imagePlaneDepth : 200;
54191         this._imageSphereRadius = imageSphereRadius != null ? imageSphereRadius : 200;
54192     }
54193     createMesh(image, transform) {
54194         if (isSpherical(transform.cameraType)) {
54195             return this._createImageSphere(image, transform);
54196         }
54197         else if (isFisheye(transform.cameraType)) {
54198             return this._createImagePlaneFisheye(image, transform);
54199         }
54200         else {
54201             return this._createImagePlane(image, transform);
54202         }
54203     }
54204     createFlatMesh(image, transform, basicX0, basicX1, basicY0, basicY1) {
54205         let texture = this._createTexture(image.image);
54206         let materialParameters = this._createDistortedPlaneMaterialParameters(transform, texture);
54207         let material = new ShaderMaterial(materialParameters);
54208         let geometry = this._getFlatImagePlaneGeoFromBasic(transform, basicX0, basicX1, basicY0, basicY1);
54209         return new Mesh(geometry, material);
54210     }
54211     createCurtainMesh(image, transform) {
54212         if (isSpherical(transform.cameraType)) {
54213             return this._createSphereCurtainMesh(image, transform);
54214         }
54215         else if (isFisheye(transform.cameraType)) {
54216             return this._createCurtainMeshFisheye(image, transform);
54217         }
54218         else {
54219             return this._createCurtainMesh(image, transform);
54220         }
54221     }
54222     createDistortedCurtainMesh(image, transform) {
54223         return this._createDistortedCurtainMesh(image, transform);
54224     }
54225     _createCurtainMesh(image, transform) {
54226         let texture = this._createTexture(image.image);
54227         let materialParameters = this._createCurtainPlaneMaterialParameters(transform, texture);
54228         let material = new ShaderMaterial(materialParameters);
54229         let geometry = this._useMesh(transform, image) ?
54230             this._getImagePlaneGeo(transform, image) :
54231             this._getRegularFlatImagePlaneGeo(transform);
54232         return new Mesh(geometry, material);
54233     }
54234     _createCurtainMeshFisheye(image, transform) {
54235         let texture = this._createTexture(image.image);
54236         let materialParameters = this._createCurtainPlaneMaterialParametersFisheye(transform, texture);
54237         let material = new ShaderMaterial(materialParameters);
54238         let geometry = this._useMesh(transform, image) ?
54239             this._getImagePlaneGeoFisheye(transform, image) :
54240             this._getRegularFlatImagePlaneGeo(transform);
54241         return new Mesh(geometry, material);
54242     }
54243     _createDistortedCurtainMesh(image, transform) {
54244         let texture = this._createTexture(image.image);
54245         let materialParameters = this._createDistortedCurtainPlaneMaterialParameters(transform, texture);
54246         let material = new ShaderMaterial(materialParameters);
54247         let geometry = this._getRegularFlatImagePlaneGeo(transform);
54248         return new Mesh(geometry, material);
54249     }
54250     _createSphereCurtainMesh(image, transform) {
54251         let texture = this._createTexture(image.image);
54252         let materialParameters = this._createCurtainSphereMaterialParameters(transform, texture);
54253         let material = new ShaderMaterial(materialParameters);
54254         return this._useMesh(transform, image) ?
54255             new Mesh(this._getImageSphereGeo(transform, image), material) :
54256             new Mesh(this._getFlatImageSphereGeo(transform), material);
54257     }
54258     _createImageSphere(image, transform) {
54259         let texture = this._createTexture(image.image);
54260         let materialParameters = this._createSphereMaterialParameters(transform, texture);
54261         let material = new ShaderMaterial(materialParameters);
54262         let mesh = this._useMesh(transform, image) ?
54263             new Mesh(this._getImageSphereGeo(transform, image), material) :
54264             new Mesh(this._getFlatImageSphereGeo(transform), material);
54265         return mesh;
54266     }
54267     _createImagePlane(image, transform) {
54268         let texture = this._createTexture(image.image);
54269         let materialParameters = this._createPlaneMaterialParameters(transform, texture);
54270         let material = new ShaderMaterial(materialParameters);
54271         let geometry = this._useMesh(transform, image) ?
54272             this._getImagePlaneGeo(transform, image) :
54273             this._getRegularFlatImagePlaneGeo(transform);
54274         return new Mesh(geometry, material);
54275     }
54276     _createImagePlaneFisheye(image, transform) {
54277         let texture = this._createTexture(image.image);
54278         let materialParameters = this._createPlaneMaterialParametersFisheye(transform, texture);
54279         let material = new ShaderMaterial(materialParameters);
54280         let geometry = this._useMesh(transform, image) ?
54281             this._getImagePlaneGeoFisheye(transform, image) :
54282             this._getRegularFlatImagePlaneGeoFisheye(transform);
54283         return new Mesh(geometry, material);
54284     }
54285     _createSphereMaterialParameters(transform, texture) {
54286         let materialParameters = {
54287             depthWrite: false,
54288             fragmentShader: Shaders.spherical.fragment,
54289             side: DoubleSide,
54290             transparent: true,
54291             uniforms: {
54292                 opacity: { value: 1.0 },
54293                 projectorMat: { value: transform.rt },
54294                 projectorTex: { value: texture },
54295             },
54296             vertexShader: Shaders.spherical.vertex,
54297         };
54298         return materialParameters;
54299     }
54300     _createCurtainSphereMaterialParameters(transform, texture) {
54301         let materialParameters = {
54302             depthWrite: false,
54303             fragmentShader: Shaders.sphericalCurtain.fragment,
54304             side: DoubleSide,
54305             transparent: true,
54306             uniforms: {
54307                 curtain: { value: 1.0 },
54308                 opacity: { value: 1.0 },
54309                 projectorMat: { value: transform.rt },
54310                 projectorTex: { value: texture },
54311             },
54312             vertexShader: Shaders.sphericalCurtain.vertex,
54313         };
54314         return materialParameters;
54315     }
54316     _createPlaneMaterialParameters(transform, texture) {
54317         let materialParameters = {
54318             depthWrite: false,
54319             fragmentShader: Shaders.perspective.fragment,
54320             side: DoubleSide,
54321             transparent: true,
54322             uniforms: {
54323                 focal: { value: transform.focal },
54324                 k1: { value: transform.ck1 },
54325                 k2: { value: transform.ck2 },
54326                 opacity: { value: 1.0 },
54327                 projectorMat: { value: transform.basicRt },
54328                 projectorTex: { value: texture },
54329                 radial_peak: { value: !!transform.radialPeak ? transform.radialPeak : 0.0 },
54330                 scale_x: { value: Math.max(transform.basicHeight, transform.basicWidth) / transform.basicWidth },
54331                 scale_y: { value: Math.max(transform.basicWidth, transform.basicHeight) / transform.basicHeight },
54332             },
54333             vertexShader: Shaders.perspective.vertex,
54334         };
54335         return materialParameters;
54336     }
54337     _createPlaneMaterialParametersFisheye(transform, texture) {
54338         let materialParameters = {
54339             depthWrite: false,
54340             fragmentShader: Shaders.fisheye.fragment,
54341             side: DoubleSide,
54342             transparent: true,
54343             uniforms: {
54344                 focal: { value: transform.focal },
54345                 k1: { value: transform.ck1 },
54346                 k2: { value: transform.ck2 },
54347                 opacity: { value: 1.0 },
54348                 projectorMat: { value: transform.basicRt },
54349                 projectorTex: { value: texture },
54350                 radial_peak: { value: !!transform.radialPeak ? transform.radialPeak : 0.0 },
54351                 scale_x: { value: Math.max(transform.basicHeight, transform.basicWidth) / transform.basicWidth },
54352                 scale_y: { value: Math.max(transform.basicWidth, transform.basicHeight) / transform.basicHeight },
54353             },
54354             vertexShader: Shaders.fisheye.vertex,
54355         };
54356         return materialParameters;
54357     }
54358     _createCurtainPlaneMaterialParametersFisheye(transform, texture) {
54359         let materialParameters = {
54360             depthWrite: false,
54361             fragmentShader: Shaders.fisheyeCurtain.fragment,
54362             side: DoubleSide,
54363             transparent: true,
54364             uniforms: {
54365                 curtain: { value: 1.0 },
54366                 focal: { value: transform.focal },
54367                 k1: { value: transform.ck1 },
54368                 k2: { value: transform.ck2 },
54369                 opacity: { value: 1.0 },
54370                 projectorMat: { value: transform.basicRt },
54371                 projectorTex: { value: texture },
54372                 radial_peak: { value: !!transform.radialPeak ? transform.radialPeak : 0.0 },
54373                 scale_x: { value: Math.max(transform.basicHeight, transform.basicWidth) / transform.basicWidth },
54374                 scale_y: { value: Math.max(transform.basicWidth, transform.basicHeight) / transform.basicHeight },
54375             },
54376             vertexShader: Shaders.fisheyeCurtain.vertex,
54377         };
54378         return materialParameters;
54379     }
54380     _createCurtainPlaneMaterialParameters(transform, texture) {
54381         let materialParameters = {
54382             depthWrite: false,
54383             fragmentShader: Shaders.perspectiveCurtain.fragment,
54384             side: DoubleSide,
54385             transparent: true,
54386             uniforms: {
54387                 curtain: { value: 1.0 },
54388                 focal: { value: transform.focal },
54389                 k1: { value: transform.ck1 },
54390                 k2: { value: transform.ck2 },
54391                 opacity: { value: 1.0 },
54392                 projectorMat: { value: transform.basicRt },
54393                 projectorTex: { value: texture },
54394                 radial_peak: { value: !!transform.radialPeak ? transform.radialPeak : 0.0 },
54395                 scale_x: { value: Math.max(transform.basicHeight, transform.basicWidth) / transform.basicWidth },
54396                 scale_y: { value: Math.max(transform.basicWidth, transform.basicHeight) / transform.basicHeight },
54397             },
54398             vertexShader: Shaders.perspectiveCurtain.vertex,
54399         };
54400         return materialParameters;
54401     }
54402     _createDistortedCurtainPlaneMaterialParameters(transform, texture) {
54403         let materialParameters = {
54404             depthWrite: false,
54405             fragmentShader: Shaders.perspectiveDistortedCurtain.fragment,
54406             side: DoubleSide,
54407             transparent: true,
54408             uniforms: {
54409                 curtain: { value: 1.0 },
54410                 opacity: { value: 1.0 },
54411                 projectorMat: { value: transform.projectorMatrix() },
54412                 projectorTex: { value: texture },
54413             },
54414             vertexShader: Shaders.perspectiveDistortedCurtain.vertex,
54415         };
54416         return materialParameters;
54417     }
54418     _createDistortedPlaneMaterialParameters(transform, texture) {
54419         let materialParameters = {
54420             depthWrite: false,
54421             fragmentShader: Shaders.perspectiveDistorted.fragment,
54422             side: DoubleSide,
54423             transparent: true,
54424             uniforms: {
54425                 opacity: { value: 1.0 },
54426                 projectorMat: { value: transform.projectorMatrix() },
54427                 projectorTex: { value: texture },
54428             },
54429             vertexShader: Shaders.perspectiveDistorted.vertex,
54430         };
54431         return materialParameters;
54432     }
54433     _createTexture(image) {
54434         let texture = new Texture(image);
54435         texture.minFilter = LinearFilter;
54436         texture.needsUpdate = true;
54437         return texture;
54438     }
54439     _useMesh(transform, image) {
54440         return image.mesh.vertices.length && transform.hasValidScale;
54441     }
54442     _getImageSphereGeo(transform, image) {
54443         const t = transform.srtInverse;
54444         // push everything at least 5 meters in front of the camera
54445         let minZ = 5.0 * transform.scale;
54446         let maxZ = this._imageSphereRadius * transform.scale;
54447         let vertices = image.mesh.vertices;
54448         let numVertices = vertices.length / 3;
54449         let positions = new Float32Array(vertices.length);
54450         for (let i = 0; i < numVertices; ++i) {
54451             let index = 3 * i;
54452             let x = vertices[index + 0];
54453             let y = vertices[index + 1];
54454             let z = vertices[index + 2];
54455             let l = Math.sqrt(x * x + y * y + z * z);
54456             let boundedL = Math.max(minZ, Math.min(l, maxZ));
54457             let factor = boundedL / l;
54458             let p = new Vector3(x * factor, y * factor, z * factor);
54459             p.applyMatrix4(t);
54460             positions[index + 0] = p.x;
54461             positions[index + 1] = p.y;
54462             positions[index + 2] = p.z;
54463         }
54464         let faces = image.mesh.faces;
54465         let indices = new Uint16Array(faces.length);
54466         for (let i = 0; i < faces.length; ++i) {
54467             indices[i] = faces[i];
54468         }
54469         let geometry = new BufferGeometry();
54470         geometry.setAttribute("position", new BufferAttribute(positions, 3));
54471         geometry.setIndex(new BufferAttribute(indices, 1));
54472         return geometry;
54473     }
54474     _getImagePlaneGeo(transform, image) {
54475         const undistortionMarginFactor = 3;
54476         const t = transform.srtInverse;
54477         // push everything at least 5 meters in front of the camera
54478         let minZ = 5.0 * transform.scale;
54479         let maxZ = this._imagePlaneDepth * transform.scale;
54480         let vertices = image.mesh.vertices;
54481         let numVertices = vertices.length / 3;
54482         let positions = new Float32Array(vertices.length);
54483         for (let i = 0; i < numVertices; ++i) {
54484             let index = 3 * i;
54485             let x = vertices[index + 0];
54486             let y = vertices[index + 1];
54487             let z = vertices[index + 2];
54488             if (i < 4) {
54489                 x *= undistortionMarginFactor;
54490                 y *= undistortionMarginFactor;
54491             }
54492             let boundedZ = Math.max(minZ, Math.min(z, maxZ));
54493             let factor = boundedZ / z;
54494             let p = new Vector3(x * factor, y * factor, boundedZ);
54495             p.applyMatrix4(t);
54496             positions[index + 0] = p.x;
54497             positions[index + 1] = p.y;
54498             positions[index + 2] = p.z;
54499         }
54500         let faces = image.mesh.faces;
54501         let indices = new Uint16Array(faces.length);
54502         for (let i = 0; i < faces.length; ++i) {
54503             indices[i] = faces[i];
54504         }
54505         let geometry = new BufferGeometry();
54506         geometry.setAttribute("position", new BufferAttribute(positions, 3));
54507         geometry.setIndex(new BufferAttribute(indices, 1));
54508         return geometry;
54509     }
54510     _getImagePlaneGeoFisheye(transform, image) {
54511         const t = transform.srtInverse;
54512         // push everything at least 5 meters in front of the camera
54513         let minZ = 5.0 * transform.scale;
54514         let maxZ = this._imagePlaneDepth * transform.scale;
54515         let vertices = image.mesh.vertices;
54516         let numVertices = vertices.length / 3;
54517         let positions = new Float32Array(vertices.length);
54518         for (let i = 0; i < numVertices; ++i) {
54519             let index = 3 * i;
54520             let x = vertices[index + 0];
54521             let y = vertices[index + 1];
54522             let z = vertices[index + 2];
54523             let l = Math.sqrt(x * x + y * y + z * z);
54524             let boundedL = Math.max(minZ, Math.min(l, maxZ));
54525             let factor = boundedL / l;
54526             let p = new Vector3(x * factor, y * factor, z * factor);
54527             p.applyMatrix4(t);
54528             positions[index + 0] = p.x;
54529             positions[index + 1] = p.y;
54530             positions[index + 2] = p.z;
54531         }
54532         let faces = image.mesh.faces;
54533         let indices = new Uint16Array(faces.length);
54534         for (let i = 0; i < faces.length; ++i) {
54535             indices[i] = faces[i];
54536         }
54537         let geometry = new BufferGeometry();
54538         geometry.setAttribute("position", new BufferAttribute(positions, 3));
54539         geometry.setIndex(new BufferAttribute(indices, 1));
54540         return geometry;
54541     }
54542     _getFlatImageSphereGeo(transform) {
54543         const geometry = new SphereGeometry(this._imageSphereRadius, 20, 40);
54544         const t = transform.rt
54545             .clone()
54546             .invert();
54547         geometry.applyMatrix4(t);
54548         return geometry;
54549     }
54550     _getRegularFlatImagePlaneGeo(transform) {
54551         let width = transform.width;
54552         let height = transform.height;
54553         let size = Math.max(width, height);
54554         let dx = width / 2.0 / size;
54555         let dy = height / 2.0 / size;
54556         return this._getFlatImagePlaneGeo(transform, dx, dy);
54557     }
54558     _getFlatImagePlaneGeo(transform, dx, dy) {
54559         let vertices = [];
54560         vertices.push(transform.unprojectSfM([-dx, -dy], this._imagePlaneDepth));
54561         vertices.push(transform.unprojectSfM([dx, -dy], this._imagePlaneDepth));
54562         vertices.push(transform.unprojectSfM([dx, dy], this._imagePlaneDepth));
54563         vertices.push(transform.unprojectSfM([-dx, dy], this._imagePlaneDepth));
54564         return this._createFlatGeometry(vertices);
54565     }
54566     _getRegularFlatImagePlaneGeoFisheye(transform) {
54567         let width = transform.width;
54568         let height = transform.height;
54569         let size = Math.max(width, height);
54570         let dx = width / 2.0 / size;
54571         let dy = height / 2.0 / size;
54572         return this._getFlatImagePlaneGeoFisheye(transform, dx, dy);
54573     }
54574     _getFlatImagePlaneGeoFisheye(transform, dx, dy) {
54575         let vertices = [];
54576         vertices.push(transform.unprojectSfM([-dx, -dy], this._imagePlaneDepth));
54577         vertices.push(transform.unprojectSfM([dx, -dy], this._imagePlaneDepth));
54578         vertices.push(transform.unprojectSfM([dx, dy], this._imagePlaneDepth));
54579         vertices.push(transform.unprojectSfM([-dx, dy], this._imagePlaneDepth));
54580         return this._createFlatGeometry(vertices);
54581     }
54582     _getFlatImagePlaneGeoFromBasic(transform, basicX0, basicX1, basicY0, basicY1) {
54583         let vertices = [];
54584         vertices.push(transform.unprojectBasic([basicX0, basicY0], this._imagePlaneDepth));
54585         vertices.push(transform.unprojectBasic([basicX1, basicY0], this._imagePlaneDepth));
54586         vertices.push(transform.unprojectBasic([basicX1, basicY1], this._imagePlaneDepth));
54587         vertices.push(transform.unprojectBasic([basicX0, basicY1], this._imagePlaneDepth));
54588         return this._createFlatGeometry(vertices);
54589     }
54590     _createFlatGeometry(vertices) {
54591         let positions = new Float32Array(12);
54592         for (let i = 0; i < vertices.length; i++) {
54593             let index = 3 * i;
54594             positions[index + 0] = vertices[i][0];
54595             positions[index + 1] = vertices[i][1];
54596             positions[index + 2] = vertices[i][2];
54597         }
54598         let indices = new Uint16Array(6);
54599         indices[0] = 0;
54600         indices[1] = 1;
54601         indices[2] = 3;
54602         indices[3] = 1;
54603         indices[4] = 2;
54604         indices[5] = 3;
54605         let geometry = new BufferGeometry();
54606         geometry.setAttribute("position", new BufferAttribute(positions, 3));
54607         geometry.setIndex(new BufferAttribute(indices, 1));
54608         return geometry;
54609     }
54610 }
54611
54612 class MeshScene {
54613     constructor() {
54614         this._planes = {};
54615         this._planesOld = {};
54616         this._planesPeriphery = {};
54617         this._scene = new Scene();
54618         this._sceneOld = new Scene();
54619         this._scenePeriphery = new Scene();
54620     }
54621     get planes() {
54622         return this._planes;
54623     }
54624     get planesOld() {
54625         return this._planesOld;
54626     }
54627     get planesPeriphery() {
54628         return this._planesPeriphery;
54629     }
54630     get scene() {
54631         return this._scene;
54632     }
54633     get sceneOld() {
54634         return this._sceneOld;
54635     }
54636     get scenePeriphery() {
54637         return this._scenePeriphery;
54638     }
54639     updateImagePlanes(planes) {
54640         this._dispose(this._planesOld, this.sceneOld);
54641         for (const key in this._planes) {
54642             if (!this._planes.hasOwnProperty(key)) {
54643                 continue;
54644             }
54645             const plane = this._planes[key];
54646             this._scene.remove(plane);
54647             this._sceneOld.add(plane);
54648         }
54649         for (const key in planes) {
54650             if (!planes.hasOwnProperty(key)) {
54651                 continue;
54652             }
54653             this._scene.add(planes[key]);
54654         }
54655         this._planesOld = this._planes;
54656         this._planes = planes;
54657     }
54658     addImagePlanes(planes) {
54659         for (const key in planes) {
54660             if (!planes.hasOwnProperty(key)) {
54661                 continue;
54662             }
54663             const plane = planes[key];
54664             this._scene.add(plane);
54665             this._planes[key] = plane;
54666         }
54667     }
54668     addImagePlanesOld(planes) {
54669         for (const key in planes) {
54670             if (!planes.hasOwnProperty(key)) {
54671                 continue;
54672             }
54673             const plane = planes[key];
54674             this._sceneOld.add(plane);
54675             this._planesOld[key] = plane;
54676         }
54677     }
54678     setImagePlanes(planes) {
54679         this._clear();
54680         this.addImagePlanes(planes);
54681     }
54682     addPeripheryPlanes(planes) {
54683         for (const key in planes) {
54684             if (!planes.hasOwnProperty(key)) {
54685                 continue;
54686             }
54687             const plane = planes[key];
54688             this._scenePeriphery.add(plane);
54689             this._planesPeriphery[key] = plane;
54690         }
54691     }
54692     setPeripheryPlanes(planes) {
54693         this._clearPeriphery();
54694         this.addPeripheryPlanes(planes);
54695     }
54696     setImagePlanesOld(planes) {
54697         this._clearOld();
54698         this.addImagePlanesOld(planes);
54699     }
54700     clear() {
54701         this._clear();
54702         this._clearOld();
54703     }
54704     _clear() {
54705         this._dispose(this._planes, this._scene);
54706         this._planes = {};
54707     }
54708     _clearOld() {
54709         this._dispose(this._planesOld, this._sceneOld);
54710         this._planesOld = {};
54711     }
54712     _clearPeriphery() {
54713         this._dispose(this._planesPeriphery, this._scenePeriphery);
54714         this._planesPeriphery = {};
54715     }
54716     _dispose(planes, scene) {
54717         for (const key in planes) {
54718             if (!planes.hasOwnProperty(key)) {
54719                 continue;
54720             }
54721             const plane = planes[key];
54722             scene.remove(plane);
54723             plane.geometry.dispose();
54724             plane.material.dispose();
54725             let texture = plane.material.uniforms.projectorTex.value;
54726             if (texture != null) {
54727                 texture.dispose();
54728             }
54729         }
54730     }
54731 }
54732
54733 class ImageGLRenderer {
54734     constructor() {
54735         this._factory = new MeshFactory();
54736         this._scene = new MeshScene();
54737         this._alpha = 0;
54738         this._alphaOld = 0;
54739         this._fadeOutSpeed = 0.05;
54740         this._currentKey = null;
54741         this._previousKey = null;
54742         this._providerDisposers = {};
54743         this._frameId = 0;
54744         this._needsRender = false;
54745     }
54746     get frameId() {
54747         return this._frameId;
54748     }
54749     get needsRender() {
54750         return this._needsRender;
54751     }
54752     indicateNeedsRender() {
54753         this._needsRender = true;
54754     }
54755     addPeripheryPlane(image, transform) {
54756         const mesh = this._factory.createMesh(image, transform);
54757         const planes = {};
54758         planes[image.id] = mesh;
54759         this._scene.addPeripheryPlanes(planes);
54760         this._needsRender = true;
54761     }
54762     clearPeripheryPlanes() {
54763         this._scene.setPeripheryPlanes({});
54764         this._needsRender = true;
54765     }
54766     updateFrame(frame) {
54767         this._updateFrameId(frame.id);
54768         this._needsRender = this._updateAlpha(frame.state.alpha) || this._needsRender;
54769         this._needsRender = this._updateAlphaOld(frame.state.alpha) || this._needsRender;
54770         this._needsRender = this._updateImagePlanes(frame.state) || this._needsRender;
54771     }
54772     setTextureProvider(key, provider) {
54773         if (key !== this._currentKey) {
54774             return;
54775         }
54776         let createdSubscription = provider.textureCreated$
54777             .subscribe((texture) => {
54778             this._updateTexture(texture);
54779         });
54780         let updatedSubscription = provider.textureUpdated$
54781             .subscribe((updated) => {
54782             this._needsRender = true;
54783         });
54784         let dispose = () => {
54785             createdSubscription.unsubscribe();
54786             updatedSubscription.unsubscribe();
54787             provider.dispose();
54788         };
54789         if (key in this._providerDisposers) {
54790             let disposeProvider = this._providerDisposers[key];
54791             disposeProvider();
54792             delete this._providerDisposers[key];
54793         }
54794         this._providerDisposers[key] = dispose;
54795     }
54796     updateTextureImage(imageElement, image) {
54797         this._needsRender = true;
54798         const planes = this._extend({}, this._scene.planes, this._scene.planesOld, this._scene.planesPeriphery);
54799         for (const key in planes) {
54800             if (!planes.hasOwnProperty(key)) {
54801                 continue;
54802             }
54803             if (key !== image.id) {
54804                 continue;
54805             }
54806             const plane = planes[key];
54807             let material = plane.material;
54808             let texture = material.uniforms.projectorTex.value;
54809             texture.image = imageElement;
54810             texture.needsUpdate = true;
54811         }
54812     }
54813     render(perspectiveCamera, renderer) {
54814         const planes = this._scene.planes;
54815         const planesOld = this._scene.planesOld;
54816         const planesPeriphery = this._scene.planesPeriphery;
54817         const planeAlpha = Object.keys(planesOld).length ? 1 : this._alpha;
54818         const peripheryAlpha = Object.keys(planesOld).length ? 1 : Math.floor(this._alpha);
54819         for (const key in planes) {
54820             if (!planes.hasOwnProperty(key)) {
54821                 continue;
54822             }
54823             const plane = planes[key];
54824             plane.material.uniforms.opacity.value = planeAlpha;
54825         }
54826         for (const key in planesOld) {
54827             if (!planesOld.hasOwnProperty(key)) {
54828                 continue;
54829             }
54830             const plane = planesOld[key];
54831             plane.material.uniforms.opacity.value = this._alphaOld;
54832         }
54833         for (const key in planesPeriphery) {
54834             if (!planesPeriphery.hasOwnProperty(key)) {
54835                 continue;
54836             }
54837             const plane = planesPeriphery[key];
54838             plane.material.uniforms.opacity.value = peripheryAlpha;
54839         }
54840         renderer.render(this._scene.scenePeriphery, perspectiveCamera);
54841         renderer.render(this._scene.scene, perspectiveCamera);
54842         renderer.render(this._scene.sceneOld, perspectiveCamera);
54843         for (const key in planes) {
54844             if (!planes.hasOwnProperty(key)) {
54845                 continue;
54846             }
54847             const plane = planes[key];
54848             plane.material.uniforms.opacity.value = this._alpha;
54849         }
54850         renderer.render(this._scene.scene, perspectiveCamera);
54851     }
54852     clearNeedsRender() {
54853         this._needsRender = false;
54854     }
54855     dispose() {
54856         this._scene.clear();
54857     }
54858     _updateFrameId(frameId) {
54859         this._frameId = frameId;
54860     }
54861     _updateAlpha(alpha) {
54862         if (alpha === this._alpha) {
54863             return false;
54864         }
54865         this._alpha = alpha;
54866         return true;
54867     }
54868     _updateAlphaOld(alpha) {
54869         if (alpha < 1 || this._alphaOld === 0) {
54870             return false;
54871         }
54872         this._alphaOld = Math.max(0, this._alphaOld - this._fadeOutSpeed);
54873         return true;
54874     }
54875     _updateImagePlanes(state) {
54876         if (state.currentImage == null ||
54877             state.currentImage.id === this._currentKey) {
54878             return false;
54879         }
54880         let previousKey = state.previousImage != null ? state.previousImage.id : null;
54881         let currentKey = state.currentImage.id;
54882         if (this._previousKey !== previousKey &&
54883             this._previousKey !== currentKey &&
54884             this._previousKey in this._providerDisposers) {
54885             let disposeProvider = this._providerDisposers[this._previousKey];
54886             disposeProvider();
54887             delete this._providerDisposers[this._previousKey];
54888         }
54889         if (previousKey != null) {
54890             if (previousKey !== this._currentKey && previousKey !== this._previousKey) {
54891                 let previousMesh = this._factory.createMesh(state.previousImage, state.previousTransform);
54892                 const previousPlanes = {};
54893                 previousPlanes[previousKey] = previousMesh;
54894                 this._scene.updateImagePlanes(previousPlanes);
54895             }
54896             this._previousKey = previousKey;
54897         }
54898         this._currentKey = currentKey;
54899         let currentMesh = this._factory.createMesh(state.currentImage, state.currentTransform);
54900         const planes = {};
54901         planes[currentKey] = currentMesh;
54902         this._scene.updateImagePlanes(planes);
54903         this._alphaOld = 1;
54904         return true;
54905     }
54906     _updateTexture(texture) {
54907         this._needsRender = true;
54908         const planes = this._scene.planes;
54909         for (const key in planes) {
54910             if (!planes.hasOwnProperty(key)) {
54911                 continue;
54912             }
54913             const plane = planes[key];
54914             let material = plane.material;
54915             let oldTexture = material.uniforms.projectorTex.value;
54916             material.uniforms.projectorTex.value = null;
54917             oldTexture.dispose();
54918             material.uniforms.projectorTex.value = texture;
54919         }
54920     }
54921     _extend(dest, ...sources) {
54922         for (const src of sources) {
54923             for (const k in src) {
54924                 if (!src.hasOwnProperty(k)) {
54925                     continue;
54926                 }
54927                 dest[k] = src[k];
54928             }
54929         }
54930         return dest;
54931     }
54932 }
54933
54934 var RenderPass$1;
54935 (function (RenderPass) {
54936     RenderPass[RenderPass["Background"] = 0] = "Background";
54937     RenderPass[RenderPass["Opaque"] = 1] = "Opaque";
54938 })(RenderPass$1 || (RenderPass$1 = {}));
54939
54940 /**
54941  * @class ImageTileLoader
54942  *
54943  * @classdesc Represents a loader of image tiles.
54944  */
54945 class TileLoader {
54946     /**
54947      * Create a new image image tile loader instance.
54948      *
54949      * @param {APIWrapper} _api - API wrapper.
54950      */
54951     constructor(_api) {
54952         this._api = _api;
54953         this._urls$ = new Map();
54954     }
54955     /**
54956      * Retrieve an image tile.
54957      *
54958      * @param {string} url - URL to the image tile resource
54959      */
54960     getImage$(url) {
54961         let aborter;
54962         const abort = new Promise((_, reject) => {
54963             aborter = reject;
54964         });
54965         return [Observable.create((subscriber) => {
54966                 this._api.data
54967                     .getImageBuffer(url, abort)
54968                     .then((buffer) => {
54969                     aborter = null;
54970                     const image = new Image();
54971                     image.crossOrigin = "Anonymous";
54972                     image.onload = () => {
54973                         window.URL.revokeObjectURL(image.src);
54974                         subscriber.next(image);
54975                         subscriber.complete();
54976                     };
54977                     image.onerror = () => {
54978                         aborter = null;
54979                         window.URL.revokeObjectURL(image.src);
54980                         subscriber.error(new Error(`Failed to load image tile`));
54981                     };
54982                     const blob = new Blob([buffer]);
54983                     image.src = window.URL.createObjectURL(blob);
54984                 }, (error) => {
54985                     aborter = null;
54986                     subscriber.error(error);
54987                 });
54988             }),
54989             () => {
54990                 if (!!aborter) {
54991                     aborter();
54992                 }
54993             }];
54994     }
54995     getURLs$(imageId, level) {
54996         const uniqueId = this._inventId(imageId, level);
54997         if (this._urls$.has(uniqueId)) {
54998             return this._urls$.get(uniqueId);
54999         }
55000         const request = { imageId, z: level };
55001         const urls$ = this._api
55002             .getImageTiles$(request)
55003             .pipe(map(contract => contract.node), finalize(() => {
55004             this._urls$.delete(uniqueId);
55005         }), publish(), refCount());
55006         this._urls$.set(uniqueId, urls$);
55007         return urls$;
55008     }
55009     _inventId(imageId, level) {
55010         return `${imageId}-${level}`;
55011     }
55012 }
55013
55014 /**
55015  * @class ImageTileStore
55016  *
55017  * @classdesc Represents a store for image tiles.
55018  */
55019 class TileStore {
55020     /**
55021      * Create a new image image tile store instance.
55022      */
55023     constructor() {
55024         this._tiles = new Map();
55025         this._urlLevels = new Set();
55026         this._urls = new Map();
55027     }
55028     /**
55029      * Add an image tile to the store.
55030      *
55031      * @param {string} id - The identifier for the image tile.
55032      * @param {HTMLImageElement} image - The image tile.
55033      */
55034     add(id, image) {
55035         if (this._tiles.has(id)) {
55036             throw new Error(`Image tile already stored (${id})`);
55037         }
55038         this._tiles.set(id, image);
55039     }
55040     addURLs(level, ents) {
55041         const urls = this._urls;
55042         for (const ent of ents) {
55043             const id = this.inventId(ent);
55044             if (this._urls.has(id)) {
55045                 throw new Error(`URL already stored (${id})`);
55046             }
55047             urls.set(id, ent.url);
55048         }
55049         this._urlLevels.add(level);
55050     }
55051     /**
55052      * Dispose the store.
55053      *
55054      * @description Disposes all cached assets.
55055      */
55056     dispose() {
55057         this._tiles
55058             .forEach(image => window.URL.revokeObjectURL(image.src));
55059         this._tiles.clear();
55060         this._urls.clear();
55061         this._urlLevels.clear();
55062     }
55063     /**
55064      * Get an image tile from the store.
55065      *
55066      * @param {string} id - The identifier for the tile.
55067      * @param {number} level - The level of the tile.
55068      */
55069     get(id) {
55070         return this._tiles.get(id);
55071     }
55072     getURL(id) {
55073         return this._urls.get(id);
55074     }
55075     /**
55076      * Check if an image tile exist in the store.
55077      *
55078      * @param {string} id - The identifier for the tile.
55079      * @param {number} level - The level of the tile.
55080      */
55081     has(id) {
55082         return this._tiles.has(id);
55083     }
55084     hasURL(id) {
55085         return this._urls.has(id);
55086     }
55087     hasURLLevel(level) {
55088         return this._urlLevels.has(level);
55089     }
55090     /**
55091      * Create a unique tile id from a tile.
55092      *
55093      * @description Tile ids are used as a hash for
55094      * storing the tile in a dictionary.
55095      *
55096      * @param {ImageTileEnt} tile - The tile.
55097      * @returns {string} Unique id.
55098      */
55099     inventId(tile) {
55100         return `${tile.z}-${tile.x}-${tile.y}`;
55101     }
55102 }
55103
55104 /**
55105  * @class RegionOfInterestCalculator
55106  *
55107  * @classdesc Represents a calculator for regions of interest.
55108  */
55109 class RegionOfInterestCalculator {
55110     constructor() {
55111         this._viewportCoords = new ViewportCoords();
55112     }
55113     /**
55114      * Compute a region of interest based on the current render camera
55115      * and the viewport size.
55116      *
55117      * @param {RenderCamera} renderCamera - Render camera used for unprojections.
55118      * @param {ViewportSize} size - Viewport size in pixels.
55119      * @param {Transform} transform - Transform used for projections.
55120      *
55121      * @returns {TileRegionOfInterest} A region of interest.
55122      */
55123     computeRegionOfInterest(renderCamera, size, transform) {
55124         const viewportBoundaryPoints = this._viewportBoundaryPoints(4);
55125         const bbox = this._viewportPointsBoundingBox(viewportBoundaryPoints, renderCamera, transform);
55126         this._clipBoundingBox(bbox);
55127         const viewportPixelWidth = 2 / size.width;
55128         const viewportPixelHeight = 2 / size.height;
55129         const centralViewportPixel = [
55130             [-0.5 * viewportPixelWidth, 0.5 * viewportPixelHeight],
55131             [0.5 * viewportPixelWidth, 0.5 * viewportPixelHeight],
55132             [0.5 * viewportPixelWidth, -0.5 * viewportPixelHeight],
55133             [-0.5 * viewportPixelWidth, -0.5 * viewportPixelHeight],
55134         ];
55135         const cpbox = this._viewportPointsBoundingBox(centralViewportPixel, renderCamera, transform);
55136         const inverted = cpbox.minX < cpbox.maxX;
55137         return {
55138             bbox: bbox,
55139             pixelHeight: cpbox.maxY - cpbox.minY,
55140             pixelWidth: cpbox.maxX - cpbox.minX + (inverted ? 0 : 1),
55141         };
55142     }
55143     _viewportBoundaryPoints(pointsPerSide) {
55144         const points = [];
55145         const os = [[-1, 1], [1, 1], [1, -1], [-1, -1]];
55146         const ds = [[2, 0], [0, -2], [-2, 0], [0, 2]];
55147         for (let side = 0; side < 4; ++side) {
55148             const o = os[side];
55149             const d = ds[side];
55150             for (let i = 0; i < pointsPerSide; ++i) {
55151                 points.push([o[0] + d[0] * i / pointsPerSide,
55152                     o[1] + d[1] * i / pointsPerSide]);
55153             }
55154         }
55155         return points;
55156     }
55157     _viewportPointsBoundingBox(viewportPoints, renderCamera, transform) {
55158         const basicPoints = viewportPoints
55159             .map((point) => {
55160             return this._viewportCoords
55161                 .viewportToBasic(point[0], point[1], transform, renderCamera.perspective);
55162         });
55163         if (isSpherical(transform.cameraType)) {
55164             return this._boundingBoxSpherical(basicPoints);
55165         }
55166         else {
55167             return this._boundingBox(basicPoints);
55168         }
55169     }
55170     _boundingBox(points) {
55171         const bbox = {
55172             maxX: Number.NEGATIVE_INFINITY,
55173             maxY: Number.NEGATIVE_INFINITY,
55174             minX: Number.POSITIVE_INFINITY,
55175             minY: Number.POSITIVE_INFINITY,
55176         };
55177         for (let i = 0; i < points.length; ++i) {
55178             bbox.minX = Math.min(bbox.minX, points[i][0]);
55179             bbox.maxX = Math.max(bbox.maxX, points[i][0]);
55180             bbox.minY = Math.min(bbox.minY, points[i][1]);
55181             bbox.maxY = Math.max(bbox.maxY, points[i][1]);
55182         }
55183         return bbox;
55184     }
55185     _boundingBoxSpherical(points) {
55186         const xs = [];
55187         const ys = [];
55188         for (let i = 0; i < points.length; ++i) {
55189             xs.push(points[i][0]);
55190             ys.push(points[i][1]);
55191         }
55192         xs.sort((a, b) => { return this._sign(a - b); });
55193         ys.sort((a, b) => { return this._sign(a - b); });
55194         const intervalX = this._intervalSpherical(xs);
55195         return {
55196             maxX: intervalX[1],
55197             maxY: ys[ys.length - 1],
55198             minX: intervalX[0],
55199             minY: ys[0],
55200         };
55201     }
55202     /**
55203      * Find the max interval between consecutive numbers.
55204      * Assumes numbers are between 0 and 1, sorted and that
55205      * x is equivalent to x + 1.
55206      */
55207     _intervalSpherical(xs) {
55208         let maxdx = 0;
55209         let maxi = -1;
55210         for (let i = 0; i < xs.length - 1; ++i) {
55211             const dx = xs[i + 1] - xs[i];
55212             if (dx > maxdx) {
55213                 maxdx = dx;
55214                 maxi = i;
55215             }
55216         }
55217         const loopdx = xs[0] + 1 - xs[xs.length - 1];
55218         if (loopdx > maxdx) {
55219             return [xs[0], xs[xs.length - 1]];
55220         }
55221         else {
55222             return [xs[maxi + 1], xs[maxi]];
55223         }
55224     }
55225     _clipBoundingBox(bbox) {
55226         bbox.minX = Math.max(0, Math.min(1, bbox.minX));
55227         bbox.maxX = Math.max(0, Math.min(1, bbox.maxX));
55228         bbox.minY = Math.max(0, Math.min(1, bbox.minY));
55229         bbox.maxY = Math.max(0, Math.min(1, bbox.maxY));
55230     }
55231     _sign(n) {
55232         return n > 0 ? 1 : n < 0 ? -1 : 0;
55233     }
55234 }
55235
55236 const TILE_MIN_REQUEST_LEVEL = 11;
55237 const TILE_SIZE = 1024;
55238
55239 function clamp(value, min, max) {
55240     return Math.max(min, Math.min(max, value));
55241 }
55242 function levelTilePixelSize(level) {
55243     return TILE_SIZE / levelScale(level);
55244 }
55245 function levelScale(level) {
55246     return Math.pow(2, level.z - level.max);
55247 }
55248 function rawImageLevel(size) {
55249     const s = Math.max(size.w, size.h);
55250     return Math.log(s) / Math.log(2);
55251 }
55252 function baseImageLevel(size) {
55253     return Math.ceil(rawImageLevel(size));
55254 }
55255 function clampedImageLevel(size, min, max) {
55256     return Math.max(min, Math.min(max, baseImageLevel(size)));
55257 }
55258 function basicToTileCoords2D(basic, size, level) {
55259     const tilePixelSize = levelTilePixelSize(level);
55260     const w = size.w;
55261     const h = size.h;
55262     const maxX = Math.ceil(w / tilePixelSize) - 1;
55263     const maxY = Math.ceil(h / tilePixelSize) - 1;
55264     const x = clamp(Math.floor(w * basic[0] / tilePixelSize), 0, maxX);
55265     const y = clamp(Math.floor(h * basic[1] / tilePixelSize), 0, maxY);
55266     return { x, y };
55267 }
55268 function tileToPixelCoords2D(tile, size, level) {
55269     const scale = 1 / levelScale(level);
55270     const scaledTS = scale * TILE_SIZE;
55271     const x = scaledTS * tile.x;
55272     const y = scaledTS * tile.y;
55273     const w = Math.min(scaledTS, size.w - x);
55274     const h = Math.min(scaledTS, size.h - y);
55275     return { h, x, y, w };
55276 }
55277 function hasOverlap1D(low, base, scale) {
55278     return (scale * low <= base &&
55279         base < scale * (low + 1));
55280 }
55281 function hasOverlap2D(tile1, tile2) {
55282     if (tile1.z === tile2.z) {
55283         return tile1.x === tile2.x && tile1.y === tile2.y;
55284     }
55285     const low = tile1.z < tile2.z ? tile1 : tile2;
55286     const base = tile1.z < tile2.z ? tile2 : tile1;
55287     const scale = 1 / levelScale({ max: base.z, z: low.z });
55288     const overlapX = hasOverlap1D(low.x, base.x, scale);
55289     const overlapY = hasOverlap1D(low.y, base.y, scale);
55290     return overlapX && overlapY;
55291 }
55292 function cornersToTilesCoords2D(topLeft, bottomRight, size, level) {
55293     const xs = [];
55294     if (topLeft.x > bottomRight.x) {
55295         const tilePixelSize = levelTilePixelSize(level);
55296         const maxX = Math.ceil(size.w / tilePixelSize) - 1;
55297         for (let x = topLeft.x; x <= maxX; x++) {
55298             xs.push(x);
55299         }
55300         for (let x = 0; x <= bottomRight.x; x++) {
55301             xs.push(x);
55302         }
55303     }
55304     else {
55305         for (let x = topLeft.x; x <= bottomRight.x; x++) {
55306             xs.push(x);
55307         }
55308     }
55309     const tiles = [];
55310     for (const x of xs) {
55311         for (let y = topLeft.y; y <= bottomRight.y; y++) {
55312             tiles.push({ x, y });
55313         }
55314     }
55315     return tiles;
55316 }
55317 function verifySize(size) {
55318     return size.w > 0 && size.h > 0;
55319 }
55320
55321 /**
55322  * @class TextureProvider
55323  *
55324  * @classdesc Represents a provider of textures.
55325  */
55326 class TextureProvider {
55327     /**
55328      * Create a new image texture provider instance.
55329      *
55330      * @param {string} imageId - The identifier of the image for which to request tiles.
55331      * @param {number} width - The full width of the original image.
55332      * @param {number} height - The full height of the original image.
55333      * @param {HTMLImageElement} background - Image to use as background.
55334      * @param {TileLoader} loader - Loader for retrieving tiles.
55335      * @param {TileStore} store - Store for saving tiles.
55336      * @param {THREE.WebGLRenderer} renderer - Renderer used for rendering tiles to texture.
55337      */
55338     constructor(imageId, width, height, background, loader, store, renderer) {
55339         const size = { h: height, w: width };
55340         if (!verifySize(size)) {
55341             console.warn(`Original image size (${width}, ${height}) ` +
55342                 `is invalid (${imageId}). Tiles will not be loaded.`);
55343         }
55344         this._imageId = imageId;
55345         this._size = size;
55346         this._level = {
55347             max: baseImageLevel(this._size),
55348             z: -1,
55349         };
55350         this._holder = new SubscriptionHolder();
55351         this._updated$ = new Subject();
55352         this._createdSubject$ = new Subject();
55353         this._created$ = this._createdSubject$
55354             .pipe(publishReplay(1), refCount());
55355         this._holder.push(this._created$.subscribe(() => { }));
55356         this._hasSubject$ = new Subject();
55357         this._has$ = this._hasSubject$
55358             .pipe(startWith(false), publishReplay(1), refCount());
55359         this._holder.push(this._has$.subscribe(() => { }));
55360         this._renderedLevel = new Set();
55361         this._rendered = new Map();
55362         this._subscriptions = new Map();
55363         this._urlSubscriptions = new Map();
55364         this._loader = loader;
55365         this._store = store;
55366         this._background = background;
55367         this._renderer = renderer;
55368         this._aborts = [];
55369         this._render = null;
55370         this._disposed = false;
55371     }
55372     /**
55373      * Get disposed.
55374      *
55375      * @returns {boolean} Value indicating whether provider has
55376      * been disposed.
55377      */
55378     get disposed() {
55379         return this._disposed;
55380     }
55381     /**
55382      * Get hasTexture$.
55383      *
55384      * @returns {Observable<boolean>} Observable emitting
55385      * values indicating when the existance of a texture
55386      * changes.
55387      */
55388     get hasTexture$() {
55389         return this._has$;
55390     }
55391     /**
55392      * Get id.
55393      *
55394      * @returns {boolean} The identifier of the image for
55395      * which to render textures.
55396      */
55397     get id() {
55398         return this._imageId;
55399     }
55400     /**
55401      * Get textureUpdated$.
55402      *
55403      * @returns {Observable<boolean>} Observable emitting
55404      * values when an existing texture has been updated.
55405      */
55406     get textureUpdated$() {
55407         return this._updated$;
55408     }
55409     /**
55410      * Get textureCreated$.
55411      *
55412      * @returns {Observable<boolean>} Observable emitting
55413      * values when a new texture has been created.
55414      */
55415     get textureCreated$() {
55416         return this._created$;
55417     }
55418     /**
55419      * Abort all outstanding image tile requests.
55420      */
55421     abort() {
55422         this._subscriptions.forEach(sub => sub.unsubscribe());
55423         this._subscriptions.clear();
55424         for (const abort of this._aborts) {
55425             abort();
55426         }
55427         this._aborts = [];
55428     }
55429     /**
55430      * Dispose the provider.
55431      *
55432      * @description Disposes all cached assets and
55433      * aborts all outstanding image tile requests.
55434      */
55435     dispose() {
55436         if (this._disposed) {
55437             console.warn(`Texture already disposed (${this._imageId})`);
55438             return;
55439         }
55440         this._urlSubscriptions.forEach(sub => sub.unsubscribe());
55441         this._urlSubscriptions.clear();
55442         this.abort();
55443         if (this._render != null) {
55444             this._render.target.dispose();
55445             this._render.target = null;
55446             this._render.camera = null;
55447             this._render = null;
55448         }
55449         this._store.dispose();
55450         this._holder.unsubscribe();
55451         this._renderedLevel.clear();
55452         this._background = null;
55453         this._renderer = null;
55454         this._disposed = true;
55455     }
55456     /**
55457      * Set the region of interest.
55458      *
55459      * @description When the region of interest is set the
55460      * the tile level is determined and tiles for the region
55461      * are fetched from the store or the loader and renderedLevel
55462      * to the texture.
55463      *
55464      * @param {TileRegionOfInterest} roi - Spatial edges to cache.
55465      */
55466     setRegionOfInterest(roi) {
55467         if (!verifySize(this._size)) {
55468             return;
55469         }
55470         const virtualWidth = 1 / roi.pixelWidth;
55471         const virtualHeight = 1 / roi.pixelHeight;
55472         const level = clampedImageLevel({ h: virtualHeight, w: virtualWidth }, TILE_MIN_REQUEST_LEVEL, this._level.max);
55473         if (level !== this._level.z) {
55474             this.abort();
55475             this._level.z = level;
55476             this._renderedLevel.clear();
55477             this._rendered
55478                 .forEach((tile, id) => {
55479                 if (tile.z !== level) {
55480                     return;
55481                 }
55482                 this._renderedLevel.add(id);
55483             });
55484         }
55485         if (this._render == null) {
55486             this._initRender();
55487         }
55488         const topLeft = basicToTileCoords2D([roi.bbox.minX, roi.bbox.minY], this._size, this._level);
55489         const bottomRight = basicToTileCoords2D([roi.bbox.maxX, roi.bbox.maxY], this._size, this._level);
55490         const tiles = cornersToTilesCoords2D(topLeft, bottomRight, this._size, this._level);
55491         this._fetchTiles(level, tiles);
55492     }
55493     /**
55494      * Retrieve an image tile.
55495      *
55496      * @description Retrieve an image tile and render it to the
55497      * texture. Add the tile to the store and emit to the updated
55498      * observable.
55499      *
55500      * @param {ImageTileEnt} tile - The tile ent.
55501      */
55502     _fetchTile(tile) {
55503         const getTile = this._loader.getImage$(tile.url);
55504         const tile$ = getTile[0];
55505         const abort = getTile[1];
55506         this._aborts.push(abort);
55507         const tileId = this._store.inventId(tile);
55508         const subscription = tile$.subscribe((image) => {
55509             const pixels = tileToPixelCoords2D(tile, this._size, this._level);
55510             this._renderToTarget(pixels, image);
55511             this._subscriptions.delete(tileId);
55512             this._removeFromArray(abort, this._aborts);
55513             this._markRendered(tile);
55514             this._store.add(tileId, image);
55515             this._updated$.next(true);
55516         }, (error) => {
55517             this._subscriptions.delete(tileId);
55518             this._removeFromArray(abort, this._aborts);
55519             console.error(error);
55520         });
55521         if (!subscription.closed) {
55522             this._subscriptions.set(tileId, subscription);
55523         }
55524     }
55525     /**
55526      * Fetch image tiles.
55527      *
55528      * @description Retrieve a image tiles and render them to the
55529      * texture. Retrieve from store if it exists, otherwise retrieve
55530      * from loader.
55531      *
55532      * @param {Array<TileCoords2D>} tiles - Array of tile coordinates to
55533      * retrieve.
55534      */
55535     _fetchTiles(level, tiles) {
55536         const urls$ = this._store.hasURLLevel(level) ?
55537             of(undefined) :
55538             this._loader
55539                 .getURLs$(this._imageId, level)
55540                 .pipe(tap(ents => {
55541                 if (!this._store.hasURLLevel(level)) {
55542                     this._store.addURLs(level, ents);
55543                 }
55544             }));
55545         const subscription = urls$.subscribe(() => {
55546             if (level !== this._level.z) {
55547                 return;
55548             }
55549             for (const tile of tiles) {
55550                 const ent = {
55551                     x: tile.x,
55552                     y: tile.y,
55553                     z: level,
55554                     url: null,
55555                 };
55556                 const id = this._store.inventId(ent);
55557                 if (this._renderedLevel.has(id) ||
55558                     this._subscriptions.has(id)) {
55559                     continue;
55560                 }
55561                 if (this._store.has(id)) {
55562                     const pixels = tileToPixelCoords2D(tile, this._size, this._level);
55563                     this._renderToTarget(pixels, this._store.get(id));
55564                     this._markRendered(ent);
55565                     this._updated$.next(true);
55566                     continue;
55567                 }
55568                 ent.url = this._store.getURL(id);
55569                 this._fetchTile(ent);
55570             }
55571             this._urlSubscriptions.delete(level);
55572         }, (error) => {
55573             this._urlSubscriptions.delete(level);
55574             console.error(error);
55575         });
55576         if (!subscription.closed) {
55577             this._urlSubscriptions.set(level, subscription);
55578         }
55579     }
55580     _initRender() {
55581         const dx = this._size.w / 2;
55582         const dy = this._size.h / 2;
55583         const near = -1;
55584         const far = 1;
55585         const camera = new OrthographicCamera(-dx, dx, dy, -dy, near, far);
55586         camera.position.z = 1;
55587         const gl = this._renderer.getContext();
55588         const maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE);
55589         const backgroundSize = Math.max(this._size.w, this._size.h);
55590         const scale = maxTextureSize > backgroundSize ?
55591             1 : maxTextureSize / backgroundSize;
55592         const targetWidth = Math.floor(scale * this._size.w);
55593         const targetHeight = Math.floor(scale * this._size.h);
55594         const target = new WebGLRenderTarget(targetWidth, targetHeight, {
55595             depthBuffer: false,
55596             format: RGBFormat,
55597             magFilter: LinearFilter,
55598             minFilter: LinearFilter,
55599             stencilBuffer: false,
55600         });
55601         this._render = { camera, target };
55602         const pixels = tileToPixelCoords2D({ x: 0, y: 0 }, this._size, { max: this._level.max, z: 0 });
55603         this._renderToTarget(pixels, this._background);
55604         this._createdSubject$.next(target.texture);
55605         this._hasSubject$.next(true);
55606     }
55607     /**
55608      * Mark a tile as rendered.
55609      *
55610      * @description Clears tiles marked as rendered in other
55611      * levels of the tile pyramid if they overlap the
55612      * newly rendered tile.
55613      *
55614      * @param {Arrary<number>} tile - The tile ent.
55615      */
55616     _markRendered(tile) {
55617         const others = Array.from(this._rendered.entries())
55618             .filter(([_, t]) => {
55619             return t.z !== tile.z;
55620         });
55621         for (const [otherId, other] of others) {
55622             if (hasOverlap2D(tile, other)) {
55623                 this._rendered.delete(otherId);
55624             }
55625         }
55626         const id = this._store.inventId(tile);
55627         this._rendered.set(id, tile);
55628         this._renderedLevel.add(id);
55629     }
55630     /**
55631      * Remove an item from an array if it exists in array.
55632      *
55633      * @param {T} item - Item to remove.
55634      * @param {Array<T>} array - Array from which item should be removed.
55635      */
55636     _removeFromArray(item, array) {
55637         const index = array.indexOf(item);
55638         if (index !== -1) {
55639             array.splice(index, 1);
55640         }
55641     }
55642     /**
55643      * Render an image tile to the target texture.
55644      *
55645      * @param {ImageTileEnt} tile - Tile ent.
55646      * @param {HTMLImageElement} image - The image tile to render.
55647      */
55648     _renderToTarget(pixel, image) {
55649         const texture = new Texture(image);
55650         texture.minFilter = LinearFilter;
55651         texture.needsUpdate = true;
55652         const geometry = new PlaneGeometry(pixel.w, pixel.h);
55653         const material = new MeshBasicMaterial({
55654             map: texture,
55655             side: FrontSide,
55656         });
55657         const mesh = new Mesh(geometry, material);
55658         mesh.position.x = -this._size.w / 2 + pixel.x + pixel.w / 2;
55659         mesh.position.y = this._size.h / 2 - pixel.y - pixel.h / 2;
55660         const scene = new Scene();
55661         scene.add(mesh);
55662         const target = this._renderer.getRenderTarget();
55663         this._renderer.resetState();
55664         this._renderer.setRenderTarget(this._render.target);
55665         this._renderer.render(scene, this._render.camera);
55666         this._renderer.setRenderTarget(target);
55667         scene.remove(mesh);
55668         geometry.dispose();
55669         material.dispose();
55670         texture.dispose();
55671     }
55672 }
55673
55674 var State;
55675 (function (State) {
55676     State[State["Custom"] = 0] = "Custom";
55677     State[State["Earth"] = 1] = "Earth";
55678     State[State["Traversing"] = 2] = "Traversing";
55679     State[State["Waiting"] = 3] = "Waiting";
55680     State[State["WaitingInteractively"] = 4] = "WaitingInteractively";
55681 })(State || (State = {}));
55682
55683 class ImageComponent extends Component {
55684     constructor(name, container, navigator) {
55685         super(name, container, navigator);
55686         this._imageTileLoader = new TileLoader(navigator.api);
55687         this._roiCalculator = new RegionOfInterestCalculator();
55688         this._rendererOperation$ = new Subject();
55689         this._rendererCreator$ = new Subject();
55690         this._rendererDisposer$ = new Subject();
55691         this._renderer$ = this._rendererOperation$.pipe(scan((renderer, operation) => {
55692             return operation(renderer);
55693         }, null), filter((renderer) => {
55694             return renderer != null;
55695         }), distinctUntilChanged(undefined, (renderer) => {
55696             return renderer.frameId;
55697         }));
55698         this._rendererCreator$.pipe(map(() => {
55699             return (renderer) => {
55700                 if (renderer != null) {
55701                     throw new Error("Multiple image plane states can not be created at the same time");
55702                 }
55703                 return new ImageGLRenderer();
55704             };
55705         }))
55706             .subscribe(this._rendererOperation$);
55707         this._rendererDisposer$.pipe(map(() => {
55708             return (renderer) => {
55709                 renderer.dispose();
55710                 return null;
55711             };
55712         }))
55713             .subscribe(this._rendererOperation$);
55714     }
55715     _activate() {
55716         const subs = this._subscriptions;
55717         subs.push(this._renderer$.pipe(map((renderer) => {
55718             const renderHash = {
55719                 name: this._name,
55720                 renderer: {
55721                     frameId: renderer.frameId,
55722                     needsRender: renderer.needsRender,
55723                     render: renderer.render.bind(renderer),
55724                     pass: RenderPass$1.Background,
55725                 },
55726             };
55727             renderer.clearNeedsRender();
55728             return renderHash;
55729         }))
55730             .subscribe(this._container.glRenderer.render$));
55731         this._rendererCreator$.next(null);
55732         subs.push(this._navigator.stateService.currentState$.pipe(map((frame) => {
55733             return (renderer) => {
55734                 renderer.updateFrame(frame);
55735                 return renderer;
55736             };
55737         }))
55738             .subscribe(this._rendererOperation$));
55739         const textureProvider$ = this._container.configurationService.imageTiling$.pipe(switchMap((active) => {
55740             return active ?
55741                 this._navigator.stateService.currentState$ :
55742                 new Subject();
55743         }), distinctUntilChanged(undefined, (frame) => {
55744             return frame.state.currentImage.id;
55745         }), withLatestFrom(this._container.glRenderer.webGLRenderer$), map(([frame, renderer]) => {
55746             const state = frame.state;
55747             const currentNode = state.currentImage;
55748             const currentTransform = state.currentTransform;
55749             return new TextureProvider(currentNode.id, currentTransform.basicWidth, currentTransform.basicHeight, currentNode.image, this._imageTileLoader, new TileStore(), renderer);
55750         }), publishReplay(1), refCount());
55751         subs.push(textureProvider$.subscribe(() => { }));
55752         subs.push(textureProvider$.pipe(map((provider) => {
55753             return (renderer) => {
55754                 renderer.setTextureProvider(provider.id, provider);
55755                 return renderer;
55756             };
55757         }))
55758             .subscribe(this._rendererOperation$));
55759         subs.push(textureProvider$.pipe(pairwise())
55760             .subscribe((pair) => {
55761             const previous = pair[0];
55762             previous.abort();
55763         }));
55764         const roiTrigger$ = this._container.configurationService.imageTiling$.pipe(switchMap((active) => {
55765             return active ?
55766                 combineLatest(this._navigator.stateService.state$, this._navigator.stateService.inTranslation$) :
55767                 new Subject();
55768         }), switchMap(([state, inTranslation]) => {
55769             const streetState = state === State.Traversing ||
55770                 state === State.Waiting ||
55771                 state === State.WaitingInteractively;
55772             const active = streetState && !inTranslation;
55773             return active ?
55774                 this._container.renderService.renderCameraFrame$ :
55775                 empty();
55776         }), map((camera) => {
55777             return {
55778                 camera,
55779                 height: camera.size.height.valueOf(),
55780                 lookat: camera.camera.lookat.clone(),
55781                 width: camera.size.width.valueOf(),
55782                 zoom: camera.zoom.valueOf(),
55783             };
55784         }), pairwise(), map(([pl0, pl1]) => {
55785             const stalled = pl0.width === pl1.width &&
55786                 pl0.height === pl1.height &&
55787                 pl0.zoom === pl1.zoom &&
55788                 pl0.lookat.equals(pl1.lookat);
55789             return { camera: pl1.camera, stalled };
55790         }), distinctUntilChanged((x, y) => {
55791             return x.stalled === y.stalled;
55792         }), filter((camera) => {
55793             return camera.stalled;
55794         }), withLatestFrom(this._container.renderService.size$, this._navigator.stateService.currentTransform$));
55795         subs.push(textureProvider$.pipe(switchMap((provider) => {
55796             return roiTrigger$.pipe(map(([stalled, size, transform]) => {
55797                 const camera = stalled.camera;
55798                 const basic = new ViewportCoords()
55799                     .viewportToBasic(0, 0, transform, camera.perspective);
55800                 if (basic[0] < 0 ||
55801                     basic[1] < 0 ||
55802                     basic[0] > 1 ||
55803                     basic[1] > 1) {
55804                     return undefined;
55805                 }
55806                 return [
55807                     this._roiCalculator
55808                         .computeRegionOfInterest(camera, size, transform),
55809                     provider,
55810                 ];
55811             }), filter((args) => {
55812                 return !!args;
55813             }));
55814         }), filter((args) => {
55815             return !args[1].disposed;
55816         }))
55817             .subscribe(([roi, provider]) => {
55818             provider.setRegionOfInterest(roi);
55819         }));
55820         const hasTexture$ = textureProvider$
55821             .pipe(switchMap((provider) => {
55822             return provider.hasTexture$;
55823         }), startWith(false), publishReplay(1), refCount());
55824         subs.push(hasTexture$.subscribe(() => { }));
55825         subs.push(this._navigator.panService.panImages$.pipe(filter((panNodes) => {
55826             return panNodes.length === 0;
55827         }), map(() => {
55828             return (renderer) => {
55829                 renderer.clearPeripheryPlanes();
55830                 return renderer;
55831             };
55832         }))
55833             .subscribe(this._rendererOperation$));
55834         const cachedPanNodes$ = this._navigator.panService.panImages$.pipe(switchMap((nts) => {
55835             return from(nts).pipe(mergeMap(([n, t]) => {
55836                 return combineLatest(this._navigator.graphService.cacheImage$(n.id).pipe(catchError((error) => {
55837                     console.error(`Failed to cache periphery image (${n.id})`, error);
55838                     return empty();
55839                 })), of(t));
55840             }));
55841         }), share());
55842         subs.push(cachedPanNodes$.pipe(map(([n, t]) => {
55843             return (renderer) => {
55844                 renderer.addPeripheryPlane(n, t);
55845                 return renderer;
55846             };
55847         }))
55848             .subscribe(this._rendererOperation$));
55849         subs.push(cachedPanNodes$.pipe(mergeMap(([n]) => {
55850             return n.cacheImage$().pipe(catchError(() => {
55851                 return empty();
55852             }));
55853         }), map((n) => {
55854             return (renderer) => {
55855                 renderer.updateTextureImage(n.image, n);
55856                 return renderer;
55857             };
55858         }))
55859             .subscribe(this._rendererOperation$));
55860         const inTransition$ = this._navigator.stateService.currentState$.pipe(map((frame) => {
55861             return frame.state.alpha < 1;
55862         }), distinctUntilChanged());
55863         const panTrigger$ = combineLatest(this._container.mouseService.active$, this._container.touchService.active$, this._navigator.stateService.inMotion$, inTransition$).pipe(map(([mouseActive, touchActive, inMotion, inTransition]) => {
55864             return !(mouseActive || touchActive || inMotion || inTransition);
55865         }), filter((trigger) => {
55866             return trigger;
55867         }));
55868         subs.push(this._navigator.stateService.state$
55869             .pipe(switchMap(state => {
55870             return state === State.Traversing ?
55871                 this._navigator.panService.panImages$ :
55872                 empty();
55873         }), switchMap((nts) => {
55874             return panTrigger$.pipe(withLatestFrom(this._container.renderService.renderCamera$, this._navigator.stateService.currentImage$, this._navigator.stateService.currentTransform$), mergeMap(([, renderCamera, currentNode, currentTransform]) => {
55875                 return of([
55876                     renderCamera,
55877                     currentNode,
55878                     currentTransform,
55879                     nts,
55880                 ]);
55881             }));
55882         }), switchMap(([camera, cn, ct, nts]) => {
55883             const direction = camera.camera.lookat.clone().sub(camera.camera.position);
55884             const cd = new Spatial().viewingDirection(cn.rotation);
55885             const ca = cd.angleTo(direction);
55886             const closest = [ca, undefined];
55887             const basic = new ViewportCoords().viewportToBasic(0, 0, ct, camera.perspective);
55888             if (basic[0] >= 0 && basic[0] <= 1 && basic[1] >= 0 && basic[1] <= 1) {
55889                 closest[0] = Number.NEGATIVE_INFINITY;
55890             }
55891             for (const [n] of nts) {
55892                 const d = new Spatial().viewingDirection(n.rotation);
55893                 const a = d.angleTo(direction);
55894                 if (a < closest[0]) {
55895                     closest[0] = a;
55896                     closest[1] = n.id;
55897                 }
55898             }
55899             if (!closest[1]) {
55900                 return empty();
55901             }
55902             return this._navigator.moveTo$(closest[1]).pipe(catchError(() => {
55903                 return empty();
55904             }));
55905         }))
55906             .subscribe());
55907     }
55908     _deactivate() {
55909         this._rendererDisposer$.next(null);
55910         this._subscriptions.unsubscribe();
55911     }
55912     _getDefaultConfiguration() {
55913         return {};
55914     }
55915 }
55916 ImageComponent.componentName = "image";
55917
55918 class HandlerBase {
55919     /** @ignore */
55920     constructor(component, container, navigator) {
55921         this._component = component;
55922         this._container = container;
55923         this._navigator = navigator;
55924         this._enabled = false;
55925     }
55926     /**
55927      * Returns a Boolean indicating whether the interaction is enabled.
55928      *
55929      * @returns {boolean} `true` if the interaction is enabled.
55930      */
55931     get isEnabled() {
55932         return this._enabled;
55933     }
55934     /**
55935      * Enables the interaction.
55936      *
55937      * @example
55938      * ```js
55939      * <component-name>.<handler-name>.enable();
55940      * ```
55941      */
55942     enable() {
55943         if (this._enabled || !this._component.activated) {
55944             return;
55945         }
55946         this._enable();
55947         this._enabled = true;
55948         this._component.configure(this._getConfiguration(true));
55949     }
55950     /**
55951      * Disables the interaction.
55952      *
55953      * @example
55954      * ```js
55955      * <component-name>.<handler-name>.disable();
55956      * ```
55957      */
55958     disable() {
55959         if (!this._enabled) {
55960             return;
55961         }
55962         this._disable();
55963         this._enabled = false;
55964         if (this._component.activated) {
55965             this._component.configure(this._getConfiguration(false));
55966         }
55967     }
55968 }
55969
55970 /**
55971  * The `KeySequenceNavigationHandler` allows the user to navigate through a sequence using the
55972  * following key commands:
55973  *
55974  * `ALT` + `Up Arrow`: Navigate to next image in the sequence.
55975  * `ALT` + `Down Arrow`: Navigate to previous image in sequence.
55976  *
55977  * @example
55978  * ```js
55979  * var keyboardComponent = viewer.getComponent("keyboard");
55980  *
55981  * keyboardComponent.keySequenceNavigation.disable();
55982  * keyboardComponent.keySequenceNavigation.enable();
55983  *
55984  * var isEnabled = keyboardComponent.keySequenceNavigation.isEnabled;
55985  * ```
55986  */
55987 class KeySequenceNavigationHandler extends HandlerBase {
55988     _enable() {
55989         const sequenceEdges$ = this._navigator.stateService.currentImage$.pipe(switchMap((image) => {
55990             return image.sequenceEdges$;
55991         }));
55992         this._keyDownSubscription = this._container.keyboardService.keyDown$.pipe(withLatestFrom(sequenceEdges$))
55993             .subscribe(([event, edgeStatus]) => {
55994             let direction = null;
55995             switch (event.keyCode) {
55996                 case 38: // up
55997                     direction = NavigationDirection.Next;
55998                     break;
55999                 case 40: // down
56000                     direction = NavigationDirection.Prev;
56001                     break;
56002                 default:
56003                     return;
56004             }
56005             event.preventDefault();
56006             if (!event.altKey || event.shiftKey || !edgeStatus.cached) {
56007                 return;
56008             }
56009             for (const edge of edgeStatus.edges) {
56010                 if (edge.data.direction === direction) {
56011                     this._navigator.moveTo$(edge.target)
56012                         .subscribe(undefined, (error) => {
56013                         if (!(error instanceof CancelMapillaryError)) {
56014                             console.error(error);
56015                         }
56016                     });
56017                     return;
56018                 }
56019             }
56020         });
56021     }
56022     _disable() {
56023         this._keyDownSubscription.unsubscribe();
56024     }
56025     _getConfiguration(enable) {
56026         return { keySequenceNavigation: enable };
56027     }
56028 }
56029
56030 /**
56031  * The `KeySpatialNavigationHandler` allows the user to navigate through a sequence using the
56032  * following key commands:
56033  *
56034  * `Up Arrow`: Step forward.
56035  * `Down Arrow`: Step backward.
56036  * `Left Arrow`: Step to the left.
56037  * `Rigth Arrow`: Step to the right.
56038  * `SHIFT` + `Down Arrow`: Turn around.
56039  * `SHIFT` + `Left Arrow`: Turn to the left.
56040  * `SHIFT` + `Rigth Arrow`: Turn to the right.
56041  *
56042  * @example
56043  * ```js
56044  * var keyboardComponent = viewer.getComponent("keyboard");
56045  *
56046  * keyboardComponent.keySpatialNavigation.disable();
56047  * keyboardComponent.keySpatialNavigation.enable();
56048  *
56049  * var isEnabled = keyboardComponent.keySpatialNavigation.isEnabled;
56050  * ```
56051  */
56052 class KeySpatialNavigationHandler extends HandlerBase {
56053     /** @ignore */
56054     constructor(component, container, navigator, spatial) {
56055         super(component, container, navigator);
56056         this._spatial = spatial;
56057     }
56058     _enable() {
56059         const spatialEdges$ = this._navigator.stateService.currentImage$.pipe(switchMap((image) => {
56060             return image.spatialEdges$;
56061         }));
56062         this._keyDownSubscription = this._container.keyboardService.keyDown$.pipe(withLatestFrom(spatialEdges$, this._navigator.stateService.currentState$))
56063             .subscribe(([event, edgeStatus, frame]) => {
56064             let spherical = isSpherical(frame.state.currentImage.cameraType);
56065             let direction = null;
56066             switch (event.keyCode) {
56067                 case 37: // left
56068                     direction = event.shiftKey && !spherical ? NavigationDirection.TurnLeft : NavigationDirection.StepLeft;
56069                     break;
56070                 case 38: // up
56071                     direction = event.shiftKey && !spherical ? NavigationDirection.Spherical : NavigationDirection.StepForward;
56072                     break;
56073                 case 39: // right
56074                     direction = event.shiftKey && !spherical ? NavigationDirection.TurnRight : NavigationDirection.StepRight;
56075                     break;
56076                 case 40: // down
56077                     direction = event.shiftKey && !spherical ? NavigationDirection.TurnU : NavigationDirection.StepBackward;
56078                     break;
56079                 default:
56080                     return;
56081             }
56082             event.preventDefault();
56083             if (event.altKey || !edgeStatus.cached ||
56084                 (event.shiftKey && spherical)) {
56085                 return;
56086             }
56087             if (!spherical) {
56088                 this._moveDir(direction, edgeStatus);
56089             }
56090             else {
56091                 const shifts = {};
56092                 shifts[NavigationDirection.StepBackward] = Math.PI;
56093                 shifts[NavigationDirection.StepForward] = 0;
56094                 shifts[NavigationDirection.StepLeft] = Math.PI / 2;
56095                 shifts[NavigationDirection.StepRight] = -Math.PI / 2;
56096                 const phi = this._rotationFromCamera(frame.state.camera).phi;
56097                 const navigationAngle = this._spatial.wrapAngle(phi + shifts[direction]);
56098                 const threshold = Math.PI / 4;
56099                 const edges = edgeStatus.edges.filter((e) => {
56100                     return e.data.direction === NavigationDirection.Spherical || e.data.direction === direction;
56101                 });
56102                 let smallestAngle = Number.MAX_VALUE;
56103                 let toKey = null;
56104                 for (const edge of edges) {
56105                     const angle = Math.abs(this._spatial.wrapAngle(edge.data.worldMotionAzimuth - navigationAngle));
56106                     if (angle < Math.min(smallestAngle, threshold)) {
56107                         smallestAngle = angle;
56108                         toKey = edge.target;
56109                     }
56110                 }
56111                 if (toKey == null) {
56112                     return;
56113                 }
56114                 this._moveTo(toKey);
56115             }
56116         });
56117     }
56118     _disable() {
56119         this._keyDownSubscription.unsubscribe();
56120     }
56121     _getConfiguration(enable) {
56122         return { keySpatialNavigation: enable };
56123     }
56124     _moveDir(direction, edgeStatus) {
56125         for (const edge of edgeStatus.edges) {
56126             if (edge.data.direction === direction) {
56127                 this._moveTo(edge.target);
56128                 return;
56129             }
56130         }
56131     }
56132     _moveTo(id) {
56133         this._navigator.moveTo$(id)
56134             .subscribe(undefined, (error) => {
56135             if (!(error instanceof CancelMapillaryError)) {
56136                 console.error(error);
56137             }
56138         });
56139     }
56140     _rotationFromCamera(camera) {
56141         let direction = camera.lookat.clone().sub(camera.position);
56142         let upProjection = direction.clone().dot(camera.up);
56143         let planeProjection = direction.clone().sub(camera.up.clone().multiplyScalar(upProjection));
56144         let phi = Math.atan2(planeProjection.y, planeProjection.x);
56145         let theta = Math.PI / 2 - this._spatial.angleToPlane(direction.toArray(), [0, 0, 1]);
56146         return { phi: phi, theta: theta };
56147     }
56148 }
56149
56150 /**
56151  * The `KeyZoomHandler` allows the user to zoom in and out using the
56152  * following key commands:
56153  *
56154  * `+`: Zoom in.
56155  * `-`: Zoom out.
56156  *
56157  * @example
56158  * ```js
56159  * var keyboardComponent = viewer.getComponent("keyboard");
56160  *
56161  * keyboardComponent.keyZoom.disable();
56162  * keyboardComponent.keyZoom.enable();
56163  *
56164  * var isEnabled = keyboardComponent.keyZoom.isEnabled;
56165  * ```
56166  */
56167 class KeyZoomHandler extends HandlerBase {
56168     /** @ignore */
56169     constructor(component, container, navigator, viewportCoords) {
56170         super(component, container, navigator);
56171         this._viewportCoords = viewportCoords;
56172     }
56173     _enable() {
56174         this._keyDownSubscription = this._container.keyboardService.keyDown$.pipe(withLatestFrom(this._container.renderService.renderCamera$, this._navigator.stateService.currentTransform$))
56175             .subscribe(([event, render, transform]) => {
56176             if (event.altKey || event.ctrlKey || event.metaKey) {
56177                 return;
56178             }
56179             let delta = 0;
56180             switch (event.key) {
56181                 case "+":
56182                     delta = 1;
56183                     break;
56184                 case "-":
56185                     delta = -1;
56186                     break;
56187                 default:
56188                     return;
56189             }
56190             event.preventDefault();
56191             const unprojected = this._viewportCoords.unprojectFromViewport(0, 0, render.perspective);
56192             const reference = transform.projectBasic(unprojected.toArray());
56193             this._navigator.stateService.zoomIn(delta, reference);
56194         });
56195     }
56196     _disable() {
56197         this._keyDownSubscription.unsubscribe();
56198     }
56199     _getConfiguration(enable) {
56200         return { keyZoom: enable };
56201     }
56202 }
56203
56204 /**
56205  * The `KeyPlayHandler` allows the user to control the play behavior
56206  * using the following key commands:
56207  *
56208  * `Spacebar`: Start or stop playing.
56209  * `SHIFT` + `D`: Switch direction.
56210  * `<`: Decrease speed.
56211  * `>`: Increase speed.
56212  *
56213  * @example
56214  * ```js
56215  * var keyboardComponent = viewer.getComponent("keyboard");
56216  *
56217  * keyboardComponent.keyPlay.disable();
56218  * keyboardComponent.keyPlay.enable();
56219  *
56220  * var isEnabled = keyboardComponent.keyPlay.isEnabled;
56221  * ```
56222  */
56223 class KeyPlayHandler extends HandlerBase {
56224     _enable() {
56225         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) => {
56226             return image.sequenceEdges$;
56227         })), this._navigator.stateService.state$.pipe(map((state) => {
56228             return state === State.Earth;
56229         }), distinctUntilChanged())))
56230             .subscribe(([event, playing, direction, speed, status, earth]) => {
56231             if (event.altKey || event.ctrlKey || event.metaKey) {
56232                 return;
56233             }
56234             switch (event.key) {
56235                 case "D":
56236                     if (!event.shiftKey) {
56237                         return;
56238                     }
56239                     const newDirection = playing ?
56240                         null : direction === NavigationDirection.Next ?
56241                         NavigationDirection.Prev : direction === NavigationDirection.Prev ?
56242                         NavigationDirection.Next : null;
56243                     if (newDirection != null) {
56244                         this._navigator.playService.setDirection(newDirection);
56245                     }
56246                     break;
56247                 case " ":
56248                     if (event.shiftKey) {
56249                         return;
56250                     }
56251                     if (!earth) {
56252                         if (playing) {
56253                             this._navigator.playService.stop();
56254                         }
56255                         else {
56256                             for (let edge of status.edges) {
56257                                 if (edge.data.direction === direction) {
56258                                     this._navigator.playService.play();
56259                                 }
56260                             }
56261                         }
56262                     }
56263                     break;
56264                 case "<":
56265                     this._navigator.playService.setSpeed(speed - 0.05);
56266                     break;
56267                 case ">":
56268                     this._navigator.playService.setSpeed(speed + 0.05);
56269                     break;
56270                 default:
56271                     return;
56272             }
56273             event.preventDefault();
56274         });
56275     }
56276     _disable() {
56277         this._keyDownSubscription.unsubscribe();
56278     }
56279     _getConfiguration(enable) {
56280         return { keyPlay: enable };
56281     }
56282 }
56283
56284 /**
56285  * @class KeyboardComponent
56286  *
56287  * @classdesc Component for keyboard event handling.
56288  *
56289  * To retrive and use the keyboard component
56290  *
56291  * @example
56292  * ```js
56293  * var viewer = new Viewer({ ... });
56294  *
56295  * var keyboardComponent = viewer.getComponent("keyboard");
56296  * ```
56297  */
56298 class KeyboardComponent extends Component {
56299     /** @ignore */
56300     constructor(name, container, navigator) {
56301         super(name, container, navigator);
56302         this._keyPlayHandler =
56303             new KeyPlayHandler(this, container, navigator);
56304         this._keySequenceNavigationHandler =
56305             new KeySequenceNavigationHandler(this, container, navigator);
56306         this._keySpatialNavigationHandler =
56307             new KeySpatialNavigationHandler(this, container, navigator, new Spatial());
56308         this._keyZoomHandler =
56309             new KeyZoomHandler(this, container, navigator, new ViewportCoords());
56310     }
56311     /**
56312      * Get key play.
56313      *
56314      * @returns {KeyPlayHandler} The key play handler.
56315      */
56316     get keyPlay() {
56317         return this._keyPlayHandler;
56318     }
56319     /**
56320      * Get key sequence navigation.
56321      *
56322      * @returns {KeySequenceNavigationHandler} The key sequence navigation handler.
56323      */
56324     get keySequenceNavigation() {
56325         return this._keySequenceNavigationHandler;
56326     }
56327     /**
56328      * Get spatial.
56329      *
56330      * @returns {KeySpatialNavigationHandler} The spatial handler.
56331      */
56332     get keySpatialNavigation() {
56333         return this._keySpatialNavigationHandler;
56334     }
56335     /**
56336      * Get key zoom.
56337      *
56338      * @returns {KeyZoomHandler} The key zoom handler.
56339      */
56340     get keyZoom() {
56341         return this._keyZoomHandler;
56342     }
56343     _activate() {
56344         this._subscriptions.push(this._configuration$
56345             .subscribe((configuration) => {
56346             if (configuration.keyPlay) {
56347                 this._keyPlayHandler.enable();
56348             }
56349             else {
56350                 this._keyPlayHandler.disable();
56351             }
56352             if (configuration.keySequenceNavigation) {
56353                 this._keySequenceNavigationHandler.enable();
56354             }
56355             else {
56356                 this._keySequenceNavigationHandler.disable();
56357             }
56358             if (configuration.keySpatialNavigation) {
56359                 this._keySpatialNavigationHandler.enable();
56360             }
56361             else {
56362                 this._keySpatialNavigationHandler.disable();
56363             }
56364             if (configuration.keyZoom) {
56365                 this._keyZoomHandler.enable();
56366             }
56367             else {
56368                 this._keyZoomHandler.disable();
56369             }
56370         }));
56371     }
56372     _deactivate() {
56373         this._subscriptions.unsubscribe();
56374         this._keyPlayHandler.disable();
56375         this._keySequenceNavigationHandler.disable();
56376         this._keySpatialNavigationHandler.disable();
56377         this._keyZoomHandler.disable();
56378     }
56379     _getDefaultConfiguration() {
56380         return { keyPlay: true, keySequenceNavigation: true, keySpatialNavigation: true, keyZoom: true };
56381     }
56382 }
56383 KeyboardComponent.componentName = "keyboard";
56384
56385 class MarkerScene {
56386     constructor(scene, raycaster) {
56387         this._needsRender = false;
56388         this._interactiveObjects = [];
56389         this._markers = {};
56390         this._objectMarkers = {};
56391         this._raycaster = !!raycaster ? raycaster : new Raycaster();
56392         this._scene = !!scene ? scene : new Scene();
56393     }
56394     get markers() {
56395         return this._markers;
56396     }
56397     get needsRender() {
56398         return this._needsRender;
56399     }
56400     add(marker, position) {
56401         if (marker.id in this._markers) {
56402             this._dispose(marker.id);
56403         }
56404         marker.createGeometry(position);
56405         this._scene.add(marker.geometry);
56406         this._markers[marker.id] = marker;
56407         for (let interactiveObject of marker.getInteractiveObjects()) {
56408             this._interactiveObjects.push(interactiveObject);
56409             this._objectMarkers[interactiveObject.uuid] = marker.id;
56410         }
56411         this._needsRender = true;
56412     }
56413     clear() {
56414         for (const id in this._markers) {
56415             if (!this._markers.hasOwnProperty) {
56416                 continue;
56417             }
56418             this._dispose(id);
56419         }
56420         this._needsRender = true;
56421     }
56422     get(id) {
56423         return this._markers[id];
56424     }
56425     getAll() {
56426         return Object
56427             .keys(this._markers)
56428             .map((id) => { return this._markers[id]; });
56429     }
56430     has(id) {
56431         return id in this._markers;
56432     }
56433     intersectObjects([viewportX, viewportY], camera) {
56434         this._raycaster.setFromCamera(new Vector2(viewportX, viewportY), camera);
56435         const intersects = this._raycaster.intersectObjects(this._interactiveObjects);
56436         for (const intersect of intersects) {
56437             if (intersect.object.uuid in this._objectMarkers) {
56438                 return this._objectMarkers[intersect.object.uuid];
56439             }
56440         }
56441         return null;
56442     }
56443     lerpAltitude(id, alt, alpha) {
56444         if (!(id in this._markers)) {
56445             return;
56446         }
56447         this._markers[id].lerpAltitude(alt, alpha);
56448         this._needsRender = true;
56449     }
56450     remove(id) {
56451         if (!(id in this._markers)) {
56452             return;
56453         }
56454         this._dispose(id);
56455         this._needsRender = true;
56456     }
56457     render(perspectiveCamera, renderer) {
56458         renderer.render(this._scene, perspectiveCamera);
56459         this._needsRender = false;
56460     }
56461     update(id, position, lngLat) {
56462         if (!(id in this._markers)) {
56463             return;
56464         }
56465         const marker = this._markers[id];
56466         marker.updatePosition(position, lngLat);
56467         this._needsRender = true;
56468     }
56469     _dispose(id) {
56470         const marker = this._markers[id];
56471         this._scene.remove(marker.geometry);
56472         for (let interactiveObject of marker.getInteractiveObjects()) {
56473             const index = this._interactiveObjects.indexOf(interactiveObject);
56474             if (index !== -1) {
56475                 this._interactiveObjects.splice(index, 1);
56476             }
56477             else {
56478                 console.warn(`Object does not exist (${interactiveObject.id}) for ${id}`);
56479             }
56480             delete this._objectMarkers[interactiveObject.uuid];
56481         }
56482         marker.disposeGeometry();
56483         delete this._markers[id];
56484     }
56485 }
56486
56487 /**
56488  * @class MarkerComponent
56489  *
56490  * @classdesc Component for showing and editing 3D marker objects.
56491  *
56492  * The `add` method is used for adding new markers or replacing
56493  * markers already in the set.
56494  *
56495  * If a marker already in the set has the same
56496  * id as one of the markers added, the old marker will be removed and
56497  * the added marker will take its place.
56498  *
56499  * It is not possible to update markers in the set by updating any properties
56500  * directly on the marker object. Markers need to be replaced by
56501  * re-adding them for updates to geographic position or configuration
56502  * to be reflected.
56503  *
56504  * Markers added to the marker component can be either interactive
56505  * or non-interactive. Different marker types define their behavior.
56506  * Markers with interaction support can be configured with options
56507  * to respond to dragging inside the viewer and be detected when
56508  * retrieving markers from pixel points with the `getMarkerIdAt` method.
56509  *
56510  * To retrive and use the marker component
56511  *
56512  * @example
56513  * ```js
56514  * var viewer = new Viewer({ component: { marker: true }, ... });
56515  *
56516  * var markerComponent = viewer.getComponent("marker");
56517  * ```
56518  */
56519 class MarkerComponent extends Component {
56520     /** @ignore */
56521     constructor(name, container, navigator) {
56522         super(name, container, navigator);
56523         this._graphCalculator = new GraphCalculator();
56524         this._markerScene = new MarkerScene();
56525         this._markerSet = new MarkerSet();
56526         this._viewportCoords = new ViewportCoords();
56527         this._relativeGroundAltitude = -2;
56528     }
56529     /**
56530      * Add markers to the marker set or replace markers in the marker set.
56531      *
56532      * @description If a marker already in the set has the same
56533      * id as one of the markers added, the old marker will be removed
56534      * the added marker will take its place.
56535      *
56536      * Any marker inside the visible bounding bbox
56537      * will be initialized and placed in the viewer.
56538      *
56539      * @param {Array<Marker>} markers - Markers to add.
56540      *
56541      * @example
56542      * ```js
56543      * markerComponent.add([marker1, marker2]);
56544      * ```
56545      */
56546     add(markers) {
56547         this._markerSet.add(markers);
56548     }
56549     fire(type, event) {
56550         super.fire(type, event);
56551     }
56552     /**
56553      * Returns the marker in the marker set with the specified id, or
56554      * undefined if the id matches no marker.
56555      *
56556      * @param {string} markerId - Id of the marker.
56557      *
56558      * @example
56559      * ```js
56560      * var marker = markerComponent.get("markerId");
56561      * ```
56562      *
56563      */
56564     get(markerId) {
56565         return this._markerSet.get(markerId);
56566     }
56567     /**
56568      * Returns an array of all markers.
56569      *
56570      * @example
56571      * ```js
56572      * var markers = markerComponent.getAll();
56573      * ```
56574      */
56575     getAll() {
56576         return this._markerSet.getAll();
56577     }
56578     /**
56579      * Returns the id of the interactive marker closest to the current camera
56580      * position at the specified point.
56581      *
56582      * @description Notice that the pixelPoint argument requires x, y
56583      * coordinates from pixel space.
56584      *
56585      * With this function, you can use the coordinates provided by mouse
56586      * events to get information out of the marker component.
56587      *
56588      * If no interactive geometry of an interactive marker exist at the pixel
56589      * point, `null` will be returned.
56590      *
56591      * @param {Array<number>} pixelPoint - Pixel coordinates on the viewer element.
56592      * @returns {string} Id of the interactive marker closest to the camera. If no
56593      * interactive marker exist at the pixel point, `null` will be returned.
56594      *
56595      * @example
56596      * ```js
56597      * markerComponent.getMarkerIdAt([100, 100])
56598      *     .then((markerId) => { console.log(markerId); });
56599      * ```
56600      */
56601     getMarkerIdAt(pixelPoint) {
56602         return new Promise((resolve, reject) => {
56603             this._container.renderService.renderCamera$.pipe(first(), map((render) => {
56604                 const viewport = this._viewportCoords
56605                     .canvasToViewport(pixelPoint[0], pixelPoint[1], this._container.container);
56606                 const id = this._markerScene.intersectObjects(viewport, render.perspective);
56607                 return id;
56608             }))
56609                 .subscribe((id) => {
56610                 resolve(id);
56611             }, (error) => {
56612                 reject(error);
56613             });
56614         });
56615     }
56616     /**
56617      * Check if a marker exist in the marker set.
56618      *
56619      * @param {string} markerId - Id of the marker.
56620      *
56621      * @example
56622      * ```js
56623      * var markerExists = markerComponent.has("markerId");
56624      * ```
56625      */
56626     has(markerId) {
56627         return this._markerSet.has(markerId);
56628     }
56629     off(type, handler) {
56630         super.off(type, handler);
56631     }
56632     on(type, handler) {
56633         super.on(type, handler);
56634     }
56635     /**
56636      * Remove markers with the specified ids from the marker set.
56637      *
56638      * @param {Array<string>} markerIds - Ids for markers to remove.
56639      *
56640      * @example
56641      * ```js
56642      * markerComponent.remove(["id-1", "id-2"]);
56643      * ```
56644      */
56645     remove(markerIds) {
56646         this._markerSet.remove(markerIds);
56647     }
56648     /**
56649      * Remove all markers from the marker set.
56650      *
56651      * @example
56652      * ```js
56653      * markerComponent.removeAll();
56654      * ```
56655      */
56656     removeAll() {
56657         this._markerSet.removeAll();
56658     }
56659     _activate() {
56660         const groundAltitude$ = this._navigator.stateService.currentState$.pipe(map((frame) => {
56661             return frame.state.camera.position.z + this._relativeGroundAltitude;
56662         }), distinctUntilChanged((a1, a2) => {
56663             return Math.abs(a1 - a2) < 0.01;
56664         }), publishReplay(1), refCount());
56665         const geoInitiated$ = combineLatest(groundAltitude$, this._navigator.stateService.reference$).pipe(first(), map(() => { }), publishReplay(1), refCount());
56666         const clampedConfiguration$ = this._configuration$.pipe(map((configuration) => {
56667             return { visibleBBoxSize: Math.max(1, Math.min(200, configuration.visibleBBoxSize)) };
56668         }));
56669         const currentLngLat$ = this._navigator.stateService.currentImage$.pipe(map((image) => { return image.lngLat; }), publishReplay(1), refCount());
56670         const visibleBBox$ = combineLatest(clampedConfiguration$, currentLngLat$).pipe(map(([configuration, lngLat]) => {
56671             return this._graphCalculator
56672                 .boundingBoxCorners(lngLat, configuration.visibleBBoxSize / 2);
56673         }), publishReplay(1), refCount());
56674         const visibleMarkers$ = combineLatest(concat(of(this._markerSet), this._markerSet.changed$), visibleBBox$).pipe(map(([set, bbox]) => {
56675             return set.search(bbox);
56676         }));
56677         const subs = this._subscriptions;
56678         subs.push(geoInitiated$.pipe(switchMap(() => {
56679             return visibleMarkers$.pipe(withLatestFrom(this._navigator.stateService.reference$, groundAltitude$));
56680         }))
56681             .subscribe(([markers, reference, alt]) => {
56682             const markerScene = this._markerScene;
56683             const sceneMarkers = markerScene.markers;
56684             const markersToRemove = Object.assign({}, sceneMarkers);
56685             for (const marker of markers) {
56686                 if (marker.id in sceneMarkers) {
56687                     delete markersToRemove[marker.id];
56688                 }
56689                 else {
56690                     const point3d = geodeticToEnu(marker.lngLat.lng, marker.lngLat.lat, reference.alt + alt, reference.lng, reference.lat, reference.alt);
56691                     markerScene.add(marker, point3d);
56692                 }
56693             }
56694             for (const id in markersToRemove) {
56695                 if (!markersToRemove.hasOwnProperty(id)) {
56696                     continue;
56697                 }
56698                 markerScene.remove(id);
56699             }
56700         }));
56701         subs.push(geoInitiated$.pipe(switchMap(() => {
56702             return this._markerSet.updated$.pipe(withLatestFrom(visibleBBox$, this._navigator.stateService.reference$, groundAltitude$));
56703         }))
56704             .subscribe(([markers, [sw, ne], reference, alt]) => {
56705             const markerScene = this._markerScene;
56706             for (const marker of markers) {
56707                 const exists = markerScene.has(marker.id);
56708                 const visible = marker.lngLat.lat > sw.lat &&
56709                     marker.lngLat.lat < ne.lat &&
56710                     marker.lngLat.lng > sw.lng &&
56711                     marker.lngLat.lng < ne.lng;
56712                 if (visible) {
56713                     const point3d = geodeticToEnu(marker.lngLat.lng, marker.lngLat.lat, reference.alt + alt, reference.lng, reference.lat, reference.alt);
56714                     markerScene.add(marker, point3d);
56715                 }
56716                 else if (!visible && exists) {
56717                     markerScene.remove(marker.id);
56718                 }
56719             }
56720         }));
56721         subs.push(this._navigator.stateService.reference$.pipe(skip(1), withLatestFrom(groundAltitude$))
56722             .subscribe(([reference, alt]) => {
56723             const markerScene = this._markerScene;
56724             for (const marker of markerScene.getAll()) {
56725                 const point3d = geodeticToEnu(marker.lngLat.lng, marker.lngLat.lat, reference.alt + alt, reference.lng, reference.lat, reference.alt);
56726                 markerScene.update(marker.id, point3d);
56727             }
56728         }));
56729         subs.push(groundAltitude$.pipe(skip(1), withLatestFrom(this._navigator.stateService.reference$, currentLngLat$))
56730             .subscribe(([alt, reference, lngLat]) => {
56731             const markerScene = this._markerScene;
56732             const position = geodeticToEnu(lngLat.lng, lngLat.lat, reference.alt + alt, reference.lng, reference.lat, reference.alt);
56733             for (const marker of markerScene.getAll()) {
56734                 const point3d = geodeticToEnu(marker.lngLat.lng, marker.lngLat.lat, reference.alt + alt, reference.lng, reference.lat, reference.alt);
56735                 const distanceX = point3d[0] - position[0];
56736                 const distanceY = point3d[1] - position[1];
56737                 const groundDistance = Math
56738                     .sqrt(distanceX * distanceX + distanceY * distanceY);
56739                 if (groundDistance > 50) {
56740                     continue;
56741                 }
56742                 markerScene.lerpAltitude(marker.id, alt, Math.min(1, Math.max(0, 1.2 - 1.2 * groundDistance / 50)));
56743             }
56744         }));
56745         subs.push(this._navigator.stateService.currentState$
56746             .pipe(map((frame) => {
56747             const scene = this._markerScene;
56748             return {
56749                 name: this._name,
56750                 renderer: {
56751                     frameId: frame.id,
56752                     needsRender: scene.needsRender,
56753                     render: scene.render.bind(scene),
56754                     pass: RenderPass$1.Opaque,
56755                 },
56756             };
56757         }))
56758             .subscribe(this._container.glRenderer.render$));
56759         const hoveredMarkerId$ = combineLatest(this._container.renderService.renderCamera$, this._container.mouseService.mouseMove$)
56760             .pipe(map(([render, event]) => {
56761             const element = this._container.container;
56762             const [canvasX, canvasY] = this._viewportCoords.canvasPosition(event, element);
56763             const viewport = this._viewportCoords
56764                 .canvasToViewport(canvasX, canvasY, element);
56765             const markerId = this._markerScene.intersectObjects(viewport, render.perspective);
56766             return markerId;
56767         }), publishReplay(1), refCount());
56768         const draggingStarted$ = this._container.mouseService
56769             .filtered$(this._name, this._container.mouseService.mouseDragStart$).pipe(map(() => {
56770             return true;
56771         }));
56772         const draggingStopped$ = this._container.mouseService
56773             .filtered$(this._name, this._container.mouseService.mouseDragEnd$).pipe(map(() => {
56774             return false;
56775         }));
56776         const filteredDragging$ = merge(draggingStarted$, draggingStopped$)
56777             .pipe(startWith(false));
56778         subs.push(merge(draggingStarted$.pipe(withLatestFrom(hoveredMarkerId$)), combineLatest(draggingStopped$, of(null))).pipe(startWith([false, null]), pairwise())
56779             .subscribe(([previous, current]) => {
56780             const dragging = current[0];
56781             const type = dragging ?
56782                 "markerdragstart" :
56783                 "markerdragend";
56784             const id = dragging ? current[1] : previous[1];
56785             const marker = this._markerScene.get(id);
56786             const event = {
56787                 marker,
56788                 target: this,
56789                 type,
56790             };
56791             this.fire(type, event);
56792         }));
56793         const mouseDown$ = merge(this._container.mouseService.mouseDown$.pipe(map(() => { return true; })), this._container.mouseService.documentMouseUp$.pipe(map(() => { return false; }))).pipe(startWith(false));
56794         subs.push(combineLatest(this._container.mouseService.active$, hoveredMarkerId$.pipe(distinctUntilChanged()), mouseDown$, filteredDragging$)
56795             .pipe(map(([active, markerId, mouseDown, filteredDragging]) => {
56796             return (!active && markerId != null && mouseDown) ||
56797                 filteredDragging;
56798         }), distinctUntilChanged())
56799             .subscribe((claim) => {
56800             if (claim) {
56801                 this._container.mouseService.claimMouse(this._name, 1);
56802                 this._container.mouseService.claimWheel(this._name, 1);
56803             }
56804             else {
56805                 this._container.mouseService.unclaimMouse(this._name);
56806                 this._container.mouseService.unclaimWheel(this._name);
56807             }
56808         }));
56809         const offset$ = this._container.mouseService
56810             .filtered$(this._name, this._container.mouseService.mouseDragStart$).pipe(withLatestFrom(hoveredMarkerId$, this._container.renderService.renderCamera$), map(([e, id, r]) => {
56811             const marker = this._markerScene.get(id);
56812             const element = this._container.container;
56813             const [groundCanvasX, groundCanvasY] = this._viewportCoords
56814                 .projectToCanvas(marker.geometry.position
56815                 .toArray(), element, r.perspective);
56816             const [canvasX, canvasY] = this._viewportCoords
56817                 .canvasPosition(e, element);
56818             const offset = [canvasX - groundCanvasX, canvasY - groundCanvasY];
56819             return [marker, offset, r];
56820         }), publishReplay(1), refCount());
56821         subs.push(this._container.mouseService
56822             .filtered$(this._name, this._container.mouseService.mouseDrag$)
56823             .pipe(withLatestFrom(offset$, this._navigator.stateService.reference$, clampedConfiguration$))
56824             .subscribe(([event, [marker, offset, render], reference, configuration]) => {
56825             if (!this._markerScene.has(marker.id)) {
56826                 return;
56827             }
56828             const element = this._container.container;
56829             const [canvasX, canvasY] = this._viewportCoords
56830                 .canvasPosition(event, element);
56831             const groundX = canvasX - offset[0];
56832             const groundY = canvasY - offset[1];
56833             const [viewportX, viewportY] = this._viewportCoords
56834                 .canvasToViewport(groundX, groundY, element);
56835             const direction = new Vector3(viewportX, viewportY, 1)
56836                 .unproject(render.perspective)
56837                 .sub(render.perspective.position)
56838                 .normalize();
56839             const distance = Math.min(this._relativeGroundAltitude / direction.z, configuration.visibleBBoxSize / 2 - 0.1);
56840             if (distance < 0) {
56841                 return;
56842             }
56843             const intersection = direction
56844                 .clone()
56845                 .multiplyScalar(distance)
56846                 .add(render.perspective.position);
56847             intersection.z =
56848                 render.perspective.position.z
56849                     + this._relativeGroundAltitude;
56850             const [lng, lat] = enuToGeodetic(intersection.x, intersection.y, intersection.z, reference.lng, reference.lat, reference.alt);
56851             this._markerScene
56852                 .update(marker.id, intersection.toArray(), { lat, lng });
56853             this._markerSet.update(marker);
56854             const type = "markerposition";
56855             const markerEvent = {
56856                 marker,
56857                 target: this,
56858                 type,
56859             };
56860             this.fire(type, markerEvent);
56861         }));
56862     }
56863     _deactivate() {
56864         this._subscriptions.unsubscribe();
56865         this._markerScene.clear();
56866     }
56867     _getDefaultConfiguration() {
56868         return { visibleBBoxSize: 100 };
56869     }
56870 }
56871 MarkerComponent.componentName = "marker";
56872
56873 function sign$1(n) {
56874     return n > 0 ? 1 : n < 0 ? -1 : 0;
56875 }
56876 function colinearPointOnSegment(p, s) {
56877     return p.x <= Math.max(s.p1.x, s.p2.x) &&
56878         p.x >= Math.min(s.p1.x, s.p2.x) &&
56879         p.y >= Math.max(s.p1.y, s.p2.y) &&
56880         p.y >= Math.min(s.p1.y, s.p2.y);
56881 }
56882 function parallel(s1, s2) {
56883     const ux = s1.p2.x - s1.p1.x;
56884     const uy = s1.p2.y - s1.p1.y;
56885     const vx = s2.p2.x - s2.p1.x;
56886     const vy = s2.p2.y - s2.p1.y;
56887     const cross = ux * vy - uy * vx;
56888     const u2 = ux * ux + uy * uy;
56889     const v2 = vx * vx + vy * vy;
56890     const epsilon2 = 1e-10;
56891     return cross * cross < epsilon2 * u2 * v2;
56892 }
56893 function tripletOrientation(p1, p2, p3) {
56894     const orientation = (p2.y - p1.y) * (p3.x - p2.x) -
56895         (p3.y - p2.y) * (p2.x - p1.x);
56896     return sign$1(orientation);
56897 }
56898 function segmentsIntersect(s1, s2) {
56899     if (parallel(s1, s2)) {
56900         return false;
56901     }
56902     const o1 = tripletOrientation(s1.p1, s1.p2, s2.p1);
56903     const o2 = tripletOrientation(s1.p1, s1.p2, s2.p2);
56904     const o3 = tripletOrientation(s2.p1, s2.p2, s1.p1);
56905     const o4 = tripletOrientation(s2.p1, s2.p2, s1.p2);
56906     if (o1 !== o2 && o3 !== o4) {
56907         return true;
56908     }
56909     if (o1 === 0 && colinearPointOnSegment(s2.p1, s1)) {
56910         return true;
56911     }
56912     if (o2 === 0 && colinearPointOnSegment(s2.p2, s1)) {
56913         return true;
56914     }
56915     if (o3 === 0 && colinearPointOnSegment(s1.p1, s2)) {
56916         return true;
56917     }
56918     if (o4 === 0 && colinearPointOnSegment(s1.p2, s2)) {
56919         return true;
56920     }
56921     return false;
56922 }
56923 function segmentIntersection(s1, s2) {
56924     if (parallel(s1, s2)) {
56925         return undefined;
56926     }
56927     const x1 = s1.p1.x;
56928     const x2 = s1.p2.x;
56929     const y1 = s1.p1.y;
56930     const y2 = s1.p2.y;
56931     const x3 = s2.p1.x;
56932     const x4 = s2.p2.x;
56933     const y3 = s2.p1.y;
56934     const y4 = s2.p2.y;
56935     const den = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
56936     const xNum = (x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4);
56937     const yNum = (x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4);
56938     return { x: xNum / den, y: yNum / den };
56939 }
56940
56941 function basicBoundaryPoints(pointsPerSide) {
56942     let points = [];
56943     let os = [[0, 0], [1, 0], [1, 1], [0, 1]];
56944     let ds = [[1, 0], [0, 1], [-1, 0], [0, -1]];
56945     for (let side = 0; side < 4; ++side) {
56946         let o = os[side];
56947         let d = ds[side];
56948         for (let i = 0; i < pointsPerSide; ++i) {
56949             points.push([o[0] + d[0] * i / pointsPerSide,
56950                 o[1] + d[1] * i / pointsPerSide]);
56951         }
56952     }
56953     return points;
56954 }
56955 function insideViewport(x, y) {
56956     return x >= -1 && x <= 1 && y >= -1 && y <= 1;
56957 }
56958 function insideBasic(x, y) {
56959     return x >= 0 && x <= 1 && y >= 0 && y <= 1;
56960 }
56961 function viewportDistances(transform, perspective, viewportCoords) {
56962     const boundaryPointsBasic = basicBoundaryPoints(100);
56963     const boundaryPointsViewport = boundaryPointsBasic
56964         .map((basic) => {
56965         return viewportCoords.basicToViewportSafe(basic[0], basic[1], transform, perspective);
56966     });
56967     const visibleBoundaryPoints = [];
56968     const viewportSides = [
56969         { x: -1, y: 1 },
56970         { x: 1, y: 1 },
56971         { x: 1, y: -1 },
56972         { x: -1, y: -1 }
56973     ];
56974     const intersections = [false, false, false, false];
56975     for (let i = 0; i < boundaryPointsViewport.length; i++) {
56976         const p1 = boundaryPointsViewport[i];
56977         const p2 = boundaryPointsViewport[(i + 1) % boundaryPointsViewport.length];
56978         if (p1 === null) {
56979             continue;
56980         }
56981         if (p2 === null) {
56982             if (insideViewport(p1[0], p1[1])) {
56983                 visibleBoundaryPoints.push(p1);
56984             }
56985             continue;
56986         }
56987         const [x1, y1] = p1;
56988         const [x2, y2] = p2;
56989         if (insideViewport(x1, y1)) {
56990             if (insideViewport(x2, y2)) {
56991                 visibleBoundaryPoints.push(p1);
56992             }
56993             else {
56994                 for (let side = 0; side < 4; side++) {
56995                     const s1 = { p1: { x: x1, y: y1 }, p2: { x: x2, y: y2 } };
56996                     const s2 = { p1: viewportSides[side], p2: viewportSides[(side + 1) % 4] };
56997                     const intersecting = segmentsIntersect(s1, s2);
56998                     if (intersecting) {
56999                         const intersection = segmentIntersection(s1, s2);
57000                         visibleBoundaryPoints.push(p1, [intersection.x, intersection.y]);
57001                         intersections[side] = true;
57002                     }
57003                 }
57004             }
57005         }
57006     }
57007     const [topLeftBasicX, topLeftBasicY] = viewportCoords.viewportToBasic(-1, 1, transform, perspective);
57008     const [topRightBasicX, topRightBasicY] = viewportCoords.viewportToBasic(1, 1, transform, perspective);
57009     const [bottomRightBasicX, bottomRightBasicY] = viewportCoords.viewportToBasic(1, -1, transform, perspective);
57010     const [bottomLeftBasicX, bottomLeftBasicY] = viewportCoords.viewportToBasic(-1, -1, transform, perspective);
57011     if (insideBasic(topLeftBasicX, topLeftBasicY)) {
57012         intersections[3] = intersections[0] = true;
57013     }
57014     if (insideBasic(topRightBasicX, topRightBasicY)) {
57015         intersections[0] = intersections[1] = true;
57016     }
57017     if (insideBasic(bottomRightBasicX, bottomRightBasicY)) {
57018         intersections[1] = intersections[2] = true;
57019     }
57020     if (insideBasic(bottomLeftBasicX, bottomLeftBasicY)) {
57021         intersections[2] = intersections[3] = true;
57022     }
57023     const maximums = [-1, -1, 1, 1];
57024     for (let visibleBoundaryPoint of visibleBoundaryPoints) {
57025         const x = visibleBoundaryPoint[0];
57026         const y = visibleBoundaryPoint[1];
57027         if (x > maximums[1]) {
57028             maximums[1] = x;
57029         }
57030         if (x < maximums[3]) {
57031             maximums[3] = x;
57032         }
57033         if (y > maximums[0]) {
57034             maximums[0] = y;
57035         }
57036         if (y < maximums[2]) {
57037             maximums[2] = y;
57038         }
57039     }
57040     const boundary = [1, 1, -1, -1];
57041     const distances = [];
57042     for (let side = 0; side < 4; side++) {
57043         if (intersections[side]) {
57044             distances.push(0);
57045             continue;
57046         }
57047         distances.push(Math.abs(boundary[side] - maximums[side]));
57048     }
57049     return distances;
57050 }
57051
57052 /**
57053  * The `BounceHandler` ensures that the viewer bounces back to the image
57054  * when drag panning outside of the image edge.
57055  */
57056 class BounceHandler extends HandlerBase {
57057     constructor(component, container, navigator, viewportCoords, spatial) {
57058         super(component, container, navigator);
57059         this._spatial = spatial;
57060         this._viewportCoords = viewportCoords;
57061     }
57062     _enable() {
57063         const inTransition$ = this._navigator.stateService.currentState$.pipe(map((frame) => {
57064             return frame.state.alpha < 1;
57065         }), distinctUntilChanged());
57066         this._bounceSubscription = combineLatest(inTransition$, this._navigator.stateService.inTranslation$, this._container.mouseService.active$, this._container.touchService.active$).pipe(map((noForce) => {
57067             return noForce[0] || noForce[1] || noForce[2] || noForce[3];
57068         }), distinctUntilChanged(), switchMap((noForce) => {
57069             return noForce ?
57070                 empty() :
57071                 combineLatest(this._container.renderService.renderCamera$, this._navigator.stateService.currentTransform$.pipe(first()));
57072         }), withLatestFrom(this._navigator.panService.panImages$))
57073             .subscribe(([[render, transform], nts]) => {
57074             if (!transform.hasValidScale && render.camera.focal < 0.1) {
57075                 return;
57076             }
57077             if (render.perspective.aspect === 0 || render.perspective.aspect === Number.POSITIVE_INFINITY) {
57078                 return;
57079             }
57080             const distances = viewportDistances(transform, render.perspective, this._viewportCoords);
57081             const basic = this._viewportCoords.viewportToBasic(0, 0, transform, render.perspective);
57082             if ((basic[0] < 0 || basic[0] > 1) && nts.length > 0) {
57083                 distances[0] = distances[2] = 0;
57084             }
57085             for (const [, t] of nts) {
57086                 const d = viewportDistances(t, render.perspective, this._viewportCoords);
57087                 for (let i = 1; i < distances.length; i += 2) {
57088                     if (d[i] < distances[i]) {
57089                         distances[i] = d[i];
57090                     }
57091                 }
57092             }
57093             if (Math.max(...distances) < 0.01) {
57094                 return;
57095             }
57096             const horizontalDistance = distances[1] - distances[3];
57097             const verticalDistance = distances[0] - distances[2];
57098             const currentDirection = this._viewportCoords
57099                 .unprojectFromViewport(0, 0, render.perspective)
57100                 .sub(render.perspective.position);
57101             const directionPhi = this._viewportCoords
57102                 .unprojectFromViewport(horizontalDistance, 0, render.perspective)
57103                 .sub(render.perspective.position);
57104             const directionTheta = this._viewportCoords
57105                 .unprojectFromViewport(0, verticalDistance, render.perspective)
57106                 .sub(render.perspective.position);
57107             let phi = (horizontalDistance > 0 ? 1 : -1) * directionPhi.angleTo(currentDirection);
57108             let theta = (verticalDistance > 0 ? 1 : -1) * directionTheta.angleTo(currentDirection);
57109             const threshold = Math.PI / 60;
57110             const coeff = 1e-1;
57111             phi = this._spatial.clamp(coeff * phi, -threshold, threshold);
57112             theta = this._spatial.clamp(coeff * theta, -threshold, threshold);
57113             this._navigator.stateService.rotateUnbounded({ phi: phi, theta: theta });
57114         });
57115     }
57116     _disable() {
57117         this._bounceSubscription.unsubscribe();
57118     }
57119     _getConfiguration() {
57120         return {};
57121     }
57122 }
57123
57124 class MouseOperator {
57125     static filteredPairwiseMouseDrag$(name, mouseService) {
57126         return this._filteredPairwiseMouseDrag$(name, mouseService, mouseService.mouseDragStart$, mouseService.mouseDrag$, mouseService.mouseDragEnd$);
57127     }
57128     static filteredPairwiseMouseRightDrag$(name, mouseService) {
57129         return this._filteredPairwiseMouseDrag$(name, mouseService, mouseService.mouseRightDragStart$, mouseService.mouseRightDrag$, mouseService.mouseRightDragEnd$);
57130     }
57131     static _filteredPairwiseMouseDrag$(name, mouseService, mouseDragStart$, mouseDrag$, mouseDragEnd$) {
57132         return mouseService
57133             .filtered$(name, mouseDragStart$).pipe(switchMap((mouseDragStart) => {
57134             const dragging$ = concat(of(mouseDragStart), mouseService
57135                 .filtered$(name, mouseDrag$));
57136             const dragEnd$ = mouseService
57137                 .filtered$(name, mouseDragEnd$).pipe(map(() => {
57138                 return null;
57139             }));
57140             return merge(dragging$, dragEnd$).pipe(takeWhile((e) => {
57141                 return !!e;
57142             }), startWith(null));
57143         }), pairwise(), filter((pair) => {
57144             return pair[0] != null && pair[1] != null;
57145         }));
57146     }
57147 }
57148
57149 /**
57150  * The `DragPanHandler` allows the user to pan the viewer image by clicking and dragging the cursor.
57151  *
57152  * @example
57153  * ```js
57154  * var pointerComponent = viewer.getComponent("pointer");
57155  *
57156  * pointerComponent.dragPan.disable();
57157  * pointerComponent.dragPan.enable();
57158  *
57159  * var isEnabled = pointerComponent.dragPan.isEnabled;
57160  * ```
57161  */
57162 class DragPanHandler extends HandlerBase {
57163     /** @ignore */
57164     constructor(component, container, navigator, viewportCoords, spatial) {
57165         super(component, container, navigator);
57166         this._spatial = spatial;
57167         this._viewportCoords = viewportCoords;
57168     }
57169     _enable() {
57170         let draggingStarted$ = this._container.mouseService
57171             .filtered$(this._component.name, this._container.mouseService.mouseDragStart$).pipe(map(() => {
57172             return true;
57173         }), share());
57174         let draggingStopped$ = this._container.mouseService
57175             .filtered$(this._component.name, this._container.mouseService.mouseDragEnd$).pipe(map(() => {
57176             return false;
57177         }), share());
57178         this._activeMouseSubscription = merge(draggingStarted$, draggingStopped$)
57179             .subscribe(this._container.mouseService.activate$);
57180         const documentMouseMove$ = merge(draggingStarted$, draggingStopped$).pipe(switchMap((dragging) => {
57181             return dragging ?
57182                 this._container.mouseService.documentMouseMove$ :
57183                 empty();
57184         }));
57185         this._preventDefaultSubscription = merge(documentMouseMove$, this._container.touchService.touchMove$)
57186             .subscribe((event) => {
57187             event.preventDefault(); // prevent selection of content outside the viewer
57188         });
57189         let touchMovingStarted$ = this._container.touchService.singleTouchDragStart$.pipe(map(() => {
57190             return true;
57191         }));
57192         let touchMovingStopped$ = this._container.touchService.singleTouchDragEnd$.pipe(map(() => {
57193             return false;
57194         }));
57195         this._activeTouchSubscription = merge(touchMovingStarted$, touchMovingStopped$)
57196             .subscribe(this._container.touchService.activate$);
57197         const rotation$ = this._navigator.stateService.currentState$.pipe(map((frame) => {
57198             return isSpherical(frame.state.currentImage.cameraType) ||
57199                 frame.state.imagesAhead < 1;
57200         }), distinctUntilChanged(), switchMap((enable) => {
57201             if (!enable) {
57202                 return empty();
57203             }
57204             const mouseDrag$ = MouseOperator.filteredPairwiseMouseDrag$(this._component.name, this._container.mouseService);
57205             const singleTouchDrag$ = merge(this._container.touchService.singleTouchDragStart$, this._container.touchService.singleTouchDrag$, this._container.touchService.singleTouchDragEnd$.pipe(map(() => { return null; }))).pipe(map((event) => {
57206                 return event != null && event.touches.length > 0 ?
57207                     event.touches[0] : null;
57208             }), pairwise(), filter((pair) => {
57209                 return pair[0] != null && pair[1] != null;
57210             }));
57211             return merge(mouseDrag$, singleTouchDrag$);
57212         }), withLatestFrom(this._container.renderService.renderCamera$, this._navigator.stateService.currentTransform$, this._navigator.panService.panImages$), map(([events, render, transform, nts]) => {
57213             let previousEvent = events[0];
57214             let event = events[1];
57215             let movementX = event.clientX - previousEvent.clientX;
57216             let movementY = event.clientY - previousEvent.clientY;
57217             let element = this._container.container;
57218             let [canvasX, canvasY] = this._viewportCoords.canvasPosition(event, element);
57219             let currentDirection = this._viewportCoords.unprojectFromCanvas(canvasX, canvasY, element, render.perspective)
57220                 .sub(render.perspective.position);
57221             let directionX = this._viewportCoords.unprojectFromCanvas(canvasX - movementX, canvasY, element, render.perspective)
57222                 .sub(render.perspective.position);
57223             let directionY = this._viewportCoords.unprojectFromCanvas(canvasX, canvasY - movementY, element, render.perspective)
57224                 .sub(render.perspective.position);
57225             let phi = (movementX > 0 ? 1 : -1) * directionX.angleTo(currentDirection);
57226             let theta = (movementY > 0 ? -1 : 1) * directionY.angleTo(currentDirection);
57227             const distances = viewportDistances(transform, render.perspective, this._viewportCoords);
57228             for (const [, t] of nts) {
57229                 const d = viewportDistances(t, render.perspective, this._viewportCoords);
57230                 for (let i = 0; i < distances.length; i++) {
57231                     if (d[i] < distances[i]) {
57232                         distances[i] = d[i];
57233                     }
57234                 }
57235             }
57236             if (distances[0] > 0 && theta < 0) {
57237                 theta /= Math.max(1, 2e2 * distances[0]);
57238             }
57239             if (distances[2] > 0 && theta > 0) {
57240                 theta /= Math.max(1, 2e2 * distances[2]);
57241             }
57242             if (distances[1] > 0 && phi < 0) {
57243                 phi /= Math.max(1, 2e2 * distances[1]);
57244             }
57245             if (distances[3] > 0 && phi > 0) {
57246                 phi /= Math.max(1, 2e2 * distances[3]);
57247             }
57248             return { phi: phi, theta: theta };
57249         }), share());
57250         this._rotateWithoutInertiaSubscription = rotation$
57251             .subscribe((rotation) => {
57252             this._navigator.stateService.rotateWithoutInertia(rotation);
57253         });
57254         this._rotateSubscription = rotation$.pipe(scan((rotationBuffer, rotation) => {
57255             this._drainBuffer(rotationBuffer);
57256             rotationBuffer.push([Date.now(), rotation]);
57257             return rotationBuffer;
57258         }, []), sample(merge(this._container.mouseService.filtered$(this._component.name, this._container.mouseService.mouseDragEnd$), this._container.touchService.singleTouchDragEnd$)), map((rotationBuffer) => {
57259             const drainedBuffer = this._drainBuffer(rotationBuffer.slice());
57260             const rotation = { phi: 0, theta: 0 };
57261             for (const bufferedRotation of drainedBuffer) {
57262                 rotation.phi += bufferedRotation[1].phi;
57263                 rotation.theta += bufferedRotation[1].theta;
57264             }
57265             const count = drainedBuffer.length;
57266             if (count > 0) {
57267                 rotation.phi /= count;
57268                 rotation.theta /= count;
57269             }
57270             const threshold = Math.PI / 18;
57271             rotation.phi = this._spatial.clamp(rotation.phi, -threshold, threshold);
57272             rotation.theta = this._spatial.clamp(rotation.theta, -threshold, threshold);
57273             return rotation;
57274         }))
57275             .subscribe((rotation) => {
57276             this._navigator.stateService.rotate(rotation);
57277         });
57278     }
57279     _disable() {
57280         this._activeMouseSubscription.unsubscribe();
57281         this._activeTouchSubscription.unsubscribe();
57282         this._preventDefaultSubscription.unsubscribe();
57283         this._rotateSubscription.unsubscribe();
57284         this._rotateWithoutInertiaSubscription.unsubscribe();
57285         this._activeMouseSubscription = null;
57286         this._activeTouchSubscription = null;
57287         this._preventDefaultSubscription = null;
57288         this._rotateSubscription = null;
57289     }
57290     _getConfiguration(enable) {
57291         return { dragPan: enable };
57292     }
57293     _drainBuffer(buffer) {
57294         const cutoff = 50;
57295         const now = Date.now();
57296         while (buffer.length > 0 && now - buffer[0][0] > cutoff) {
57297             buffer.shift();
57298         }
57299         return buffer;
57300     }
57301 }
57302
57303 class EarthControlHandler extends HandlerBase {
57304     /** @ignore */
57305     constructor(component, container, navigator, viewportCoords, spatial) {
57306         super(component, container, navigator);
57307         this._spatial = spatial;
57308         this._viewportCoords = viewportCoords;
57309         this._subscriptions = new SubscriptionHolder();
57310     }
57311     _enable() {
57312         const earth$ = this._navigator.stateService.state$.pipe(map((state) => {
57313             return state === State.Earth;
57314         }), publishReplay(1), refCount());
57315         const subs = this._subscriptions;
57316         subs.push(earth$.pipe(switchMap((earth) => {
57317             return earth ?
57318                 this._container.mouseService.mouseWheel$ :
57319                 empty();
57320         }))
57321             .subscribe((event) => {
57322             event.preventDefault();
57323         }));
57324         subs.push(earth$.pipe(switchMap((earth) => {
57325             if (!earth) {
57326                 return empty();
57327             }
57328             return MouseOperator.filteredPairwiseMouseDrag$(this._component.name, this._container.mouseService).pipe(filter(([e1, e2]) => {
57329                 return !(e1.ctrlKey && e2.ctrlKey);
57330             }));
57331         }), withLatestFrom(this._container.renderService.renderCamera$, this._navigator.stateService.currentTransform$), map(([[previous, current], render, transform]) => {
57332             const planeNormal = [0, 0, 1];
57333             const planePoint = [0, 0, -2];
57334             const currentIntersection = this._planeIntersection(current, planeNormal, planePoint, render.perspective, this._container.container);
57335             const previousIntersection = this._planeIntersection(previous, planeNormal, planePoint, render.perspective, this._container.container);
57336             if (!currentIntersection || !previousIntersection) {
57337                 return null;
57338             }
57339             const direction = new Vector3()
57340                 .subVectors(currentIntersection, previousIntersection)
57341                 .multiplyScalar(-1)
57342                 .toArray();
57343             return direction;
57344         }), filter((direction) => {
57345             return !!direction;
57346         }))
57347             .subscribe((direction) => {
57348             this._navigator.stateService.truck(direction);
57349         }));
57350         subs.push(earth$.pipe(switchMap((earth) => {
57351             if (!earth) {
57352                 return empty();
57353             }
57354             return MouseOperator.filteredPairwiseMouseDrag$(this._component.name, this._container.mouseService).pipe(filter(([e1, e2]) => {
57355                 return e1.ctrlKey && e2.ctrlKey;
57356             }));
57357         }), map(([previous, current]) => {
57358             return this._mousePairToRotation(previous, current);
57359         }))
57360             .subscribe((rotation) => {
57361             this._navigator.stateService.orbit(rotation);
57362         }));
57363         subs.push(earth$.pipe(switchMap((earth) => {
57364             if (!earth) {
57365                 return empty();
57366             }
57367             return MouseOperator.filteredPairwiseMouseRightDrag$(this._component.name, this._container.mouseService).pipe(filter(([e1, e2]) => {
57368                 return !e1.ctrlKey && !e2.ctrlKey;
57369             }));
57370         }), map(([previous, current]) => {
57371             return this._mousePairToRotation(previous, current);
57372         }))
57373             .subscribe((rotation) => {
57374             this._navigator.stateService.orbit(rotation);
57375         }));
57376         subs.push(earth$.pipe(switchMap((earth) => {
57377             if (!earth) {
57378                 return empty();
57379             }
57380             return this._container.mouseService
57381                 .filteredWheel$(this._component.name, this._container.mouseService.mouseWheel$);
57382         }), map((event) => {
57383             let delta = event.deltaY;
57384             if (event.deltaMode === 1) {
57385                 delta = 40 * delta;
57386             }
57387             else if (event.deltaMode === 2) {
57388                 delta = 800 * delta;
57389             }
57390             const canvasSize = this._viewportCoords.containerToCanvas(this._container.container);
57391             return -delta / canvasSize[1];
57392         }))
57393             .subscribe((delta) => {
57394             this._navigator.stateService.dolly(delta);
57395         }));
57396     }
57397     _disable() {
57398         this._subscriptions.unsubscribe();
57399     }
57400     _getConfiguration() {
57401         return {};
57402     }
57403     _eventToViewport(event, element) {
57404         const previousCanvas = this._viewportCoords.canvasPosition(event, element);
57405         return this._viewportCoords.canvasToViewport(previousCanvas[0], previousCanvas[1], element);
57406     }
57407     _mousePairToRotation(previous, current) {
57408         const [currentX, currentY] = this._eventToViewport(current, this._container.container);
57409         const [previousX, previousY] = this._eventToViewport(previous, this._container.container);
57410         const phi = (previousX - currentX) * Math.PI;
57411         const theta = (currentY - previousY) * Math.PI / 2;
57412         return { phi: phi, theta: theta };
57413     }
57414     _planeIntersection(event, planeNormal, planePoint, camera, element) {
57415         const [canvasX, canvasY] = this._viewportCoords.canvasPosition(event, element);
57416         const direction = this._viewportCoords
57417             .unprojectFromCanvas(canvasX, canvasY, element, camera)
57418             .sub(camera.position)
57419             .normalize();
57420         if (Math.abs(this._spatial.angleToPlane(direction.toArray(), planeNormal)) < Math.PI / 90) {
57421             return null;
57422         }
57423         const l0 = camera.position.clone();
57424         const n = new Vector3().fromArray(planeNormal);
57425         const p0 = new Vector3().fromArray(planePoint);
57426         const d = new Vector3().subVectors(p0, l0).dot(n) / direction.clone().dot(n);
57427         const intersection = new Vector3().addVectors(l0, direction.multiplyScalar(d));
57428         if (this._viewportCoords.worldToCamera(intersection.toArray(), camera)[2] > 0) {
57429             return null;
57430         }
57431         return intersection;
57432     }
57433 }
57434
57435 /**
57436  * The `ScrollZoomHandler` allows the user to zoom the viewer image by scrolling.
57437  *
57438  * @example
57439  * ```js
57440  * var pointerComponent = viewer.getComponent("pointer");
57441  *
57442  * pointerComponent.scrollZoom.disable();
57443  * pointerComponent.scrollZoom.enable();
57444  *
57445  * var isEnabled = pointerComponent.scrollZoom.isEnabled;
57446  * ```
57447  */
57448 class ScrollZoomHandler extends HandlerBase {
57449     /** @ignore */
57450     constructor(component, container, navigator, viewportCoords) {
57451         super(component, container, navigator);
57452         this._viewportCoords = viewportCoords;
57453     }
57454     _enable() {
57455         this._container.mouseService.claimWheel(this._component.name, 0);
57456         this._preventDefaultSubscription = this._container.mouseService.mouseWheel$
57457             .subscribe((event) => {
57458             event.preventDefault();
57459         });
57460         this._zoomSubscription = this._container.mouseService
57461             .filteredWheel$(this._component.name, this._container.mouseService.mouseWheel$).pipe(withLatestFrom(this._navigator.stateService.currentState$, (w, f) => {
57462             return [w, f];
57463         }), filter((args) => {
57464             let state = args[1].state;
57465             return isSpherical(state.currentImage.cameraType) ||
57466                 state.imagesAhead < 1;
57467         }), map((args) => {
57468             return args[0];
57469         }), withLatestFrom(this._container.renderService.renderCamera$, this._navigator.stateService.currentTransform$, (w, r, t) => {
57470             return [w, r, t];
57471         }))
57472             .subscribe((args) => {
57473             let event = args[0];
57474             let render = args[1];
57475             let transform = args[2];
57476             let element = this._container.container;
57477             let [canvasX, canvasY] = this._viewportCoords.canvasPosition(event, element);
57478             let unprojected = this._viewportCoords.unprojectFromCanvas(canvasX, canvasY, element, render.perspective);
57479             let reference = transform.projectBasic(unprojected.toArray());
57480             let deltaY = event.deltaY;
57481             if (event.deltaMode === 1) {
57482                 deltaY = 40 * deltaY;
57483             }
57484             else if (event.deltaMode === 2) {
57485                 deltaY = 800 * deltaY;
57486             }
57487             const canvasSize = this._viewportCoords.containerToCanvas(element);
57488             let zoom = -3 * deltaY / canvasSize[1];
57489             this._navigator.stateService.zoomIn(zoom, reference);
57490         });
57491     }
57492     _disable() {
57493         this._container.mouseService.unclaimWheel(this._component.name);
57494         this._preventDefaultSubscription.unsubscribe();
57495         this._zoomSubscription.unsubscribe();
57496         this._preventDefaultSubscription = null;
57497         this._zoomSubscription = null;
57498     }
57499     _getConfiguration(enable) {
57500         return { scrollZoom: enable };
57501     }
57502 }
57503
57504 /**
57505  * The `TouchZoomHandler` allows the user to zoom the viewer image by pinching on a touchscreen.
57506  *
57507  * @example
57508  * ```js
57509  * var pointerComponent = viewer.getComponent("pointer");
57510  *
57511  * pointerComponent.touchZoom.disable();
57512  * pointerComponent.touchZoom.enable();
57513  *
57514  * var isEnabled = pointerComponent.touchZoom.isEnabled;
57515  * ```
57516  */
57517 class TouchZoomHandler extends HandlerBase {
57518     /** @ignore */
57519     constructor(component, container, navigator, viewportCoords) {
57520         super(component, container, navigator);
57521         this._viewportCoords = viewportCoords;
57522     }
57523     _enable() {
57524         this._preventDefaultSubscription = this._container.touchService.pinch$
57525             .subscribe((pinch) => {
57526             pinch.originalEvent.preventDefault();
57527         });
57528         let pinchStarted$ = this._container.touchService.pinchStart$.pipe(map((event) => {
57529             return true;
57530         }));
57531         let pinchStopped$ = this._container.touchService.pinchEnd$.pipe(map((event) => {
57532             return false;
57533         }));
57534         this._activeSubscription = merge(pinchStarted$, pinchStopped$)
57535             .subscribe(this._container.touchService.activate$);
57536         this._zoomSubscription = this._container.touchService.pinch$.pipe(withLatestFrom(this._navigator.stateService.currentState$), filter((args) => {
57537             let state = args[1].state;
57538             return isSpherical(state.currentImage.cameraType) ||
57539                 state.imagesAhead < 1;
57540         }), map((args) => {
57541             return args[0];
57542         }), withLatestFrom(this._container.renderService.renderCamera$, this._navigator.stateService.currentTransform$))
57543             .subscribe(([pinch, render, transform]) => {
57544             let element = this._container.container;
57545             let [canvasX, canvasY] = this._viewportCoords.canvasPosition(pinch, element);
57546             let unprojected = this._viewportCoords.unprojectFromCanvas(canvasX, canvasY, element, render.perspective);
57547             let reference = transform.projectBasic(unprojected.toArray());
57548             const [canvasWidth, canvasHeight] = this._viewportCoords.containerToCanvas(element);
57549             let zoom = 3 * pinch.distanceChange / Math.min(canvasWidth, canvasHeight);
57550             this._navigator.stateService.zoomIn(zoom, reference);
57551         });
57552     }
57553     _disable() {
57554         this._activeSubscription.unsubscribe();
57555         this._preventDefaultSubscription.unsubscribe();
57556         this._zoomSubscription.unsubscribe();
57557         this._preventDefaultSubscription = null;
57558         this._zoomSubscription = null;
57559     }
57560     _getConfiguration(enable) {
57561         return { touchZoom: enable };
57562     }
57563 }
57564
57565 /**
57566  * @class PointerComponent
57567  *
57568  * @classdesc Component handling mouse, pen, and touch events for camera movement.
57569  *
57570  * To retrive and use the mouse component
57571  *
57572  * @example
57573  * ```js
57574  * var viewer = new Viewer({ ... });
57575  *
57576  * var pointerComponent = viewer.getComponent("pointer");
57577  * ```
57578  */
57579 class PointerComponent extends Component {
57580     /** @ignore */
57581     constructor(name, container, navigator) {
57582         super(name, container, navigator);
57583         const spatial = new Spatial();
57584         const viewportCoords = new ViewportCoords();
57585         this._bounceHandler =
57586             new BounceHandler(this, container, navigator, viewportCoords, spatial);
57587         this._dragPanHandler =
57588             new DragPanHandler(this, container, navigator, viewportCoords, spatial);
57589         this._earthControlHandler =
57590             new EarthControlHandler(this, container, navigator, viewportCoords, spatial);
57591         this._scrollZoomHandler =
57592             new ScrollZoomHandler(this, container, navigator, viewportCoords);
57593         this._touchZoomHandler =
57594             new TouchZoomHandler(this, container, navigator, viewportCoords);
57595     }
57596     /**
57597      * Get drag pan.
57598      *
57599      * @returns {DragPanHandler} The drag pan handler.
57600      */
57601     get dragPan() {
57602         return this._dragPanHandler;
57603     }
57604     /**
57605      * Get earth control.
57606      *
57607      * @returns {EarthControlHandler} The earth control handler.
57608      */
57609     get earthControl() {
57610         return this._earthControlHandler;
57611     }
57612     /**
57613      * Get scroll zoom.
57614      *
57615      * @returns {ScrollZoomHandler} The scroll zoom handler.
57616      */
57617     get scrollZoom() {
57618         return this._scrollZoomHandler;
57619     }
57620     /**
57621      * Get touch zoom.
57622      *
57623      * @returns {TouchZoomHandler} The touch zoom handler.
57624      */
57625     get touchZoom() {
57626         return this._touchZoomHandler;
57627     }
57628     _activate() {
57629         this._bounceHandler.enable();
57630         this._subscriptions.push(this._configuration$
57631             .subscribe((configuration) => {
57632             if (configuration.dragPan) {
57633                 this._dragPanHandler.enable();
57634             }
57635             else {
57636                 this._dragPanHandler.disable();
57637             }
57638             if (configuration.earthControl) {
57639                 this._earthControlHandler.enable();
57640             }
57641             else {
57642                 this._earthControlHandler.disable();
57643             }
57644             if (configuration.scrollZoom) {
57645                 this._scrollZoomHandler.enable();
57646             }
57647             else {
57648                 this._scrollZoomHandler.disable();
57649             }
57650             if (configuration.touchZoom) {
57651                 this._touchZoomHandler.enable();
57652             }
57653             else {
57654                 this._touchZoomHandler.disable();
57655             }
57656         }));
57657         this._container.mouseService.claimMouse(this._name, 0);
57658     }
57659     _deactivate() {
57660         this._container.mouseService.unclaimMouse(this._name);
57661         this._subscriptions.unsubscribe();
57662         this._bounceHandler.disable();
57663         this._dragPanHandler.disable();
57664         this._earthControlHandler.disable();
57665         this._scrollZoomHandler.disable();
57666         this._touchZoomHandler.disable();
57667     }
57668     _getDefaultConfiguration() {
57669         return {
57670             dragPan: true,
57671             earthControl: true,
57672             scrollZoom: true,
57673             touchZoom: true,
57674         };
57675     }
57676 }
57677 /** @inheritdoc */
57678 PointerComponent.componentName = "pointer";
57679
57680 class DOM {
57681     constructor(doc) {
57682         this._document = !!doc ? doc : document;
57683     }
57684     get document() {
57685         return this._document;
57686     }
57687     createElement(tagName, className, container) {
57688         const element = this._document.createElement(tagName);
57689         if (!!className) {
57690             element.className = className;
57691         }
57692         if (!!container) {
57693             container.appendChild(element);
57694         }
57695         return element;
57696     }
57697 }
57698
57699 /**
57700  * @class PopupComponent
57701  *
57702  * @classdesc Component for showing HTML popup objects.
57703  *
57704  * The `add` method is used for adding new popups. Popups are removed by reference.
57705  *
57706  * It is not possible to update popups in the set by updating any properties
57707  * directly on the popup object. Popups need to be replaced by
57708  * removing them and creating new ones with relevant changed properties and
57709  * adding those instead.
57710  *
57711  * Popups are only relevant to a single image because they are based on
57712  * 2D basic image coordinates. Popups related to a certain image should
57713  * be removed when the viewer is moved to another image.
57714  *
57715  * To retrive and use the popup component
57716  *
57717  * @example
57718  * ```js
57719  * var viewer = new Viewer({ component: { popup: true }, ... });
57720  *
57721  * var popupComponent = viewer.getComponent("popup");
57722  * ```
57723  */
57724 class PopupComponent extends Component {
57725     /** @ignore */
57726     constructor(name, container, navigator, dom) {
57727         super(name, container, navigator);
57728         this._dom = !!dom ? dom : new DOM();
57729         this._popups = [];
57730         this._added$ = new Subject();
57731         this._popups$ = new Subject();
57732     }
57733     /**
57734      * Add popups to the popups set.
57735      *
57736      * @description Adding a new popup never replaces an old one
57737      * because they are stored by reference. Adding an already
57738      * existing popup has no effect.
57739      *
57740      * @param {Array<Popup>} popups - Popups to add.
57741      *
57742      * @example
57743      * ```js
57744      * popupComponent.add([popup1, popup2]);
57745      * ```
57746      */
57747     add(popups) {
57748         for (const popup of popups) {
57749             if (this._popups.indexOf(popup) !== -1) {
57750                 continue;
57751             }
57752             this._popups.push(popup);
57753             if (this._activated) {
57754                 popup.setParentContainer(this._popupContainer);
57755             }
57756         }
57757         this._added$.next(popups);
57758         this._popups$.next(this._popups);
57759     }
57760     /**
57761      * Returns an array of all popups.
57762      *
57763      * @example
57764      * ```js
57765      * var popups = popupComponent.getAll();
57766      * ```
57767      */
57768     getAll() {
57769         return this._popups.slice();
57770     }
57771     /**
57772      * Remove popups based on reference from the popup set.
57773      *
57774      * @param {Array<Popup>} popups - Popups to remove.
57775      *
57776      * @example
57777      * ```js
57778      * popupComponent.remove([popup1, popup2]);
57779      * ```
57780      */
57781     remove(popups) {
57782         for (const popup of popups) {
57783             this._remove(popup);
57784         }
57785         this._popups$.next(this._popups);
57786     }
57787     /**
57788      * Remove all popups from the popup set.
57789      *
57790      * @example
57791      * ```js
57792      * popupComponent.removeAll();
57793      * ```
57794      */
57795     removeAll() {
57796         for (const popup of this._popups.slice()) {
57797             this._remove(popup);
57798         }
57799         this._popups$.next(this._popups);
57800     }
57801     _activate() {
57802         this._popupContainer = this._dom.createElement("div", "mapillary-popup-container", this._container.container);
57803         for (const popup of this._popups) {
57804             popup.setParentContainer(this._popupContainer);
57805         }
57806         const subs = this._subscriptions;
57807         subs.push(combineLatest(this._container.renderService.renderCamera$, this._container.renderService.size$, this._navigator.stateService.currentTransform$)
57808             .subscribe(([renderCamera, size, transform]) => {
57809             for (const popup of this._popups) {
57810                 popup.update(renderCamera, size, transform);
57811             }
57812         }));
57813         const changed$ = this._popups$.pipe(startWith(this._popups), switchMap((popups) => {
57814             return from(popups).pipe(mergeMap((popup) => {
57815                 return popup.changed$;
57816             }));
57817         }), map((popup) => {
57818             return [popup];
57819         }));
57820         subs.push(merge(this._added$, changed$).pipe(withLatestFrom(this._container.renderService.renderCamera$, this._container.renderService.size$, this._navigator.stateService.currentTransform$))
57821             .subscribe(([popups, renderCamera, size, transform]) => {
57822             for (const popup of popups) {
57823                 popup.update(renderCamera, size, transform);
57824             }
57825         }));
57826     }
57827     _deactivate() {
57828         this._subscriptions.unsubscribe();
57829         for (const popup of this._popups) {
57830             popup.remove();
57831         }
57832         this._container.container.removeChild(this._popupContainer);
57833         delete this._popupContainer;
57834     }
57835     _getDefaultConfiguration() {
57836         return {};
57837     }
57838     _remove(popup) {
57839         const index = this._popups.indexOf(popup);
57840         if (index === -1) {
57841             return;
57842         }
57843         const removed = this._popups.splice(index, 1)[0];
57844         if (this._activated) {
57845             removed.remove();
57846         }
57847     }
57848 }
57849 PopupComponent.componentName = "popup";
57850
57851 /**
57852  * Enumeration for graph modes.
57853  * @enum {number}
57854  * @readonly
57855  * @description Modes for the retrieval and caching performed
57856  * by the graph service on the graph.
57857  */
57858 var GraphMode;
57859 (function (GraphMode) {
57860     /**
57861      * Caching is performed on sequences only and sequence edges are
57862      * calculated. Spatial tiles
57863      * are not retrieved and spatial edges are not calculated when
57864      * caching nodes. Complete sequences are being cached for requested
57865      * nodes within the graph.
57866      */
57867     GraphMode[GraphMode["Sequence"] = 0] = "Sequence";
57868     /**
57869      * Caching is performed with emphasis on spatial data. Sequence edges
57870      * as well as spatial edges are cached. Sequence data
57871      * is still requested but complete sequences are not being cached
57872      * for requested nodes.
57873      *
57874      * This is the initial mode of the graph service.
57875      */
57876     GraphMode[GraphMode["Spatial"] = 1] = "Spatial";
57877 })(GraphMode || (GraphMode = {}));
57878
57879 var SequenceMode;
57880 (function (SequenceMode) {
57881     SequenceMode[SequenceMode["Default"] = 0] = "Default";
57882     SequenceMode[SequenceMode["Playback"] = 1] = "Playback";
57883     SequenceMode[SequenceMode["Timeline"] = 2] = "Timeline";
57884 })(SequenceMode || (SequenceMode = {}));
57885
57886 class SequenceDOMRenderer {
57887     constructor(container) {
57888         this._container = container;
57889         this._minThresholdWidth = 320;
57890         this._maxThresholdWidth = 1480;
57891         this._minThresholdHeight = 240;
57892         this._maxThresholdHeight = 820;
57893         this._stepperDefaultWidth = 108;
57894         this._controlsDefaultWidth = 88;
57895         this._defaultHeight = 30;
57896         this._expandControls = false;
57897         this._mode = SequenceMode.Default;
57898         this._speed = 0.5;
57899         this._changingSpeed = false;
57900         this._index = null;
57901         this._changingPosition = false;
57902         this._mouseEnterDirection$ = new Subject();
57903         this._mouseLeaveDirection$ = new Subject();
57904         this._notifyChanged$ = new Subject();
57905         this._notifyChangingPositionChanged$ = new Subject();
57906         this._notifySpeedChanged$ = new Subject();
57907         this._notifyIndexChanged$ = new Subject();
57908     }
57909     get changed$() {
57910         return this._notifyChanged$;
57911     }
57912     get changingPositionChanged$() {
57913         return this._notifyChangingPositionChanged$;
57914     }
57915     get speed$() {
57916         return this._notifySpeedChanged$;
57917     }
57918     get index$() {
57919         return this._notifyIndexChanged$;
57920     }
57921     get mouseEnterDirection$() {
57922         return this._mouseEnterDirection$;
57923     }
57924     get mouseLeaveDirection$() {
57925         return this._mouseLeaveDirection$;
57926     }
57927     activate() {
57928         if (!!this._changingSubscription) {
57929             return;
57930         }
57931         this._changingSubscription = merge(this._container.mouseService.documentMouseUp$, this._container.touchService.touchEnd$.pipe(filter((touchEvent) => {
57932             return touchEvent.touches.length === 0;
57933         })))
57934             .subscribe(() => {
57935             if (this._changingSpeed) {
57936                 this._changingSpeed = false;
57937             }
57938             if (this._changingPosition) {
57939                 this._setChangingPosition(false);
57940             }
57941         });
57942     }
57943     deactivate() {
57944         if (!this._changingSubscription) {
57945             return;
57946         }
57947         this._changingSpeed = false;
57948         this._changingPosition = false;
57949         this._expandControls = false;
57950         this._mode = SequenceMode.Default;
57951         this._changingSubscription.unsubscribe();
57952         this._changingSubscription = null;
57953     }
57954     render(edgeStatus, configuration, containerWidth, speed, index, max, playEnabled, component, navigator) {
57955         if (configuration.visible === false) {
57956             return virtualDom.h("div.mapillary-sequence-container", {}, []);
57957         }
57958         const stepper = this._createStepper(edgeStatus, configuration, playEnabled, containerWidth, component, navigator);
57959         const controls = this._createSequenceControls(containerWidth);
57960         const playback = this._createPlaybackControls(containerWidth, speed, component, configuration);
57961         const timeline = this._createTimelineControls(containerWidth, index, max);
57962         return virtualDom.h("div.mapillary-sequence-container", [stepper, controls, playback, timeline]);
57963     }
57964     getContainerWidth(size, configuration) {
57965         let minWidth = configuration.minWidth;
57966         let maxWidth = configuration.maxWidth;
57967         if (maxWidth < minWidth) {
57968             maxWidth = minWidth;
57969         }
57970         let relativeWidth = (size.width - this._minThresholdWidth) / (this._maxThresholdWidth - this._minThresholdWidth);
57971         let relativeHeight = (size.height - this._minThresholdHeight) / (this._maxThresholdHeight - this._minThresholdHeight);
57972         let coeff = Math.max(0, Math.min(1, Math.min(relativeWidth, relativeHeight)));
57973         return minWidth + coeff * (maxWidth - minWidth);
57974     }
57975     _createPositionInput(index, max) {
57976         this._index = index;
57977         const onPosition = (e) => {
57978             this._index = Number(e.target.value);
57979             this._notifyIndexChanged$.next(this._index);
57980         };
57981         const boundingRect = this._container.domContainer.getBoundingClientRect();
57982         const width = Math.max(276, Math.min(410, 5 + 0.8 * boundingRect.width)) - 65;
57983         const onStart = (e) => {
57984             e.stopPropagation();
57985             this._setChangingPosition(true);
57986         };
57987         const onMove = (e) => {
57988             if (this._changingPosition === true) {
57989                 e.stopPropagation();
57990             }
57991         };
57992         const onKeyDown = (e) => {
57993             if (e.key === "ArrowDown" || e.key === "ArrowLeft" ||
57994                 e.key === "ArrowRight" || e.key === "ArrowUp") {
57995                 e.preventDefault();
57996             }
57997         };
57998         const positionInputProperties = {
57999             max: max != null ? max : 1,
58000             min: 0,
58001             onchange: onPosition,
58002             oninput: onPosition,
58003             onkeydown: onKeyDown,
58004             onpointerdown: onStart,
58005             onpointermove: onMove,
58006             ontouchmove: onMove,
58007             ontouchstart: onStart,
58008             style: {
58009                 width: `${width}px`,
58010             },
58011             type: "range",
58012             value: index != null ? index : 0,
58013         };
58014         const disabled = index == null || max == null || max <= 1;
58015         if (disabled) {
58016             positionInputProperties.disabled = "true";
58017         }
58018         const positionInput = virtualDom.h("input.mapillary-sequence-position", positionInputProperties, []);
58019         const positionContainerClass = disabled ? ".mapillary-sequence-position-container-inactive" : ".mapillary-sequence-position-container";
58020         return virtualDom.h("div" + positionContainerClass, [positionInput]);
58021     }
58022     _createSpeedInput(speed) {
58023         this._speed = speed;
58024         const onSpeed = (e) => {
58025             this._speed = Number(e.target.value) / 1000;
58026             this._notifySpeedChanged$.next(this._speed);
58027         };
58028         const boundingRect = this._container.domContainer.getBoundingClientRect();
58029         const width = Math.max(276, Math.min(410, 5 + 0.8 * boundingRect.width)) - 160;
58030         const onStart = (e) => {
58031             this._changingSpeed = true;
58032             e.stopPropagation();
58033         };
58034         const onMove = (e) => {
58035             if (this._changingSpeed === true) {
58036                 e.stopPropagation();
58037             }
58038         };
58039         const onKeyDown = (e) => {
58040             if (e.key === "ArrowDown" || e.key === "ArrowLeft" ||
58041                 e.key === "ArrowRight" || e.key === "ArrowUp") {
58042                 e.preventDefault();
58043             }
58044         };
58045         const speedInput = virtualDom.h("input.mapillary-sequence-speed", {
58046             max: 1000,
58047             min: 0,
58048             onchange: onSpeed,
58049             oninput: onSpeed,
58050             onkeydown: onKeyDown,
58051             onpointerdown: onStart,
58052             onpointermove: onMove,
58053             ontouchmove: onMove,
58054             ontouchstart: onStart,
58055             style: {
58056                 width: `${width}px`,
58057             },
58058             type: "range",
58059             value: 1000 * speed,
58060         }, []);
58061         return virtualDom.h("div.mapillary-sequence-speed-container", [speedInput]);
58062     }
58063     _createPlaybackControls(containerWidth, speed, component, configuration) {
58064         if (this._mode !== SequenceMode.Playback) {
58065             return virtualDom.h("div.mapillary-sequence-playback", []);
58066         }
58067         const switchIcon = virtualDom.h("div.mapillary-sequence-switch-icon.mapillary-sequence-icon-visible", []);
58068         const direction = configuration.direction === NavigationDirection.Next ?
58069             NavigationDirection.Prev : NavigationDirection.Next;
58070         const playing = configuration.playing;
58071         const switchButtonProperties = {
58072             onclick: () => {
58073                 if (!playing) {
58074                     component.configure({ direction });
58075                 }
58076             },
58077         };
58078         const switchButtonClassName = configuration.playing ? ".mapillary-sequence-switch-button-inactive" : ".mapillary-sequence-switch-button";
58079         const switchButton = virtualDom.h("div" + switchButtonClassName, switchButtonProperties, [switchIcon]);
58080         const slowIcon = virtualDom.h("div.mapillary-sequence-slow-icon.mapillary-sequence-icon-visible", []);
58081         const slowContainer = virtualDom.h("div.mapillary-sequence-slow-container", [slowIcon]);
58082         const fastIcon = virtualDom.h("div.mapillary-sequence-fast-icon.mapillary-sequence-icon-visible", []);
58083         const fastContainer = virtualDom.h("div.mapillary-sequence-fast-container", [fastIcon]);
58084         const closeIcon = virtualDom.h("div.mapillary-sequence-close-icon.mapillary-sequence-icon-visible", []);
58085         const closeButtonProperties = {
58086             onclick: () => {
58087                 this._mode = SequenceMode.Default;
58088                 this._notifyChanged$.next(this);
58089             },
58090         };
58091         const closeButton = virtualDom.h("div.mapillary-sequence-close-button", closeButtonProperties, [closeIcon]);
58092         const speedInput = this._createSpeedInput(speed);
58093         const playbackChildren = [switchButton, slowContainer, speedInput, fastContainer, closeButton];
58094         const top = Math.round(containerWidth / this._stepperDefaultWidth * this._defaultHeight + 10);
58095         const playbackProperties = { style: { top: `${top}px` } };
58096         return virtualDom.h("div.mapillary-sequence-playback", playbackProperties, playbackChildren);
58097     }
58098     _createPlayingButton(nextId, prevId, playEnabled, configuration, component) {
58099         let canPlay = (configuration.direction === NavigationDirection.Next && nextId != null) ||
58100             (configuration.direction === NavigationDirection.Prev && prevId != null);
58101         canPlay = canPlay && playEnabled;
58102         let onclick = configuration.playing ?
58103             () => { component.stop(); } :
58104             canPlay ? () => { component.play(); } : null;
58105         let buttonProperties = { onclick: onclick };
58106         let iconProperties = {};
58107         if (configuration.direction === NavigationDirection.Prev) {
58108             iconProperties.style = {
58109                 transform: "rotate(180deg) translate(50%, 50%)",
58110             };
58111         }
58112         let icon = virtualDom.h("div.mapillary-sequence-icon", iconProperties, []);
58113         let buttonClass = configuration.playing ?
58114             "mapillary-sequence-stop" :
58115             canPlay ?
58116                 "mapillary-sequence-play" :
58117                 "mapillary-sequence-play-inactive";
58118         return virtualDom.h("div." + buttonClass, buttonProperties, [icon]);
58119     }
58120     _createSequenceControls(containerWidth) {
58121         const borderRadius = Math.round(8 / this._stepperDefaultWidth * containerWidth);
58122         const expanderProperties = {
58123             onclick: () => {
58124                 this._expandControls = !this._expandControls;
58125                 this._mode = SequenceMode.Default;
58126                 this._notifyChanged$.next(this);
58127             },
58128             style: {
58129                 "border-bottom-right-radius": `${borderRadius}px`,
58130                 "border-top-right-radius": `${borderRadius}px`,
58131             },
58132         };
58133         const expanderBar = virtualDom.h("div.mapillary-sequence-expander-bar", []);
58134         const expander = virtualDom.h("div.mapillary-sequence-expander-button", expanderProperties, [expanderBar]);
58135         const fastIconClassName = this._mode === SequenceMode.Playback ?
58136             ".mapillary-sequence-fast-icon-gray.mapillary-sequence-icon-visible" : ".mapillary-sequence-fast-icon";
58137         const fastIcon = virtualDom.h("div" + fastIconClassName, []);
58138         const playbackProperties = {
58139             onclick: () => {
58140                 this._mode = this._mode === SequenceMode.Playback ?
58141                     SequenceMode.Default :
58142                     SequenceMode.Playback;
58143                 this._notifyChanged$.next(this);
58144             },
58145         };
58146         const playback = virtualDom.h("div.mapillary-sequence-playback-button", playbackProperties, [fastIcon]);
58147         const timelineIconClassName = this._mode === SequenceMode.Timeline ?
58148             ".mapillary-sequence-timeline-icon-gray.mapillary-sequence-icon-visible" : ".mapillary-sequence-timeline-icon";
58149         const timelineIcon = virtualDom.h("div" + timelineIconClassName, []);
58150         const timelineProperties = {
58151             onclick: () => {
58152                 this._mode = this._mode === SequenceMode.Timeline ?
58153                     SequenceMode.Default :
58154                     SequenceMode.Timeline;
58155                 this._notifyChanged$.next(this);
58156             },
58157         };
58158         const timeline = virtualDom.h("div.mapillary-sequence-timeline-button", timelineProperties, [timelineIcon]);
58159         const properties = {
58160             style: {
58161                 height: (this._defaultHeight / this._stepperDefaultWidth * containerWidth) + "px",
58162                 transform: `translate(${containerWidth / 2 + 2}px, 0)`,
58163                 width: (this._controlsDefaultWidth / this._stepperDefaultWidth * containerWidth) + "px",
58164             },
58165         };
58166         const className = ".mapillary-sequence-controls" +
58167             (this._expandControls ? ".mapillary-sequence-controls-expanded" : "");
58168         return virtualDom.h("div" + className, properties, [playback, timeline, expander]);
58169     }
58170     _createSequenceArrows(nextId, prevId, containerWidth, configuration, navigator) {
58171         let nextProperties = {
58172             onclick: nextId != null ?
58173                 () => {
58174                     navigator.moveDir$(NavigationDirection.Next)
58175                         .subscribe(undefined, (error) => {
58176                         if (!(error instanceof CancelMapillaryError)) {
58177                             console.error(error);
58178                         }
58179                     });
58180                 } :
58181                 null,
58182             onpointerenter: () => { this._mouseEnterDirection$.next(NavigationDirection.Next); },
58183             onpointerleave: () => { this._mouseLeaveDirection$.next(NavigationDirection.Next); },
58184         };
58185         const borderRadius = Math.round(8 / this._stepperDefaultWidth * containerWidth);
58186         let prevProperties = {
58187             onclick: prevId != null ?
58188                 () => {
58189                     navigator.moveDir$(NavigationDirection.Prev)
58190                         .subscribe(undefined, (error) => {
58191                         if (!(error instanceof CancelMapillaryError)) {
58192                             console.error(error);
58193                         }
58194                     });
58195                 } :
58196                 null,
58197             onpointerenter: () => { this._mouseEnterDirection$.next(NavigationDirection.Prev); },
58198             onpointerleave: () => { this._mouseLeaveDirection$.next(NavigationDirection.Prev); },
58199             style: {
58200                 "border-bottom-left-radius": `${borderRadius}px`,
58201                 "border-top-left-radius": `${borderRadius}px`,
58202             },
58203         };
58204         let nextClass = this._getStepClassName(NavigationDirection.Next, nextId, configuration.highlightId);
58205         let prevClass = this._getStepClassName(NavigationDirection.Prev, prevId, configuration.highlightId);
58206         let nextIcon = virtualDom.h("div.mapillary-sequence-icon", []);
58207         let prevIcon = virtualDom.h("div.mapillary-sequence-icon", []);
58208         return [
58209             virtualDom.h("div." + prevClass, prevProperties, [prevIcon]),
58210             virtualDom.h("div." + nextClass, nextProperties, [nextIcon]),
58211         ];
58212     }
58213     _createStepper(edgeStatus, configuration, playEnabled, containerWidth, component, navigator) {
58214         let nextId = null;
58215         let prevId = null;
58216         for (let edge of edgeStatus.edges) {
58217             if (edge.data.direction === NavigationDirection.Next) {
58218                 nextId = edge.target;
58219             }
58220             if (edge.data.direction === NavigationDirection.Prev) {
58221                 prevId = edge.target;
58222             }
58223         }
58224         const playingButton = this._createPlayingButton(nextId, prevId, playEnabled, configuration, component);
58225         const buttons = this._createSequenceArrows(nextId, prevId, containerWidth, configuration, navigator);
58226         buttons.splice(1, 0, playingButton);
58227         const containerProperties = {
58228             oncontextmenu: (event) => { event.preventDefault(); },
58229             style: {
58230                 height: (this._defaultHeight / this._stepperDefaultWidth * containerWidth) + "px",
58231                 width: containerWidth + "px",
58232             },
58233         };
58234         return virtualDom.h("div.mapillary-sequence-stepper", containerProperties, buttons);
58235     }
58236     _createTimelineControls(containerWidth, index, max) {
58237         if (this._mode !== SequenceMode.Timeline) {
58238             return virtualDom.h("div.mapillary-sequence-timeline", []);
58239         }
58240         const positionInput = this._createPositionInput(index, max);
58241         const closeIcon = virtualDom.h("div.mapillary-sequence-close-icon.mapillary-sequence-icon-visible", []);
58242         const closeButtonProperties = {
58243             onclick: () => {
58244                 this._mode = SequenceMode.Default;
58245                 this._notifyChanged$.next(this);
58246             },
58247         };
58248         const closeButton = virtualDom.h("div.mapillary-sequence-close-button", closeButtonProperties, [closeIcon]);
58249         const top = Math.round(containerWidth / this._stepperDefaultWidth * this._defaultHeight + 10);
58250         const playbackProperties = { style: { top: `${top}px` } };
58251         return virtualDom.h("div.mapillary-sequence-timeline", playbackProperties, [positionInput, closeButton]);
58252     }
58253     _getStepClassName(direction, imageId, highlightId) {
58254         let className = direction === NavigationDirection.Next ?
58255             "mapillary-sequence-step-next" :
58256             "mapillary-sequence-step-prev";
58257         if (imageId == null) {
58258             className += "-inactive";
58259         }
58260         else {
58261             if (highlightId === imageId) {
58262                 className += "-highlight";
58263             }
58264         }
58265         return className;
58266     }
58267     _setChangingPosition(value) {
58268         this._changingPosition = value;
58269         this._notifyChangingPositionChanged$.next(value);
58270     }
58271 }
58272
58273 /**
58274  * @class SequenceComponent
58275  * @classdesc Component showing navigation arrows for sequence directions
58276  * as well as playing button. Exposes an API to start and stop play.
58277  */
58278 class SequenceComponent extends Component {
58279     constructor(name, container, navigator, renderer, scheduler) {
58280         super(name, container, navigator);
58281         this._sequenceDOMRenderer = !!renderer ? renderer : new SequenceDOMRenderer(container);
58282         this._scheduler = scheduler;
58283         this._containerWidth$ = new Subject();
58284         this._hoveredIdSubject$ = new Subject();
58285         this._hoveredId$ = this._hoveredIdSubject$.pipe(share());
58286         this._navigator.playService.playing$.pipe(skip(1), withLatestFrom(this._configuration$))
58287             .subscribe(([playing, configuration]) => {
58288             const type = "playing";
58289             const event = {
58290                 playing,
58291                 target: this,
58292                 type,
58293             };
58294             this.fire(type, event);
58295             if (playing === configuration.playing) {
58296                 return;
58297             }
58298             if (playing) {
58299                 this.play();
58300             }
58301             else {
58302                 this.stop();
58303             }
58304         });
58305         this._navigator.playService.direction$.pipe(skip(1), withLatestFrom(this._configuration$))
58306             .subscribe(([direction, configuration]) => {
58307             if (direction !== configuration.direction) {
58308                 this.configure({ direction });
58309             }
58310         });
58311     }
58312     fire(type, event) {
58313         super.fire(type, event);
58314     }
58315     off(type, handler) {
58316         super.off(type, handler);
58317     }
58318     on(type, handler) {
58319         super.on(type, handler);
58320     }
58321     /**
58322      * Start playing.
58323      *
58324      * @fires playing
58325      */
58326     play() { this.configure({ playing: true }); }
58327     /**
58328      * Stop playing.
58329      *
58330      * @fires playing
58331      */
58332     stop() { this.configure({ playing: false }); }
58333     _activate() {
58334         this._sequenceDOMRenderer.activate();
58335         const edgeStatus$ = this._navigator.stateService.currentImage$.pipe(switchMap((image) => {
58336             return image.sequenceEdges$;
58337         }), publishReplay(1), refCount());
58338         const sequence$ = this._navigator.stateService.currentImage$.pipe(distinctUntilChanged(undefined, (image) => {
58339             return image.sequenceId;
58340         }), switchMap((image) => {
58341             return concat(of(null), this._navigator.graphService.cacheSequence$(image.sequenceId).pipe(retry(3), catchError((e) => {
58342                 console.error("Failed to cache sequence", e);
58343                 return of(null);
58344             })));
58345         }), startWith(null), publishReplay(1), refCount());
58346         const subs = this._subscriptions;
58347         subs.push(sequence$.subscribe());
58348         const rendererId$ = this._sequenceDOMRenderer.index$.pipe(withLatestFrom(sequence$), map(([index, sequence]) => {
58349             return sequence != null ? sequence.imageIds[index] : null;
58350         }), filter((id) => {
58351             return !!id;
58352         }), distinctUntilChanged(), publish(), refCount());
58353         subs.push(merge(rendererId$.pipe(debounceTime(100, this._scheduler)), rendererId$.pipe(auditTime(400, this._scheduler))).pipe(distinctUntilChanged(), switchMap((id) => {
58354             return this._navigator.moveTo$(id).pipe(catchError(() => {
58355                 return empty();
58356             }));
58357         }))
58358             .subscribe());
58359         subs.push(this._sequenceDOMRenderer.changingPositionChanged$.pipe(filter((changing) => {
58360             return changing;
58361         }))
58362             .subscribe(() => {
58363             this._navigator.graphService.setGraphMode(GraphMode.Sequence);
58364         }));
58365         subs.push(this._sequenceDOMRenderer.changingPositionChanged$.pipe(filter((changing) => {
58366             return !changing;
58367         }))
58368             .subscribe(() => {
58369             this._navigator.graphService.setGraphMode(GraphMode.Spatial);
58370         }));
58371         this._navigator.graphService.graphMode$.pipe(switchMap((mode) => {
58372             return mode === GraphMode.Spatial ?
58373                 this._navigator.stateService.currentImage$.pipe(take(2)) :
58374                 empty();
58375         }), filter((image) => {
58376             return !image.spatialEdges.cached;
58377         }), switchMap((image) => {
58378             return this._navigator.graphService.cacheImage$(image.id).pipe(catchError(() => {
58379                 return empty();
58380             }));
58381         }))
58382             .subscribe();
58383         subs.push(this._sequenceDOMRenderer.changingPositionChanged$.pipe(filter((changing) => {
58384             return changing;
58385         }))
58386             .subscribe(() => {
58387             this._navigator.playService.stop();
58388         }));
58389         subs.push(combineLatest(this._navigator.graphService.graphMode$, this._sequenceDOMRenderer.changingPositionChanged$.pipe(startWith(false), distinctUntilChanged())).pipe(withLatestFrom(this._navigator.stateService.currentImage$), switchMap(([[mode, changing], image]) => {
58390             return changing && mode === GraphMode.Sequence ?
58391                 this._navigator.graphService.cacheSequenceImages$(image.sequenceId, image.id).pipe(retry(3), catchError((error) => {
58392                     console.error("Failed to cache sequence images.", error);
58393                     return empty();
58394                 })) :
58395                 empty();
58396         }))
58397             .subscribe());
58398         const position$ = sequence$.pipe(switchMap((sequence) => {
58399             if (!sequence) {
58400                 return of({ index: null, max: null });
58401             }
58402             let firstCurrentId = true;
58403             return this._sequenceDOMRenderer.changingPositionChanged$.pipe(startWith(false), distinctUntilChanged(), switchMap((changingPosition) => {
58404                 const skipCount = !changingPosition &&
58405                     firstCurrentId ?
58406                     0 : 1;
58407                 firstCurrentId = false;
58408                 return changingPosition ?
58409                     rendererId$ :
58410                     this._navigator.stateService.currentImage$.pipe(map((image) => {
58411                         return image.id;
58412                     }), distinctUntilChanged(), skip(skipCount));
58413             }), map((imageId) => {
58414                 const index = sequence.imageIds.indexOf(imageId);
58415                 if (index === -1) {
58416                     return { index: null, max: null };
58417                 }
58418                 return { index: index, max: sequence.imageIds.length - 1 };
58419             }));
58420         }));
58421         const earth$ = this._navigator.stateService.state$.pipe(map((state) => {
58422             return state === State.Earth;
58423         }), distinctUntilChanged());
58424         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]) => {
58425             const vNode = this._sequenceDOMRenderer
58426                 .render(edgeStatus, configuration, containerWidth, speed, position.index, position.max, !earth, this, this._navigator);
58427             return { name: this._name, vNode: vNode };
58428         }))
58429             .subscribe(this._container.domRenderer.render$));
58430         subs.push(this._sequenceDOMRenderer.speed$
58431             .subscribe((speed) => {
58432             this._navigator.playService.setSpeed(speed);
58433         }));
58434         subs.push(this._configuration$.pipe(map((configuration) => {
58435             return configuration.direction;
58436         }), distinctUntilChanged())
58437             .subscribe((direction) => {
58438             this._navigator.playService.setDirection(direction);
58439         }));
58440         subs.push(combineLatest(this._container.renderService.size$, this._configuration$.pipe(distinctUntilChanged((value1, value2) => {
58441             return value1[0] === value2[0] && value1[1] === value2[1];
58442         }, (configuration) => {
58443             return [configuration.minWidth, configuration.maxWidth];
58444         }))).pipe(map(([size, configuration]) => {
58445             return this._sequenceDOMRenderer.getContainerWidth(size, configuration);
58446         }))
58447             .subscribe(this._containerWidth$));
58448         subs.push(this._configuration$.pipe(map((configuration) => {
58449             return configuration.playing;
58450         }), distinctUntilChanged())
58451             .subscribe((playing) => {
58452             if (playing) {
58453                 this._navigator.playService.play();
58454             }
58455             else {
58456                 this._navigator.playService.stop();
58457             }
58458         }));
58459         subs.push(this._sequenceDOMRenderer.mouseEnterDirection$.pipe(switchMap((direction) => {
58460             const edgeTo$ = edgeStatus$.pipe(map((edgeStatus) => {
58461                 for (let edge of edgeStatus.edges) {
58462                     if (edge.data.direction === direction) {
58463                         return edge.target;
58464                     }
58465                 }
58466                 return null;
58467             }), takeUntil(this._sequenceDOMRenderer.mouseLeaveDirection$));
58468             return concat(edgeTo$, of(null));
58469         }), distinctUntilChanged())
58470             .subscribe(this._hoveredIdSubject$));
58471         subs.push(this._hoveredId$
58472             .subscribe((id) => {
58473             const type = "hover";
58474             const event = {
58475                 id,
58476                 target: this,
58477                 type,
58478             };
58479             this.fire(type, event);
58480         }));
58481     }
58482     _deactivate() {
58483         this._subscriptions.unsubscribe();
58484         this._sequenceDOMRenderer.deactivate();
58485     }
58486     _getDefaultConfiguration() {
58487         return {
58488             direction: NavigationDirection.Next,
58489             maxWidth: 108,
58490             minWidth: 70,
58491             playing: false,
58492             visible: true,
58493         };
58494     }
58495 }
58496 /** @inheritdoc */
58497 SequenceComponent.componentName = "sequence";
58498
58499 /**
58500  * Enumeration for slider mode.
58501  *
58502  * @enum {number}
58503  * @readonly
58504  *
58505  * @description Modes for specifying how transitions
58506  * between images are performed in slider mode. Only
58507  * applicable when the slider component determines
58508  * that transitions with motion is possilble. When it
58509  * is not, the stationary mode will be applied.
58510  */
58511 var SliderConfigurationMode;
58512 (function (SliderConfigurationMode) {
58513     /**
58514      * Transitions with motion.
58515      *
58516      * @description The slider component moves the
58517      * camera between the image origins.
58518      *
58519      * In this mode it is not possible to zoom or pan.
58520      *
58521      * The slider component falls back to stationary
58522      * mode when it determines that the pair of images
58523      * does not have a strong enough relation.
58524      */
58525     SliderConfigurationMode[SliderConfigurationMode["Motion"] = 0] = "Motion";
58526     /**
58527      * Stationary transitions.
58528      *
58529      * @description The camera is stationary.
58530      *
58531      * In this mode it is possible to zoom and pan.
58532      */
58533     SliderConfigurationMode[SliderConfigurationMode["Stationary"] = 1] = "Stationary";
58534 })(SliderConfigurationMode || (SliderConfigurationMode = {}));
58535
58536 const EPSILON = 1e-8;
58537 /**
58538  * @class Transform
58539  *
58540  * @classdesc Class used for calculating coordinate transformations
58541  * and projections.
58542  */
58543 class Transform {
58544     /**
58545      * Create a new transform instance.
58546      * @param {number} orientation - Image orientation.
58547      * @param {number} width - Image height.
58548      * @param {number} height - Image width.
58549      * @param {number} focal - Focal length.
58550      * @param {number} scale - Atomic scale.
58551      * @param {Array<number>} rotation - Rotation vector in three dimensions.
58552      * @param {Array<number>} translation - Translation vector in three dimensions.
58553      * @param {HTMLImageElement} image - Image for fallback size calculations.
58554      */
58555     constructor(orientation, width, height, scale, rotation, translation, image, textureScale, cameraParameters, cameraType) {
58556         this._orientation = this._getValue(orientation, 1);
58557         let imageWidth = image != null ? image.width : 4;
58558         let imageHeight = image != null ? image.height : 3;
58559         let keepOrientation = this._orientation < 5;
58560         this._width = this._getValue(width, keepOrientation ? imageWidth : imageHeight);
58561         this._height = this._getValue(height, keepOrientation ? imageHeight : imageWidth);
58562         this._basicAspect = keepOrientation ?
58563             this._width / this._height :
58564             this._height / this._width;
58565         this._basicWidth = keepOrientation ? width : height;
58566         this._basicHeight = keepOrientation ? height : width;
58567         const parameters = this._getCameraParameters(cameraParameters, cameraType);
58568         const focal = parameters[0];
58569         const ck1 = parameters[1];
58570         const ck2 = parameters[2];
58571         this._focal = this._getValue(focal, 1);
58572         this._scale = this._getValue(scale, 0);
58573         this._worldToCamera = this.createWorldToCamera(rotation, translation);
58574         this._worldToCameraInverse = new Matrix4()
58575             .copy(this._worldToCamera)
58576             .invert();
58577         this._scaledWorldToCamera =
58578             this._createScaledWorldToCamera(this._worldToCamera, this._scale);
58579         this._scaledWorldToCameraInverse = new Matrix4()
58580             .copy(this._scaledWorldToCamera)
58581             .invert();
58582         this._basicWorldToCamera = this._createBasicWorldToCamera(this._worldToCamera, orientation);
58583         this._textureScale = !!textureScale ? textureScale : [1, 1];
58584         this._ck1 = !!ck1 ? ck1 : 0;
58585         this._ck2 = !!ck2 ? ck2 : 0;
58586         this._cameraType = !!cameraType ?
58587             cameraType :
58588             "perspective";
58589         this._radialPeak = this._getRadialPeak(this._ck1, this._ck2);
58590     }
58591     get ck1() {
58592         return this._ck1;
58593     }
58594     get ck2() {
58595         return this._ck2;
58596     }
58597     get cameraType() {
58598         return this._cameraType;
58599     }
58600     /**
58601      * Get basic aspect.
58602      * @returns {number} The orientation adjusted aspect ratio.
58603      */
58604     get basicAspect() {
58605         return this._basicAspect;
58606     }
58607     /**
58608      * Get basic height.
58609      *
58610      * @description Does not fall back to image image height but
58611      * uses original value from API so can be faulty.
58612      *
58613      * @returns {number} The height of the basic version image
58614      * (adjusted for orientation).
58615      */
58616     get basicHeight() {
58617         return this._basicHeight;
58618     }
58619     get basicRt() {
58620         return this._basicWorldToCamera;
58621     }
58622     /**
58623      * Get basic width.
58624      *
58625      * @description Does not fall back to image image width but
58626      * uses original value from API so can be faulty.
58627      *
58628      * @returns {number} The width of the basic version image
58629      * (adjusted for orientation).
58630      */
58631     get basicWidth() {
58632         return this._basicWidth;
58633     }
58634     /**
58635      * Get focal.
58636      * @returns {number} The image focal length.
58637      */
58638     get focal() {
58639         return this._focal;
58640     }
58641     /**
58642      * Get height.
58643      *
58644      * @description Falls back to the image image height if
58645      * the API data is faulty.
58646      *
58647      * @returns {number} The orientation adjusted image height.
58648      */
58649     get height() {
58650         return this._height;
58651     }
58652     /**
58653      * Get orientation.
58654      * @returns {number} The image orientation.
58655      */
58656     get orientation() {
58657         return this._orientation;
58658     }
58659     /**
58660      * Get rt.
58661      * @returns {THREE.Matrix4} The extrinsic camera matrix.
58662      */
58663     get rt() {
58664         return this._worldToCamera;
58665     }
58666     /**
58667      * Get srt.
58668      * @returns {THREE.Matrix4} The scaled extrinsic camera matrix.
58669      */
58670     get srt() {
58671         return this._scaledWorldToCamera;
58672     }
58673     /**
58674      * Get srtInverse.
58675      * @returns {THREE.Matrix4} The scaled extrinsic camera matrix.
58676      */
58677     get srtInverse() {
58678         return this._scaledWorldToCameraInverse;
58679     }
58680     /**
58681      * Get scale.
58682      * @returns {number} The image atomic reconstruction scale.
58683      */
58684     get scale() {
58685         return this._scale;
58686     }
58687     /**
58688      * Get has valid scale.
58689      * @returns {boolean} Value indicating if the scale of the transform is valid.
58690      */
58691     get hasValidScale() {
58692         return this._scale > 1e-2 && this._scale < 50;
58693     }
58694     /**
58695      * Get radial peak.
58696      * @returns {number} Value indicating the radius where the radial
58697      * undistortion function peaks.
58698      */
58699     get radialPeak() {
58700         return this._radialPeak;
58701     }
58702     /**
58703      * Get width.
58704      *
58705      * @description Falls back to the image image width if
58706      * the API data is faulty.
58707      *
58708      * @returns {number} The orientation adjusted image width.
58709      */
58710     get width() {
58711         return this._width;
58712     }
58713     /**
58714      * Calculate the up vector for the image transform.
58715      *
58716      * @returns {THREE.Vector3} Normalized and orientation adjusted up vector.
58717      */
58718     upVector() {
58719         let rte = this._worldToCamera.elements;
58720         switch (this._orientation) {
58721             case 1:
58722                 return new Vector3(-rte[1], -rte[5], -rte[9]);
58723             case 3:
58724                 return new Vector3(rte[1], rte[5], rte[9]);
58725             case 6:
58726                 return new Vector3(-rte[0], -rte[4], -rte[8]);
58727             case 8:
58728                 return new Vector3(rte[0], rte[4], rte[8]);
58729             default:
58730                 return new Vector3(-rte[1], -rte[5], -rte[9]);
58731         }
58732     }
58733     /**
58734      * Calculate projector matrix for projecting 3D points to texture map
58735      * coordinates (u and v).
58736      *
58737      * @returns {THREE.Matrix4} Projection matrix for 3D point to texture
58738      * map coordinate calculations.
58739      */
58740     projectorMatrix() {
58741         let projector = this._normalizedToTextureMatrix();
58742         let f = this._focal;
58743         let projection = new Matrix4().set(f, 0, 0, 0, 0, f, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0);
58744         projector.multiply(projection);
58745         projector.multiply(this._worldToCamera);
58746         return projector;
58747     }
58748     /**
58749      * Project 3D world coordinates to basic coordinates.
58750      *
58751      * @param {Array<number>} point3d - 3D world coordinates.
58752      * @return {Array<number>} 2D basic coordinates.
58753      */
58754     projectBasic(point3d) {
58755         let sfm = this.projectSfM(point3d);
58756         return this._sfmToBasic(sfm);
58757     }
58758     /**
58759      * Unproject basic coordinates to 3D world coordinates.
58760      *
58761      * @param {Array<number>} basic - 2D basic coordinates.
58762      * @param {Array<number>} distance - Distance to unproject from camera center.
58763      * @param {boolean} [depth] - Treat the distance value as depth from camera center.
58764      *                            Only applicable for perspective images. Will be
58765      *                            ignored for spherical.
58766      * @returns {Array<number>} Unprojected 3D world coordinates.
58767      */
58768     unprojectBasic(basic, distance, depth) {
58769         let sfm = this._basicToSfm(basic);
58770         return this.unprojectSfM(sfm, distance, depth);
58771     }
58772     /**
58773      * Project 3D world coordinates to SfM coordinates.
58774      *
58775      * @param {Array<number>} point3d - 3D world coordinates.
58776      * @return {Array<number>} 2D SfM coordinates.
58777      */
58778     projectSfM(point3d) {
58779         let v = new Vector4(point3d[0], point3d[1], point3d[2], 1);
58780         v.applyMatrix4(this._worldToCamera);
58781         return this._bearingToSfm([v.x, v.y, v.z]);
58782     }
58783     /**
58784      * Unproject SfM coordinates to a 3D world coordinates.
58785      *
58786      * @param {Array<number>} sfm - 2D SfM coordinates.
58787      * @param {Array<number>} distance - Distance to unproject
58788      * from camera center.
58789      * @param {boolean} [depth] - Treat the distance value as
58790      * depth from camera center. Only applicable for perspective
58791      * images. Will be ignored for spherical.
58792      * @returns {Array<number>} Unprojected 3D world coordinates.
58793      */
58794     unprojectSfM(sfm, distance, depth) {
58795         const bearing = this._sfmToBearing(sfm);
58796         const unprojectedCamera = depth && !isSpherical(this._cameraType) ?
58797             new Vector4(distance * bearing[0] / bearing[2], distance * bearing[1] / bearing[2], distance, 1) :
58798             new Vector4(distance * bearing[0], distance * bearing[1], distance * bearing[2], 1);
58799         const unprojectedWorld = unprojectedCamera
58800             .applyMatrix4(this._worldToCameraInverse);
58801         return [
58802             unprojectedWorld.x / unprojectedWorld.w,
58803             unprojectedWorld.y / unprojectedWorld.w,
58804             unprojectedWorld.z / unprojectedWorld.w,
58805         ];
58806     }
58807     /**
58808      * Transform SfM coordinates to bearing vector (3D cartesian
58809      * coordinates on the unit sphere).
58810      *
58811      * @param {Array<number>} sfm - 2D SfM coordinates.
58812      * @returns {Array<number>} Bearing vector (3D cartesian coordinates
58813      * on the unit sphere).
58814      */
58815     _sfmToBearing(sfm) {
58816         if (isSpherical(this._cameraType)) {
58817             let lng = sfm[0] * 2 * Math.PI;
58818             let lat = -sfm[1] * 2 * Math.PI;
58819             let x = Math.cos(lat) * Math.sin(lng);
58820             let y = -Math.sin(lat);
58821             let z = Math.cos(lat) * Math.cos(lng);
58822             return [x, y, z];
58823         }
58824         else if (isFisheye(this._cameraType)) {
58825             let [dxn, dyn] = [sfm[0] / this._focal, sfm[1] / this._focal];
58826             const dTheta = Math.sqrt(dxn * dxn + dyn * dyn);
58827             let d = this._distortionFromDistortedRadius(dTheta, this._ck1, this._ck2, this._radialPeak);
58828             let theta = dTheta / d;
58829             let z = Math.cos(theta);
58830             let r = Math.sin(theta);
58831             const denomTheta = dTheta > EPSILON ? 1 / dTheta : 1;
58832             let x = r * dxn * denomTheta;
58833             let y = r * dyn * denomTheta;
58834             return [x, y, z];
58835         }
58836         else {
58837             let [dxn, dyn] = [sfm[0] / this._focal, sfm[1] / this._focal];
58838             const dr = Math.sqrt(dxn * dxn + dyn * dyn);
58839             let d = this._distortionFromDistortedRadius(dr, this._ck1, this._ck2, this._radialPeak);
58840             const xn = dxn / d;
58841             const yn = dyn / d;
58842             let v = new Vector3(xn, yn, 1);
58843             v.normalize();
58844             return [v.x, v.y, v.z];
58845         }
58846     }
58847     /** Compute distortion given the distorted radius.
58848      *
58849      *  Solves for d in the equation
58850      *    y = d(x, k1, k2) * x
58851      * given the distorted radius, y.
58852      */
58853     _distortionFromDistortedRadius(distortedRadius, k1, k2, radialPeak) {
58854         let d = 1.0;
58855         for (let i = 0; i < 10; i++) {
58856             let radius = distortedRadius / d;
58857             if (radius > radialPeak) {
58858                 radius = radialPeak;
58859             }
58860             d = 1 + k1 * Math.pow(radius, 2) + k2 * Math.pow(radius, 4);
58861         }
58862         return d;
58863     }
58864     /**
58865      * Transform bearing vector (3D cartesian coordiantes on the unit sphere) to
58866      * SfM coordinates.
58867      *
58868      * @param {Array<number>} bearing - Bearing vector (3D cartesian coordinates on the
58869      * unit sphere).
58870      * @returns {Array<number>} 2D SfM coordinates.
58871      */
58872     _bearingToSfm(bearing) {
58873         if (isSpherical(this._cameraType)) {
58874             let x = bearing[0];
58875             let y = bearing[1];
58876             let z = bearing[2];
58877             let lng = Math.atan2(x, z);
58878             let lat = Math.atan2(-y, Math.sqrt(x * x + z * z));
58879             return [lng / (2 * Math.PI), -lat / (2 * Math.PI)];
58880         }
58881         else if (isFisheye(this._cameraType)) {
58882             if (bearing[2] > 0) {
58883                 const [x, y, z] = bearing;
58884                 const r = Math.sqrt(x * x + y * y);
58885                 let theta = Math.atan2(r, z);
58886                 if (theta > this._radialPeak) {
58887                     theta = this._radialPeak;
58888                 }
58889                 const distortion = 1.0 + Math.pow(theta, 2) * (this._ck1 + Math.pow(theta, 2) * this._ck2);
58890                 const s = this._focal * distortion * theta / r;
58891                 return [s * x, s * y];
58892             }
58893             else {
58894                 return [
58895                     bearing[0] < 0 ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY,
58896                     bearing[1] < 0 ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY,
58897                 ];
58898             }
58899         }
58900         else {
58901             if (bearing[2] > 0) {
58902                 let [xn, yn] = [bearing[0] / bearing[2], bearing[1] / bearing[2]];
58903                 let r2 = xn * xn + yn * yn;
58904                 const rp2 = Math.pow(this._radialPeak, 2);
58905                 if (r2 > rp2) {
58906                     r2 = rp2;
58907                 }
58908                 const d = 1 + this._ck1 * r2 + this._ck2 * Math.pow(r2, 2);
58909                 return [
58910                     this._focal * d * xn,
58911                     this._focal * d * yn,
58912                 ];
58913             }
58914             else {
58915                 return [
58916                     bearing[0] < 0 ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY,
58917                     bearing[1] < 0 ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY,
58918                 ];
58919             }
58920         }
58921     }
58922     /**
58923      * Convert basic coordinates to SfM coordinates.
58924      *
58925      * @param {Array<number>} basic - 2D basic coordinates.
58926      * @returns {Array<number>} 2D SfM coordinates.
58927      */
58928     _basicToSfm(basic) {
58929         let rotatedX;
58930         let rotatedY;
58931         switch (this._orientation) {
58932             case 1:
58933                 rotatedX = basic[0];
58934                 rotatedY = basic[1];
58935                 break;
58936             case 3:
58937                 rotatedX = 1 - basic[0];
58938                 rotatedY = 1 - basic[1];
58939                 break;
58940             case 6:
58941                 rotatedX = basic[1];
58942                 rotatedY = 1 - basic[0];
58943                 break;
58944             case 8:
58945                 rotatedX = 1 - basic[1];
58946                 rotatedY = basic[0];
58947                 break;
58948             default:
58949                 rotatedX = basic[0];
58950                 rotatedY = basic[1];
58951                 break;
58952         }
58953         let w = this._width;
58954         let h = this._height;
58955         let s = Math.max(w, h);
58956         let sfmX = rotatedX * w / s - w / s / 2;
58957         let sfmY = rotatedY * h / s - h / s / 2;
58958         return [sfmX, sfmY];
58959     }
58960     /**
58961      * Convert SfM coordinates to basic coordinates.
58962      *
58963      * @param {Array<number>} sfm - 2D SfM coordinates.
58964      * @returns {Array<number>} 2D basic coordinates.
58965      */
58966     _sfmToBasic(sfm) {
58967         let w = this._width;
58968         let h = this._height;
58969         let s = Math.max(w, h);
58970         let rotatedX = (sfm[0] + w / s / 2) / w * s;
58971         let rotatedY = (sfm[1] + h / s / 2) / h * s;
58972         let basicX;
58973         let basicY;
58974         switch (this._orientation) {
58975             case 1:
58976                 basicX = rotatedX;
58977                 basicY = rotatedY;
58978                 break;
58979             case 3:
58980                 basicX = 1 - rotatedX;
58981                 basicY = 1 - rotatedY;
58982                 break;
58983             case 6:
58984                 basicX = 1 - rotatedY;
58985                 basicY = rotatedX;
58986                 break;
58987             case 8:
58988                 basicX = rotatedY;
58989                 basicY = 1 - rotatedX;
58990                 break;
58991             default:
58992                 basicX = rotatedX;
58993                 basicY = rotatedY;
58994                 break;
58995         }
58996         return [basicX, basicY];
58997     }
58998     /**
58999      * Checks a value and returns it if it exists and is larger than 0.
59000      * Fallbacks if it is null.
59001      *
59002      * @param {number} value - Value to check.
59003      * @param {number} fallback - Value to fall back to.
59004      * @returns {number} The value or its fallback value if it is not defined or negative.
59005      */
59006     _getValue(value, fallback) {
59007         return value != null && value > 0 ? value : fallback;
59008     }
59009     _getCameraParameters(value, cameraType) {
59010         if (isSpherical(cameraType)) {
59011             return [];
59012         }
59013         if (!value || value.length === 0) {
59014             return [1, 0, 0];
59015         }
59016         const padding = 3 - value.length;
59017         if (padding <= 0) {
59018             return value;
59019         }
59020         return value
59021             .concat(new Array(padding)
59022             .fill(0));
59023     }
59024     /**
59025      * Creates the extrinsic camera matrix [ R | t ].
59026      *
59027      * @param {Array<number>} rotation - Rotation vector in angle axis representation.
59028      * @param {Array<number>} translation - Translation vector.
59029      * @returns {THREE.Matrix4} Extrisic camera matrix.
59030      */
59031     createWorldToCamera(rotation, translation) {
59032         const axis = new Vector3(rotation[0], rotation[1], rotation[2]);
59033         const angle = axis.length();
59034         if (angle > 0) {
59035             axis.normalize();
59036         }
59037         const worldToCamera = new Matrix4();
59038         worldToCamera.makeRotationAxis(axis, angle);
59039         worldToCamera.setPosition(new Vector3(translation[0], translation[1], translation[2]));
59040         return worldToCamera;
59041     }
59042     /**
59043      * Calculates the scaled extrinsic camera matrix scale * [ R | t ].
59044      *
59045      * @param {THREE.Matrix4} worldToCamera - Extrisic camera matrix.
59046      * @param {number} scale - Scale factor.
59047      * @returns {THREE.Matrix4} Scaled extrisic camera matrix.
59048      */
59049     _createScaledWorldToCamera(worldToCamera, scale) {
59050         const scaledWorldToCamera = worldToCamera.clone();
59051         const elements = scaledWorldToCamera.elements;
59052         elements[12] = scale * elements[12];
59053         elements[13] = scale * elements[13];
59054         elements[14] = scale * elements[14];
59055         scaledWorldToCamera.scale(new Vector3(scale, scale, scale));
59056         return scaledWorldToCamera;
59057     }
59058     _createBasicWorldToCamera(rt, orientation) {
59059         const axis = new Vector3(0, 0, 1);
59060         let angle = 0;
59061         switch (orientation) {
59062             case 3:
59063                 angle = Math.PI;
59064                 break;
59065             case 6:
59066                 angle = Math.PI / 2;
59067                 break;
59068             case 8:
59069                 angle = 3 * Math.PI / 2;
59070                 break;
59071         }
59072         return new Matrix4()
59073             .makeRotationAxis(axis, angle)
59074             .multiply(rt);
59075     }
59076     _getRadialPeak(k1, k2) {
59077         const a = 5 * k2;
59078         const b = 3 * k1;
59079         const c = 1;
59080         const d = Math.pow(b, 2) - 4 * a * c;
59081         if (d < 0) {
59082             return undefined;
59083         }
59084         const root1 = (-b - Math.sqrt(d)) / 2 / a;
59085         const root2 = (-b + Math.sqrt(d)) / 2 / a;
59086         const minRoot = Math.min(root1, root2);
59087         const maxRoot = Math.max(root1, root2);
59088         return minRoot > 0 ?
59089             Math.sqrt(minRoot) :
59090             maxRoot > 0 ?
59091                 Math.sqrt(maxRoot) :
59092                 undefined;
59093     }
59094     /**
59095      * Calculate a transformation matrix from normalized coordinates for
59096      * texture map coordinates.
59097      *
59098      * @returns {THREE.Matrix4} Normalized coordinates to texture map
59099      * coordinates transformation matrix.
59100      */
59101     _normalizedToTextureMatrix() {
59102         const size = Math.max(this._width, this._height);
59103         const scaleX = this._orientation < 5 ? this._textureScale[0] : this._textureScale[1];
59104         const scaleY = this._orientation < 5 ? this._textureScale[1] : this._textureScale[0];
59105         const w = size / this._width * scaleX;
59106         const h = size / this._height * scaleY;
59107         switch (this._orientation) {
59108             case 1:
59109                 return new Matrix4().set(w, 0, 0, 0.5, 0, -h, 0, 0.5, 0, 0, 1, 0, 0, 0, 0, 1);
59110             case 3:
59111                 return new Matrix4().set(-w, 0, 0, 0.5, 0, h, 0, 0.5, 0, 0, 1, 0, 0, 0, 0, 1);
59112             case 6:
59113                 return new Matrix4().set(0, -h, 0, 0.5, -w, 0, 0, 0.5, 0, 0, 1, 0, 0, 0, 0, 1);
59114             case 8:
59115                 return new Matrix4().set(0, h, 0, 0.5, w, 0, 0, 0.5, 0, 0, 1, 0, 0, 0, 0, 1);
59116             default:
59117                 return new Matrix4().set(w, 0, 0, 0.5, 0, -h, 0, 0.5, 0, 0, 1, 0, 0, 0, 0, 1);
59118         }
59119     }
59120 }
59121
59122 class SliderGLRenderer {
59123     constructor() {
59124         this._factory = new MeshFactory();
59125         this._scene = new MeshScene();
59126         this._spatial = new Spatial();
59127         this._currentKey = null;
59128         this._previousKey = null;
59129         this._disabled = false;
59130         this._curtain = 1;
59131         this._frameId = 0;
59132         this._needsRender = false;
59133         this._mode = null;
59134         this._currentProviderDisposers = {};
59135         this._previousProviderDisposers = {};
59136     }
59137     get disabled() {
59138         return this._disabled;
59139     }
59140     get frameId() {
59141         return this._frameId;
59142     }
59143     get needsRender() {
59144         return this._needsRender;
59145     }
59146     setTextureProvider(key, provider) {
59147         this._setTextureProvider(key, this._currentKey, provider, this._currentProviderDisposers, this._updateTexture.bind(this));
59148     }
59149     setTextureProviderPrev(key, provider) {
59150         this._setTextureProvider(key, this._previousKey, provider, this._previousProviderDisposers, this._updateTexturePrev.bind(this));
59151     }
59152     update(frame, mode) {
59153         this._updateFrameId(frame.id);
59154         this._updateImagePlanes(frame.state, mode);
59155     }
59156     updateCurtain(curtain) {
59157         if (this._curtain === curtain) {
59158             return;
59159         }
59160         this._curtain = curtain;
59161         this._updateCurtain();
59162         this._needsRender = true;
59163     }
59164     updateTexture(imageElement, image) {
59165         const planes = image.id === this._currentKey ?
59166             this._scene.planes :
59167             image.id === this._previousKey ?
59168                 this._scene.planesOld :
59169                 {};
59170         if (Object.keys(planes).length === 0) {
59171             return;
59172         }
59173         this._needsRender = true;
59174         for (const key in planes) {
59175             if (!planes.hasOwnProperty(key)) {
59176                 continue;
59177             }
59178             const plane = planes[key];
59179             let material = plane.material;
59180             let texture = material.uniforms.projectorTex.value;
59181             texture.image = imageElement;
59182             texture.needsUpdate = true;
59183         }
59184     }
59185     updateTextureImage(imageElement, image) {
59186         if (this._currentKey !== image.id) {
59187             return;
59188         }
59189         this._needsRender = true;
59190         const planes = this._scene.planes;
59191         for (const key in planes) {
59192             if (!planes.hasOwnProperty(key)) {
59193                 continue;
59194             }
59195             const plane = planes[key];
59196             let material = plane.material;
59197             let texture = material.uniforms.projectorTex.value;
59198             texture.image = imageElement;
59199             texture.needsUpdate = true;
59200         }
59201     }
59202     render(perspectiveCamera, renderer) {
59203         if (!this.disabled) {
59204             renderer.render(this._scene.sceneOld, perspectiveCamera);
59205         }
59206         renderer.render(this._scene.scene, perspectiveCamera);
59207         this._needsRender = false;
59208     }
59209     dispose() {
59210         this._scene.clear();
59211         for (const key in this._currentProviderDisposers) {
59212             if (!this._currentProviderDisposers.hasOwnProperty(key)) {
59213                 continue;
59214             }
59215             this._currentProviderDisposers[key]();
59216         }
59217         for (const key in this._previousProviderDisposers) {
59218             if (!this._previousProviderDisposers.hasOwnProperty(key)) {
59219                 continue;
59220             }
59221             this._previousProviderDisposers[key]();
59222         }
59223         this._currentProviderDisposers = {};
59224         this._previousProviderDisposers = {};
59225     }
59226     _getBasicCorners(currentAspect, previousAspect) {
59227         let offsetX;
59228         let offsetY;
59229         if (currentAspect > previousAspect) {
59230             offsetX = 0.5;
59231             offsetY = 0.5 * currentAspect / previousAspect;
59232         }
59233         else {
59234             offsetX = 0.5 * previousAspect / currentAspect;
59235             offsetY = 0.5;
59236         }
59237         return [[0.5 - offsetX, 0.5 - offsetY], [0.5 + offsetX, 0.5 + offsetY]];
59238     }
59239     _setDisabled(state) {
59240         this._disabled = state.currentImage == null ||
59241             state.previousImage == null ||
59242             (isSpherical(state.currentImage.cameraType) &&
59243                 !isSpherical(state.previousImage.cameraType));
59244     }
59245     _setTextureProvider(key, originalKey, provider, providerDisposers, updateTexture) {
59246         if (key !== originalKey) {
59247             return;
59248         }
59249         let createdSubscription = provider.textureCreated$
59250             .subscribe(updateTexture);
59251         let updatedSubscription = provider.textureUpdated$
59252             .subscribe((updated) => {
59253             this._needsRender = true;
59254         });
59255         let dispose = () => {
59256             createdSubscription.unsubscribe();
59257             updatedSubscription.unsubscribe();
59258             provider.dispose();
59259         };
59260         if (key in providerDisposers) {
59261             let disposeProvider = providerDisposers[key];
59262             disposeProvider();
59263             delete providerDisposers[key];
59264         }
59265         providerDisposers[key] = dispose;
59266     }
59267     _updateCurtain() {
59268         const planes = this._scene.planes;
59269         for (const key in planes) {
59270             if (!planes.hasOwnProperty(key)) {
59271                 continue;
59272             }
59273             const plane = planes[key];
59274             let shaderMaterial = plane.material;
59275             if (!!shaderMaterial.uniforms.curtain) {
59276                 shaderMaterial.uniforms.curtain.value = this._curtain;
59277             }
59278         }
59279     }
59280     _updateFrameId(frameId) {
59281         this._frameId = frameId;
59282     }
59283     _updateImagePlanes(state, mode) {
59284         const currentChanged = state.currentImage != null && this._currentKey !== state.currentImage.id;
59285         const previousChanged = state.previousImage != null && this._previousKey !== state.previousImage.id;
59286         const modeChanged = this._mode !== mode;
59287         if (!(currentChanged || previousChanged || modeChanged)) {
59288             return;
59289         }
59290         this._setDisabled(state);
59291         this._needsRender = true;
59292         this._mode = mode;
59293         const motionless = state.motionless ||
59294             mode === SliderConfigurationMode.Stationary ||
59295             isSpherical(state.currentImage.cameraType);
59296         if (this.disabled || previousChanged) {
59297             if (this._previousKey in this._previousProviderDisposers) {
59298                 this._previousProviderDisposers[this._previousKey]();
59299                 delete this._previousProviderDisposers[this._previousKey];
59300             }
59301         }
59302         if (this.disabled) {
59303             this._scene.setImagePlanesOld({});
59304         }
59305         else {
59306             if (previousChanged || modeChanged) {
59307                 const previousNode = state.previousImage;
59308                 this._previousKey = previousNode.id;
59309                 const elements = state.currentTransform.rt.elements;
59310                 let translation = [elements[12], elements[13], elements[14]];
59311                 const currentAspect = state.currentTransform.basicAspect;
59312                 const previousAspect = state.previousTransform.basicAspect;
59313                 const textureScale = currentAspect > previousAspect ?
59314                     [1, previousAspect / currentAspect] :
59315                     [currentAspect / previousAspect, 1];
59316                 let rotation = state.currentImage.rotation;
59317                 let width = state.currentImage.width;
59318                 let height = state.currentImage.height;
59319                 if (isSpherical(previousNode.cameraType)) {
59320                     rotation = state.previousImage.rotation;
59321                     translation = this._spatial
59322                         .rotate(this._spatial
59323                         .opticalCenter(state.currentImage.rotation, translation)
59324                         .toArray(), rotation)
59325                         .multiplyScalar(-1)
59326                         .toArray();
59327                     width = state.previousImage.width;
59328                     height = state.previousImage.height;
59329                 }
59330                 const transform = new Transform(state.currentImage.exifOrientation, width, height, state.currentImage.scale, rotation, translation, previousNode.image, textureScale, state.currentImage.cameraParameters, state.currentImage.cameraType);
59331                 let mesh = undefined;
59332                 if (isSpherical(previousNode.cameraType)) {
59333                     mesh = this._factory.createMesh(previousNode, motionless ||
59334                         isSpherical(state.currentImage.cameraType) ?
59335                         transform : state.previousTransform);
59336                 }
59337                 else {
59338                     if (motionless) {
59339                         const [[basicX0, basicY0], [basicX1, basicY1]] = this._getBasicCorners(currentAspect, previousAspect);
59340                         mesh = this._factory.createFlatMesh(state.previousImage, transform, basicX0, basicX1, basicY0, basicY1);
59341                     }
59342                     else {
59343                         mesh = this._factory.createMesh(state.previousImage, state.previousTransform);
59344                     }
59345                 }
59346                 const previousPlanes = {};
59347                 previousPlanes[previousNode.id] = mesh;
59348                 this._scene.setImagePlanesOld(previousPlanes);
59349             }
59350         }
59351         if (currentChanged || modeChanged) {
59352             if (this._currentKey in this._currentProviderDisposers) {
59353                 this._currentProviderDisposers[this._currentKey]();
59354                 delete this._currentProviderDisposers[this._currentKey];
59355             }
59356             this._currentKey = state.currentImage.id;
59357             const planes = {};
59358             if (isSpherical(state.currentImage.cameraType)) {
59359                 planes[state.currentImage.id] =
59360                     this._factory.createCurtainMesh(state.currentImage, state.currentTransform);
59361             }
59362             else {
59363                 if (motionless) {
59364                     planes[state.currentImage.id] = this._factory.createDistortedCurtainMesh(state.currentImage, state.currentTransform);
59365                 }
59366                 else {
59367                     planes[state.currentImage.id] = this._factory.createCurtainMesh(state.currentImage, state.currentTransform);
59368                 }
59369             }
59370             this._scene.setImagePlanes(planes);
59371             this._updateCurtain();
59372         }
59373     }
59374     _updateTexture(texture) {
59375         this._needsRender = true;
59376         const planes = this._scene.planes;
59377         for (const key in planes) {
59378             if (!planes.hasOwnProperty(key)) {
59379                 continue;
59380             }
59381             const plane = planes[key];
59382             let material = plane.material;
59383             let oldTexture = material.uniforms.projectorTex.value;
59384             material.uniforms.projectorTex.value = null;
59385             oldTexture.dispose();
59386             material.uniforms.projectorTex.value = texture;
59387         }
59388     }
59389     _updateTexturePrev(texture) {
59390         this._needsRender = true;
59391         const planes = this._scene.planesOld;
59392         for (const key in planes) {
59393             if (!planes.hasOwnProperty(key)) {
59394                 continue;
59395             }
59396             const plane = planes[key];
59397             let material = plane.material;
59398             let oldTexture = material.uniforms.projectorTex.value;
59399             material.uniforms.projectorTex.value = null;
59400             oldTexture.dispose();
59401             material.uniforms.projectorTex.value = texture;
59402         }
59403     }
59404 }
59405
59406 class SliderDOMRenderer {
59407     constructor(container) {
59408         this._container = container;
59409         this._interacting = false;
59410         this._notifyModeChanged$ = new Subject();
59411         this._notifyPositionChanged$ = new Subject();
59412         this._stopInteractionSubscription = null;
59413     }
59414     get mode$() {
59415         return this._notifyModeChanged$;
59416     }
59417     get position$() {
59418         return this._notifyPositionChanged$;
59419     }
59420     activate() {
59421         if (!!this._stopInteractionSubscription) {
59422             return;
59423         }
59424         this._stopInteractionSubscription = merge(this._container.mouseService.documentMouseUp$, this._container.touchService.touchEnd$.pipe(filter((touchEvent) => {
59425             return touchEvent.touches.length === 0;
59426         })))
59427             .subscribe((event) => {
59428             if (this._interacting) {
59429                 this._interacting = false;
59430             }
59431         });
59432     }
59433     deactivate() {
59434         if (!this._stopInteractionSubscription) {
59435             return;
59436         }
59437         this._interacting = false;
59438         this._stopInteractionSubscription.unsubscribe();
59439         this._stopInteractionSubscription = null;
59440     }
59441     render(position, mode, motionless, spherical, visible) {
59442         const children = [];
59443         if (visible) {
59444             children.push(virtualDom.h("div.mapillary-slider-border", []));
59445             const modeVisible = !(motionless || spherical);
59446             if (modeVisible) {
59447                 children.push(this._createModeButton(mode));
59448                 children.push(this._createModeButton2d(mode));
59449             }
59450             children.push(this._createPositionInput(position, modeVisible));
59451         }
59452         const boundingRect = this._container.domContainer.getBoundingClientRect();
59453         const width = Math.max(215, Math.min(400, boundingRect.width - 100));
59454         return virtualDom.h("div.mapillary-slider-container", { style: { width: `${width}px` } }, children);
59455     }
59456     _createModeButton(mode) {
59457         const properties = {
59458             onclick: () => {
59459                 if (mode === SliderConfigurationMode.Motion) {
59460                     return;
59461                 }
59462                 this._notifyModeChanged$.next(SliderConfigurationMode.Motion);
59463             },
59464         };
59465         const className = mode === SliderConfigurationMode.Stationary ?
59466             "mapillary-slider-mode-button-inactive" :
59467             "mapillary-slider-mode-button";
59468         return virtualDom.h("div." + className, properties, [virtualDom.h("div.mapillary-slider-mode-icon", [])]);
59469     }
59470     _createModeButton2d(mode) {
59471         const properties = {
59472             onclick: () => {
59473                 if (mode === SliderConfigurationMode.Stationary) {
59474                     return;
59475                 }
59476                 this._notifyModeChanged$.next(SliderConfigurationMode.Stationary);
59477             },
59478         };
59479         const className = mode === SliderConfigurationMode.Motion ?
59480             "mapillary-slider-mode-button-2d-inactive" :
59481             "mapillary-slider-mode-button-2d";
59482         return virtualDom.h("div." + className, properties, [virtualDom.h("div.mapillary-slider-mode-icon-2d", [])]);
59483     }
59484     _createPositionInput(position, modeVisible) {
59485         const onChange = (e) => {
59486             this._notifyPositionChanged$.next(Number(e.target.value) / 1000);
59487         };
59488         const onStart = (e) => {
59489             this._interacting = true;
59490             e.stopPropagation();
59491         };
59492         const onMove = (e) => {
59493             if (this._interacting) {
59494                 e.stopPropagation();
59495             }
59496         };
59497         const onKeyDown = (e) => {
59498             if (e.key === "ArrowDown" || e.key === "ArrowLeft" ||
59499                 e.key === "ArrowRight" || e.key === "ArrowUp") {
59500                 e.preventDefault();
59501             }
59502         };
59503         const boundingRect = this._container.domContainer.getBoundingClientRect();
59504         const width = Math.max(215, Math.min(400, boundingRect.width - 105)) - 84 + (modeVisible ? 0 : 52);
59505         const positionInput = virtualDom.h("input.mapillary-slider-position", {
59506             max: 1000,
59507             min: 0,
59508             onchange: onChange,
59509             oninput: onChange,
59510             onkeydown: onKeyDown,
59511             onpointerdown: onStart,
59512             onpointermove: onMove,
59513             ontouchmove: onMove,
59514             ontouchstart: onStart,
59515             style: {
59516                 width: `${width}px`,
59517             },
59518             type: "range",
59519             value: 1000 * position,
59520         }, []);
59521         return virtualDom.h("div.mapillary-slider-position-container", [positionInput]);
59522     }
59523 }
59524
59525 /**
59526  * @class SliderComponent
59527  *
59528  * @classdesc Component for comparing pairs of images. Renders
59529  * a slider for adjusting the curtain of the first image.
59530  *
59531  * Deactivate the sequence, direction and image plane
59532  * components when activating the slider component to avoid
59533  * interfering UI elements.
59534  *
59535  * To retrive and use the slider component
59536  *
59537  * @example
59538  * ```js
59539  * var viewer = new Viewer({ ... });
59540  *
59541  * viewer.deactivateComponent("image");
59542  * viewer.deactivateComponent("direction");
59543  * viewer.deactivateComponent("sequence");
59544  *
59545  * viewer.activateComponent("slider");
59546  *
59547  * var sliderComponent = viewer.getComponent("slider");
59548  * ```
59549  */
59550 class SliderComponent extends Component {
59551     /** @ignore */
59552     constructor(name, container, navigator, viewportCoords) {
59553         super(name, container, navigator);
59554         this._viewportCoords = !!viewportCoords ? viewportCoords : new ViewportCoords();
59555         this._domRenderer = new SliderDOMRenderer(container);
59556         this._imageTileLoader = new TileLoader(navigator.api);
59557         this._roiCalculator = new RegionOfInterestCalculator();
59558         this._spatial = new Spatial();
59559         this._glRendererOperation$ = new Subject();
59560         this._glRendererCreator$ = new Subject();
59561         this._glRendererDisposer$ = new Subject();
59562         this._glRenderer$ = this._glRendererOperation$.pipe(scan((glRenderer, operation) => {
59563             return operation(glRenderer);
59564         }, null), filter((glRenderer) => {
59565             return glRenderer != null;
59566         }), distinctUntilChanged(undefined, (glRenderer) => {
59567             return glRenderer.frameId;
59568         }));
59569         this._glRendererCreator$.pipe(map(() => {
59570             return (glRenderer) => {
59571                 if (glRenderer != null) {
59572                     throw new Error("Multiple slider states can not be created at the same time");
59573                 }
59574                 return new SliderGLRenderer();
59575             };
59576         }))
59577             .subscribe(this._glRendererOperation$);
59578         this._glRendererDisposer$.pipe(map(() => {
59579             return (glRenderer) => {
59580                 glRenderer.dispose();
59581                 return null;
59582             };
59583         }))
59584             .subscribe(this._glRendererOperation$);
59585     }
59586     _activate() {
59587         const subs = this._subscriptions;
59588         subs.push(this._domRenderer.mode$
59589             .subscribe((mode) => {
59590             this.configure({ mode });
59591         }));
59592         subs.push(this._glRenderer$.pipe(map((glRenderer) => {
59593             let renderHash = {
59594                 name: this._name,
59595                 renderer: {
59596                     frameId: glRenderer.frameId,
59597                     needsRender: glRenderer.needsRender,
59598                     render: glRenderer.render.bind(glRenderer),
59599                     pass: RenderPass$1.Background,
59600                 },
59601             };
59602             return renderHash;
59603         }))
59604             .subscribe(this._container.glRenderer.render$));
59605         const position$ = concat(this.configuration$.pipe(map((configuration) => {
59606             return configuration.initialPosition != null ?
59607                 configuration.initialPosition : 1;
59608         }), first()), this._domRenderer.position$);
59609         const mode$ = this.configuration$.pipe(map((configuration) => {
59610             return configuration.mode;
59611         }), distinctUntilChanged());
59612         const motionless$ = this._navigator.stateService.currentState$.pipe(map((frame) => {
59613             return frame.state.motionless;
59614         }), distinctUntilChanged());
59615         const spherical$ = this._navigator.stateService.currentState$.pipe(map((frame) => {
59616             return isSpherical(frame.state.currentImage.cameraType);
59617         }), distinctUntilChanged());
59618         const sliderVisible$ = combineLatest(this._configuration$.pipe(map((configuration) => {
59619             return configuration.sliderVisible;
59620         })), this._navigator.stateService.currentState$.pipe(map((frame) => {
59621             return !(frame.state.currentImage == null ||
59622                 frame.state.previousImage == null ||
59623                 (isSpherical(frame.state.currentImage.cameraType) &&
59624                     !isSpherical(frame.state.previousImage.cameraType)));
59625         }), distinctUntilChanged())).pipe(map(([sliderVisible, enabledState]) => {
59626             return sliderVisible && enabledState;
59627         }), distinctUntilChanged());
59628         this._waitSubscription = combineLatest(mode$, motionless$, spherical$, sliderVisible$).pipe(withLatestFrom(this._navigator.stateService.state$))
59629             .subscribe(([[mode, motionless, spherical, sliderVisible], state]) => {
59630             const interactive = sliderVisible &&
59631                 (motionless ||
59632                     mode === SliderConfigurationMode.Stationary ||
59633                     spherical);
59634             if (interactive && state !== State.WaitingInteractively) {
59635                 this._navigator.stateService.waitInteractively();
59636             }
59637             else if (!interactive && state !== State.Waiting) {
59638                 this._navigator.stateService.wait();
59639             }
59640         });
59641         subs.push(combineLatest(position$, mode$, motionless$, spherical$, sliderVisible$)
59642             .subscribe(([position, mode, motionless, spherical]) => {
59643             if (motionless || mode === SliderConfigurationMode.Stationary || spherical) {
59644                 this._navigator.stateService.moveTo(1);
59645             }
59646             else {
59647                 this._navigator.stateService.moveTo(position);
59648             }
59649         }));
59650         subs.push(combineLatest(position$, mode$, motionless$, spherical$, sliderVisible$, this._container.renderService.size$).pipe(map(([position, mode, motionless, spherical, sliderVisible]) => {
59651             return {
59652                 name: this._name,
59653                 vNode: this._domRenderer.render(position, mode, motionless, spherical, sliderVisible),
59654             };
59655         }))
59656             .subscribe(this._container.domRenderer.render$));
59657         this._glRendererCreator$.next(null);
59658         subs.push(combineLatest(position$, spherical$, sliderVisible$, this._container.renderService.renderCamera$, this._navigator.stateService.currentTransform$).pipe(map(([position, spherical, visible, render, transform]) => {
59659             if (!spherical) {
59660                 return visible ? position : 1;
59661             }
59662             const basicMin = this._viewportCoords.viewportToBasic(-1.15, 0, transform, render.perspective);
59663             const basicMax = this._viewportCoords.viewportToBasic(1.15, 0, transform, render.perspective);
59664             const shiftedMax = basicMax[0] < basicMin[0] ? basicMax[0] + 1 : basicMax[0];
59665             const basicPosition = basicMin[0] + position * (shiftedMax - basicMin[0]);
59666             return basicPosition > 1 ? basicPosition - 1 : basicPosition;
59667         }), map((position) => {
59668             return (glRenderer) => {
59669                 glRenderer.updateCurtain(position);
59670                 return glRenderer;
59671             };
59672         }))
59673             .subscribe(this._glRendererOperation$));
59674         subs.push(combineLatest(this._navigator.stateService.currentState$, mode$).pipe(map(([frame, mode]) => {
59675             return (glRenderer) => {
59676                 glRenderer.update(frame, mode);
59677                 return glRenderer;
59678             };
59679         }))
59680             .subscribe(this._glRendererOperation$));
59681         subs.push(this._configuration$.pipe(filter((configuration) => {
59682             return configuration.ids != null;
59683         }), switchMap((configuration) => {
59684             return zip(zip(this._catchCacheImage$(configuration.ids.background), this._catchCacheImage$(configuration.ids.foreground)).pipe(map((images) => {
59685                 return { background: images[0], foreground: images[1] };
59686             })), this._navigator.stateService.currentState$.pipe(first())).pipe(map((nf) => {
59687                 return { images: nf[0], state: nf[1].state };
59688             }));
59689         }))
59690             .subscribe((co) => {
59691             if (co.state.currentImage != null &&
59692                 co.state.previousImage != null &&
59693                 co.state.currentImage.id === co.images.foreground.id &&
59694                 co.state.previousImage.id === co.images.background.id) {
59695                 return;
59696             }
59697             if (co.state.currentImage.id === co.images.background.id) {
59698                 this._navigator.stateService.setImages([co.images.foreground]);
59699                 return;
59700             }
59701             if (co.state.currentImage.id === co.images.foreground.id &&
59702                 co.state.trajectory.length === 1) {
59703                 this._navigator.stateService.prependImages([co.images.background]);
59704                 return;
59705             }
59706             this._navigator.stateService.setImages([co.images.background]);
59707             this._navigator.stateService.setImages([co.images.foreground]);
59708         }, (e) => {
59709             console.error(e);
59710         }));
59711         const textureProvider$ = this._container.configurationService.imageTiling$.pipe(switchMap((active) => {
59712             return active ?
59713                 this._navigator.stateService.currentState$ :
59714                 new Subject();
59715         }), distinctUntilChanged(undefined, (frame) => {
59716             return frame.state.currentImage.id;
59717         }), withLatestFrom(this._container.glRenderer.webGLRenderer$, this._container.renderService.size$), map(([frame, renderer, size]) => {
59718             const state = frame.state;
59719             Math.max(size.width, size.height);
59720             const currentImage = state.currentImage;
59721             const currentTransform = state.currentTransform;
59722             return new TextureProvider(currentImage.id, currentTransform.basicWidth, currentTransform.basicHeight, currentImage.image, this._imageTileLoader, new TileStore(), renderer);
59723         }), publishReplay(1), refCount());
59724         subs.push(textureProvider$.subscribe(() => { }));
59725         subs.push(textureProvider$.pipe(map((provider) => {
59726             return (renderer) => {
59727                 renderer.setTextureProvider(provider.id, provider);
59728                 return renderer;
59729             };
59730         }))
59731             .subscribe(this._glRendererOperation$));
59732         subs.push(textureProvider$.pipe(pairwise())
59733             .subscribe((pair) => {
59734             let previous = pair[0];
59735             previous.abort();
59736         }));
59737         const roiTrigger$ = this._container.configurationService.imageTiling$.pipe(switchMap((active) => {
59738             return active ?
59739                 combineLatest(this._container.renderService.renderCameraFrame$, this._container.renderService.size$.pipe(debounceTime(250))) :
59740                 new Subject();
59741         }), map(([camera, size]) => {
59742             return [
59743                 camera.camera.position.clone(),
59744                 camera.camera.lookat.clone(),
59745                 camera.zoom.valueOf(),
59746                 size.height.valueOf(),
59747                 size.width.valueOf()
59748             ];
59749         }), pairwise(), skipWhile((pls) => {
59750             return pls[1][2] - pls[0][2] < 0 || pls[1][2] === 0;
59751         }), map((pls) => {
59752             let samePosition = pls[0][0].equals(pls[1][0]);
59753             let sameLookat = pls[0][1].equals(pls[1][1]);
59754             let sameZoom = pls[0][2] === pls[1][2];
59755             let sameHeight = pls[0][3] === pls[1][3];
59756             let sameWidth = pls[0][4] === pls[1][4];
59757             return samePosition && sameLookat && sameZoom && sameHeight && sameWidth;
59758         }), distinctUntilChanged(), filter((stalled) => {
59759             return stalled;
59760         }), switchMap(() => {
59761             return this._container.renderService.renderCameraFrame$.pipe(first());
59762         }), withLatestFrom(this._container.renderService.size$, this._navigator.stateService.currentTransform$));
59763         subs.push(textureProvider$.pipe(switchMap((provider) => {
59764             return roiTrigger$.pipe(map(([camera, size, transform]) => {
59765                 return [
59766                     this._roiCalculator.computeRegionOfInterest(camera, size, transform),
59767                     provider,
59768                 ];
59769             }));
59770         }), filter((args) => {
59771             return !args[1].disposed;
59772         }))
59773             .subscribe((args) => {
59774             let roi = args[0];
59775             let provider = args[1];
59776             provider.setRegionOfInterest(roi);
59777         }));
59778         const hasTexture$ = textureProvider$.pipe(switchMap((provider) => {
59779             return provider.hasTexture$;
59780         }), startWith(false), publishReplay(1), refCount());
59781         subs.push(hasTexture$.subscribe(() => { }));
59782         const textureProviderPrev$ = this._container.configurationService.imageTiling$.pipe(switchMap((active) => {
59783             return active ?
59784                 this._navigator.stateService.currentState$ :
59785                 new Subject();
59786         }), filter((frame) => {
59787             return !!frame.state.previousImage;
59788         }), distinctUntilChanged(undefined, (frame) => {
59789             return frame.state.previousImage.id;
59790         }), withLatestFrom(this._container.glRenderer.webGLRenderer$, this._container.renderService.size$), map(([frame, renderer, size]) => {
59791             const state = frame.state;
59792             const previousImage = state.previousImage;
59793             const previousTransform = state.previousTransform;
59794             return new TextureProvider(previousImage.id, previousTransform.basicWidth, previousTransform.basicHeight, previousImage.image, this._imageTileLoader, new TileStore(), renderer);
59795         }), publishReplay(1), refCount());
59796         subs.push(textureProviderPrev$.subscribe(() => { }));
59797         subs.push(textureProviderPrev$.pipe(map((provider) => {
59798             return (renderer) => {
59799                 renderer.setTextureProviderPrev(provider.id, provider);
59800                 return renderer;
59801             };
59802         }))
59803             .subscribe(this._glRendererOperation$));
59804         subs.push(textureProviderPrev$.pipe(pairwise())
59805             .subscribe((pair) => {
59806             let previous = pair[0];
59807             previous.abort();
59808         }));
59809         const roiTriggerPrev$ = this._container.configurationService.imageTiling$.pipe(switchMap((active) => {
59810             return active ?
59811                 combineLatest(this._container.renderService.renderCameraFrame$, this._container.renderService.size$.pipe(debounceTime(250))) :
59812                 new Subject();
59813         }), map(([camera, size]) => {
59814             return [
59815                 camera.camera.position.clone(),
59816                 camera.camera.lookat.clone(),
59817                 camera.zoom.valueOf(),
59818                 size.height.valueOf(),
59819                 size.width.valueOf()
59820             ];
59821         }), pairwise(), skipWhile((pls) => {
59822             return pls[1][2] - pls[0][2] < 0 || pls[1][2] === 0;
59823         }), map((pls) => {
59824             let samePosition = pls[0][0].equals(pls[1][0]);
59825             let sameLookat = pls[0][1].equals(pls[1][1]);
59826             let sameZoom = pls[0][2] === pls[1][2];
59827             let sameHeight = pls[0][3] === pls[1][3];
59828             let sameWidth = pls[0][4] === pls[1][4];
59829             return samePosition && sameLookat && sameZoom && sameHeight && sameWidth;
59830         }), distinctUntilChanged(), filter((stalled) => {
59831             return stalled;
59832         }), switchMap(() => {
59833             return this._container.renderService.renderCameraFrame$.pipe(first());
59834         }), withLatestFrom(this._container.renderService.size$, this._navigator.stateService.currentTransform$));
59835         subs.push(textureProviderPrev$.pipe(switchMap((provider) => {
59836             return roiTriggerPrev$.pipe(map(([camera, size, transform]) => {
59837                 return [
59838                     this._roiCalculator.computeRegionOfInterest(camera, size, transform),
59839                     provider,
59840                 ];
59841             }));
59842         }), filter((args) => {
59843             return !args[1].disposed;
59844         }), withLatestFrom(this._navigator.stateService.currentState$))
59845             .subscribe(([[roi, provider], frame]) => {
59846             let shiftedRoi = null;
59847             if (isSpherical(frame.state.previousImage.cameraType)) {
59848                 if (isSpherical(frame.state.currentImage.cameraType)) {
59849                     const currentViewingDirection = this._spatial.viewingDirection(frame.state.currentImage.rotation);
59850                     const previousViewingDirection = this._spatial.viewingDirection(frame.state.previousImage.rotation);
59851                     const directionDiff = this._spatial.angleBetweenVector2(currentViewingDirection.x, currentViewingDirection.y, previousViewingDirection.x, previousViewingDirection.y);
59852                     const shift = directionDiff / (2 * Math.PI);
59853                     const bbox = {
59854                         maxX: this._spatial.wrap(roi.bbox.maxX + shift, 0, 1),
59855                         maxY: roi.bbox.maxY,
59856                         minX: this._spatial.wrap(roi.bbox.minX + shift, 0, 1),
59857                         minY: roi.bbox.minY,
59858                     };
59859                     shiftedRoi = {
59860                         bbox: bbox,
59861                         pixelHeight: roi.pixelHeight,
59862                         pixelWidth: roi.pixelWidth,
59863                     };
59864                 }
59865                 else {
59866                     const currentViewingDirection = this._spatial.viewingDirection(frame.state.currentImage.rotation);
59867                     const previousViewingDirection = this._spatial.viewingDirection(frame.state.previousImage.rotation);
59868                     const directionDiff = this._spatial.angleBetweenVector2(currentViewingDirection.x, currentViewingDirection.y, previousViewingDirection.x, previousViewingDirection.y);
59869                     const shiftX = directionDiff / (2 * Math.PI);
59870                     const a1 = this._spatial.angleToPlane(currentViewingDirection.toArray(), [0, 0, 1]);
59871                     const a2 = this._spatial.angleToPlane(previousViewingDirection.toArray(), [0, 0, 1]);
59872                     const shiftY = (a2 - a1) / (2 * Math.PI);
59873                     const currentTransform = frame.state.currentTransform;
59874                     const size = Math.max(currentTransform.basicWidth, currentTransform.basicHeight);
59875                     const hFov = size > 0 ?
59876                         2 * Math.atan(0.5 * currentTransform.basicWidth / (size * currentTransform.focal)) :
59877                         Math.PI / 3;
59878                     const vFov = size > 0 ?
59879                         2 * Math.atan(0.5 * currentTransform.basicHeight / (size * currentTransform.focal)) :
59880                         Math.PI / 3;
59881                     const spanningWidth = hFov / (2 * Math.PI);
59882                     const spanningHeight = vFov / Math.PI;
59883                     const basicWidth = (roi.bbox.maxX - roi.bbox.minX) * spanningWidth;
59884                     const basicHeight = (roi.bbox.maxY - roi.bbox.minY) * spanningHeight;
59885                     const pixelWidth = roi.pixelWidth * spanningWidth;
59886                     const pixelHeight = roi.pixelHeight * spanningHeight;
59887                     const zoomShiftX = (roi.bbox.minX + roi.bbox.maxX) / 2 - 0.5;
59888                     const zoomShiftY = (roi.bbox.minY + roi.bbox.maxY) / 2 - 0.5;
59889                     const minX = 0.5 + shiftX + spanningWidth * zoomShiftX - basicWidth / 2;
59890                     const maxX = 0.5 + shiftX + spanningWidth * zoomShiftX + basicWidth / 2;
59891                     const minY = 0.5 + shiftY + spanningHeight * zoomShiftY - basicHeight / 2;
59892                     const maxY = 0.5 + shiftY + spanningHeight * zoomShiftY + basicHeight / 2;
59893                     const bbox = {
59894                         maxX: this._spatial.wrap(maxX, 0, 1),
59895                         maxY: maxY,
59896                         minX: this._spatial.wrap(minX, 0, 1),
59897                         minY: minY,
59898                     };
59899                     shiftedRoi = {
59900                         bbox: bbox,
59901                         pixelHeight: pixelHeight,
59902                         pixelWidth: pixelWidth,
59903                     };
59904                 }
59905             }
59906             else {
59907                 const currentBasicAspect = frame.state.currentTransform.basicAspect;
59908                 const previousBasicAspect = frame.state.previousTransform.basicAspect;
59909                 const [[cornerMinX, cornerMinY], [cornerMaxX, cornerMaxY]] = this._getBasicCorners(currentBasicAspect, previousBasicAspect);
59910                 const basicWidth = cornerMaxX - cornerMinX;
59911                 const basicHeight = cornerMaxY - cornerMinY;
59912                 const pixelWidth = roi.pixelWidth / basicWidth;
59913                 const pixelHeight = roi.pixelHeight / basicHeight;
59914                 const minX = (basicWidth - 1) / (2 * basicWidth) + roi.bbox.minX / basicWidth;
59915                 const maxX = (basicWidth - 1) / (2 * basicWidth) + roi.bbox.maxX / basicWidth;
59916                 const minY = (basicHeight - 1) / (2 * basicHeight) + roi.bbox.minY / basicHeight;
59917                 const maxY = (basicHeight - 1) / (2 * basicHeight) + roi.bbox.maxY / basicHeight;
59918                 const bbox = {
59919                     maxX: maxX,
59920                     maxY: maxY,
59921                     minX: minX,
59922                     minY: minY,
59923                 };
59924                 this._clipBoundingBox(bbox);
59925                 shiftedRoi = {
59926                     bbox: bbox,
59927                     pixelHeight: pixelHeight,
59928                     pixelWidth: pixelWidth,
59929                 };
59930             }
59931             provider.setRegionOfInterest(shiftedRoi);
59932         }));
59933         const hasTexturePrev$ = textureProviderPrev$.pipe(switchMap((provider) => {
59934             return provider.hasTexture$;
59935         }), startWith(false), publishReplay(1), refCount());
59936         subs.push(hasTexturePrev$.subscribe(() => { }));
59937     }
59938     _deactivate() {
59939         this._waitSubscription.unsubscribe();
59940         this._navigator.stateService.state$.pipe(first())
59941             .subscribe((state) => {
59942             if (state !== State.Traversing) {
59943                 this._navigator.stateService.traverse();
59944             }
59945         });
59946         this._glRendererDisposer$.next(null);
59947         this._domRenderer.deactivate();
59948         this._subscriptions.unsubscribe();
59949         this.configure({ ids: null });
59950     }
59951     _getDefaultConfiguration() {
59952         return {
59953             initialPosition: 1,
59954             mode: SliderConfigurationMode.Motion,
59955             sliderVisible: true,
59956         };
59957     }
59958     _catchCacheImage$(imageId) {
59959         return this._navigator.graphService.cacheImage$(imageId).pipe(catchError((error) => {
59960             console.error(`Failed to cache slider image (${imageId})`, error);
59961             return empty();
59962         }));
59963     }
59964     _getBasicCorners(currentAspect, previousAspect) {
59965         let offsetX;
59966         let offsetY;
59967         if (currentAspect > previousAspect) {
59968             offsetX = 0.5;
59969             offsetY = 0.5 * currentAspect / previousAspect;
59970         }
59971         else {
59972             offsetX = 0.5 * previousAspect / currentAspect;
59973             offsetY = 0.5;
59974         }
59975         return [[0.5 - offsetX, 0.5 - offsetY], [0.5 + offsetX, 0.5 + offsetY]];
59976     }
59977     _clipBoundingBox(bbox) {
59978         bbox.minX = Math.max(0, Math.min(1, bbox.minX));
59979         bbox.maxX = Math.max(0, Math.min(1, bbox.maxX));
59980         bbox.minY = Math.max(0, Math.min(1, bbox.minY));
59981         bbox.maxY = Math.max(0, Math.min(1, bbox.maxY));
59982     }
59983 }
59984 SliderComponent.componentName = "slider";
59985
59986 class PlayService {
59987     constructor(graphService, stateService) {
59988         this._subscriptions = new SubscriptionHolder();
59989         this._graphService = graphService;
59990         this._stateService = stateService;
59991         const subs = this._subscriptions;
59992         this._directionSubject$ = new Subject();
59993         this._direction$ = this._directionSubject$.pipe(startWith(NavigationDirection.Next), publishReplay(1), refCount());
59994         subs.push(this._direction$.subscribe());
59995         this._playing = false;
59996         this._playingSubject$ = new Subject();
59997         this._playing$ = this._playingSubject$.pipe(startWith(this._playing), publishReplay(1), refCount());
59998         subs.push(this._playing$.subscribe());
59999         this._speed = 0.5;
60000         this._speedSubject$ = new Subject();
60001         this._speed$ = this._speedSubject$.pipe(startWith(this._speed), publishReplay(1), refCount());
60002         subs.push(this._speed$.subscribe());
60003         this._imagesAhead = this._mapImagesAhead(this._mapSpeed(this._speed));
60004         this._bridging$ = null;
60005     }
60006     get playing() {
60007         return this._playing;
60008     }
60009     get direction$() {
60010         return this._direction$;
60011     }
60012     get playing$() {
60013         return this._playing$;
60014     }
60015     get speed$() {
60016         return this._speed$;
60017     }
60018     play() {
60019         if (this._playing) {
60020             return;
60021         }
60022         this._stateService.cutImages();
60023         const stateSpeed = this._setSpeed(this._speed);
60024         this._stateService.setSpeed(stateSpeed);
60025         this._graphModeSubscription = this._speed$.pipe(map((speed) => {
60026             return speed > PlayService.sequenceSpeed ? GraphMode.Sequence : GraphMode.Spatial;
60027         }), distinctUntilChanged())
60028             .subscribe((mode) => {
60029             this._graphService.setGraphMode(mode);
60030         });
60031         this._cacheSubscription = combineLatest(this._stateService.currentImage$.pipe(map((image) => {
60032             return [image.sequenceId, image.id];
60033         }), distinctUntilChanged(undefined, ([sequenceId]) => {
60034             return sequenceId;
60035         })), this._graphService.graphMode$, this._direction$).pipe(switchMap(([[sequenceId, imageId], mode, direction]) => {
60036             if (direction !== NavigationDirection.Next && direction !== NavigationDirection.Prev) {
60037                 return of([undefined, direction]);
60038             }
60039             const sequence$ = (mode === GraphMode.Sequence ?
60040                 this._graphService.cacheSequenceImages$(sequenceId, imageId) :
60041                 this._graphService.cacheSequence$(sequenceId)).pipe(retry(3), catchError((error) => {
60042                 console.error(error);
60043                 return of(undefined);
60044             }));
60045             return combineLatest(sequence$, of(direction));
60046         }), switchMap(([sequence, direction]) => {
60047             if (sequence === undefined) {
60048                 return empty();
60049             }
60050             const imageIds = sequence.imageIds.slice();
60051             if (direction === NavigationDirection.Prev) {
60052                 imageIds.reverse();
60053             }
60054             return this._stateService.currentState$.pipe(map((frame) => {
60055                 return [frame.state.trajectory[frame.state.trajectory.length - 1].id, frame.state.imagesAhead];
60056             }), scan(([lastRequestKey, previousRequestKeys], [lastTrajectoryKey, imagesAhead]) => {
60057                 if (lastRequestKey === undefined) {
60058                     lastRequestKey = lastTrajectoryKey;
60059                 }
60060                 const lastIndex = imageIds.length - 1;
60061                 if (imagesAhead >= this._imagesAhead || imageIds[lastIndex] === lastRequestKey) {
60062                     return [lastRequestKey, []];
60063                 }
60064                 const current = imageIds.indexOf(lastTrajectoryKey);
60065                 const start = imageIds.indexOf(lastRequestKey) + 1;
60066                 const end = Math.min(lastIndex, current + this._imagesAhead - imagesAhead) + 1;
60067                 if (end <= start) {
60068                     return [lastRequestKey, []];
60069                 }
60070                 return [imageIds[end - 1], imageIds.slice(start, end)];
60071             }, [undefined, []]), mergeMap(([lastRequestKey, newRequestKeys]) => {
60072                 return from(newRequestKeys);
60073             }));
60074         }), mergeMap((key) => {
60075             return this._graphService.cacheImage$(key).pipe(catchError(() => {
60076                 return empty();
60077             }));
60078         }, 6))
60079             .subscribe();
60080         this._playingSubscription = this._stateService.currentState$.pipe(filter((frame) => {
60081             return frame.state.imagesAhead < this._imagesAhead;
60082         }), distinctUntilChanged(undefined, (frame) => {
60083             return frame.state.lastImage.id;
60084         }), map((frame) => {
60085             const lastImage = frame.state.lastImage;
60086             const trajectory = frame.state.trajectory;
60087             let increasingTime = undefined;
60088             for (let i = trajectory.length - 2; i >= 0; i--) {
60089                 const image = trajectory[i];
60090                 if (image.sequenceId !== lastImage.sequenceId) {
60091                     break;
60092                 }
60093                 if (image.capturedAt !== lastImage.capturedAt) {
60094                     increasingTime = image.capturedAt < lastImage.capturedAt;
60095                     break;
60096                 }
60097             }
60098             return [frame.state.lastImage, increasingTime];
60099         }), withLatestFrom(this._direction$), switchMap(([[image, increasingTime], direction]) => {
60100             return zip(([NavigationDirection.Next, NavigationDirection.Prev].indexOf(direction) > -1 ?
60101                 image.sequenceEdges$ :
60102                 image.spatialEdges$).pipe(first((status) => {
60103                 return status.cached;
60104             }), timeout(15000)), of(direction)).pipe(map(([s, d]) => {
60105                 for (let edge of s.edges) {
60106                     if (edge.data.direction === d) {
60107                         return edge.target;
60108                     }
60109                 }
60110                 return null;
60111             }), switchMap((key) => {
60112                 return key != null ?
60113                     this._graphService.cacheImage$(key) :
60114                     empty();
60115             }));
60116         }))
60117             .subscribe((image) => {
60118             this._stateService.appendImagess([image]);
60119         }, (error) => {
60120             console.error(error);
60121             this.stop();
60122         });
60123         this._clearSubscription = this._stateService.currentImage$.pipe(bufferCount(1, 10))
60124             .subscribe((images) => {
60125             this._stateService.clearPriorImages();
60126         });
60127         this._setPlaying(true);
60128         const currentLastImages$ = this._stateService.currentState$.pipe(map((frame) => {
60129             return frame.state;
60130         }), distinctUntilChanged(([kc1, kl1], [kc2, kl2]) => {
60131             return kc1 === kc2 && kl1 === kl2;
60132         }, (state) => {
60133             return [state.currentImage.id, state.lastImage.id];
60134         }), filter((state) => {
60135             return state.currentImage.id === state.lastImage.id &&
60136                 state.currentIndex === state.trajectory.length - 1;
60137         }), map((state) => {
60138             return state.currentImage;
60139         }));
60140         this._stopSubscription = combineLatest(currentLastImages$, this._direction$).pipe(switchMap(([image, direction]) => {
60141             const edgeStatus$ = ([NavigationDirection.Next, NavigationDirection.Prev].indexOf(direction) > -1 ?
60142                 image.sequenceEdges$ :
60143                 image.spatialEdges$).pipe(first((status) => {
60144                 return status.cached;
60145             }), timeout(15000), catchError((error) => {
60146                 console.error(error);
60147                 return of({ cached: false, edges: [] });
60148             }));
60149             return combineLatest(of(direction), edgeStatus$).pipe(map(([d, es]) => {
60150                 for (const edge of es.edges) {
60151                     if (edge.data.direction === d) {
60152                         return true;
60153                     }
60154                 }
60155                 return false;
60156             }));
60157         }), mergeMap((hasEdge) => {
60158             if (hasEdge || !this._bridging$) {
60159                 return of(hasEdge);
60160             }
60161             return this._bridging$.pipe(map((image) => {
60162                 return image != null;
60163             }), catchError((error) => {
60164                 console.error(error);
60165                 return of(false);
60166             }));
60167         }), first((hasEdge) => {
60168             return !hasEdge;
60169         }))
60170             .subscribe(undefined, undefined, () => { this.stop(); });
60171         if (this._stopSubscription.closed) {
60172             this._stopSubscription = null;
60173         }
60174         this._earthSubscription = this._stateService.state$
60175             .pipe(map((state) => {
60176             return state === State.Earth;
60177         }), distinctUntilChanged(), first((earth) => {
60178             return earth;
60179         }))
60180             .subscribe(undefined, undefined, () => { this.stop(); });
60181         if (this._earthSubscription.closed) {
60182             this._earthSubscription = null;
60183         }
60184     }
60185     dispose() {
60186         this.stop();
60187         this._subscriptions.unsubscribe();
60188     }
60189     setDirection(direction) {
60190         this._directionSubject$.next(direction);
60191     }
60192     setSpeed(speed) {
60193         speed = Math.max(0, Math.min(1, speed));
60194         if (speed === this._speed) {
60195             return;
60196         }
60197         const stateSpeed = this._setSpeed(speed);
60198         if (this._playing) {
60199             this._stateService.setSpeed(stateSpeed);
60200         }
60201         this._speedSubject$.next(this._speed);
60202     }
60203     stop() {
60204         if (!this._playing) {
60205             return;
60206         }
60207         if (!!this._stopSubscription) {
60208             if (!this._stopSubscription.closed) {
60209                 this._stopSubscription.unsubscribe();
60210             }
60211             this._stopSubscription = null;
60212         }
60213         if (!!this._earthSubscription) {
60214             if (!this._earthSubscription.closed) {
60215                 this._earthSubscription.unsubscribe();
60216             }
60217             this._earthSubscription = null;
60218         }
60219         this._graphModeSubscription.unsubscribe();
60220         this._graphModeSubscription = null;
60221         this._cacheSubscription.unsubscribe();
60222         this._cacheSubscription = null;
60223         this._playingSubscription.unsubscribe();
60224         this._playingSubscription = null;
60225         this._clearSubscription.unsubscribe();
60226         this._clearSubscription = null;
60227         this._stateService.setSpeed(1);
60228         this._stateService.cutImages();
60229         this._graphService.setGraphMode(GraphMode.Spatial);
60230         this._setPlaying(false);
60231     }
60232     _mapSpeed(speed) {
60233         const x = 2 * speed - 1;
60234         return Math.pow(10, x) - 0.2 * x;
60235     }
60236     _mapImagesAhead(stateSpeed) {
60237         return Math.round(Math.max(10, Math.min(50, 8 + 6 * stateSpeed)));
60238     }
60239     _setPlaying(playing) {
60240         this._playing = playing;
60241         this._playingSubject$.next(playing);
60242     }
60243     _setSpeed(speed) {
60244         this._speed = speed;
60245         const stateSpeed = this._mapSpeed(this._speed);
60246         this._imagesAhead = this._mapImagesAhead(stateSpeed);
60247         return stateSpeed;
60248     }
60249 }
60250 PlayService.sequenceSpeed = 0.54;
60251
60252 var CameraVisualizationMode;
60253 (function (CameraVisualizationMode) {
60254     /**
60255      * Cameras are hidden.
60256      */
60257     CameraVisualizationMode[CameraVisualizationMode["Hidden"] = 0] = "Hidden";
60258     /**
60259      * Cameras are shown, all with the same color.
60260      */
60261     CameraVisualizationMode[CameraVisualizationMode["Homogeneous"] = 1] = "Homogeneous";
60262     /**
60263      * Cameras are shown with colors based on the
60264      * their clusters.
60265      */
60266     CameraVisualizationMode[CameraVisualizationMode["Cluster"] = 2] = "Cluster";
60267     /**
60268      * Cameras are shown with colors based on the
60269      * their connected components.
60270      */
60271     CameraVisualizationMode[CameraVisualizationMode["ConnectedComponent"] = 3] = "ConnectedComponent";
60272     /**
60273      * Cameras are shown, with colors based on the
60274      * their sequence.
60275      */
60276     CameraVisualizationMode[CameraVisualizationMode["Sequence"] = 4] = "Sequence";
60277 })(CameraVisualizationMode || (CameraVisualizationMode = {}));
60278
60279 var OriginalPositionMode;
60280 (function (OriginalPositionMode) {
60281     /**
60282      * Original positions are hidden.
60283      */
60284     OriginalPositionMode[OriginalPositionMode["Hidden"] = 0] = "Hidden";
60285     /**
60286      * Visualize original positions with altitude change.
60287      */
60288     OriginalPositionMode[OriginalPositionMode["Altitude"] = 1] = "Altitude";
60289     /**
60290      * Visualize original positions without altitude change,
60291      * i.e. as flat lines from the camera origin.
60292      */
60293     OriginalPositionMode[OriginalPositionMode["Flat"] = 2] = "Flat";
60294 })(OriginalPositionMode || (OriginalPositionMode = {}));
60295
60296 class ClusterPoints extends Points {
60297     constructor(parameters) {
60298         super();
60299         this._originalSize = parameters.originalSize;
60300         const { cluster, color, scale, translation } = parameters;
60301         this._makeAttributes(cluster);
60302         this.material.size = scale * this._originalSize;
60303         this.setColor(color);
60304         this.matrixAutoUpdate = false;
60305         this.position.fromArray(translation);
60306         this.updateMatrix();
60307         this.updateMatrixWorld(false);
60308     }
60309     dispose() {
60310         this.geometry.dispose();
60311         this.material.dispose();
60312     }
60313     setColor(color) {
60314         this.material.vertexColors = color == null;
60315         this.material.color = new Color(color);
60316         this.material.needsUpdate = true;
60317     }
60318     resize(scale) {
60319         this.material.size = scale * this._originalSize;
60320         this.material.needsUpdate = true;
60321     }
60322     _makeAttributes(cluster) {
60323         const positions = [];
60324         const colors = [];
60325         const points = cluster.points;
60326         for (const pointId in points) {
60327             if (!points.hasOwnProperty(pointId)) {
60328                 continue;
60329             }
60330             const point = points[pointId];
60331             positions.push(...point.coordinates);
60332             const color = point.color;
60333             colors.push(color[0]);
60334             colors.push(color[1]);
60335             colors.push(color[2]);
60336         }
60337         const geometry = this.geometry;
60338         geometry.setAttribute("position", new BufferAttribute(new Float32Array(positions), 3));
60339         geometry.setAttribute("color", new BufferAttribute(new Float32Array(colors), 3));
60340     }
60341 }
60342
60343 class CellLine extends Line {
60344     constructor(vertices) {
60345         super();
60346         this._makeAttributes(vertices);
60347         this.matrixAutoUpdate = false;
60348         this.updateMatrix();
60349         this.updateMatrixWorld(false);
60350     }
60351     dispose() {
60352         this.geometry.dispose();
60353         this.material.dispose();
60354     }
60355     _makeAttributes(vertices) {
60356         const closedPolygon = vertices.slice();
60357         closedPolygon.push(vertices[0]);
60358         let index = 0;
60359         const positions = new Float32Array(3 * (vertices.length + 1));
60360         for (const vertex of closedPolygon) {
60361             positions[index++] = vertex[0];
60362             positions[index++] = vertex[1];
60363             positions[index++] = vertex[2];
60364         }
60365         this.geometry.setAttribute("position", new BufferAttribute(positions, 3));
60366     }
60367 }
60368
60369 // Level 0: 1 x 1 x 1 meter cubes
60370 const OCTREE_ROOT_LEVEL = 14; // 16384 meters
60371 const OCTREE_LEAF_LEVEL = 6; // 64 meters
60372 function isLeafLevel(level, leafLevel) {
60373     return level === leafLevel;
60374 }
60375 function levelToSize(level) {
60376     return Math.pow(2, level);
60377 }
60378 function levelToRootBoundingBox(level) {
60379     const size = levelToSize(level);
60380     const half = size / 2;
60381     const min = [-half, -half, -half];
60382     const max = [half, half, half];
60383     return { min, max };
60384 }
60385
60386 class SpatialOctreeNode {
60387     constructor(level, leafLevel, boundingBox, parent) {
60388         this.level = level;
60389         this.leafLevel = leafLevel;
60390         this.boundingBox = boundingBox;
60391         this.parent = parent;
60392         this.children = [];
60393         this.items = [];
60394         if (parent) {
60395             parent.children.push(this);
60396         }
60397     }
60398     get isEmpty() {
60399         return !(this.children.length || this.items.length);
60400     }
60401     add(object) {
60402         const self = this;
60403         if (!self.boundingBox.containsPoint(object.position)) {
60404             throw new Error(`Item not contained in node`);
60405         }
60406         if (isLeafLevel(self.level, self.leafLevel)) {
60407             self.items.push(object);
60408             return this;
60409         }
60410         for (const child of self.children) {
60411             if (child.boundingBox.containsPoint(object.position)) {
60412                 return child.add(object);
60413             }
60414         }
60415         for (const boundingBox of self._generateBoundingBoxes()) {
60416             if (boundingBox.containsPoint(object.position)) {
60417                 const child = new SpatialOctreeNode(self.level - 1, self.leafLevel, boundingBox, self);
60418                 return child.add(object);
60419             }
60420         }
60421         throw new Error(`Item not contained in children`);
60422     }
60423     intersect(ray, target, nodes) {
60424         if (!ray.intersectBox(this.boundingBox, target)) {
60425             return;
60426         }
60427         if (isLeafLevel(this.level, this.leafLevel)) {
60428             nodes.push(this);
60429             return;
60430         }
60431         for (const child of this.children) {
60432             child.intersect(ray, target, nodes);
60433         }
60434     }
60435     remove(object) {
60436         const index = this.items.indexOf(object);
60437         if (index < 0) {
60438             throw new Error(`Item does not exist ${object.uuid}`);
60439         }
60440         this.items.splice(index, 1);
60441     }
60442     traverse() {
60443         const self = this;
60444         if (!self.isEmpty) {
60445             return;
60446         }
60447         const parent = self.parent;
60448         if (!parent) {
60449             return;
60450         }
60451         const index = parent.children.indexOf(self);
60452         if (index < 0) {
60453             throw new Error(`Corrupt octree`);
60454         }
60455         parent.children.splice(index, 1);
60456         this.parent = null;
60457         parent.traverse();
60458     }
60459     _generateBoundingBoxes() {
60460         const self = this;
60461         const min = self.boundingBox.min;
60462         const max = self.boundingBox.max;
60463         const size = (max.x - min.x) / 2;
60464         const mins = [
60465             [min.x, min.y + size, min.z + size],
60466             [min.x + size, min.y + size, min.z + size],
60467             [min.x, min.y, min.z + size],
60468             [min.x + size, min.y, min.z + size],
60469             [min.x, min.y + size, min.z],
60470             [min.x + size, min.y + size, min.z],
60471             [min.x, min.y, min.z],
60472             [min.x + size, min.y, min.z],
60473         ];
60474         const boundingBoxes = [];
60475         for (const [minX, minY, minZ] of mins) {
60476             boundingBoxes.push(new Box3(new Vector3(minX, minY, minZ), new Vector3(minX + size, minY + size, minZ + size)));
60477         }
60478         return boundingBoxes;
60479     }
60480 }
60481
60482 class SpatialOctree {
60483     constructor(rootLevel, leafLevel) {
60484         this.rootLevel = rootLevel;
60485         this.leafLevel = leafLevel;
60486         if (leafLevel > rootLevel) {
60487             throw new Error();
60488         }
60489         this._index = new Map();
60490         this._root = this._makeRoot();
60491     }
60492     get root() {
60493         return this._root;
60494     }
60495     add(object) {
60496         if (!this.root.boundingBox.containsPoint(object.position)) {
60497             console.warn(`Object outside bounding box ${object.uuid}`);
60498             return;
60499         }
60500         const leaf = this._root.add(object);
60501         this._index.set(object.uuid, leaf);
60502     }
60503     has(object) {
60504         return this._index.has(object.uuid);
60505     }
60506     intersect(ray) {
60507         const leaves = [];
60508         const target = new Vector3();
60509         this._root.intersect(ray, target, leaves);
60510         return leaves
60511             .map(leaf => leaf.items)
60512             .reduce((acc, items) => {
60513             acc.push(...items);
60514             return acc;
60515         }, []);
60516     }
60517     reset() {
60518         this._root = this._makeRoot();
60519         this._index.clear();
60520     }
60521     remove(object) {
60522         if (!this.has(object)) {
60523             throw new Error(`Frame does not exist ${object.uuid}`);
60524         }
60525         const leaf = this._index.get(object.uuid);
60526         leaf.remove(object);
60527         leaf.traverse();
60528         this._index.delete(object.uuid);
60529     }
60530     _makeRoot() {
60531         const level = this.rootLevel;
60532         const bbox = levelToRootBoundingBox(level);
60533         const box = new Box3(new Vector3().fromArray(bbox.min), new Vector3().fromArray(bbox.max));
60534         return new SpatialOctreeNode(level, this.leafLevel, box);
60535     }
60536 }
60537
60538 class SpatialIntersection {
60539     constructor(octree, raycaster) {
60540         this._objects = [];
60541         this._objectImageMap = new Map();
60542         this._octree = octree !== null && octree !== void 0 ? octree : new SpatialOctree(OCTREE_ROOT_LEVEL, OCTREE_LEAF_LEVEL);
60543         this._raycaster = raycaster !== null && raycaster !== void 0 ? raycaster : new Raycaster();
60544         this._interactiveLayer = 1;
60545         this._raycaster = !!raycaster ?
60546             raycaster :
60547             new Raycaster(undefined, undefined, 1, 10000);
60548         this._lineThreshold = 0.2;
60549         this._largeLineThreshold = 0.4;
60550         this._raycaster.params.Line.threshold = this._lineThreshold;
60551         this._raycaster.layers.set(this._interactiveLayer);
60552     }
60553     get interactiveLayer() { return this._interactiveLayer; }
60554     get octree() { return this._octree; }
60555     get raycaster() { return this._raycaster; }
60556     add(object, imageId) {
60557         const uuid = object.uuid;
60558         this._objectImageMap.set(uuid, imageId);
60559         this._objects.push(object);
60560         this._octree.add(object);
60561     }
60562     intersectObjects(viewport, camera) {
60563         this._raycaster.setFromCamera(new Vector2().fromArray(viewport), camera);
60564         const objects = this._octree.intersect(this.raycaster.ray);
60565         const intersects = this._raycaster.intersectObjects(objects);
60566         const onMap = this._objectImageMap;
60567         for (const intersect of intersects) {
60568             const uuid = intersect.object.uuid;
60569             if (!onMap.has(uuid)) {
60570                 continue;
60571             }
60572             return onMap.get(uuid);
60573         }
60574         return null;
60575     }
60576     remove(object) {
60577         const objects = this._objects;
60578         const index = objects.indexOf(object);
60579         if (index !== -1) {
60580             const deleted = objects.splice(index, 1);
60581             for (const d of deleted) {
60582                 this._objectImageMap.delete(d.uuid);
60583             }
60584             this._octree.remove(object);
60585         }
60586         else {
60587             console.warn(`Object does not exist`);
60588         }
60589     }
60590     resetIntersectionThreshold(useLarge) {
60591         this._raycaster.params.Line.threshold = useLarge ?
60592             this._largeLineThreshold :
60593             this._lineThreshold;
60594     }
60595 }
60596
60597 class PositionLine extends Line {
60598     constructor(parameters) {
60599         super(parameters.geometry, parameters.material);
60600         const mode = parameters.mode;
60601         const originalOrigin = parameters.originalOrigin;
60602         const transform = parameters.transform;
60603         const origin = transform.unprojectBasic([0, 0], 0);
60604         this._relativeAltitude = originalOrigin[2] - origin[2];
60605         this._makeAttributes(origin, originalOrigin, mode);
60606         this.matrixAutoUpdate = false;
60607         this.position.fromArray(origin);
60608         this.updateMatrix();
60609         this.updateMatrixWorld(false);
60610     }
60611     dispose() {
60612         this.geometry.dispose();
60613         this.material.dispose();
60614     }
60615     setMode(mode) {
60616         const positionAttribute = this.geometry.attributes.position;
60617         const positions = positionAttribute.array;
60618         positions[5] = this._modeToAltitude(mode);
60619         positionAttribute.needsUpdate = true;
60620         this.geometry.computeBoundingSphere();
60621     }
60622     _makeAttributes(origin, originalOrigin, mode) {
60623         const positions = new Float32Array(6);
60624         positions[0] = 0;
60625         positions[1] = 0;
60626         positions[2] = 0;
60627         positions[3] = originalOrigin[0] - origin[0];
60628         positions[4] = originalOrigin[1] - origin[1];
60629         positions[5] = this._modeToAltitude(mode);
60630         const attribute = new BufferAttribute(positions, 3);
60631         this.geometry.setAttribute("position", attribute);
60632         attribute.needsUpdate = true;
60633         this.geometry.computeBoundingSphere();
60634     }
60635     _modeToAltitude(mode) {
60636         return mode === OriginalPositionMode.Altitude ?
60637             this._relativeAltitude : 0;
60638     }
60639 }
60640
60641 class CameraFrameBase extends LineSegments {
60642     constructor(parameters) {
60643         super(parameters.geometry, parameters.material);
60644         const color = parameters.color;
60645         const size = parameters.size;
60646         const scale = parameters.scale;
60647         const transform = parameters.transform;
60648         const origin = transform.unprojectBasic([0, 0], 0);
60649         const positions = this._makePositions(size, transform, origin);
60650         this._makeAttributes(positions, color);
60651         this.geometry.computeBoundingSphere();
60652         this.geometry.computeBoundingBox();
60653         this.matrixAutoUpdate = false;
60654         this.position.fromArray(origin);
60655         this.scale.set(scale, scale, scale);
60656         this.updateMatrix();
60657         this.updateMatrixWorld(false);
60658     }
60659     dispose() {
60660         this.geometry.dispose();
60661         this.material.dispose();
60662     }
60663     setColor(color) {
60664         this._updateColorAttribute(color);
60665         return this;
60666     }
60667     resize(scale) {
60668         this.scale.set(scale, scale, scale);
60669         this.updateMatrix();
60670         this.updateMatrixWorld(false);
60671         return this;
60672     }
60673     _makeAttributes(positions, color) {
60674         const geometry = this.geometry;
60675         const positionAttribute = new BufferAttribute(new Float32Array(positions), 3);
60676         geometry.setAttribute("position", positionAttribute);
60677         positionAttribute.needsUpdate = true;
60678         const colorAttribute = new BufferAttribute(new Float32Array(positions.length), 3);
60679         geometry.setAttribute("color", colorAttribute);
60680         this._updateColorAttribute(color);
60681     }
60682     _updateColorAttribute(color) {
60683         const [r, g, b] = new Color(color).toArray();
60684         const colorAttribute = this.geometry.attributes.color;
60685         const colors = colorAttribute.array;
60686         const length = colors.length;
60687         let index = 0;
60688         for (let i = 0; i < length; i++) {
60689             colors[index++] = r;
60690             colors[index++] = g;
60691             colors[index++] = b;
60692         }
60693         colorAttribute.needsUpdate = true;
60694     }
60695 }
60696
60697 class SphericalCameraFrame extends CameraFrameBase {
60698     _makePositions(size, transform, origin) {
60699         const vs = 10;
60700         const positions = [];
60701         positions.push(...this._makeAxis(size, transform, origin));
60702         positions.push(...this._makeLat(0.5, vs, size, transform, origin));
60703         for (const lat of [0, 0.25, 0.5, 0.75]) {
60704             positions
60705                 .push(...this._makeLng(lat, vs, size, transform, origin));
60706         }
60707         return positions;
60708     }
60709     _makeAxis(size, transform, origin) {
60710         const south = transform.unprojectBasic([0.5, 1], 0.8 * size);
60711         const north = transform.unprojectBasic([0.5, 0], 1.2 * size);
60712         return [
60713             south[0] - origin[0],
60714             south[1] - origin[1],
60715             south[2] - origin[2],
60716             north[0] - origin[0],
60717             north[1] - origin[1],
60718             north[2] - origin[2],
60719         ];
60720     }
60721     _makeLat(basicY, numVertices, size, transform, origin) {
60722         const dist = 0.8 * size;
60723         const [originX, originY, originZ] = origin;
60724         const positions = [];
60725         const first = transform.unprojectBasic([0, basicY], dist);
60726         first[0] -= originX;
60727         first[1] -= originY;
60728         first[2] -= originZ;
60729         positions.push(...first);
60730         for (let i = 1; i <= numVertices; i++) {
60731             const position = transform.unprojectBasic([i / numVertices, basicY], dist);
60732             position[0] -= originX;
60733             position[1] -= originY;
60734             position[2] -= originZ;
60735             positions.push(...position, ...position);
60736         }
60737         positions.push(...first);
60738         return positions;
60739     }
60740     _makeLng(basicX, numVertices, size, transform, origin) {
60741         const dist = 0.8 * size;
60742         const [originX, originY, originZ] = origin;
60743         const positions = [];
60744         const first = transform.unprojectBasic([basicX, 0], dist);
60745         first[0] -= originX;
60746         first[1] -= originY;
60747         first[2] -= originZ;
60748         positions.push(...first);
60749         for (let i = 0; i <= numVertices; i++) {
60750             const position = transform.unprojectBasic([basicX, i / numVertices], dist);
60751             position[0] -= originX;
60752             position[1] -= originY;
60753             position[2] -= originZ;
60754             positions.push(...position, ...position);
60755         }
60756         positions.push(...first);
60757         return positions;
60758     }
60759 }
60760
60761 class PerspectiveCameraFrame extends CameraFrameBase {
60762     _makePositions(size, transform, origin) {
60763         const samples = 8;
60764         const positions = [];
60765         positions.push(...this._makeDiags(size, transform, origin));
60766         positions.push(...this._makeFrame(size, samples, transform, origin));
60767         return positions;
60768     }
60769     _makeDiags(size, transform, origin) {
60770         const [originX, originY, originZ] = origin;
60771         const cameraCenter = [0, 0, 0];
60772         const positions = [];
60773         for (const vertex2d of [[0, 0], [1, 0], [1, 1], [0, 1]]) {
60774             const corner = transform.unprojectBasic(vertex2d, size);
60775             corner[0] -= originX;
60776             corner[1] -= originY;
60777             corner[2] -= originZ;
60778             positions.push(...cameraCenter, ...corner);
60779         }
60780         return positions;
60781     }
60782     _makeFrame(size, samples, transform, origin) {
60783         const vertices2d = [];
60784         vertices2d.push(...this._subsample([0, 1], [0, 0], samples));
60785         vertices2d.push(...this._subsample([0, 0], [1, 0], samples));
60786         vertices2d.push(...this._subsample([1, 0], [1, 1], samples));
60787         const [originX, originY, originZ] = origin;
60788         const positions = [];
60789         for (const vertex2d of vertices2d) {
60790             const position = transform.unprojectBasic(vertex2d, size);
60791             position[0] -= originX;
60792             position[1] -= originY;
60793             position[2] -= originZ;
60794             positions.push(...position);
60795         }
60796         return positions;
60797     }
60798     _interpolate(a, b, alpha) {
60799         return a + alpha * (b - a);
60800     }
60801     _subsample(p1, p2, subsamples) {
60802         if (subsamples < 1) {
60803             return [p1, p2];
60804         }
60805         const samples = [];
60806         samples.push(p1);
60807         for (let i = 0; i <= subsamples; i++) {
60808             const p = [];
60809             for (let j = 0; j < 3; j++) {
60810                 p.push(this._interpolate(p1[j], p2[j], i / (subsamples + 1)));
60811             }
60812             samples.push(p);
60813             samples.push(p);
60814         }
60815         samples.push(p2);
60816         return samples;
60817     }
60818 }
60819
60820 function resetEnu(reference, prevEnu, prevReference) {
60821     const [prevX, prevY, prevZ] = prevEnu;
60822     const [lng, lat, alt] = enuToGeodetic(prevX, prevY, prevZ, prevReference.lng, prevReference.lat, prevReference.alt);
60823     return geodeticToEnu(lng, lat, alt, reference.lng, reference.lat, reference.alt);
60824 }
60825
60826 class SpatialCell {
60827     constructor(id, _scene, _intersection) {
60828         this.id = id;
60829         this._scene = _scene;
60830         this._intersection = _intersection;
60831         this.cameras = new Object3D();
60832         this.keys = [];
60833         this._positionLines = {};
60834         this._positions = new Object3D();
60835         this._cameraFrames = {};
60836         this._clusters = new Map();
60837         this._connectedComponents = new Map();
60838         this._sequences = new Map();
60839         this._props = {};
60840         this.clusterVisibles = {};
60841         this._frameMaterial = new LineBasicMaterial({
60842             fog: false,
60843             vertexColors: true,
60844         });
60845         this._positionMaterial = new LineBasicMaterial({
60846             fog: false,
60847             color: 0xff0000,
60848         });
60849         this._scene.add(this.cameras, this._positions);
60850     }
60851     addImage(props) {
60852         const image = props.image;
60853         const id = image.id;
60854         if (this.hasImage(id)) {
60855             throw new Error(`Image exists ${id}`);
60856         }
60857         const ccId = props.idMap.ccId;
60858         if (!(this._connectedComponents.has(ccId))) {
60859             this._connectedComponents.set(ccId, []);
60860         }
60861         const cId = props.idMap.clusterId;
60862         if (!this._clusters.has(cId)) {
60863             this._clusters.set(cId, []);
60864         }
60865         const sId = props.idMap.sequenceId;
60866         if (!this._sequences.has(sId)) {
60867             this._sequences.set(sId, []);
60868         }
60869         this._props[id] = {
60870             image: image,
60871             ids: { ccId, clusterId: cId, sequenceId: sId },
60872         };
60873         this.keys.push(id);
60874     }
60875     applyCameraColor(imageId, color) {
60876         this._cameraFrames[imageId].setColor(color);
60877     }
60878     applyCameraSize(size) {
60879         for (const camera of this.cameras.children) {
60880             camera.resize(size);
60881         }
60882     }
60883     applyFilter(filter) {
60884         var _a;
60885         const clusterVisibles = this.clusterVisibles;
60886         for (const clusterId in clusterVisibles) {
60887             if (!clusterVisibles.hasOwnProperty(clusterId)) {
60888                 continue;
60889             }
60890             clusterVisibles[clusterId] = false;
60891         }
60892         const cameraFrames = this._cameraFrames;
60893         const positionLines = this._positionLines;
60894         const interactiveLayer = this._intersection.interactiveLayer;
60895         for (const props of Object.values(this._props)) {
60896             const image = props.image;
60897             const visible = filter(image);
60898             const key = image.id;
60899             positionLines[key].visible = visible;
60900             const camera = cameraFrames[key];
60901             this._setCameraVisibility(camera, visible, interactiveLayer);
60902             clusterVisibles[_a = props.ids.clusterId] || (clusterVisibles[_a] = visible);
60903         }
60904     }
60905     applyPositionMode(mode) {
60906         this._positions.visible =
60907             mode !== OriginalPositionMode.Hidden;
60908         for (const position of this._positions.children) {
60909             position.setMode(mode);
60910         }
60911     }
60912     dispose() {
60913         this._disposeCameras();
60914         this._disposePositions();
60915         this._scene = null;
60916         this._intersection = null;
60917     }
60918     getCamerasByMode(mode) {
60919         if (mode === CameraVisualizationMode.Cluster) {
60920             return this._clusters;
60921         }
60922         else if (mode === CameraVisualizationMode.ConnectedComponent) {
60923             return this._connectedComponents;
60924         }
60925         else if (mode === CameraVisualizationMode.Sequence) {
60926             return this._sequences;
60927         }
60928         const cvm = CameraVisualizationMode;
60929         const defaultId = cvm[cvm.Homogeneous];
60930         const cameras = new Map();
60931         cameras.set(defaultId, this.cameras.children);
60932         return cameras;
60933     }
60934     getColorId(imageId, mode) {
60935         const props = this._props[imageId];
60936         const cvm = CameraVisualizationMode;
60937         switch (mode) {
60938             case cvm.Cluster:
60939                 return props.ids.clusterId;
60940             case cvm.ConnectedComponent:
60941                 return props.ids.ccId;
60942             case cvm.Sequence:
60943                 return props.ids.sequenceId;
60944             default:
60945                 return cvm[cvm.Homogeneous];
60946         }
60947     }
60948     hasImage(key) {
60949         return this.keys.indexOf(key) !== -1;
60950     }
60951     resetReference(reference, prevReference) {
60952         const frames = this._cameraFrames;
60953         for (const frameId in frames) {
60954             if (!frames.hasOwnProperty(frameId)) {
60955                 continue;
60956             }
60957             const frame = frames[frameId];
60958             frame.position.fromArray(resetEnu(reference, frame.position.toArray(), prevReference));
60959         }
60960         const lines = this._positionLines;
60961         for (const lineId in lines) {
60962             if (!lines.hasOwnProperty(lineId)) {
60963                 continue;
60964             }
60965             const line = lines[lineId];
60966             line.position.fromArray(resetEnu(reference, line.position.toArray(), prevReference));
60967         }
60968     }
60969     visualize(props) {
60970         var _a, _b;
60971         const id = props.id;
60972         const visible = props.visible;
60973         const transform = props.transform;
60974         const cameraParameters = {
60975             color: props.color,
60976             material: this._frameMaterial,
60977             scale: props.scale,
60978             size: props.maxSize,
60979             transform,
60980         };
60981         const camera = isSpherical(transform.cameraType) ?
60982             new SphericalCameraFrame(cameraParameters) :
60983             new PerspectiveCameraFrame(cameraParameters);
60984         const interactiveLayer = this._intersection.interactiveLayer;
60985         this._setCameraVisibility(camera, visible, interactiveLayer);
60986         this.cameras.add(camera);
60987         this._cameraFrames[id] = camera;
60988         const intersection = this._intersection;
60989         intersection.add(camera, id);
60990         const ids = this._props[id].ids;
60991         (_a = this.clusterVisibles)[_b = ids.clusterId] || (_a[_b] = visible);
60992         this._connectedComponents.get(ids.ccId).push(camera);
60993         this._clusters.get(ids.clusterId).push(camera);
60994         this._sequences.get(ids.sequenceId).push(camera);
60995         const positionParameters = {
60996             material: this._positionMaterial,
60997             mode: props.positionMode,
60998             originalOrigin: props.originalPosition,
60999             transform,
61000         };
61001         const position = new PositionLine(positionParameters);
61002         position.visible = visible;
61003         this._positions.add(position);
61004         this._positionLines[id] = position;
61005     }
61006     _disposeCameras() {
61007         const intersection = this._intersection;
61008         const cameras = this.cameras;
61009         for (const camera of cameras.children.slice()) {
61010             camera.dispose();
61011             intersection.remove(camera);
61012             cameras.remove(camera);
61013         }
61014         this._scene.remove(this.cameras);
61015     }
61016     _disposePositions() {
61017         const positions = this._positions;
61018         for (const position of positions.children.slice()) {
61019             position.dispose();
61020             positions.remove(position);
61021         }
61022         this._scene.remove(this._positions);
61023     }
61024     _setCameraVisibility(camera, visible, layer) {
61025         camera.visible = visible;
61026         if (visible) {
61027             camera.layers.enable(layer);
61028         }
61029         else {
61030             camera.layers.disable(layer);
61031         }
61032     }
61033 }
61034
61035 class SpatialAssets {
61036     constructor() {
61037         this._colors = new Map();
61038         const cvm = CameraVisualizationMode;
61039         this._colors.set(cvm[cvm.Homogeneous], "#FFFFFF");
61040     }
61041     getColor(id) {
61042         const colors = this._colors;
61043         if (!colors.has(id)) {
61044             colors.set(id, this._randomColor());
61045         }
61046         return colors.get(id);
61047     }
61048     _randomColor() {
61049         return `hsl(${Math.floor(360 * Math.random())}, 100%, 50%)`;
61050     }
61051 }
61052
61053 function isModeVisible(mode) {
61054     return mode !== CameraVisualizationMode.Hidden;
61055 }
61056 function isOverviewState(state) {
61057     return state === State.Custom || state === State.Earth;
61058 }
61059
61060 var PointVisualizationMode;
61061 (function (PointVisualizationMode) {
61062     /**
61063      * Points are hidden.
61064      */
61065     PointVisualizationMode[PointVisualizationMode["Hidden"] = 0] = "Hidden";
61066     /**
61067      * Visualize points with original colors.
61068      */
61069     PointVisualizationMode[PointVisualizationMode["Original"] = 1] = "Original";
61070     /**
61071      * Paint all points belonging to a specific
61072      * cluster with the same random color.
61073      */
61074     PointVisualizationMode[PointVisualizationMode["Cluster"] = 2] = "Cluster";
61075 })(PointVisualizationMode || (PointVisualizationMode = {}));
61076
61077 const NO_CLUSTER_ID = "NO_CLUSTER_ID";
61078 const NO_MERGE_ID = "NO_MERGE_ID";
61079 const NO_SEQUENCE_ID = "NO_SEQUENCE_ID";
61080 class SpatialScene {
61081     constructor(configuration, scene) {
61082         this._rayNearScale = 1.1;
61083         this._originalPointSize = 2;
61084         this._originalCameraSize = 2;
61085         this._imageCellMap = new Map();
61086         this._scene = !!scene ? scene : new Scene();
61087         this._scene.autoUpdate = false;
61088         this._intersection = new SpatialIntersection();
61089         this._assets = new SpatialAssets();
61090         this._needsRender = false;
61091         this._images = {};
61092         this._cells = {};
61093         this._cellClusters = {};
61094         this._clusters = {};
61095         this._cameraVisualizationMode =
61096             !!configuration.cameraVisualizationMode ?
61097                 configuration.cameraVisualizationMode :
61098                 CameraVisualizationMode.Homogeneous;
61099         this._cameraSize = configuration.cameraSize;
61100         this._pointSize = configuration.pointSize;
61101         this._pointVisualizationMode =
61102             !!configuration.pointVisualizationMode ?
61103                 configuration.pointVisualizationMode :
61104                 PointVisualizationMode.Original;
61105         this._positionMode = configuration.originalPositionMode;
61106         this._cellsVisible = configuration.cellsVisible;
61107         this._hoveredId = null;
61108         this._selectedId = null;
61109         this._colors = { hover: "#FF0000", select: "#FF8000" };
61110         this._filter = () => true;
61111     }
61112     get needsRender() { return this._needsRender; }
61113     get intersection() {
61114         return this._intersection;
61115     }
61116     addCluster(reconstruction, translation, cellId) {
61117         if (this.hasCluster(reconstruction.id, cellId)) {
61118             return;
61119         }
61120         const clusterId = reconstruction.id;
61121         if (!(clusterId in this._clusters)) {
61122             this._clusters[clusterId] = {
61123                 points: new Object3D(),
61124                 cellIds: [],
61125             };
61126             const visible = this._getClusterVisible(clusterId);
61127             const cluster = this._clusters[clusterId];
61128             const color = this._pointVisualizationMode === PointVisualizationMode.Cluster ? this._assets.getColor(clusterId) : null;
61129             const points = new ClusterPoints({
61130                 cluster: reconstruction,
61131                 color,
61132                 originalSize: this._originalPointSize,
61133                 scale: this._pointSize,
61134                 translation,
61135             });
61136             cluster.points.visible = visible;
61137             cluster.points.add(points);
61138             this._scene.add(cluster.points);
61139         }
61140         if (this._clusters[clusterId].cellIds.indexOf(cellId) === -1) {
61141             this._clusters[clusterId].cellIds.push(cellId);
61142         }
61143         if (!(cellId in this._cellClusters)) {
61144             this._cellClusters[cellId] = { keys: [] };
61145         }
61146         if (this._cellClusters[cellId].keys.indexOf(clusterId) === -1) {
61147             this._cellClusters[cellId].keys.push(clusterId);
61148         }
61149         this._needsRender = true;
61150     }
61151     addImage(image, transform, originalPosition, cellId) {
61152         var _a, _b, _c;
61153         const imageId = image.id;
61154         const idMap = {
61155             clusterId: (_a = image.clusterId) !== null && _a !== void 0 ? _a : NO_CLUSTER_ID,
61156             sequenceId: (_b = image.sequenceId) !== null && _b !== void 0 ? _b : NO_SEQUENCE_ID,
61157             ccId: (_c = image.mergeId) !== null && _c !== void 0 ? _c : NO_MERGE_ID,
61158         };
61159         if (!(cellId in this._images)) {
61160             const created = new SpatialCell(cellId, this._scene, this._intersection);
61161             created.cameras.visible =
61162                 isModeVisible(this._cameraVisualizationMode);
61163             created.applyPositionMode(this._positionMode);
61164             this._images[cellId] = created;
61165         }
61166         const cell = this._images[cellId];
61167         if (cell.hasImage(imageId)) {
61168             return;
61169         }
61170         cell.addImage({ idMap, image: image });
61171         const colorId = cell.getColorId(imageId, this._cameraVisualizationMode);
61172         const color = this._assets.getColor(colorId);
61173         const visible = this._filter(image);
61174         cell.visualize({
61175             id: imageId,
61176             color,
61177             positionMode: this._positionMode,
61178             scale: this._cameraSize,
61179             transform,
61180             visible,
61181             maxSize: this._originalCameraSize,
61182             originalPosition
61183         });
61184         this._imageCellMap.set(imageId, cellId);
61185         if (imageId === this._selectedId) {
61186             this._highlight(imageId, this._colors.select, this._cameraVisualizationMode);
61187         }
61188         if (idMap.clusterId in this._clusters) {
61189             const clusterVisible = this._getClusterVisible(idMap.clusterId);
61190             this._clusters[idMap.clusterId].points.visible = clusterVisible;
61191         }
61192         this._needsRender = true;
61193     }
61194     addCell(vertices, cellId) {
61195         if (this.hasCell(cellId)) {
61196             return;
61197         }
61198         const cell = new CellLine(vertices);
61199         this._cells[cellId] = new Object3D();
61200         this._cells[cellId].visible = this._cellsVisible;
61201         this._cells[cellId].add(cell);
61202         this._scene.add(this._cells[cellId]);
61203         this._needsRender = true;
61204     }
61205     deactivate() {
61206         this._filter = () => true;
61207         this._selectedId = null;
61208         this._hoveredId = null;
61209         this.uncache();
61210     }
61211     hasCluster(clusterId, cellId) {
61212         return clusterId in this._clusters &&
61213             this._clusters[clusterId].cellIds.indexOf(cellId) !== -1;
61214     }
61215     hasCell(cellId) {
61216         return cellId in this._cells;
61217     }
61218     hasImage(imageId, cellId) {
61219         return cellId in this._images &&
61220             this._images[cellId].hasImage(imageId);
61221     }
61222     render(camera, renderer) {
61223         renderer.render(this._scene, camera);
61224         this._needsRender = false;
61225     }
61226     resetReference(reference, prevReference) {
61227         const clusters = this._clusters;
61228         for (const clusterId in clusters) {
61229             if (!clusters.hasOwnProperty(clusterId)) {
61230                 continue;
61231             }
61232             const cluster = clusters[clusterId];
61233             cluster.points.position.fromArray(resetEnu(reference, cluster.points.position.toArray(), prevReference));
61234         }
61235         const cells = this._cells;
61236         for (const cellId in cells) {
61237             if (!cells.hasOwnProperty(cellId)) {
61238                 continue;
61239             }
61240             const cell = cells[cellId];
61241             cell.position.fromArray(resetEnu(reference, cell.position.toArray(), prevReference));
61242         }
61243         const images = this._images;
61244         for (const cellId in images) {
61245             if (!images.hasOwnProperty(cellId)) {
61246                 continue;
61247             }
61248             const spatialCell = images[cellId];
61249             spatialCell.resetReference(reference, prevReference);
61250         }
61251     }
61252     setCameraSize(cameraSize) {
61253         if (Math.abs(cameraSize - this._cameraSize) < 1e-3) {
61254             return;
61255         }
61256         const imageCells = this._images;
61257         for (const cellId of Object.keys(imageCells)) {
61258             imageCells[cellId].applyCameraSize(cameraSize);
61259         }
61260         this._intersection.raycaster.near = this._getNear(cameraSize);
61261         this._cameraSize = cameraSize;
61262         this._needsRender = true;
61263     }
61264     setFilter(filter) {
61265         this._filter = filter;
61266         const clusterVisibles = {};
61267         for (const imageCell of Object.values(this._images)) {
61268             imageCell.applyFilter(filter);
61269             const imageCV = imageCell.clusterVisibles;
61270             for (const clusterId in imageCV) {
61271                 if (!imageCV.hasOwnProperty(clusterId)) {
61272                     continue;
61273                 }
61274                 if (!(clusterId in clusterVisibles)) {
61275                     clusterVisibles[clusterId] = false;
61276                 }
61277                 clusterVisibles[clusterId] || (clusterVisibles[clusterId] = imageCV[clusterId]);
61278             }
61279         }
61280         const pointsVisible = this._pointVisualizationMode !== PointVisualizationMode.Hidden;
61281         for (const clusterId in clusterVisibles) {
61282             if (!clusterVisibles.hasOwnProperty(clusterId)) {
61283                 continue;
61284             }
61285             clusterVisibles[clusterId] && (clusterVisibles[clusterId] = pointsVisible);
61286             const visible = clusterVisibles[clusterId];
61287             if (clusterId in this._clusters) {
61288                 this._clusters[clusterId].points.visible = visible;
61289             }
61290         }
61291         this._needsRender = true;
61292     }
61293     setHoveredImage(imageId) {
61294         if (imageId != null && !this._imageCellMap.has(imageId)) {
61295             throw new MapillaryError(`Image does not exist: ${imageId}`);
61296         }
61297         if (this._hoveredId === imageId) {
61298             return;
61299         }
61300         this._needsRender = true;
61301         if (this._hoveredId != null) {
61302             if (this._hoveredId === this._selectedId) {
61303                 this._highlight(this._hoveredId, this._colors.select, this._cameraVisualizationMode);
61304             }
61305             else {
61306                 this._resetCameraColor(this._hoveredId);
61307             }
61308         }
61309         this._highlight(imageId, this._colors.hover, this._cameraVisualizationMode);
61310         this._hoveredId = imageId;
61311     }
61312     setNavigationState(isOverview) {
61313         this._intersection.resetIntersectionThreshold(isOverview);
61314     }
61315     setPointSize(pointSize) {
61316         if (Math.abs(pointSize - this._pointSize) < 1e-3) {
61317             return;
61318         }
61319         const clusters = this._clusters;
61320         for (const key in clusters) {
61321             if (!clusters.hasOwnProperty(key)) {
61322                 continue;
61323             }
61324             for (const points of clusters[key].points.children) {
61325                 points.resize(pointSize);
61326             }
61327         }
61328         this._pointSize = pointSize;
61329         this._needsRender = true;
61330     }
61331     setPointVisualizationMode(mode) {
61332         if (mode === this._pointVisualizationMode) {
61333             return;
61334         }
61335         this._pointVisualizationMode = mode;
61336         for (const clusterId in this._clusters) {
61337             if (!this._clusters.hasOwnProperty(clusterId)) {
61338                 continue;
61339             }
61340             const cluster = this._clusters[clusterId];
61341             cluster.points.visible = this._getClusterVisible(clusterId);
61342             for (const points of cluster.points.children) {
61343                 const color = mode === PointVisualizationMode.Cluster ?
61344                     this._assets.getColor(clusterId) : null;
61345                 points.setColor(color);
61346             }
61347         }
61348         this._needsRender = true;
61349     }
61350     setPositionMode(mode) {
61351         if (mode === this._positionMode) {
61352             return;
61353         }
61354         for (const cell of Object.values(this._images)) {
61355             cell.applyPositionMode(mode);
61356         }
61357         this._positionMode = mode;
61358         this._needsRender = true;
61359     }
61360     setSelectedImage(id) {
61361         if (this._selectedId === id) {
61362             return;
61363         }
61364         this._needsRender = true;
61365         if (this._selectedId != null) {
61366             this._resetCameraColor(this._selectedId);
61367         }
61368         this._highlight(id, this._colors.select, this._cameraVisualizationMode);
61369         this._selectedId = id;
61370     }
61371     setCellVisibility(visible) {
61372         if (visible === this._cellsVisible) {
61373             return;
61374         }
61375         for (const cellId in this._cells) {
61376             if (!this._cells.hasOwnProperty(cellId)) {
61377                 continue;
61378             }
61379             this._cells[cellId].visible = visible;
61380         }
61381         this._cellsVisible = visible;
61382         this._needsRender = true;
61383     }
61384     setCameraVisualizationMode(mode) {
61385         if (mode === this._cameraVisualizationMode) {
61386             return;
61387         }
61388         const visible = isModeVisible(mode);
61389         const assets = this._assets;
61390         for (const cell of Object.values(this._images)) {
61391             cell.cameras.visible = visible;
61392             const cameraMap = cell.getCamerasByMode(mode);
61393             cameraMap.forEach((cameras, colorId) => {
61394                 const color = assets.getColor(colorId);
61395                 for (const camera of cameras) {
61396                     camera.setColor(color);
61397                 }
61398             });
61399         }
61400         this._highlight(this._hoveredId, this._colors.hover, mode);
61401         this._highlight(this._selectedId, this._colors.select, mode);
61402         this._cameraVisualizationMode = mode;
61403         this._needsRender = true;
61404     }
61405     uncache(keepCellIds) {
61406         for (const cellId of Object.keys(this._cellClusters)) {
61407             if (!!keepCellIds && keepCellIds.indexOf(cellId) !== -1) {
61408                 continue;
61409             }
61410             this._disposeReconstruction(cellId);
61411         }
61412         for (const cellId of Object.keys(this._images)) {
61413             if (!!keepCellIds && keepCellIds.indexOf(cellId) !== -1) {
61414                 continue;
61415             }
61416             const nceMap = this._imageCellMap;
61417             const keys = this._images[cellId].keys;
61418             for (const key of keys) {
61419                 nceMap.delete(key);
61420             }
61421             this._images[cellId].dispose();
61422             delete this._images[cellId];
61423         }
61424         for (const cellId of Object.keys(this._cells)) {
61425             if (!!keepCellIds && keepCellIds.indexOf(cellId) !== -1) {
61426                 continue;
61427             }
61428             this._disposeCell(cellId);
61429         }
61430         this._needsRender = true;
61431     }
61432     _getClusterVisible(clusterId) {
61433         if (this._pointVisualizationMode === PointVisualizationMode.Hidden) {
61434             return false;
61435         }
61436         let visible = false;
61437         for (const imageCell of Object.values(this._images)) {
61438             const imageCV = imageCell.clusterVisibles;
61439             if (!(clusterId in imageCV)) {
61440                 continue;
61441             }
61442             visible || (visible = imageCV[clusterId]);
61443         }
61444         return visible;
61445     }
61446     _disposePoints(cellId) {
61447         for (const clusterId of this._cellClusters[cellId].keys) {
61448             if (!(clusterId in this._clusters)) {
61449                 continue;
61450             }
61451             const index = this._clusters[clusterId].cellIds.indexOf(cellId);
61452             if (index === -1) {
61453                 continue;
61454             }
61455             this._clusters[clusterId].cellIds.splice(index, 1);
61456             if (this._clusters[clusterId].cellIds.length > 0) {
61457                 continue;
61458             }
61459             for (const points of this._clusters[clusterId].points.children.slice()) {
61460                 points.dispose();
61461             }
61462             this._scene.remove(this._clusters[clusterId].points);
61463             delete this._clusters[clusterId];
61464         }
61465     }
61466     _disposeReconstruction(cellId) {
61467         this._disposePoints(cellId);
61468         delete this._cellClusters[cellId];
61469     }
61470     _disposeCell(cellId) {
61471         const cell = this._cells[cellId];
61472         for (const line of cell.children.slice()) {
61473             line.dispose();
61474             cell.remove(line);
61475         }
61476         this._scene.remove(cell);
61477         delete this._cells[cellId];
61478     }
61479     _getNear(cameraSize) {
61480         const near = this._rayNearScale *
61481             this._originalCameraSize *
61482             cameraSize;
61483         return Math.max(1, near);
61484     }
61485     _resetCameraColor(imageId) {
61486         const nceMap = this._imageCellMap;
61487         if (imageId == null || !nceMap.has(imageId)) {
61488             return;
61489         }
61490         const cellId = nceMap.get(imageId);
61491         const cell = this._images[cellId];
61492         const colorId = cell.getColorId(imageId, this._cameraVisualizationMode);
61493         const color = this._assets.getColor(colorId);
61494         cell.applyCameraColor(imageId, color);
61495     }
61496     _highlight(imageId, color, mode) {
61497         const nceMap = this._imageCellMap;
61498         if (imageId == null || !nceMap.has(imageId)) {
61499             return;
61500         }
61501         const cellId = nceMap.get(imageId);
61502         color = mode === CameraVisualizationMode.Homogeneous ?
61503             color : "#FFFFFF";
61504         this._images[cellId].applyCameraColor(imageId, color);
61505     }
61506 }
61507
61508 class SpatialCache {
61509     constructor(graphService, provider) {
61510         this._graphService = graphService;
61511         this._data = provider;
61512         this._cells = {};
61513         this._cacheRequests = {};
61514         this._clusters = {};
61515         this._clusterCells = {};
61516         this._cellClusters = {};
61517         this._cachingCells$ = {};
61518         this._cachingClusters$ = {};
61519     }
61520     cacheClusters$(cellId) {
61521         if (!this.hasCell(cellId)) {
61522             throw new Error("Cannot cache reconstructions of a non-existing cell.");
61523         }
61524         if (this.hasClusters(cellId)) {
61525             throw new Error("Cannot cache reconstructions that already exists.");
61526         }
61527         if (this.isCachingClusters(cellId)) {
61528             return this._cachingClusters$[cellId];
61529         }
61530         const duplicatedClusters = this.getCell(cellId)
61531             .filter((n) => {
61532             return !!n.clusterId && !!n.clusterUrl;
61533         })
61534             .map((n) => {
61535             return { key: n.clusterId, url: n.clusterUrl };
61536         });
61537         const clusters = Array
61538             .from(new Map(duplicatedClusters.map((cd) => {
61539             return [cd.key, cd];
61540         }))
61541             .values());
61542         this._cellClusters[cellId] = clusters;
61543         this._cacheRequests[cellId] = [];
61544         let aborter;
61545         const abort = new Promise((_, reject) => {
61546             aborter = reject;
61547         });
61548         this._cacheRequests[cellId].push(aborter);
61549         this._cachingClusters$[cellId] =
61550             this._cacheClusters$(clusters, cellId, abort).pipe(finalize(() => {
61551                 if (cellId in this._cachingClusters$) {
61552                     delete this._cachingClusters$[cellId];
61553                 }
61554                 if (cellId in this._cacheRequests) {
61555                     delete this._cacheRequests[cellId];
61556                 }
61557             }), publish(), refCount());
61558         return this._cachingClusters$[cellId];
61559     }
61560     cacheCell$(cellId) {
61561         if (this.hasCell(cellId)) {
61562             throw new Error("Cannot cache cell that already exists.");
61563         }
61564         if (this.isCachingCell(cellId)) {
61565             return this._cachingCells$[cellId];
61566         }
61567         this._cachingCells$[cellId] = this._graphService.cacheCell$(cellId).pipe(catchError((error) => {
61568             console.error(error);
61569             return empty();
61570         }), filter(() => {
61571             return !(cellId in this._cells);
61572         }), tap((images) => {
61573             this._cells[cellId] = [];
61574             this._cells[cellId].push(...images);
61575             delete this._cachingCells$[cellId];
61576         }), finalize(() => {
61577             if (cellId in this._cachingCells$) {
61578                 delete this._cachingCells$[cellId];
61579             }
61580         }), publish(), refCount());
61581         return this._cachingCells$[cellId];
61582     }
61583     isCachingClusters(cellId) {
61584         return cellId in this._cachingClusters$;
61585     }
61586     isCachingCell(cellId) {
61587         return cellId in this._cachingCells$;
61588     }
61589     hasClusters(cellId) {
61590         if (cellId in this._cachingClusters$ ||
61591             !(cellId in this._cellClusters)) {
61592             return false;
61593         }
61594         for (const cd of this._cellClusters[cellId]) {
61595             if (!(cd.key in this._clusters)) {
61596                 return false;
61597             }
61598         }
61599         return true;
61600     }
61601     hasCell(cellId) {
61602         return !(cellId in this._cachingCells$) && cellId in this._cells;
61603     }
61604     getClusters(cellId) {
61605         return cellId in this._cellClusters ?
61606             this._cellClusters[cellId]
61607                 .map((cd) => {
61608                 return this._clusters[cd.key];
61609             })
61610                 .filter((reconstruction) => {
61611                 return !!reconstruction;
61612             }) :
61613             [];
61614     }
61615     getCell(cellId) {
61616         return cellId in this._cells ? this._cells[cellId] : [];
61617     }
61618     uncache(keepCellIds) {
61619         for (let cellId of Object.keys(this._cacheRequests)) {
61620             if (!!keepCellIds && keepCellIds.indexOf(cellId) !== -1) {
61621                 continue;
61622             }
61623             for (const aborter of this._cacheRequests[cellId]) {
61624                 aborter();
61625             }
61626             delete this._cacheRequests[cellId];
61627         }
61628         for (let cellId of Object.keys(this._cellClusters)) {
61629             if (!!keepCellIds && keepCellIds.indexOf(cellId) !== -1) {
61630                 continue;
61631             }
61632             for (const cd of this._cellClusters[cellId]) {
61633                 if (!(cd.key in this._clusterCells)) {
61634                     continue;
61635                 }
61636                 const index = this._clusterCells[cd.key].indexOf(cellId);
61637                 if (index === -1) {
61638                     continue;
61639                 }
61640                 this._clusterCells[cd.key].splice(index, 1);
61641                 if (this._clusterCells[cd.key].length > 0) {
61642                     continue;
61643                 }
61644                 delete this._clusterCells[cd.key];
61645                 delete this._clusters[cd.key];
61646             }
61647             delete this._cellClusters[cellId];
61648         }
61649         for (let cellId of Object.keys(this._cells)) {
61650             if (!!keepCellIds && keepCellIds.indexOf(cellId) !== -1) {
61651                 continue;
61652             }
61653             delete this._cells[cellId];
61654         }
61655     }
61656     updateCell$(cellId) {
61657         if (!this.hasCell(cellId)) {
61658             throw new Error("Cannot update cell that does not exists.");
61659         }
61660         return this._graphService.cacheCell$(cellId).pipe(catchError((error) => {
61661             console.error(error);
61662             return empty();
61663         }), filter(() => {
61664             return cellId in this._cells;
61665         }), tap((images) => {
61666             this._cells[cellId] = [];
61667             this._cells[cellId].push(...images);
61668         }), publish(), refCount());
61669     }
61670     updateClusters$(cellId) {
61671         if (!this.hasCell(cellId)) {
61672             throw new Error("Cannot update reconstructions of a non-existing cell.");
61673         }
61674         if (!this.hasClusters(cellId)) {
61675             throw new Error("Cannot update reconstructions for cell that is not cached.");
61676         }
61677         const duplicatedClusters = this.getCell(cellId)
61678             .filter((n) => {
61679             return !!n.clusterId && !!n.clusterUrl;
61680         })
61681             .map((n) => {
61682             return { key: n.clusterId, url: n.clusterUrl };
61683         });
61684         const clusters = Array
61685             .from(new Map(duplicatedClusters.map((cd) => {
61686             return [cd.key, cd];
61687         }))
61688             .values())
61689             .filter(cd => {
61690             return !(cd.key in this._clusters);
61691         });
61692         this._cellClusters[cellId].push(...clusters);
61693         return this._cacheClusters$(clusters, cellId, null);
61694     }
61695     _cacheClusters$(clusters, cellId, cancellation) {
61696         return from(clusters).pipe(mergeMap((cd) => {
61697             if (this._hasCluster(cd.key)) {
61698                 return of(this._getCluster(cd.key));
61699             }
61700             return this._getCluster$(cd.url, cd.key, cancellation)
61701                 .pipe(catchError((error) => {
61702                 if (error instanceof CancelMapillaryError) {
61703                     return empty();
61704                 }
61705                 console.error(error);
61706                 return empty();
61707             }));
61708         }, 6), filter(() => {
61709             return cellId in this._cellClusters;
61710         }), tap((reconstruction) => {
61711             if (!this._hasCluster(reconstruction.id)) {
61712                 this._clusters[reconstruction.id] = reconstruction;
61713             }
61714             if (!(reconstruction.id in this._clusterCells)) {
61715                 this._clusterCells[reconstruction.id] = [];
61716             }
61717             if (this._clusterCells[reconstruction.id].indexOf(cellId) === -1) {
61718                 this._clusterCells[reconstruction.id].push(cellId);
61719             }
61720         }));
61721     }
61722     _getCluster(id) {
61723         return this._clusters[id];
61724     }
61725     _getCluster$(url, clusterId, abort) {
61726         return Observable.create((subscriber) => {
61727             this._data.getCluster(url, abort)
61728                 .then((reconstruction) => {
61729                 reconstruction.id = clusterId;
61730                 subscriber.next(reconstruction);
61731                 subscriber.complete();
61732             }, (error) => {
61733                 subscriber.error(error);
61734             });
61735         });
61736     }
61737     _hasCluster(id) {
61738         return id in this._clusters;
61739     }
61740 }
61741
61742 function connectedComponent(cellId, depth, geometry) {
61743     const cells = new Set();
61744     cells.add(cellId);
61745     connectedComponentRecursive(cells, [cellId], 0, depth, geometry);
61746     return Array.from(cells);
61747 }
61748 function connectedComponentRecursive(cells, current, currentDepth, maxDepth, geometry) {
61749     if (currentDepth >= maxDepth) {
61750         return;
61751     }
61752     const adjacent = [];
61753     for (const cellId of current) {
61754         const aCells = geometry.getAdjacent(cellId);
61755         adjacent.push(...aCells);
61756     }
61757     const newCells = [];
61758     for (const a of adjacent) {
61759         if (cells.has(a)) {
61760             continue;
61761         }
61762         cells.add(a);
61763         newCells.push(a);
61764     }
61765     connectedComponentRecursive(cells, newCells, currentDepth + 1, maxDepth, geometry);
61766 }
61767
61768 class SpatialComponent extends Component {
61769     /** @ignore */
61770     constructor(name, container, navigator) {
61771         super(name, container, navigator);
61772         this._cache = new SpatialCache(navigator.graphService, navigator.api.data);
61773         this._scene = new SpatialScene(this._getDefaultConfiguration());
61774         this._viewportCoords = new ViewportCoords();
61775         this._spatial = new Spatial();
61776     }
61777     /**
61778      * Returns the image id of the camera frame closest to the current
61779      * render camera position at the specified point.
61780      *
61781      * @description Notice that the pixelPoint argument requires x, y
61782      * coordinates from pixel space.
61783      *
61784      * With this function, you can use the coordinates provided by mouse
61785      * events to get information out of the spatial component.
61786      *
61787      * If no camera frame exist at the pixel
61788      * point, `null` will be returned.
61789      *
61790      * @param {Array<number>} pixelPoint - Pixel coordinates on
61791      * the viewer element.
61792      * @returns {string} Image id of the camera frame closest to
61793      * the camera. If no camera frame is intersected at the
61794      * pixel point, `null` will be returned.
61795      *
61796      * @example
61797      * ```js
61798      * spatialComponent.getFrameIdAt([100, 125])
61799      *     .then((imageId) => { console.log(imageId); });
61800      * ```
61801      */
61802     getFrameIdAt(pixelPoint) {
61803         return new Promise((resolve, reject) => {
61804             this._container.renderService.renderCamera$.pipe(first(), map((render) => {
61805                 const viewport = this._viewportCoords
61806                     .canvasToViewport(pixelPoint[0], pixelPoint[1], this._container.container);
61807                 const id = this._scene.intersection
61808                     .intersectObjects(viewport, render.perspective);
61809                 return id;
61810             }))
61811                 .subscribe((id) => {
61812                 resolve(id);
61813             }, (error) => {
61814                 reject(error);
61815             });
61816         });
61817     }
61818     _activate() {
61819         this._navigator.cacheService.configure({ cellDepth: 3 });
61820         const subs = this._subscriptions;
61821         subs.push(this._navigator.stateService.reference$
61822             .pipe(pairwise())
61823             .subscribe(([prevReference, reference]) => {
61824             this._scene.resetReference(reference, prevReference);
61825         }));
61826         subs.push(this._navigator.graphService.filter$
61827             .subscribe(imageFilter => { this._scene.setFilter(imageFilter); }));
61828         const bearing$ = this._container.renderService.bearing$.pipe(map((bearing) => {
61829             const interval = 6;
61830             const discrete = interval * Math.floor(bearing / interval);
61831             return discrete;
61832         }), distinctUntilChanged(), publishReplay(1), refCount());
61833         const cellId$ = this._navigator.stateService.currentImage$
61834             .pipe(map((image) => {
61835             return this._navigator.api.data.geometry
61836                 .lngLatToCellId(image.originalLngLat);
61837         }), distinctUntilChanged(), publishReplay(1), refCount());
61838         const cellGridDepth$ = this._configuration$
61839             .pipe(map((c) => {
61840             return this._spatial.clamp(c.cellGridDepth, 1, 3);
61841         }), distinctUntilChanged(), publishReplay(1), refCount());
61842         const sequencePlay$ = combineLatest(this._navigator.playService.playing$, this._navigator.playService.speed$).pipe(map(([playing, speed]) => {
61843             return playing && speed > PlayService.sequenceSpeed;
61844         }), distinctUntilChanged(), publishReplay(1), refCount());
61845         const isOverview$ = this._navigator.stateService.state$.pipe(map((state) => {
61846             return isOverviewState(state);
61847         }), distinctUntilChanged(), publishReplay(1), refCount());
61848         subs.push(isOverview$.subscribe((isOverview) => {
61849             this._scene.setNavigationState(isOverview);
61850         }));
61851         const cell$ = combineLatest(isOverview$, sequencePlay$, bearing$, cellGridDepth$, this._navigator.stateService.currentImage$)
61852             .pipe(distinctUntilChanged(([o1, s1, b1, d1, i1], [o2, s2, b2, d2, i2]) => {
61853             if (o1 !== o2) {
61854                 return false;
61855             }
61856             const isd = i1.id === i2.id && s1 === s2 && d1 === d2;
61857             if (o1) {
61858                 return isd;
61859             }
61860             return isd && b1 === b2;
61861         }), concatMap(([isOverview, sequencePlay, bearing, depth, image]) => {
61862             if (isOverview) {
61863                 const geometry = this._navigator.api.data.geometry;
61864                 const cellId = geometry
61865                     .lngLatToCellId(image.originalLngLat);
61866                 const cells = sequencePlay ?
61867                     [cellId] :
61868                     connectedComponent(cellId, depth, geometry);
61869                 return of(cells);
61870             }
61871             const fov = sequencePlay ? 30 : 90;
61872             return of(this._cellsInFov(image, bearing, fov));
61873         }), switchMap((cellIds) => {
61874             return from(cellIds).pipe(mergeMap((cellId) => {
61875                 const t$ = this._cache.hasCell(cellId) ?
61876                     of(this._cache.getCell(cellId)) :
61877                     this._cache.cacheCell$(cellId);
61878                 return t$.pipe(map((images) => ({ id: cellId, images })));
61879             }, 6));
61880         }));
61881         subs.push(cell$.pipe(withLatestFrom(this._navigator.stateService.reference$))
61882             .subscribe(([cell, reference]) => {
61883             if (this._scene.hasCell(cell.id)) {
61884                 return;
61885             }
61886             this._scene.addCell(this._cellToTopocentric(cell.id, reference), cell.id);
61887         }));
61888         subs.push(cell$.pipe(withLatestFrom(this._navigator.stateService.reference$))
61889             .subscribe(([cell, reference]) => {
61890             this._addSceneImages(cell, reference);
61891         }));
61892         subs.push(cell$.pipe(concatMap((cell) => {
61893             const cellId = cell.id;
61894             let reconstructions$;
61895             if (this._cache.hasClusters(cellId)) {
61896                 reconstructions$ = from(this._cache.getClusters(cellId));
61897             }
61898             else if (this._cache.isCachingClusters(cellId)) {
61899                 reconstructions$ = this._cache.cacheClusters$(cellId).pipe(last(null, {}), switchMap(() => {
61900                     return from(this._cache.getClusters(cellId));
61901                 }));
61902             }
61903             else if (this._cache.hasCell(cellId)) {
61904                 reconstructions$ = this._cache.cacheClusters$(cellId);
61905             }
61906             else {
61907                 reconstructions$ = empty();
61908             }
61909             return combineLatest(of(cellId), reconstructions$);
61910         }), withLatestFrom(this._navigator.stateService.reference$))
61911             .subscribe(([[cellId, reconstruction], reference]) => {
61912             if (this._scene
61913                 .hasCluster(reconstruction.id, cellId)) {
61914                 return;
61915             }
61916             this._scene.addCluster(reconstruction, this._computeTranslation(reconstruction, reference), cellId);
61917         }));
61918         subs.push(this._configuration$.pipe(map((c) => {
61919             var _a;
61920             c.cameraSize = this._spatial.clamp(c.cameraSize, 0.01, 1);
61921             c.pointSize = this._spatial.clamp(c.pointSize, 0.01, 1);
61922             const pointVisualizationMode = c.pointsVisible ?
61923                 (_a = c.pointVisualizationMode) !== null && _a !== void 0 ? _a : PointVisualizationMode.Original :
61924                 PointVisualizationMode.Hidden;
61925             return {
61926                 cameraSize: c.cameraSize,
61927                 cameraVisualizationMode: c.cameraVisualizationMode,
61928                 cellsVisible: c.cellsVisible,
61929                 originalPositionMode: c.originalPositionMode,
61930                 pointSize: c.pointSize,
61931                 pointVisualizationMode,
61932             };
61933         }), distinctUntilChanged((c1, c2) => {
61934             return c1.cameraSize === c2.cameraSize &&
61935                 c1.cameraVisualizationMode === c2.cameraVisualizationMode &&
61936                 c1.cellsVisible === c2.cellsVisible &&
61937                 c1.originalPositionMode === c2.originalPositionMode &&
61938                 c1.pointSize === c2.pointSize &&
61939                 c1.pointVisualizationMode === c2.pointVisualizationMode;
61940         }))
61941             .subscribe((c) => {
61942             this._scene.setCameraSize(c.cameraSize);
61943             const cvm = c.cameraVisualizationMode;
61944             this._scene.setCameraVisualizationMode(cvm);
61945             this._scene.setCellVisibility(c.cellsVisible);
61946             this._scene.setPointSize(c.pointSize);
61947             const pvm = c.pointVisualizationMode;
61948             this._scene.setPointVisualizationMode(pvm);
61949             const opm = c.originalPositionMode;
61950             this._scene.setPositionMode(opm);
61951         }));
61952         subs.push(combineLatest(cellId$, cellGridDepth$)
61953             .subscribe(([cellId, depth]) => {
61954             const keepCells = connectedComponent(cellId, depth, this._navigator.api.data.geometry);
61955             this._scene.uncache(keepCells);
61956             this._cache.uncache(keepCells);
61957         }));
61958         subs.push(this._navigator.playService.playing$.pipe(switchMap((playing) => {
61959             return playing ?
61960                 empty() :
61961                 this._container.mouseService.dblClick$;
61962         }), withLatestFrom(this._container.renderService.renderCamera$), switchMap(([event, render]) => {
61963             const element = this._container.container;
61964             const [canvasX, canvasY] = this._viewportCoords
61965                 .canvasPosition(event, element);
61966             const viewport = this._viewportCoords.canvasToViewport(canvasX, canvasY, element);
61967             const id = this._scene.intersection
61968                 .intersectObjects(viewport, render.perspective);
61969             return !!id ?
61970                 this._navigator.moveTo$(id).pipe(catchError(() => {
61971                     return empty();
61972                 })) :
61973                 empty();
61974         }))
61975             .subscribe());
61976         const intersectChange$ = combineLatest(this._configuration$, this._navigator.stateService.state$).pipe(map(([c, state]) => {
61977             c.cameraSize = this._spatial.clamp(c.cameraSize, 0.01, 1);
61978             return {
61979                 size: c.cameraSize,
61980                 visible: isModeVisible(c.cameraVisualizationMode),
61981                 state,
61982             };
61983         }), distinctUntilChanged((c1, c2) => {
61984             return c1.size === c2.size &&
61985                 c1.visible === c2.visible &&
61986                 c1.state === c2.state;
61987         }));
61988         const mouseMove$ = this._container.mouseService.mouseMove$.pipe(publishReplay(1), refCount());
61989         subs.push(mouseMove$.subscribe());
61990         const mouseHover$ = merge(this._container.mouseService.mouseEnter$, this._container.mouseService.mouseLeave$, this._container.mouseService.windowBlur$);
61991         subs.push(combineLatest(this._navigator.playService.playing$, mouseHover$, isOverview$, this._navigator.graphService.filter$)
61992             .pipe(switchMap(([playing, mouseHover]) => {
61993             return !playing && mouseHover.type === "pointerenter" ?
61994                 combineLatest(concat(mouseMove$.pipe(take(1)), this._container.mouseService.mouseMove$), this._container.renderService.renderCamera$, intersectChange$) :
61995                 combineLatest(of(mouseHover), of(null), of(null));
61996         }))
61997             .subscribe(([event, render]) => {
61998             if (event.type !== "pointermove") {
61999                 this._scene.setHoveredImage(null);
62000                 return;
62001             }
62002             const element = this._container.container;
62003             const [canvasX, canvasY] = this._viewportCoords.canvasPosition(event, element);
62004             const viewport = this._viewportCoords.canvasToViewport(canvasX, canvasY, element);
62005             const key = this._scene.intersection
62006                 .intersectObjects(viewport, render.perspective);
62007             this._scene.setHoveredImage(key);
62008         }));
62009         subs.push(this._navigator.stateService.currentId$
62010             .subscribe((id) => {
62011             this._scene.setSelectedImage(id);
62012         }));
62013         subs.push(this._navigator.stateService.currentState$
62014             .pipe(map((frame) => {
62015             const scene = this._scene;
62016             return {
62017                 name: this._name,
62018                 renderer: {
62019                     frameId: frame.id,
62020                     needsRender: scene.needsRender,
62021                     render: scene.render.bind(scene),
62022                     pass: RenderPass$1.Opaque,
62023                 },
62024             };
62025         }))
62026             .subscribe(this._container.glRenderer.render$));
62027         const updatedCell$ = this._navigator.graphService.dataAdded$
62028             .pipe(filter((cellId) => {
62029             return this._cache.hasCell(cellId);
62030         }), mergeMap((cellId) => {
62031             return this._cache.updateCell$(cellId).pipe(map((images) => ({ id: cellId, images })), withLatestFrom(this._navigator.stateService.reference$));
62032         }), publish(), refCount());
62033         subs.push(updatedCell$
62034             .subscribe(([cell, reference]) => {
62035             this._addSceneImages(cell, reference);
62036         }));
62037         subs.push(updatedCell$
62038             .pipe(concatMap(([cell]) => {
62039             const cellId = cell.id;
62040             const cache = this._cache;
62041             let reconstructions$;
62042             if (cache.hasClusters(cellId)) {
62043                 reconstructions$ =
62044                     cache.updateClusters$(cellId);
62045             }
62046             else if (cache.isCachingClusters(cellId)) {
62047                 reconstructions$ = this._cache.cacheClusters$(cellId).pipe(last(null, {}), switchMap(() => {
62048                     return from(cache.updateClusters$(cellId));
62049                 }));
62050             }
62051             else {
62052                 reconstructions$ = empty();
62053             }
62054             return combineLatest(of(cellId), reconstructions$);
62055         }), withLatestFrom(this._navigator.stateService.reference$))
62056             .subscribe(([[cellId, reconstruction], reference]) => {
62057             if (this._scene.hasCluster(reconstruction.id, cellId)) {
62058                 return;
62059             }
62060             this._scene.addCluster(reconstruction, this._computeTranslation(reconstruction, reference), cellId);
62061         }));
62062     }
62063     _deactivate() {
62064         this._subscriptions.unsubscribe();
62065         this._cache.uncache();
62066         this._scene.deactivate();
62067         this._navigator.cacheService.configure();
62068     }
62069     _getDefaultConfiguration() {
62070         return {
62071             cameraSize: 0.1,
62072             cameraVisualizationMode: CameraVisualizationMode.Homogeneous,
62073             cellGridDepth: 1,
62074             originalPositionMode: OriginalPositionMode.Hidden,
62075             pointSize: 0.1,
62076             pointsVisible: true,
62077             pointVisualizationMode: PointVisualizationMode.Original,
62078             cellsVisible: false,
62079         };
62080     }
62081     _addSceneImages(cell, reference) {
62082         const cellId = cell.id;
62083         const images = cell.images;
62084         for (const image of images) {
62085             if (this._scene.hasImage(image.id, cellId)) {
62086                 continue;
62087             }
62088             this._scene.addImage(image, this._createTransform(image, reference), this._computeOriginalPosition(image, reference), cellId);
62089         }
62090     }
62091     _cellsInFov(image, bearing, fov) {
62092         const spatial = this._spatial;
62093         const geometry = this._navigator.api.data.geometry;
62094         const cell = geometry.lngLatToCellId(image.originalLngLat);
62095         const cells = [cell];
62096         const threshold = fov / 2;
62097         const adjacent = geometry.getAdjacent(cell);
62098         for (const a of adjacent) {
62099             const vertices = geometry.getVertices(a);
62100             for (const vertex of vertices) {
62101                 const [x, y] = geodeticToEnu(vertex.lng, vertex.lat, 0, image.lngLat.lng, image.lngLat.lat, 0);
62102                 const azimuthal = Math.atan2(y, x);
62103                 const vertexBearing = spatial.radToDeg(spatial.azimuthalToBearing(azimuthal));
62104                 if (Math.abs(vertexBearing - bearing) < threshold) {
62105                     cells.push(a);
62106                 }
62107             }
62108         }
62109         return cells;
62110     }
62111     _computeOriginalPosition(image, reference) {
62112         return geodeticToEnu(image.originalLngLat.lng, image.originalLngLat.lat, image.originalAltitude != null ? image.originalAltitude : image.computedAltitude, reference.lng, reference.lat, reference.alt);
62113     }
62114     _cellToTopocentric(cellId, reference) {
62115         const vertices = this._navigator.api.data.geometry
62116             .getVertices(cellId)
62117             .map((vertex) => {
62118             return geodeticToEnu(vertex.lng, vertex.lat, -2, reference.lng, reference.lat, reference.alt);
62119         });
62120         return vertices;
62121     }
62122     _computeTranslation(reconstruction, reference) {
62123         return geodeticToEnu(reconstruction.reference.lng, reconstruction.reference.lat, reconstruction.reference.alt, reference.lng, reference.lat, reference.alt);
62124     }
62125     _createTransform(image, reference) {
62126         const translation = computeTranslation({ alt: image.computedAltitude, lat: image.lngLat.lat, lng: image.lngLat.lng }, image.rotation, reference);
62127         const transform = new Transform(image.exifOrientation, image.width, image.height, image.scale, image.rotation, translation, undefined, undefined, image.cameraParameters, image.cameraType);
62128         return transform;
62129     }
62130 }
62131 SpatialComponent.componentName = "spatial";
62132
62133 /**
62134  * @class Geometry
62135  * @abstract
62136  * @classdesc Represents a geometry.
62137  */
62138 class Geometry {
62139     /**
62140      * Create a geometry.
62141      *
62142      * @constructor
62143      * @ignore
62144      */
62145     constructor() {
62146         this._notifyChanged$ = new Subject();
62147     }
62148     /**
62149      * Get changed observable.
62150      *
62151      * @description Emits the geometry itself every time the geometry
62152      * has changed.
62153      *
62154      * @returns {Observable<Geometry>} Observable emitting the geometry instance.
62155      * @ignore
62156      */
62157     get changed$() {
62158         return this._notifyChanged$;
62159     }
62160 }
62161
62162 class GeometryTagError extends MapillaryError {
62163     constructor(message) {
62164         super(message != null ? message : "The provided geometry value is incorrect");
62165         Object.setPrototypeOf(this, GeometryTagError.prototype);
62166         this.name = "GeometryTagError";
62167     }
62168 }
62169
62170 /**
62171  * @class PointsGeometry
62172  *
62173  * @classdesc Represents a point set in the 2D basic image coordinate system.
62174  *
62175  * @example
62176  * ```js
62177  * var points = [[0.5, 0.3], [0.7, 0.3], [0.6, 0.5]];
62178  * var pointsGeometry = new PointsGeometry(points);
62179  * ```
62180  */
62181 class PointsGeometry extends Geometry {
62182     /**
62183      * Create a points geometry.
62184      *
62185      * @constructor
62186      * @param {Array<Array<number>>} points - Array of 2D points on the basic coordinate
62187      * system. The number of points must be greater than or equal to two.
62188      *
62189      * @throws {GeometryTagError} Point coordinates must be valid basic coordinates.
62190      */
62191     constructor(points) {
62192         super();
62193         const pointsLength = points.length;
62194         if (pointsLength < 2) {
62195             throw new GeometryTagError("A points geometry must have two or more positions.");
62196         }
62197         this._points = [];
62198         for (const point of points) {
62199             if (point[0] < 0 || point[0] > 1 ||
62200                 point[1] < 0 || point[1] > 1) {
62201                 throw new GeometryTagError("Basic coordinates of points must be on the interval [0, 1].");
62202             }
62203             this._points.push(point.slice());
62204         }
62205     }
62206     /**
62207      * Get points property.
62208      * @returns {Array<Array<number>>} Array of 2d points.
62209      */
62210     get points() {
62211         return this._points;
62212     }
62213     /**
62214      * Add a point to the point set.
62215      *
62216      * @param {Array<number>} point - Point to add.
62217      * @ignore
62218      */
62219     addPoint2d(point) {
62220         const clamped = [
62221             Math.max(0, Math.min(1, point[0])),
62222             Math.max(0, Math.min(1, point[1])),
62223         ];
62224         this._points.push(clamped);
62225         this._notifyChanged$.next(this);
62226     }
62227     /**
62228      * Get the coordinates of a point from the point set representation of the geometry.
62229      *
62230      * @param {number} index - Point index.
62231      * @returns {Array<number>} Array representing the 2D basic coordinates of the point.
62232      * @ignore
62233      */
62234     getPoint2d(index) {
62235         return this._points[index].slice();
62236     }
62237     /**
62238      * Remove a point from the point set.
62239      *
62240      * @param {number} index - The index of the point to remove.
62241      * @ignore
62242      */
62243     removePoint2d(index) {
62244         if (index < 0 ||
62245             index >= this._points.length ||
62246             this._points.length < 3) {
62247             throw new GeometryTagError("Index for removed point must be valid.");
62248         }
62249         this._points.splice(index, 1);
62250         this._notifyChanged$.next(this);
62251     }
62252     /** @ignore */
62253     setVertex2d(index, value, transform) {
62254         this.setPoint2d(index, value, transform);
62255     }
62256     /** @ignore */
62257     setPoint2d(index, value, transform) {
62258         const changed = [
62259             Math.max(0, Math.min(1, value[0])),
62260             Math.max(0, Math.min(1, value[1])),
62261         ];
62262         this._points[index] = changed;
62263         this._notifyChanged$.next(this);
62264     }
62265     /** @ignore */
62266     getPoints3d(transform) {
62267         return this._getPoints3d(this._points, transform);
62268     }
62269     /** @ignore */
62270     getPoint3d(index, transform) {
62271         return transform.unprojectBasic(this._points[index], 200);
62272     }
62273     /** @ignore */
62274     getPoints2d() {
62275         return this._points.slice();
62276     }
62277     /** @ignore */
62278     getCentroid2d(transform) {
62279         if (!transform) {
62280             throw new GeometryTagError("Get centroid must be called with a transform for points geometries.");
62281         }
62282         const [minX, minY, maxX, maxY] = this.getRect2d(transform);
62283         const centroidX = minX < maxX ?
62284             (minX + maxX) / 2 :
62285             ((minX + maxX + 1) / 2) % 1;
62286         const centroidY = (minY + maxY) / 2;
62287         return [centroidX, centroidY];
62288     }
62289     /** @ignore */
62290     getCentroid3d(transform) {
62291         let centroid2d = this.getCentroid2d();
62292         return transform.unprojectBasic(centroid2d, 200);
62293     }
62294     /** @ignore */
62295     getRect2d(transform) {
62296         let minX = 1;
62297         let maxX = 0;
62298         let minY = 1;
62299         let maxY = 0;
62300         const points = this._points;
62301         for (const point of points) {
62302             if (point[0] < minX) {
62303                 minX = point[0];
62304             }
62305             if (point[0] > maxX) {
62306                 maxX = point[0];
62307             }
62308             if (point[1] < minY) {
62309                 minY = point[1];
62310             }
62311             if (point[1] > maxY) {
62312                 maxY = point[1];
62313             }
62314         }
62315         if (isSpherical(transform.cameraType)) {
62316             const indices = [];
62317             for (let i = 0; i < points.length; i++) {
62318                 indices[i] = i;
62319             }
62320             indices.sort((a, b) => {
62321                 return points[a][0] < points[b][0] ?
62322                     -1 :
62323                     points[a][0] > points[b][0] ?
62324                         1 :
62325                         a < b ? -1 : 1;
62326             });
62327             let maxDistanceX = points[indices[0]][0] + 1 - points[indices[indices.length - 1]][0];
62328             let leftMostIndex = 0;
62329             for (let i = 0; i < indices.length - 1; i++) {
62330                 const index1 = indices[i];
62331                 const index2 = indices[i + 1];
62332                 const distanceX = points[index2][0] - points[index1][0];
62333                 if (distanceX > maxDistanceX) {
62334                     maxDistanceX = distanceX;
62335                     leftMostIndex = i + 1;
62336                 }
62337             }
62338             if (leftMostIndex > 0) {
62339                 minX = points[indices[leftMostIndex]][0];
62340                 maxX = points[indices[leftMostIndex - 1]][0];
62341             }
62342         }
62343         return [minX, minY, maxX, maxY];
62344     }
62345     /** @ignore */
62346     setCentroid2d(value, transform) {
62347         throw new Error("Not implemented");
62348     }
62349     _getPoints3d(points2d, transform) {
62350         return points2d
62351             .map((point) => {
62352             return transform.unprojectBasic(point, 200);
62353         });
62354     }
62355 }
62356
62357 class CreateTag {
62358     constructor(geometry, transform, viewportCoords) {
62359         this._geometry = geometry;
62360         this._transform = transform;
62361         this._viewportCoords = !!viewportCoords ? viewportCoords : new ViewportCoords();
62362         this._aborted$ = new Subject();
62363         this._created$ = new Subject();
62364         this._glObjectsChanged$ = new Subject();
62365         this._geometryChangedSubscription = this._geometry.changed$
62366             .subscribe(() => {
62367             this._onGeometryChanged();
62368             this._glObjectsChanged$.next(this);
62369         });
62370     }
62371     get geometry() {
62372         return this._geometry;
62373     }
62374     get glObjects() {
62375         return this._glObjects;
62376     }
62377     get aborted$() {
62378         return this._aborted$;
62379     }
62380     get created$() {
62381         return this._created$;
62382     }
62383     get glObjectsChanged$() {
62384         return this._glObjectsChanged$;
62385     }
62386     get geometryChanged$() {
62387         return this._geometry.changed$.pipe(map(() => {
62388             return this;
62389         }));
62390     }
62391     dispose() {
62392         this._geometryChangedSubscription.unsubscribe();
62393     }
62394     _canvasToTransform(canvas) {
62395         const canvasX = Math.round(canvas[0]);
62396         const canvasY = Math.round(canvas[1]);
62397         const transform = `translate(-50%,-50%) translate(${canvasX}px,${canvasY}px)`;
62398         return transform;
62399     }
62400     _colorToBackground(color) {
62401         return "#" + ("000000" + color.toString(16)).substr(-6);
62402     }
62403     _createOutine(polygon3d, color) {
62404         const positions = this._getLinePositions(polygon3d);
62405         const geometry = new BufferGeometry();
62406         geometry.setAttribute("position", new BufferAttribute(positions, 3));
62407         const material = new LineBasicMaterial({
62408             color: color,
62409             linewidth: 1,
62410         });
62411         return new Line(geometry, material);
62412     }
62413     _disposeLine(line) {
62414         if (line == null) {
62415             return;
62416         }
62417         line.geometry.dispose();
62418         line.material.dispose();
62419     }
62420     _getLinePositions(polygon3d) {
62421         const length = polygon3d.length;
62422         const positions = new Float32Array(length * 3);
62423         for (let i = 0; i < length; ++i) {
62424             const index = 3 * i;
62425             const position = polygon3d[i];
62426             positions[index] = position[0];
62427             positions[index + 1] = position[1];
62428             positions[index + 2] = position[2];
62429         }
62430         return positions;
62431     }
62432 }
62433
62434 var earcut$2 = {exports: {}};
62435
62436 earcut$2.exports = earcut;
62437 earcut$2.exports.default = earcut;
62438
62439 function earcut(data, holeIndices, dim) {
62440
62441     dim = dim || 2;
62442
62443     var hasHoles = holeIndices && holeIndices.length,
62444         outerLen = hasHoles ? holeIndices[0] * dim : data.length,
62445         outerNode = linkedList(data, 0, outerLen, dim, true),
62446         triangles = [];
62447
62448     if (!outerNode || outerNode.next === outerNode.prev) return triangles;
62449
62450     var minX, minY, maxX, maxY, x, y, invSize;
62451
62452     if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim);
62453
62454     // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
62455     if (data.length > 80 * dim) {
62456         minX = maxX = data[0];
62457         minY = maxY = data[1];
62458
62459         for (var i = dim; i < outerLen; i += dim) {
62460             x = data[i];
62461             y = data[i + 1];
62462             if (x < minX) minX = x;
62463             if (y < minY) minY = y;
62464             if (x > maxX) maxX = x;
62465             if (y > maxY) maxY = y;
62466         }
62467
62468         // minX, minY and invSize are later used to transform coords into integers for z-order calculation
62469         invSize = Math.max(maxX - minX, maxY - minY);
62470         invSize = invSize !== 0 ? 1 / invSize : 0;
62471     }
62472
62473     earcutLinked(outerNode, triangles, dim, minX, minY, invSize);
62474
62475     return triangles;
62476 }
62477
62478 // create a circular doubly linked list from polygon points in the specified winding order
62479 function linkedList(data, start, end, dim, clockwise) {
62480     var i, last;
62481
62482     if (clockwise === (signedArea$1(data, start, end, dim) > 0)) {
62483         for (i = start; i < end; i += dim) last = insertNode(i, data[i], data[i + 1], last);
62484     } else {
62485         for (i = end - dim; i >= start; i -= dim) last = insertNode(i, data[i], data[i + 1], last);
62486     }
62487
62488     if (last && equals$1(last, last.next)) {
62489         removeNode(last);
62490         last = last.next;
62491     }
62492
62493     return last;
62494 }
62495
62496 // eliminate colinear or duplicate points
62497 function filterPoints(start, end) {
62498     if (!start) return start;
62499     if (!end) end = start;
62500
62501     var p = start,
62502         again;
62503     do {
62504         again = false;
62505
62506         if (!p.steiner && (equals$1(p, p.next) || area(p.prev, p, p.next) === 0)) {
62507             removeNode(p);
62508             p = end = p.prev;
62509             if (p === p.next) break;
62510             again = true;
62511
62512         } else {
62513             p = p.next;
62514         }
62515     } while (again || p !== end);
62516
62517     return end;
62518 }
62519
62520 // main ear slicing loop which triangulates a polygon (given as a linked list)
62521 function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) {
62522     if (!ear) return;
62523
62524     // interlink polygon nodes in z-order
62525     if (!pass && invSize) indexCurve(ear, minX, minY, invSize);
62526
62527     var stop = ear,
62528         prev, next;
62529
62530     // iterate through ears, slicing them one by one
62531     while (ear.prev !== ear.next) {
62532         prev = ear.prev;
62533         next = ear.next;
62534
62535         if (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear)) {
62536             // cut off the triangle
62537             triangles.push(prev.i / dim);
62538             triangles.push(ear.i / dim);
62539             triangles.push(next.i / dim);
62540
62541             removeNode(ear);
62542
62543             // skipping the next vertex leads to less sliver triangles
62544             ear = next.next;
62545             stop = next.next;
62546
62547             continue;
62548         }
62549
62550         ear = next;
62551
62552         // if we looped through the whole remaining polygon and can't find any more ears
62553         if (ear === stop) {
62554             // try filtering points and slicing again
62555             if (!pass) {
62556                 earcutLinked(filterPoints(ear), triangles, dim, minX, minY, invSize, 1);
62557
62558             // if this didn't work, try curing all small self-intersections locally
62559             } else if (pass === 1) {
62560                 ear = cureLocalIntersections(filterPoints(ear), triangles, dim);
62561                 earcutLinked(ear, triangles, dim, minX, minY, invSize, 2);
62562
62563             // as a last resort, try splitting the remaining polygon into two
62564             } else if (pass === 2) {
62565                 splitEarcut(ear, triangles, dim, minX, minY, invSize);
62566             }
62567
62568             break;
62569         }
62570     }
62571 }
62572
62573 // check whether a polygon node forms a valid ear with adjacent nodes
62574 function isEar(ear) {
62575     var a = ear.prev,
62576         b = ear,
62577         c = ear.next;
62578
62579     if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
62580
62581     // now make sure we don't have other points inside the potential ear
62582     var p = ear.next.next;
62583
62584     while (p !== ear.prev) {
62585         if (pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
62586             area(p.prev, p, p.next) >= 0) return false;
62587         p = p.next;
62588     }
62589
62590     return true;
62591 }
62592
62593 function isEarHashed(ear, minX, minY, invSize) {
62594     var a = ear.prev,
62595         b = ear,
62596         c = ear.next;
62597
62598     if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
62599
62600     // triangle bbox; min & max are calculated like this for speed
62601     var minTX = a.x < b.x ? (a.x < c.x ? a.x : c.x) : (b.x < c.x ? b.x : c.x),
62602         minTY = a.y < b.y ? (a.y < c.y ? a.y : c.y) : (b.y < c.y ? b.y : c.y),
62603         maxTX = a.x > b.x ? (a.x > c.x ? a.x : c.x) : (b.x > c.x ? b.x : c.x),
62604         maxTY = a.y > b.y ? (a.y > c.y ? a.y : c.y) : (b.y > c.y ? b.y : c.y);
62605
62606     // z-order range for the current triangle bbox;
62607     var minZ = zOrder(minTX, minTY, minX, minY, invSize),
62608         maxZ = zOrder(maxTX, maxTY, minX, minY, invSize);
62609
62610     var p = ear.prevZ,
62611         n = ear.nextZ;
62612
62613     // look for points inside the triangle in both directions
62614     while (p && p.z >= minZ && n && n.z <= maxZ) {
62615         if (p !== ear.prev && p !== ear.next &&
62616             pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
62617             area(p.prev, p, p.next) >= 0) return false;
62618         p = p.prevZ;
62619
62620         if (n !== ear.prev && n !== ear.next &&
62621             pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) &&
62622             area(n.prev, n, n.next) >= 0) return false;
62623         n = n.nextZ;
62624     }
62625
62626     // look for remaining points in decreasing z-order
62627     while (p && p.z >= minZ) {
62628         if (p !== ear.prev && p !== ear.next &&
62629             pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
62630             area(p.prev, p, p.next) >= 0) return false;
62631         p = p.prevZ;
62632     }
62633
62634     // look for remaining points in increasing z-order
62635     while (n && n.z <= maxZ) {
62636         if (n !== ear.prev && n !== ear.next &&
62637             pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) &&
62638             area(n.prev, n, n.next) >= 0) return false;
62639         n = n.nextZ;
62640     }
62641
62642     return true;
62643 }
62644
62645 // go through all polygon nodes and cure small local self-intersections
62646 function cureLocalIntersections(start, triangles, dim) {
62647     var p = start;
62648     do {
62649         var a = p.prev,
62650             b = p.next.next;
62651
62652         if (!equals$1(a, b) && intersects(a, p, p.next, b) && locallyInside(a, b) && locallyInside(b, a)) {
62653
62654             triangles.push(a.i / dim);
62655             triangles.push(p.i / dim);
62656             triangles.push(b.i / dim);
62657
62658             // remove two nodes involved
62659             removeNode(p);
62660             removeNode(p.next);
62661
62662             p = start = b;
62663         }
62664         p = p.next;
62665     } while (p !== start);
62666
62667     return filterPoints(p);
62668 }
62669
62670 // try splitting polygon into two and triangulate them independently
62671 function splitEarcut(start, triangles, dim, minX, minY, invSize) {
62672     // look for a valid diagonal that divides the polygon into two
62673     var a = start;
62674     do {
62675         var b = a.next.next;
62676         while (b !== a.prev) {
62677             if (a.i !== b.i && isValidDiagonal(a, b)) {
62678                 // split the polygon in two by the diagonal
62679                 var c = splitPolygon(a, b);
62680
62681                 // filter colinear points around the cuts
62682                 a = filterPoints(a, a.next);
62683                 c = filterPoints(c, c.next);
62684
62685                 // run earcut on each half
62686                 earcutLinked(a, triangles, dim, minX, minY, invSize);
62687                 earcutLinked(c, triangles, dim, minX, minY, invSize);
62688                 return;
62689             }
62690             b = b.next;
62691         }
62692         a = a.next;
62693     } while (a !== start);
62694 }
62695
62696 // link every hole into the outer loop, producing a single-ring polygon without holes
62697 function eliminateHoles(data, holeIndices, outerNode, dim) {
62698     var queue = [],
62699         i, len, start, end, list;
62700
62701     for (i = 0, len = holeIndices.length; i < len; i++) {
62702         start = holeIndices[i] * dim;
62703         end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
62704         list = linkedList(data, start, end, dim, false);
62705         if (list === list.next) list.steiner = true;
62706         queue.push(getLeftmost(list));
62707     }
62708
62709     queue.sort(compareX);
62710
62711     // process holes from left to right
62712     for (i = 0; i < queue.length; i++) {
62713         outerNode = eliminateHole(queue[i], outerNode);
62714         outerNode = filterPoints(outerNode, outerNode.next);
62715     }
62716
62717     return outerNode;
62718 }
62719
62720 function compareX(a, b) {
62721     return a.x - b.x;
62722 }
62723
62724 // find a bridge between vertices that connects hole with an outer ring and and link it
62725 function eliminateHole(hole, outerNode) {
62726     var bridge = findHoleBridge(hole, outerNode);
62727     if (!bridge) {
62728         return outerNode;
62729     }
62730
62731     var bridgeReverse = splitPolygon(bridge, hole);
62732
62733     // filter collinear points around the cuts
62734     var filteredBridge = filterPoints(bridge, bridge.next);
62735     filterPoints(bridgeReverse, bridgeReverse.next);
62736
62737     // Check if input node was removed by the filtering
62738     return outerNode === bridge ? filteredBridge : outerNode;
62739 }
62740
62741 // David Eberly's algorithm for finding a bridge between hole and outer polygon
62742 function findHoleBridge(hole, outerNode) {
62743     var p = outerNode,
62744         hx = hole.x,
62745         hy = hole.y,
62746         qx = -Infinity,
62747         m;
62748
62749     // find a segment intersected by a ray from the hole's leftmost point to the left;
62750     // segment's endpoint with lesser x will be potential connection point
62751     do {
62752         if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) {
62753             var x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
62754             if (x <= hx && x > qx) {
62755                 qx = x;
62756                 if (x === hx) {
62757                     if (hy === p.y) return p;
62758                     if (hy === p.next.y) return p.next;
62759                 }
62760                 m = p.x < p.next.x ? p : p.next;
62761             }
62762         }
62763         p = p.next;
62764     } while (p !== outerNode);
62765
62766     if (!m) return null;
62767
62768     if (hx === qx) return m; // hole touches outer segment; pick leftmost endpoint
62769
62770     // look for points inside the triangle of hole point, segment intersection and endpoint;
62771     // if there are no points found, we have a valid connection;
62772     // otherwise choose the point of the minimum angle with the ray as connection point
62773
62774     var stop = m,
62775         mx = m.x,
62776         my = m.y,
62777         tanMin = Infinity,
62778         tan;
62779
62780     p = m;
62781
62782     do {
62783         if (hx >= p.x && p.x >= mx && hx !== p.x &&
62784                 pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) {
62785
62786             tan = Math.abs(hy - p.y) / (hx - p.x); // tangential
62787
62788             if (locallyInside(p, hole) &&
62789                 (tan < tanMin || (tan === tanMin && (p.x > m.x || (p.x === m.x && sectorContainsSector(m, p)))))) {
62790                 m = p;
62791                 tanMin = tan;
62792             }
62793         }
62794
62795         p = p.next;
62796     } while (p !== stop);
62797
62798     return m;
62799 }
62800
62801 // whether sector in vertex m contains sector in vertex p in the same coordinates
62802 function sectorContainsSector(m, p) {
62803     return area(m.prev, m, p.prev) < 0 && area(p.next, m, m.next) < 0;
62804 }
62805
62806 // interlink polygon nodes in z-order
62807 function indexCurve(start, minX, minY, invSize) {
62808     var p = start;
62809     do {
62810         if (p.z === null) p.z = zOrder(p.x, p.y, minX, minY, invSize);
62811         p.prevZ = p.prev;
62812         p.nextZ = p.next;
62813         p = p.next;
62814     } while (p !== start);
62815
62816     p.prevZ.nextZ = null;
62817     p.prevZ = null;
62818
62819     sortLinked(p);
62820 }
62821
62822 // Simon Tatham's linked list merge sort algorithm
62823 // http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
62824 function sortLinked(list) {
62825     var i, p, q, e, tail, numMerges, pSize, qSize,
62826         inSize = 1;
62827
62828     do {
62829         p = list;
62830         list = null;
62831         tail = null;
62832         numMerges = 0;
62833
62834         while (p) {
62835             numMerges++;
62836             q = p;
62837             pSize = 0;
62838             for (i = 0; i < inSize; i++) {
62839                 pSize++;
62840                 q = q.nextZ;
62841                 if (!q) break;
62842             }
62843             qSize = inSize;
62844
62845             while (pSize > 0 || (qSize > 0 && q)) {
62846
62847                 if (pSize !== 0 && (qSize === 0 || !q || p.z <= q.z)) {
62848                     e = p;
62849                     p = p.nextZ;
62850                     pSize--;
62851                 } else {
62852                     e = q;
62853                     q = q.nextZ;
62854                     qSize--;
62855                 }
62856
62857                 if (tail) tail.nextZ = e;
62858                 else list = e;
62859
62860                 e.prevZ = tail;
62861                 tail = e;
62862             }
62863
62864             p = q;
62865         }
62866
62867         tail.nextZ = null;
62868         inSize *= 2;
62869
62870     } while (numMerges > 1);
62871
62872     return list;
62873 }
62874
62875 // z-order of a point given coords and inverse of the longer side of data bbox
62876 function zOrder(x, y, minX, minY, invSize) {
62877     // coords are transformed into non-negative 15-bit integer range
62878     x = 32767 * (x - minX) * invSize;
62879     y = 32767 * (y - minY) * invSize;
62880
62881     x = (x | (x << 8)) & 0x00FF00FF;
62882     x = (x | (x << 4)) & 0x0F0F0F0F;
62883     x = (x | (x << 2)) & 0x33333333;
62884     x = (x | (x << 1)) & 0x55555555;
62885
62886     y = (y | (y << 8)) & 0x00FF00FF;
62887     y = (y | (y << 4)) & 0x0F0F0F0F;
62888     y = (y | (y << 2)) & 0x33333333;
62889     y = (y | (y << 1)) & 0x55555555;
62890
62891     return x | (y << 1);
62892 }
62893
62894 // find the leftmost node of a polygon ring
62895 function getLeftmost(start) {
62896     var p = start,
62897         leftmost = start;
62898     do {
62899         if (p.x < leftmost.x || (p.x === leftmost.x && p.y < leftmost.y)) leftmost = p;
62900         p = p.next;
62901     } while (p !== start);
62902
62903     return leftmost;
62904 }
62905
62906 // check if a point lies within a convex triangle
62907 function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
62908     return (cx - px) * (ay - py) - (ax - px) * (cy - py) >= 0 &&
62909            (ax - px) * (by - py) - (bx - px) * (ay - py) >= 0 &&
62910            (bx - px) * (cy - py) - (cx - px) * (by - py) >= 0;
62911 }
62912
62913 // check if a diagonal between two polygon nodes is valid (lies in polygon interior)
62914 function isValidDiagonal(a, b) {
62915     return a.next.i !== b.i && a.prev.i !== b.i && !intersectsPolygon(a, b) && // dones't intersect other edges
62916            (locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) && // locally visible
62917             (area(a.prev, a, b.prev) || area(a, b.prev, b)) || // does not create opposite-facing sectors
62918             equals$1(a, b) && area(a.prev, a, a.next) > 0 && area(b.prev, b, b.next) > 0); // special zero-length case
62919 }
62920
62921 // signed area of a triangle
62922 function area(p, q, r) {
62923     return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
62924 }
62925
62926 // check if two points are equal
62927 function equals$1(p1, p2) {
62928     return p1.x === p2.x && p1.y === p2.y;
62929 }
62930
62931 // check if two segments intersect
62932 function intersects(p1, q1, p2, q2) {
62933     var o1 = sign(area(p1, q1, p2));
62934     var o2 = sign(area(p1, q1, q2));
62935     var o3 = sign(area(p2, q2, p1));
62936     var o4 = sign(area(p2, q2, q1));
62937
62938     if (o1 !== o2 && o3 !== o4) return true; // general case
62939
62940     if (o1 === 0 && onSegment(p1, p2, q1)) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1
62941     if (o2 === 0 && onSegment(p1, q2, q1)) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1
62942     if (o3 === 0 && onSegment(p2, p1, q2)) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2
62943     if (o4 === 0 && onSegment(p2, q1, q2)) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2
62944
62945     return false;
62946 }
62947
62948 // for collinear points p, q, r, check if point q lies on segment pr
62949 function onSegment(p, q, r) {
62950     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);
62951 }
62952
62953 function sign(num) {
62954     return num > 0 ? 1 : num < 0 ? -1 : 0;
62955 }
62956
62957 // check if a polygon diagonal intersects any polygon segments
62958 function intersectsPolygon(a, b) {
62959     var p = a;
62960     do {
62961         if (p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i &&
62962                 intersects(p, p.next, a, b)) return true;
62963         p = p.next;
62964     } while (p !== a);
62965
62966     return false;
62967 }
62968
62969 // check if a polygon diagonal is locally inside the polygon
62970 function locallyInside(a, b) {
62971     return area(a.prev, a, a.next) < 0 ?
62972         area(a, b, a.next) >= 0 && area(a, a.prev, b) >= 0 :
62973         area(a, b, a.prev) < 0 || area(a, a.next, b) < 0;
62974 }
62975
62976 // check if the middle point of a polygon diagonal is inside the polygon
62977 function middleInside(a, b) {
62978     var p = a,
62979         inside = false,
62980         px = (a.x + b.x) / 2,
62981         py = (a.y + b.y) / 2;
62982     do {
62983         if (((p.y > py) !== (p.next.y > py)) && p.next.y !== p.y &&
62984                 (px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x))
62985             inside = !inside;
62986         p = p.next;
62987     } while (p !== a);
62988
62989     return inside;
62990 }
62991
62992 // link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;
62993 // if one belongs to the outer ring and another to a hole, it merges it into a single ring
62994 function splitPolygon(a, b) {
62995     var a2 = new Node(a.i, a.x, a.y),
62996         b2 = new Node(b.i, b.x, b.y),
62997         an = a.next,
62998         bp = b.prev;
62999
63000     a.next = b;
63001     b.prev = a;
63002
63003     a2.next = an;
63004     an.prev = a2;
63005
63006     b2.next = a2;
63007     a2.prev = b2;
63008
63009     bp.next = b2;
63010     b2.prev = bp;
63011
63012     return b2;
63013 }
63014
63015 // create a node and optionally link it with previous one (in a circular doubly linked list)
63016 function insertNode(i, x, y, last) {
63017     var p = new Node(i, x, y);
63018
63019     if (!last) {
63020         p.prev = p;
63021         p.next = p;
63022
63023     } else {
63024         p.next = last.next;
63025         p.prev = last;
63026         last.next.prev = p;
63027         last.next = p;
63028     }
63029     return p;
63030 }
63031
63032 function removeNode(p) {
63033     p.next.prev = p.prev;
63034     p.prev.next = p.next;
63035
63036     if (p.prevZ) p.prevZ.nextZ = p.nextZ;
63037     if (p.nextZ) p.nextZ.prevZ = p.prevZ;
63038 }
63039
63040 function Node(i, x, y) {
63041     // vertex index in coordinates array
63042     this.i = i;
63043
63044     // vertex coordinates
63045     this.x = x;
63046     this.y = y;
63047
63048     // previous and next vertex nodes in a polygon ring
63049     this.prev = null;
63050     this.next = null;
63051
63052     // z-order curve value
63053     this.z = null;
63054
63055     // previous and next nodes in z-order
63056     this.prevZ = null;
63057     this.nextZ = null;
63058
63059     // indicates whether this is a steiner point
63060     this.steiner = false;
63061 }
63062
63063 // return a percentage difference between the polygon area and its triangulation area;
63064 // used to verify correctness of triangulation
63065 earcut.deviation = function (data, holeIndices, dim, triangles) {
63066     var hasHoles = holeIndices && holeIndices.length;
63067     var outerLen = hasHoles ? holeIndices[0] * dim : data.length;
63068
63069     var polygonArea = Math.abs(signedArea$1(data, 0, outerLen, dim));
63070     if (hasHoles) {
63071         for (var i = 0, len = holeIndices.length; i < len; i++) {
63072             var start = holeIndices[i] * dim;
63073             var end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
63074             polygonArea -= Math.abs(signedArea$1(data, start, end, dim));
63075         }
63076     }
63077
63078     var trianglesArea = 0;
63079     for (i = 0; i < triangles.length; i += 3) {
63080         var a = triangles[i] * dim;
63081         var b = triangles[i + 1] * dim;
63082         var c = triangles[i + 2] * dim;
63083         trianglesArea += Math.abs(
63084             (data[a] - data[c]) * (data[b + 1] - data[a + 1]) -
63085             (data[a] - data[b]) * (data[c + 1] - data[a + 1]));
63086     }
63087
63088     return polygonArea === 0 && trianglesArea === 0 ? 0 :
63089         Math.abs((trianglesArea - polygonArea) / polygonArea);
63090 };
63091
63092 function signedArea$1(data, start, end, dim) {
63093     var sum = 0;
63094     for (var i = start, j = end - dim; i < end; i += dim) {
63095         sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
63096         j = i;
63097     }
63098     return sum;
63099 }
63100
63101 // turn a polygon in a multi-dimensional array form (e.g. as in GeoJSON) into a form Earcut accepts
63102 earcut.flatten = function (data) {
63103     var dim = data[0][0].length,
63104         result = {vertices: [], holes: [], dimensions: dim},
63105         holeIndex = 0;
63106
63107     for (var i = 0; i < data.length; i++) {
63108         for (var j = 0; j < data[i].length; j++) {
63109             for (var d = 0; d < dim; d++) result.vertices.push(data[i][j][d]);
63110         }
63111         if (i > 0) {
63112             holeIndex += data[i - 1].length;
63113             result.holes.push(holeIndex);
63114         }
63115     }
63116     return result;
63117 };
63118
63119 var earcut$1 = earcut$2.exports;
63120
63121 var polylabel$2 = {exports: {}};
63122
63123 class TinyQueue$1 {
63124     constructor(data = [], compare = defaultCompare$1) {
63125         this.data = data;
63126         this.length = this.data.length;
63127         this.compare = compare;
63128
63129         if (this.length > 0) {
63130             for (let i = (this.length >> 1) - 1; i >= 0; i--) this._down(i);
63131         }
63132     }
63133
63134     push(item) {
63135         this.data.push(item);
63136         this.length++;
63137         this._up(this.length - 1);
63138     }
63139
63140     pop() {
63141         if (this.length === 0) return undefined;
63142
63143         const top = this.data[0];
63144         const bottom = this.data.pop();
63145         this.length--;
63146
63147         if (this.length > 0) {
63148             this.data[0] = bottom;
63149             this._down(0);
63150         }
63151
63152         return top;
63153     }
63154
63155     peek() {
63156         return this.data[0];
63157     }
63158
63159     _up(pos) {
63160         const {data, compare} = this;
63161         const item = data[pos];
63162
63163         while (pos > 0) {
63164             const parent = (pos - 1) >> 1;
63165             const current = data[parent];
63166             if (compare(item, current) >= 0) break;
63167             data[pos] = current;
63168             pos = parent;
63169         }
63170
63171         data[pos] = item;
63172     }
63173
63174     _down(pos) {
63175         const {data, compare} = this;
63176         const halfLength = this.length >> 1;
63177         const item = data[pos];
63178
63179         while (pos < halfLength) {
63180             let left = (pos << 1) + 1;
63181             let best = data[left];
63182             const right = left + 1;
63183
63184             if (right < this.length && compare(data[right], best) < 0) {
63185                 left = right;
63186                 best = data[right];
63187             }
63188             if (compare(best, item) >= 0) break;
63189
63190             data[pos] = best;
63191             pos = left;
63192         }
63193
63194         data[pos] = item;
63195     }
63196 }
63197
63198 function defaultCompare$1(a, b) {
63199     return a < b ? -1 : a > b ? 1 : 0;
63200 }
63201
63202 var tinyqueue$1 = /*#__PURE__*/Object.freeze({
63203     __proto__: null,
63204     'default': TinyQueue$1
63205 });
63206
63207 var require$$0 = /*@__PURE__*/getAugmentedNamespace(tinyqueue$1);
63208
63209 var Queue$1 = require$$0;
63210
63211 if (Queue$1.default) Queue$1 = Queue$1.default; // temporary webpack fix
63212
63213 polylabel$2.exports = polylabel;
63214 polylabel$2.exports.default = polylabel;
63215
63216 function polylabel(polygon, precision, debug) {
63217     precision = precision || 1.0;
63218
63219     // find the bounding box of the outer ring
63220     var minX, minY, maxX, maxY;
63221     for (var i = 0; i < polygon[0].length; i++) {
63222         var p = polygon[0][i];
63223         if (!i || p[0] < minX) minX = p[0];
63224         if (!i || p[1] < minY) minY = p[1];
63225         if (!i || p[0] > maxX) maxX = p[0];
63226         if (!i || p[1] > maxY) maxY = p[1];
63227     }
63228
63229     var width = maxX - minX;
63230     var height = maxY - minY;
63231     var cellSize = Math.min(width, height);
63232     var h = cellSize / 2;
63233
63234     if (cellSize === 0) {
63235         var degeneratePoleOfInaccessibility = [minX, minY];
63236         degeneratePoleOfInaccessibility.distance = 0;
63237         return degeneratePoleOfInaccessibility;
63238     }
63239
63240     // a priority queue of cells in order of their "potential" (max distance to polygon)
63241     var cellQueue = new Queue$1(undefined, compareMax);
63242
63243     // cover polygon with initial cells
63244     for (var x = minX; x < maxX; x += cellSize) {
63245         for (var y = minY; y < maxY; y += cellSize) {
63246             cellQueue.push(new Cell(x + h, y + h, h, polygon));
63247         }
63248     }
63249
63250     // take centroid as the first best guess
63251     var bestCell = getCentroidCell(polygon);
63252
63253     // special case for rectangular polygons
63254     var bboxCell = new Cell(minX + width / 2, minY + height / 2, 0, polygon);
63255     if (bboxCell.d > bestCell.d) bestCell = bboxCell;
63256
63257     var numProbes = cellQueue.length;
63258
63259     while (cellQueue.length) {
63260         // pick the most promising cell from the queue
63261         var cell = cellQueue.pop();
63262
63263         // update the best cell if we found a better one
63264         if (cell.d > bestCell.d) {
63265             bestCell = cell;
63266             if (debug) console.log('found best %d after %d probes', Math.round(1e4 * cell.d) / 1e4, numProbes);
63267         }
63268
63269         // do not drill down further if there's no chance of a better solution
63270         if (cell.max - bestCell.d <= precision) continue;
63271
63272         // split the cell into four cells
63273         h = cell.h / 2;
63274         cellQueue.push(new Cell(cell.x - h, cell.y - h, h, polygon));
63275         cellQueue.push(new Cell(cell.x + h, cell.y - h, h, polygon));
63276         cellQueue.push(new Cell(cell.x - h, cell.y + h, h, polygon));
63277         cellQueue.push(new Cell(cell.x + h, cell.y + h, h, polygon));
63278         numProbes += 4;
63279     }
63280
63281     if (debug) {
63282         console.log('num probes: ' + numProbes);
63283         console.log('best distance: ' + bestCell.d);
63284     }
63285
63286     var poleOfInaccessibility = [bestCell.x, bestCell.y];
63287     poleOfInaccessibility.distance = bestCell.d;
63288     return poleOfInaccessibility;
63289 }
63290
63291 function compareMax(a, b) {
63292     return b.max - a.max;
63293 }
63294
63295 function Cell(x, y, h, polygon) {
63296     this.x = x; // cell center x
63297     this.y = y; // cell center y
63298     this.h = h; // half the cell size
63299     this.d = pointToPolygonDist(x, y, polygon); // distance from cell center to polygon
63300     this.max = this.d + this.h * Math.SQRT2; // max distance to polygon within a cell
63301 }
63302
63303 // signed distance from point to polygon outline (negative if point is outside)
63304 function pointToPolygonDist(x, y, polygon) {
63305     var inside = false;
63306     var minDistSq = Infinity;
63307
63308     for (var k = 0; k < polygon.length; k++) {
63309         var ring = polygon[k];
63310
63311         for (var i = 0, len = ring.length, j = len - 1; i < len; j = i++) {
63312             var a = ring[i];
63313             var b = ring[j];
63314
63315             if ((a[1] > y !== b[1] > y) &&
63316                 (x < (b[0] - a[0]) * (y - a[1]) / (b[1] - a[1]) + a[0])) inside = !inside;
63317
63318             minDistSq = Math.min(minDistSq, getSegDistSq(x, y, a, b));
63319         }
63320     }
63321
63322     return minDistSq === 0 ? 0 : (inside ? 1 : -1) * Math.sqrt(minDistSq);
63323 }
63324
63325 // get polygon centroid
63326 function getCentroidCell(polygon) {
63327     var area = 0;
63328     var x = 0;
63329     var y = 0;
63330     var points = polygon[0];
63331
63332     for (var i = 0, len = points.length, j = len - 1; i < len; j = i++) {
63333         var a = points[i];
63334         var b = points[j];
63335         var f = a[0] * b[1] - b[0] * a[1];
63336         x += (a[0] + b[0]) * f;
63337         y += (a[1] + b[1]) * f;
63338         area += f * 3;
63339     }
63340     if (area === 0) return new Cell(points[0][0], points[0][1], 0, polygon);
63341     return new Cell(x / area, y / area, 0, polygon);
63342 }
63343
63344 // get squared distance from a point to a segment
63345 function getSegDistSq(px, py, a, b) {
63346
63347     var x = a[0];
63348     var y = a[1];
63349     var dx = b[0] - x;
63350     var dy = b[1] - y;
63351
63352     if (dx !== 0 || dy !== 0) {
63353
63354         var t = ((px - x) * dx + (py - y) * dy) / (dx * dx + dy * dy);
63355
63356         if (t > 1) {
63357             x = b[0];
63358             y = b[1];
63359
63360         } else if (t > 0) {
63361             x += dx * t;
63362             y += dy * t;
63363         }
63364     }
63365
63366     dx = px - x;
63367     dy = py - y;
63368
63369     return dx * dx + dy * dy;
63370 }
63371
63372 var polylabel$1 = polylabel$2.exports;
63373
63374 function DEFAULT_COMPARE (a, b) { return a > b ? 1 : a < b ? -1 : 0; }
63375
63376 class SplayTree {
63377
63378   constructor(compare = DEFAULT_COMPARE, noDuplicates = false) {
63379     this._compare = compare;
63380     this._root = null;
63381     this._size = 0;
63382     this._noDuplicates = !!noDuplicates;
63383   }
63384
63385
63386   rotateLeft(x) {
63387     var y = x.right;
63388     if (y) {
63389       x.right = y.left;
63390       if (y.left) y.left.parent = x;
63391       y.parent = x.parent;
63392     }
63393
63394     if (!x.parent)                this._root = y;
63395     else if (x === x.parent.left) x.parent.left = y;
63396     else                          x.parent.right = y;
63397     if (y) y.left = x;
63398     x.parent = y;
63399   }
63400
63401
63402   rotateRight(x) {
63403     var y = x.left;
63404     if (y) {
63405       x.left = y.right;
63406       if (y.right) y.right.parent = x;
63407       y.parent = x.parent;
63408     }
63409
63410     if (!x.parent)               this._root = y;
63411     else if(x === x.parent.left) x.parent.left = y;
63412     else                         x.parent.right = y;
63413     if (y) y.right = x;
63414     x.parent = y;
63415   }
63416
63417
63418   _splay(x) {
63419     while (x.parent) {
63420       var p = x.parent;
63421       if (!p.parent) {
63422         if (p.left === x) this.rotateRight(p);
63423         else              this.rotateLeft(p);
63424       } else if (p.left === x && p.parent.left === p) {
63425         this.rotateRight(p.parent);
63426         this.rotateRight(p);
63427       } else if (p.right === x && p.parent.right === p) {
63428         this.rotateLeft(p.parent);
63429         this.rotateLeft(p);
63430       } else if (p.left === x && p.parent.right === p) {
63431         this.rotateRight(p);
63432         this.rotateLeft(p);
63433       } else {
63434         this.rotateLeft(p);
63435         this.rotateRight(p);
63436       }
63437     }
63438   }
63439
63440
63441   splay(x) {
63442     var p, gp, ggp, l, r;
63443
63444     while (x.parent) {
63445       p = x.parent;
63446       gp = p.parent;
63447
63448       if (gp && gp.parent) {
63449         ggp = gp.parent;
63450         if (ggp.left === gp) ggp.left  = x;
63451         else                 ggp.right = x;
63452         x.parent = ggp;
63453       } else {
63454         x.parent = null;
63455         this._root = x;
63456       }
63457
63458       l = x.left; r = x.right;
63459
63460       if (x === p.left) { // left
63461         if (gp) {
63462           if (gp.left === p) {
63463             /* zig-zig */
63464             if (p.right) {
63465               gp.left = p.right;
63466               gp.left.parent = gp;
63467             } else gp.left = null;
63468
63469             p.right   = gp;
63470             gp.parent = p;
63471           } else {
63472             /* zig-zag */
63473             if (l) {
63474               gp.right = l;
63475               l.parent = gp;
63476             } else gp.right = null;
63477
63478             x.left    = gp;
63479             gp.parent = x;
63480           }
63481         }
63482         if (r) {
63483           p.left = r;
63484           r.parent = p;
63485         } else p.left = null;
63486
63487         x.right  = p;
63488         p.parent = x;
63489       } else { // right
63490         if (gp) {
63491           if (gp.right === p) {
63492             /* zig-zig */
63493             if (p.left) {
63494               gp.right = p.left;
63495               gp.right.parent = gp;
63496             } else gp.right = null;
63497
63498             p.left = gp;
63499             gp.parent = p;
63500           } else {
63501             /* zig-zag */
63502             if (r) {
63503               gp.left = r;
63504               r.parent = gp;
63505             } else gp.left = null;
63506
63507             x.right   = gp;
63508             gp.parent = x;
63509           }
63510         }
63511         if (l) {
63512           p.right = l;
63513           l.parent = p;
63514         } else p.right = null;
63515
63516         x.left   = p;
63517         p.parent = x;
63518       }
63519     }
63520   }
63521
63522
63523   replace(u, v) {
63524     if (!u.parent) this._root = v;
63525     else if (u === u.parent.left) u.parent.left = v;
63526     else u.parent.right = v;
63527     if (v) v.parent = u.parent;
63528   }
63529
63530
63531   minNode(u = this._root) {
63532     if (u) while (u.left) u = u.left;
63533     return u;
63534   }
63535
63536
63537   maxNode(u = this._root) {
63538     if (u) while (u.right) u = u.right;
63539     return u;
63540   }
63541
63542
63543   insert(key, data) {
63544     var z = this._root;
63545     var p = null;
63546     var comp = this._compare;
63547     var cmp;
63548
63549     if (this._noDuplicates) {
63550       while (z) {
63551         p = z;
63552         cmp = comp(z.key, key);
63553         if (cmp === 0) return;
63554         else if (comp(z.key, key) < 0) z = z.right;
63555         else z = z.left;
63556       }
63557     } else {
63558       while (z) {
63559         p = z;
63560         if (comp(z.key, key) < 0) z = z.right;
63561         else z = z.left;
63562       }
63563     }
63564
63565     z = { key, data, left: null, right: null, parent: p };
63566
63567     if (!p)                          this._root = z;
63568     else if (comp(p.key, z.key) < 0) p.right = z;
63569     else                             p.left  = z;
63570
63571     this.splay(z);
63572     this._size++;
63573     return z;
63574   }
63575
63576
63577   find (key) {
63578     var z    = this._root;
63579     var comp = this._compare;
63580     while (z) {
63581       var cmp = comp(z.key, key);
63582       if      (cmp < 0) z = z.right;
63583       else if (cmp > 0) z = z.left;
63584       else              return z;
63585     }
63586     return null;
63587   }
63588
63589   /**
63590    * Whether the tree contains a node with the given key
63591    * @param  {Key} key
63592    * @return {boolean} true/false
63593    */
63594   contains (key) {
63595     var node       = this._root;
63596     var comparator = this._compare;
63597     while (node)  {
63598       var cmp = comparator(key, node.key);
63599       if      (cmp === 0) return true;
63600       else if (cmp < 0)   node = node.left;
63601       else                node = node.right;
63602     }
63603
63604     return false;
63605   }
63606
63607
63608   remove (key) {
63609     var z = this.find(key);
63610
63611     if (!z) return false;
63612
63613     this.splay(z);
63614
63615     if (!z.left) this.replace(z, z.right);
63616     else if (!z.right) this.replace(z, z.left);
63617     else {
63618       var y = this.minNode(z.right);
63619       if (y.parent !== z) {
63620         this.replace(y, y.right);
63621         y.right = z.right;
63622         y.right.parent = y;
63623       }
63624       this.replace(z, y);
63625       y.left = z.left;
63626       y.left.parent = y;
63627     }
63628
63629     this._size--;
63630     return true;
63631   }
63632
63633
63634   removeNode(z) {
63635     if (!z) return false;
63636
63637     this.splay(z);
63638
63639     if (!z.left) this.replace(z, z.right);
63640     else if (!z.right) this.replace(z, z.left);
63641     else {
63642       var y = this.minNode(z.right);
63643       if (y.parent !== z) {
63644         this.replace(y, y.right);
63645         y.right = z.right;
63646         y.right.parent = y;
63647       }
63648       this.replace(z, y);
63649       y.left = z.left;
63650       y.left.parent = y;
63651     }
63652
63653     this._size--;
63654     return true;
63655   }
63656
63657
63658   erase (key) {
63659     var z = this.find(key);
63660     if (!z) return;
63661
63662     this.splay(z);
63663
63664     var s = z.left;
63665     var t = z.right;
63666
63667     var sMax = null;
63668     if (s) {
63669       s.parent = null;
63670       sMax = this.maxNode(s);
63671       this.splay(sMax);
63672       this._root = sMax;
63673     }
63674     if (t) {
63675       if (s) sMax.right = t;
63676       else   this._root = t;
63677       t.parent = sMax;
63678     }
63679
63680     this._size--;
63681   }
63682
63683   /**
63684    * Removes and returns the node with smallest key
63685    * @return {?Node}
63686    */
63687   pop () {
63688     var node = this._root, returnValue = null;
63689     if (node) {
63690       while (node.left) node = node.left;
63691       returnValue = { key: node.key, data: node.data };
63692       this.remove(node.key);
63693     }
63694     return returnValue;
63695   }
63696
63697
63698   /* eslint-disable class-methods-use-this */
63699
63700   /**
63701    * Successor node
63702    * @param  {Node} node
63703    * @return {?Node}
63704    */
63705   next (node) {
63706     var successor = node;
63707     if (successor) {
63708       if (successor.right) {
63709         successor = successor.right;
63710         while (successor && successor.left) successor = successor.left;
63711       } else {
63712         successor = node.parent;
63713         while (successor && successor.right === node) {
63714           node = successor; successor = successor.parent;
63715         }
63716       }
63717     }
63718     return successor;
63719   }
63720
63721
63722   /**
63723    * Predecessor node
63724    * @param  {Node} node
63725    * @return {?Node}
63726    */
63727   prev (node) {
63728     var predecessor = node;
63729     if (predecessor) {
63730       if (predecessor.left) {
63731         predecessor = predecessor.left;
63732         while (predecessor && predecessor.right) predecessor = predecessor.right;
63733       } else {
63734         predecessor = node.parent;
63735         while (predecessor && predecessor.left === node) {
63736           node = predecessor;
63737           predecessor = predecessor.parent;
63738         }
63739       }
63740     }
63741     return predecessor;
63742   }
63743   /* eslint-enable class-methods-use-this */
63744
63745
63746   /**
63747    * @param  {forEachCallback} callback
63748    * @return {SplayTree}
63749    */
63750   forEach(callback) {
63751     var current = this._root;
63752     var s = [], done = false, i = 0;
63753
63754     while (!done) {
63755       // Reach the left most Node of the current Node
63756       if (current) {
63757         // Place pointer to a tree node on the stack
63758         // before traversing the node's left subtree
63759         s.push(current);
63760         current = current.left;
63761       } else {
63762         // BackTrack from the empty subtree and visit the Node
63763         // at the top of the stack; however, if the stack is
63764         // empty you are done
63765         if (s.length > 0) {
63766           current = s.pop();
63767           callback(current, i++);
63768
63769           // We have visited the node and its left
63770           // subtree. Now, it's right subtree's turn
63771           current = current.right;
63772         } else done = true;
63773       }
63774     }
63775     return this;
63776   }
63777
63778
63779   /**
63780    * Walk key range from `low` to `high`. Stops if `fn` returns a value.
63781    * @param  {Key}      low
63782    * @param  {Key}      high
63783    * @param  {Function} fn
63784    * @param  {*?}       ctx
63785    * @return {SplayTree}
63786    */
63787   range(low, high, fn, ctx) {
63788     const Q = [];
63789     const compare = this._compare;
63790     let node = this._root, cmp;
63791
63792     while (Q.length !== 0 || node) {
63793       if (node) {
63794         Q.push(node);
63795         node = node.left;
63796       } else {
63797         node = Q.pop();
63798         cmp = compare(node.key, high);
63799         if (cmp > 0) {
63800           break;
63801         } else if (compare(node.key, low) >= 0) {
63802           if (fn.call(ctx, node)) return this; // stop if smth is returned
63803         }
63804         node = node.right;
63805       }
63806     }
63807     return this;
63808   }
63809
63810   /**
63811    * Returns all keys in order
63812    * @return {Array<Key>}
63813    */
63814   keys () {
63815     var current = this._root;
63816     var s = [], r = [], done = false;
63817
63818     while (!done) {
63819       if (current) {
63820         s.push(current);
63821         current = current.left;
63822       } else {
63823         if (s.length > 0) {
63824           current = s.pop();
63825           r.push(current.key);
63826           current = current.right;
63827         } else done = true;
63828       }
63829     }
63830     return r;
63831   }
63832
63833
63834   /**
63835    * Returns `data` fields of all nodes in order.
63836    * @return {Array<Value>}
63837    */
63838   values () {
63839     var current = this._root;
63840     var s = [], r = [], done = false;
63841
63842     while (!done) {
63843       if (current) {
63844         s.push(current);
63845         current = current.left;
63846       } else {
63847         if (s.length > 0) {
63848           current = s.pop();
63849           r.push(current.data);
63850           current = current.right;
63851         } else done = true;
63852       }
63853     }
63854     return r;
63855   }
63856
63857
63858   /**
63859    * Returns node at given index
63860    * @param  {number} index
63861    * @return {?Node}
63862    */
63863   at (index) {
63864     // removed after a consideration, more misleading than useful
63865     // index = index % this.size;
63866     // if (index < 0) index = this.size - index;
63867
63868     var current = this._root;
63869     var s = [], done = false, i = 0;
63870
63871     while (!done) {
63872       if (current) {
63873         s.push(current);
63874         current = current.left;
63875       } else {
63876         if (s.length > 0) {
63877           current = s.pop();
63878           if (i === index) return current;
63879           i++;
63880           current = current.right;
63881         } else done = true;
63882       }
63883     }
63884     return null;
63885   }
63886
63887   /**
63888    * Bulk-load items. Both array have to be same size
63889    * @param  {Array<Key>}    keys
63890    * @param  {Array<Value>}  [values]
63891    * @param  {Boolean}       [presort=false] Pre-sort keys and values, using
63892    *                                         tree's comparator. Sorting is done
63893    *                                         in-place
63894    * @return {AVLTree}
63895    */
63896   load(keys = [], values = [], presort = false) {
63897     if (this._size !== 0) throw new Error('bulk-load: tree is not empty');
63898     const size = keys.length;
63899     if (presort) sort(keys, values, 0, size - 1, this._compare);
63900     this._root = loadRecursive(null, keys, values, 0, size);
63901     this._size = size;
63902     return this;
63903   }
63904
63905
63906   min() {
63907     var node = this.minNode(this._root);
63908     if (node) return node.key;
63909     else      return null;
63910   }
63911
63912
63913   max() {
63914     var node = this.maxNode(this._root);
63915     if (node) return node.key;
63916     else      return null;
63917   }
63918
63919   isEmpty() { return this._root === null; }
63920   get size() { return this._size; }
63921
63922
63923   /**
63924    * Create a tree and load it with items
63925    * @param  {Array<Key>}          keys
63926    * @param  {Array<Value>?}        [values]
63927
63928    * @param  {Function?}            [comparator]
63929    * @param  {Boolean?}             [presort=false] Pre-sort keys and values, using
63930    *                                               tree's comparator. Sorting is done
63931    *                                               in-place
63932    * @param  {Boolean?}             [noDuplicates=false]   Allow duplicates
63933    * @return {SplayTree}
63934    */
63935   static createTree(keys, values, comparator, presort, noDuplicates) {
63936     return new SplayTree(comparator, noDuplicates).load(keys, values, presort);
63937   }
63938 }
63939
63940
63941 function loadRecursive (parent, keys, values, start, end) {
63942   const size = end - start;
63943   if (size > 0) {
63944     const middle = start + Math.floor(size / 2);
63945     const key    = keys[middle];
63946     const data   = values[middle];
63947     const node   = { key, data, parent };
63948     node.left    = loadRecursive(node, keys, values, start, middle);
63949     node.right   = loadRecursive(node, keys, values, middle + 1, end);
63950     return node;
63951   }
63952   return null;
63953 }
63954
63955
63956 function sort(keys, values, left, right, compare) {
63957   if (left >= right) return;
63958
63959   const pivot = keys[(left + right) >> 1];
63960   let i = left - 1;
63961   let j = right + 1;
63962
63963   while (true) {
63964     do i++; while (compare(keys[i], pivot) < 0);
63965     do j--; while (compare(keys[j], pivot) > 0);
63966     if (i >= j) break;
63967
63968     let tmp = keys[i];
63969     keys[i] = keys[j];
63970     keys[j] = tmp;
63971
63972     tmp = values[i];
63973     values[i] = values[j];
63974     values[j] = tmp;
63975   }
63976
63977   sort(keys, values,  left,     j, compare);
63978   sort(keys, values, j + 1, right, compare);
63979 }
63980
63981 const NORMAL               = 0;
63982 const NON_CONTRIBUTING     = 1;
63983 const SAME_TRANSITION      = 2;
63984 const DIFFERENT_TRANSITION = 3;
63985
63986 const INTERSECTION = 0;
63987 const UNION        = 1;
63988 const DIFFERENCE   = 2;
63989 const XOR          = 3;
63990
63991 /**
63992  * @param  {SweepEvent} event
63993  * @param  {SweepEvent} prev
63994  * @param  {Operation} operation
63995  */
63996 function computeFields (event, prev, operation) {
63997   // compute inOut and otherInOut fields
63998   if (prev === null) {
63999     event.inOut      = false;
64000     event.otherInOut = true;
64001
64002   // previous line segment in sweepline belongs to the same polygon
64003   } else {
64004     if (event.isSubject === prev.isSubject) {
64005       event.inOut      = !prev.inOut;
64006       event.otherInOut = prev.otherInOut;
64007
64008     // previous line segment in sweepline belongs to the clipping polygon
64009     } else {
64010       event.inOut      = !prev.otherInOut;
64011       event.otherInOut = prev.isVertical() ? !prev.inOut : prev.inOut;
64012     }
64013
64014     // compute prevInResult field
64015     if (prev) {
64016       event.prevInResult = (!inResult(prev, operation) || prev.isVertical())
64017         ? prev.prevInResult : prev;
64018     }
64019   }
64020
64021   // check if the line segment belongs to the Boolean operation
64022   let isInResult = inResult(event, operation);
64023   if (isInResult) {
64024     event.resultTransition = determineResultTransition(event, operation);
64025   } else {
64026     event.resultTransition = 0;
64027   }
64028 }
64029
64030
64031 /* eslint-disable indent */
64032 function inResult(event, operation) {
64033   switch (event.type) {
64034     case NORMAL:
64035       switch (operation) {
64036         case INTERSECTION:
64037           return !event.otherInOut;
64038         case UNION:
64039           return event.otherInOut;
64040         case DIFFERENCE:
64041           // return (event.isSubject && !event.otherInOut) ||
64042           //         (!event.isSubject && event.otherInOut);
64043           return (event.isSubject && event.otherInOut) ||
64044                   (!event.isSubject && !event.otherInOut);
64045         case XOR:
64046           return true;
64047       }
64048       break;
64049     case SAME_TRANSITION:
64050       return operation === INTERSECTION || operation === UNION;
64051     case DIFFERENT_TRANSITION:
64052       return operation === DIFFERENCE;
64053     case NON_CONTRIBUTING:
64054       return false;
64055   }
64056   return false;
64057 }
64058 /* eslint-enable indent */
64059
64060
64061 function determineResultTransition(event, operation) {
64062   let thisIn = !event.inOut;
64063   let thatIn = !event.otherInOut;
64064
64065   let isIn;
64066   switch (operation) {
64067     case INTERSECTION:
64068       isIn = thisIn && thatIn; break;
64069     case UNION:
64070       isIn = thisIn || thatIn; break;
64071     case XOR:
64072       isIn = thisIn ^ thatIn; break;
64073     case DIFFERENCE:
64074       if (event.isSubject) {
64075         isIn = thisIn && !thatIn;
64076       } else {
64077         isIn = thatIn && !thisIn;
64078       }
64079       break;
64080   }
64081   return isIn ? +1 : -1;
64082 }
64083
64084 class SweepEvent {
64085
64086
64087   /**
64088    * Sweepline event
64089    *
64090    * @class {SweepEvent}
64091    * @param {Array.<Number>}  point
64092    * @param {Boolean}         left
64093    * @param {SweepEvent=}     otherEvent
64094    * @param {Boolean}         isSubject
64095    * @param {Number}          edgeType
64096    */
64097   constructor (point, left, otherEvent, isSubject, edgeType) {
64098
64099     /**
64100      * Is left endpoint?
64101      * @type {Boolean}
64102      */
64103     this.left = left;
64104
64105     /**
64106      * @type {Array.<Number>}
64107      */
64108     this.point = point;
64109
64110     /**
64111      * Other edge reference
64112      * @type {SweepEvent}
64113      */
64114     this.otherEvent = otherEvent;
64115
64116     /**
64117      * Belongs to source or clipping polygon
64118      * @type {Boolean}
64119      */
64120     this.isSubject = isSubject;
64121
64122     /**
64123      * Edge contribution type
64124      * @type {Number}
64125      */
64126     this.type = edgeType || NORMAL;
64127
64128
64129     /**
64130      * In-out transition for the sweepline crossing polygon
64131      * @type {Boolean}
64132      */
64133     this.inOut = false;
64134
64135
64136     /**
64137      * @type {Boolean}
64138      */
64139     this.otherInOut = false;
64140
64141     /**
64142      * Previous event in result?
64143      * @type {SweepEvent}
64144      */
64145     this.prevInResult = null;
64146
64147     /**
64148      * Type of result transition (0 = not in result, +1 = out-in, -1, in-out)
64149      * @type {Number}
64150      */
64151     this.resultTransition = 0;
64152
64153     // connection step
64154
64155     /**
64156      * @type {Number}
64157      */
64158     this.otherPos = -1;
64159
64160     /**
64161      * @type {Number}
64162      */
64163     this.outputContourId = -1;
64164
64165     this.isExteriorRing = true;   // TODO: Looks unused, remove?
64166   }
64167
64168
64169   /**
64170    * @param  {Array.<Number>}  p
64171    * @return {Boolean}
64172    */
64173   isBelow (p) {
64174     const p0 = this.point, p1 = this.otherEvent.point;
64175     return this.left
64176       ? (p0[0] - p[0]) * (p1[1] - p[1]) - (p1[0] - p[0]) * (p0[1] - p[1]) > 0
64177       // signedArea(this.point, this.otherEvent.point, p) > 0 :
64178       : (p1[0] - p[0]) * (p0[1] - p[1]) - (p0[0] - p[0]) * (p1[1] - p[1]) > 0;
64179       //signedArea(this.otherEvent.point, this.point, p) > 0;
64180   }
64181
64182
64183   /**
64184    * @param  {Array.<Number>}  p
64185    * @return {Boolean}
64186    */
64187   isAbove (p) {
64188     return !this.isBelow(p);
64189   }
64190
64191
64192   /**
64193    * @return {Boolean}
64194    */
64195   isVertical () {
64196     return this.point[0] === this.otherEvent.point[0];
64197   }
64198
64199
64200   /**
64201    * Does event belong to result?
64202    * @return {Boolean}
64203    */
64204   get inResult() {
64205     return this.resultTransition !== 0;
64206   }
64207
64208
64209   clone () {
64210     const copy = new SweepEvent(
64211       this.point, this.left, this.otherEvent, this.isSubject, this.type);
64212
64213     copy.contourId        = this.contourId;
64214     copy.resultTransition = this.resultTransition;
64215     copy.prevInResult     = this.prevInResult;
64216     copy.isExteriorRing   = this.isExteriorRing;
64217     copy.inOut            = this.inOut;
64218     copy.otherInOut       = this.otherInOut;
64219
64220     return copy;
64221   }
64222 }
64223
64224 function equals(p1, p2) {
64225   if (p1[0] === p2[0]) {
64226     if (p1[1] === p2[1]) {
64227       return true;
64228     } else {
64229       return false;
64230     }
64231   }
64232   return false;
64233 }
64234
64235 // const EPSILON = 1e-9;
64236 // const abs = Math.abs;
64237 // TODO https://github.com/w8r/martinez/issues/6#issuecomment-262847164
64238 // Precision problem.
64239 //
64240 // module.exports = function equals(p1, p2) {
64241 //   return abs(p1[0] - p2[0]) <= EPSILON && abs(p1[1] - p2[1]) <= EPSILON;
64242 // };
64243
64244 const epsilon = 1.1102230246251565e-16;
64245 const splitter = 134217729;
64246 const resulterrbound = (3 + 8 * epsilon) * epsilon;
64247
64248 // fast_expansion_sum_zeroelim routine from oritinal code
64249 function sum(elen, e, flen, f, h) {
64250     let Q, Qnew, hh, bvirt;
64251     let enow = e[0];
64252     let fnow = f[0];
64253     let eindex = 0;
64254     let findex = 0;
64255     if ((fnow > enow) === (fnow > -enow)) {
64256         Q = enow;
64257         enow = e[++eindex];
64258     } else {
64259         Q = fnow;
64260         fnow = f[++findex];
64261     }
64262     let hindex = 0;
64263     if (eindex < elen && findex < flen) {
64264         if ((fnow > enow) === (fnow > -enow)) {
64265             Qnew = enow + Q;
64266             hh = Q - (Qnew - enow);
64267             enow = e[++eindex];
64268         } else {
64269             Qnew = fnow + Q;
64270             hh = Q - (Qnew - fnow);
64271             fnow = f[++findex];
64272         }
64273         Q = Qnew;
64274         if (hh !== 0) {
64275             h[hindex++] = hh;
64276         }
64277         while (eindex < elen && findex < flen) {
64278             if ((fnow > enow) === (fnow > -enow)) {
64279                 Qnew = Q + enow;
64280                 bvirt = Qnew - Q;
64281                 hh = Q - (Qnew - bvirt) + (enow - bvirt);
64282                 enow = e[++eindex];
64283             } else {
64284                 Qnew = Q + fnow;
64285                 bvirt = Qnew - Q;
64286                 hh = Q - (Qnew - bvirt) + (fnow - bvirt);
64287                 fnow = f[++findex];
64288             }
64289             Q = Qnew;
64290             if (hh !== 0) {
64291                 h[hindex++] = hh;
64292             }
64293         }
64294     }
64295     while (eindex < elen) {
64296         Qnew = Q + enow;
64297         bvirt = Qnew - Q;
64298         hh = Q - (Qnew - bvirt) + (enow - bvirt);
64299         enow = e[++eindex];
64300         Q = Qnew;
64301         if (hh !== 0) {
64302             h[hindex++] = hh;
64303         }
64304     }
64305     while (findex < flen) {
64306         Qnew = Q + fnow;
64307         bvirt = Qnew - Q;
64308         hh = Q - (Qnew - bvirt) + (fnow - bvirt);
64309         fnow = f[++findex];
64310         Q = Qnew;
64311         if (hh !== 0) {
64312             h[hindex++] = hh;
64313         }
64314     }
64315     if (Q !== 0 || hindex === 0) {
64316         h[hindex++] = Q;
64317     }
64318     return hindex;
64319 }
64320
64321 function estimate(elen, e) {
64322     let Q = e[0];
64323     for (let i = 1; i < elen; i++) Q += e[i];
64324     return Q;
64325 }
64326
64327 function vec(n) {
64328     return new Float64Array(n);
64329 }
64330
64331 const ccwerrboundA = (3 + 16 * epsilon) * epsilon;
64332 const ccwerrboundB = (2 + 12 * epsilon) * epsilon;
64333 const ccwerrboundC = (9 + 64 * epsilon) * epsilon * epsilon;
64334
64335 const B = vec(4);
64336 const C1 = vec(8);
64337 const C2 = vec(12);
64338 const D = vec(16);
64339 const u = vec(4);
64340
64341 function orient2dadapt(ax, ay, bx, by, cx, cy, detsum) {
64342     let acxtail, acytail, bcxtail, bcytail;
64343     let bvirt, c, ahi, alo, bhi, blo, _i, _j, _0, s1, s0, t1, t0, u3;
64344
64345     const acx = ax - cx;
64346     const bcx = bx - cx;
64347     const acy = ay - cy;
64348     const bcy = by - cy;
64349
64350     s1 = acx * bcy;
64351     c = splitter * acx;
64352     ahi = c - (c - acx);
64353     alo = acx - ahi;
64354     c = splitter * bcy;
64355     bhi = c - (c - bcy);
64356     blo = bcy - bhi;
64357     s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
64358     t1 = acy * bcx;
64359     c = splitter * acy;
64360     ahi = c - (c - acy);
64361     alo = acy - ahi;
64362     c = splitter * bcx;
64363     bhi = c - (c - bcx);
64364     blo = bcx - bhi;
64365     t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
64366     _i = s0 - t0;
64367     bvirt = s0 - _i;
64368     B[0] = s0 - (_i + bvirt) + (bvirt - t0);
64369     _j = s1 + _i;
64370     bvirt = _j - s1;
64371     _0 = s1 - (_j - bvirt) + (_i - bvirt);
64372     _i = _0 - t1;
64373     bvirt = _0 - _i;
64374     B[1] = _0 - (_i + bvirt) + (bvirt - t1);
64375     u3 = _j + _i;
64376     bvirt = u3 - _j;
64377     B[2] = _j - (u3 - bvirt) + (_i - bvirt);
64378     B[3] = u3;
64379
64380     let det = estimate(4, B);
64381     let errbound = ccwerrboundB * detsum;
64382     if (det >= errbound || -det >= errbound) {
64383         return det;
64384     }
64385
64386     bvirt = ax - acx;
64387     acxtail = ax - (acx + bvirt) + (bvirt - cx);
64388     bvirt = bx - bcx;
64389     bcxtail = bx - (bcx + bvirt) + (bvirt - cx);
64390     bvirt = ay - acy;
64391     acytail = ay - (acy + bvirt) + (bvirt - cy);
64392     bvirt = by - bcy;
64393     bcytail = by - (bcy + bvirt) + (bvirt - cy);
64394
64395     if (acxtail === 0 && acytail === 0 && bcxtail === 0 && bcytail === 0) {
64396         return det;
64397     }
64398
64399     errbound = ccwerrboundC * detsum + resulterrbound * Math.abs(det);
64400     det += (acx * bcytail + bcy * acxtail) - (acy * bcxtail + bcx * acytail);
64401     if (det >= errbound || -det >= errbound) return det;
64402
64403     s1 = acxtail * bcy;
64404     c = splitter * acxtail;
64405     ahi = c - (c - acxtail);
64406     alo = acxtail - ahi;
64407     c = splitter * bcy;
64408     bhi = c - (c - bcy);
64409     blo = bcy - bhi;
64410     s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
64411     t1 = acytail * bcx;
64412     c = splitter * acytail;
64413     ahi = c - (c - acytail);
64414     alo = acytail - ahi;
64415     c = splitter * bcx;
64416     bhi = c - (c - bcx);
64417     blo = bcx - bhi;
64418     t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
64419     _i = s0 - t0;
64420     bvirt = s0 - _i;
64421     u[0] = s0 - (_i + bvirt) + (bvirt - t0);
64422     _j = s1 + _i;
64423     bvirt = _j - s1;
64424     _0 = s1 - (_j - bvirt) + (_i - bvirt);
64425     _i = _0 - t1;
64426     bvirt = _0 - _i;
64427     u[1] = _0 - (_i + bvirt) + (bvirt - t1);
64428     u3 = _j + _i;
64429     bvirt = u3 - _j;
64430     u[2] = _j - (u3 - bvirt) + (_i - bvirt);
64431     u[3] = u3;
64432     const C1len = sum(4, B, 4, u, C1);
64433
64434     s1 = acx * bcytail;
64435     c = splitter * acx;
64436     ahi = c - (c - acx);
64437     alo = acx - ahi;
64438     c = splitter * bcytail;
64439     bhi = c - (c - bcytail);
64440     blo = bcytail - bhi;
64441     s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
64442     t1 = acy * bcxtail;
64443     c = splitter * acy;
64444     ahi = c - (c - acy);
64445     alo = acy - ahi;
64446     c = splitter * bcxtail;
64447     bhi = c - (c - bcxtail);
64448     blo = bcxtail - bhi;
64449     t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
64450     _i = s0 - t0;
64451     bvirt = s0 - _i;
64452     u[0] = s0 - (_i + bvirt) + (bvirt - t0);
64453     _j = s1 + _i;
64454     bvirt = _j - s1;
64455     _0 = s1 - (_j - bvirt) + (_i - bvirt);
64456     _i = _0 - t1;
64457     bvirt = _0 - _i;
64458     u[1] = _0 - (_i + bvirt) + (bvirt - t1);
64459     u3 = _j + _i;
64460     bvirt = u3 - _j;
64461     u[2] = _j - (u3 - bvirt) + (_i - bvirt);
64462     u[3] = u3;
64463     const C2len = sum(C1len, C1, 4, u, C2);
64464
64465     s1 = acxtail * bcytail;
64466     c = splitter * acxtail;
64467     ahi = c - (c - acxtail);
64468     alo = acxtail - ahi;
64469     c = splitter * bcytail;
64470     bhi = c - (c - bcytail);
64471     blo = bcytail - bhi;
64472     s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
64473     t1 = acytail * bcxtail;
64474     c = splitter * acytail;
64475     ahi = c - (c - acytail);
64476     alo = acytail - ahi;
64477     c = splitter * bcxtail;
64478     bhi = c - (c - bcxtail);
64479     blo = bcxtail - bhi;
64480     t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
64481     _i = s0 - t0;
64482     bvirt = s0 - _i;
64483     u[0] = s0 - (_i + bvirt) + (bvirt - t0);
64484     _j = s1 + _i;
64485     bvirt = _j - s1;
64486     _0 = s1 - (_j - bvirt) + (_i - bvirt);
64487     _i = _0 - t1;
64488     bvirt = _0 - _i;
64489     u[1] = _0 - (_i + bvirt) + (bvirt - t1);
64490     u3 = _j + _i;
64491     bvirt = u3 - _j;
64492     u[2] = _j - (u3 - bvirt) + (_i - bvirt);
64493     u[3] = u3;
64494     const Dlen = sum(C2len, C2, 4, u, D);
64495
64496     return D[Dlen - 1];
64497 }
64498
64499 function orient2d(ax, ay, bx, by, cx, cy) {
64500     const detleft = (ay - cy) * (bx - cx);
64501     const detright = (ax - cx) * (by - cy);
64502     const det = detleft - detright;
64503
64504     if (detleft === 0 || detright === 0 || (detleft > 0) !== (detright > 0)) return det;
64505
64506     const detsum = Math.abs(detleft + detright);
64507     if (Math.abs(det) >= ccwerrboundA * detsum) return det;
64508
64509     return -orient2dadapt(ax, ay, bx, by, cx, cy, detsum);
64510 }
64511
64512 /**
64513  * Signed area of the triangle (p0, p1, p2)
64514  * @param  {Array.<Number>} p0
64515  * @param  {Array.<Number>} p1
64516  * @param  {Array.<Number>} p2
64517  * @return {Number}
64518  */
64519 function signedArea(p0, p1, p2) {
64520   const res = orient2d(p0[0], p0[1], p1[0], p1[1], p2[0], p2[1]);
64521   if (res > 0) return -1;
64522   if (res < 0) return 1;
64523   return 0;
64524 }
64525
64526 /**
64527  * @param  {SweepEvent} e1
64528  * @param  {SweepEvent} e2
64529  * @return {Number}
64530  */
64531 function compareEvents(e1, e2) {
64532   const p1 = e1.point;
64533   const p2 = e2.point;
64534
64535   // Different x-coordinate
64536   if (p1[0] > p2[0]) return 1;
64537   if (p1[0] < p2[0]) return -1;
64538
64539   // Different points, but same x-coordinate
64540   // Event with lower y-coordinate is processed first
64541   if (p1[1] !== p2[1]) return p1[1] > p2[1] ? 1 : -1;
64542
64543   return specialCases(e1, e2, p1);
64544 }
64545
64546
64547 /* eslint-disable no-unused-vars */
64548 function specialCases(e1, e2, p1, p2) {
64549   // Same coordinates, but one is a left endpoint and the other is
64550   // a right endpoint. The right endpoint is processed first
64551   if (e1.left !== e2.left)
64552     return e1.left ? 1 : -1;
64553
64554   // const p2 = e1.otherEvent.point, p3 = e2.otherEvent.point;
64555   // const sa = (p1[0] - p3[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p3[1])
64556   // Same coordinates, both events
64557   // are left endpoints or right endpoints.
64558   // not collinear
64559   if (signedArea(p1, e1.otherEvent.point, e2.otherEvent.point) !== 0) {
64560     // the event associate to the bottom segment is processed first
64561     return (!e1.isBelow(e2.otherEvent.point)) ? 1 : -1;
64562   }
64563
64564   return (!e1.isSubject && e2.isSubject) ? 1 : -1;
64565 }
64566 /* eslint-enable no-unused-vars */
64567
64568 /**
64569  * @param  {SweepEvent} se
64570  * @param  {Array.<Number>} p
64571  * @param  {Queue} queue
64572  * @return {Queue}
64573  */
64574 function divideSegment(se, p, queue)  {
64575   const r = new SweepEvent(p, false, se,            se.isSubject);
64576   const l = new SweepEvent(p, true,  se.otherEvent, se.isSubject);
64577
64578   /* eslint-disable no-console */
64579   if (equals(se.point, se.otherEvent.point)) {
64580     console.warn('what is that, a collapsed segment?', se);
64581   }
64582   /* eslint-enable no-console */
64583
64584   r.contourId = l.contourId = se.contourId;
64585
64586   // avoid a rounding error. The left event would be processed after the right event
64587   if (compareEvents(l, se.otherEvent) > 0) {
64588     se.otherEvent.left = true;
64589     l.left = false;
64590   }
64591
64592   // avoid a rounding error. The left event would be processed after the right event
64593   // if (compareEvents(se, r) > 0) {}
64594
64595   se.otherEvent.otherEvent = l;
64596   se.otherEvent = r;
64597
64598   queue.push(l);
64599   queue.push(r);
64600
64601   return queue;
64602 }
64603
64604 //const EPS = 1e-9;
64605
64606 /**
64607  * Finds the magnitude of the cross product of two vectors (if we pretend
64608  * they're in three dimensions)
64609  *
64610  * @param {Object} a First vector
64611  * @param {Object} b Second vector
64612  * @private
64613  * @returns {Number} The magnitude of the cross product
64614  */
64615 function crossProduct(a, b) {
64616   return (a[0] * b[1]) - (a[1] * b[0]);
64617 }
64618
64619 /**
64620  * Finds the dot product of two vectors.
64621  *
64622  * @param {Object} a First vector
64623  * @param {Object} b Second vector
64624  * @private
64625  * @returns {Number} The dot product
64626  */
64627 function dotProduct(a, b) {
64628   return (a[0] * b[0]) + (a[1] * b[1]);
64629 }
64630
64631 /**
64632  * Finds the intersection (if any) between two line segments a and b, given the
64633  * line segments' end points a1, a2 and b1, b2.
64634  *
64635  * This algorithm is based on Schneider and Eberly.
64636  * http://www.cimec.org.ar/~ncalvo/Schneider_Eberly.pdf
64637  * Page 244.
64638  *
64639  * @param {Array.<Number>} a1 point of first line
64640  * @param {Array.<Number>} a2 point of first line
64641  * @param {Array.<Number>} b1 point of second line
64642  * @param {Array.<Number>} b2 point of second line
64643  * @param {Boolean=}       noEndpointTouch whether to skip single touchpoints
64644  *                                         (meaning connected segments) as
64645  *                                         intersections
64646  * @returns {Array.<Array.<Number>>|Null} If the lines intersect, the point of
64647  * intersection. If they overlap, the two end points of the overlapping segment.
64648  * Otherwise, null.
64649  */
64650 function intersection$1 (a1, a2, b1, b2, noEndpointTouch) {
64651   // The algorithm expects our lines in the form P + sd, where P is a point,
64652   // s is on the interval [0, 1], and d is a vector.
64653   // We are passed two points. P can be the first point of each pair. The
64654   // vector, then, could be thought of as the distance (in x and y components)
64655   // from the first point to the second point.
64656   // So first, let's make our vectors:
64657   const va = [a2[0] - a1[0], a2[1] - a1[1]];
64658   const vb = [b2[0] - b1[0], b2[1] - b1[1]];
64659   // We also define a function to convert back to regular point form:
64660
64661   /* eslint-disable arrow-body-style */
64662
64663   function toPoint(p, s, d) {
64664     return [
64665       p[0] + s * d[0],
64666       p[1] + s * d[1]
64667     ];
64668   }
64669
64670   /* eslint-enable arrow-body-style */
64671
64672   // The rest is pretty much a straight port of the algorithm.
64673   const e = [b1[0] - a1[0], b1[1] - a1[1]];
64674   let kross    = crossProduct(va, vb);
64675   let sqrKross = kross * kross;
64676   const sqrLenA  = dotProduct(va, va);
64677   //const sqrLenB  = dotProduct(vb, vb);
64678
64679   // Check for line intersection. This works because of the properties of the
64680   // cross product -- specifically, two vectors are parallel if and only if the
64681   // cross product is the 0 vector. The full calculation involves relative error
64682   // to account for possible very small line segments. See Schneider & Eberly
64683   // for details.
64684   if (sqrKross > 0/* EPS * sqrLenB * sqLenA */) {
64685     // If they're not parallel, then (because these are line segments) they
64686     // still might not actually intersect. This code checks that the
64687     // intersection point of the lines is actually on both line segments.
64688     const s = crossProduct(e, vb) / kross;
64689     if (s < 0 || s > 1) {
64690       // not on line segment a
64691       return null;
64692     }
64693     const t = crossProduct(e, va) / kross;
64694     if (t < 0 || t > 1) {
64695       // not on line segment b
64696       return null;
64697     }
64698     if (s === 0 || s === 1) {
64699       // on an endpoint of line segment a
64700       return noEndpointTouch ? null : [toPoint(a1, s, va)];
64701     }
64702     if (t === 0 || t === 1) {
64703       // on an endpoint of line segment b
64704       return noEndpointTouch ? null : [toPoint(b1, t, vb)];
64705     }
64706     return [toPoint(a1, s, va)];
64707   }
64708
64709   // If we've reached this point, then the lines are either parallel or the
64710   // same, but the segments could overlap partially or fully, or not at all.
64711   // So we need to find the overlap, if any. To do that, we can use e, which is
64712   // the (vector) difference between the two initial points. If this is parallel
64713   // with the line itself, then the two lines are the same line, and there will
64714   // be overlap.
64715   //const sqrLenE = dotProduct(e, e);
64716   kross = crossProduct(e, va);
64717   sqrKross = kross * kross;
64718
64719   if (sqrKross > 0 /* EPS * sqLenB * sqLenE */) {
64720   // Lines are just parallel, not the same. No overlap.
64721     return null;
64722   }
64723
64724   const sa = dotProduct(va, e) / sqrLenA;
64725   const sb = sa + dotProduct(va, vb) / sqrLenA;
64726   const smin = Math.min(sa, sb);
64727   const smax = Math.max(sa, sb);
64728
64729   // this is, essentially, the FindIntersection acting on floats from
64730   // Schneider & Eberly, just inlined into this function.
64731   if (smin <= 1 && smax >= 0) {
64732
64733     // overlap on an end point
64734     if (smin === 1) {
64735       return noEndpointTouch ? null : [toPoint(a1, smin > 0 ? smin : 0, va)];
64736     }
64737
64738     if (smax === 0) {
64739       return noEndpointTouch ? null : [toPoint(a1, smax < 1 ? smax : 1, va)];
64740     }
64741
64742     if (noEndpointTouch && smin === 0 && smax === 1) return null;
64743
64744     // There's overlap on a segment -- two points of intersection. Return both.
64745     return [
64746       toPoint(a1, smin > 0 ? smin : 0, va),
64747       toPoint(a1, smax < 1 ? smax : 1, va)
64748     ];
64749   }
64750
64751   return null;
64752 }
64753
64754 /**
64755  * @param  {SweepEvent} se1
64756  * @param  {SweepEvent} se2
64757  * @param  {Queue}      queue
64758  * @return {Number}
64759  */
64760 function possibleIntersection (se1, se2, queue) {
64761   // that disallows self-intersecting polygons,
64762   // did cost us half a day, so I'll leave it
64763   // out of respect
64764   // if (se1.isSubject === se2.isSubject) return;
64765   const inter = intersection$1(
64766     se1.point, se1.otherEvent.point,
64767     se2.point, se2.otherEvent.point
64768   );
64769
64770   const nintersections = inter ? inter.length : 0;
64771   if (nintersections === 0) return 0; // no intersection
64772
64773   // the line segments intersect at an endpoint of both line segments
64774   if ((nintersections === 1) &&
64775       (equals(se1.point, se2.point) ||
64776        equals(se1.otherEvent.point, se2.otherEvent.point))) {
64777     return 0;
64778   }
64779
64780   if (nintersections === 2 && se1.isSubject === se2.isSubject) {
64781     // if(se1.contourId === se2.contourId){
64782     // console.warn('Edges of the same polygon overlap',
64783     //   se1.point, se1.otherEvent.point, se2.point, se2.otherEvent.point);
64784     // }
64785     //throw new Error('Edges of the same polygon overlap');
64786     return 0;
64787   }
64788
64789   // The line segments associated to se1 and se2 intersect
64790   if (nintersections === 1) {
64791
64792     // if the intersection point is not an endpoint of se1
64793     if (!equals(se1.point, inter[0]) && !equals(se1.otherEvent.point, inter[0])) {
64794       divideSegment(se1, inter[0], queue);
64795     }
64796
64797     // if the intersection point is not an endpoint of se2
64798     if (!equals(se2.point, inter[0]) && !equals(se2.otherEvent.point, inter[0])) {
64799       divideSegment(se2, inter[0], queue);
64800     }
64801     return 1;
64802   }
64803
64804   // The line segments associated to se1 and se2 overlap
64805   const events        = [];
64806   let leftCoincide  = false;
64807   let rightCoincide = false;
64808
64809   if (equals(se1.point, se2.point)) {
64810     leftCoincide = true; // linked
64811   } else if (compareEvents(se1, se2) === 1) {
64812     events.push(se2, se1);
64813   } else {
64814     events.push(se1, se2);
64815   }
64816
64817   if (equals(se1.otherEvent.point, se2.otherEvent.point)) {
64818     rightCoincide = true;
64819   } else if (compareEvents(se1.otherEvent, se2.otherEvent) === 1) {
64820     events.push(se2.otherEvent, se1.otherEvent);
64821   } else {
64822     events.push(se1.otherEvent, se2.otherEvent);
64823   }
64824
64825   if ((leftCoincide && rightCoincide) || leftCoincide) {
64826     // both line segments are equal or share the left endpoint
64827     se2.type = NON_CONTRIBUTING;
64828     se1.type = (se2.inOut === se1.inOut)
64829       ? SAME_TRANSITION : DIFFERENT_TRANSITION;
64830
64831     if (leftCoincide && !rightCoincide) {
64832       // honestly no idea, but changing events selection from [2, 1]
64833       // to [0, 1] fixes the overlapping self-intersecting polygons issue
64834       divideSegment(events[1].otherEvent, events[0].point, queue);
64835     }
64836     return 2;
64837   }
64838
64839   // the line segments share the right endpoint
64840   if (rightCoincide) {
64841     divideSegment(events[0], events[1].point, queue);
64842     return 3;
64843   }
64844
64845   // no line segment includes totally the other one
64846   if (events[0] !== events[3].otherEvent) {
64847     divideSegment(events[0], events[1].point, queue);
64848     divideSegment(events[1], events[2].point, queue);
64849     return 3;
64850   }
64851
64852   // one line segment includes the other one
64853   divideSegment(events[0], events[1].point, queue);
64854   divideSegment(events[3].otherEvent, events[2].point, queue);
64855
64856   return 3;
64857 }
64858
64859 /**
64860  * @param  {SweepEvent} le1
64861  * @param  {SweepEvent} le2
64862  * @return {Number}
64863  */
64864 function compareSegments(le1, le2) {
64865   if (le1 === le2) return 0;
64866
64867   // Segments are not collinear
64868   if (signedArea(le1.point, le1.otherEvent.point, le2.point) !== 0 ||
64869     signedArea(le1.point, le1.otherEvent.point, le2.otherEvent.point) !== 0) {
64870
64871     // If they share their left endpoint use the right endpoint to sort
64872     if (equals(le1.point, le2.point)) return le1.isBelow(le2.otherEvent.point) ? -1 : 1;
64873
64874     // Different left endpoint: use the left endpoint to sort
64875     if (le1.point[0] === le2.point[0]) return le1.point[1] < le2.point[1] ? -1 : 1;
64876
64877     // has the line segment associated to e1 been inserted
64878     // into S after the line segment associated to e2 ?
64879     if (compareEvents(le1, le2) === 1) return le2.isAbove(le1.point) ? -1 : 1;
64880
64881     // The line segment associated to e2 has been inserted
64882     // into S after the line segment associated to e1
64883     return le1.isBelow(le2.point) ? -1 : 1;
64884   }
64885
64886   if (le1.isSubject === le2.isSubject) { // same polygon
64887     let p1 = le1.point, p2 = le2.point;
64888     if (p1[0] === p2[0] && p1[1] === p2[1]/*equals(le1.point, le2.point)*/) {
64889       p1 = le1.otherEvent.point; p2 = le2.otherEvent.point;
64890       if (p1[0] === p2[0] && p1[1] === p2[1]) return 0;
64891       else return le1.contourId > le2.contourId ? 1 : -1;
64892     }
64893   } else { // Segments are collinear, but belong to separate polygons
64894     return le1.isSubject ? -1 : 1;
64895   }
64896
64897   return compareEvents(le1, le2) === 1 ? 1 : -1;
64898 }
64899
64900 function subdivide(eventQueue, subject, clipping, sbbox, cbbox, operation) {
64901   const sweepLine = new SplayTree(compareSegments);
64902   const sortedEvents = [];
64903
64904   const rightbound = Math.min(sbbox[2], cbbox[2]);
64905
64906   let prev, next, begin;
64907
64908   while (eventQueue.length !== 0) {
64909     let event = eventQueue.pop();
64910     sortedEvents.push(event);
64911
64912     // optimization by bboxes for intersection and difference goes here
64913     if ((operation === INTERSECTION && event.point[0] > rightbound) ||
64914         (operation === DIFFERENCE   && event.point[0] > sbbox[2])) {
64915       break;
64916     }
64917
64918     if (event.left) {
64919       next  = prev = sweepLine.insert(event);
64920       begin = sweepLine.minNode();
64921
64922       if (prev !== begin) prev = sweepLine.prev(prev);
64923       else                prev = null;
64924
64925       next = sweepLine.next(next);
64926
64927       const prevEvent = prev ? prev.key : null;
64928       let prevprevEvent;
64929       computeFields(event, prevEvent, operation);
64930       if (next) {
64931         if (possibleIntersection(event, next.key, eventQueue) === 2) {
64932           computeFields(event, prevEvent, operation);
64933           computeFields(event, next.key, operation);
64934         }
64935       }
64936
64937       if (prev) {
64938         if (possibleIntersection(prev.key, event, eventQueue) === 2) {
64939           let prevprev = prev;
64940           if (prevprev !== begin) prevprev = sweepLine.prev(prevprev);
64941           else                    prevprev = null;
64942
64943           prevprevEvent = prevprev ? prevprev.key : null;
64944           computeFields(prevEvent, prevprevEvent, operation);
64945           computeFields(event,     prevEvent,     operation);
64946         }
64947       }
64948     } else {
64949       event = event.otherEvent;
64950       next = prev = sweepLine.find(event);
64951
64952       if (prev && next) {
64953
64954         if (prev !== begin) prev = sweepLine.prev(prev);
64955         else                prev = null;
64956
64957         next = sweepLine.next(next);
64958         sweepLine.remove(event);
64959
64960         if (next && prev) {
64961           possibleIntersection(prev.key, next.key, eventQueue);
64962         }
64963       }
64964     }
64965   }
64966   return sortedEvents;
64967 }
64968
64969 class Contour {
64970
64971   /**
64972    * Contour
64973    *
64974    * @class {Contour}
64975    */
64976   constructor() {
64977     this.points = [];
64978     this.holeIds = [];
64979     this.holeOf = null;
64980     this.depth = null;
64981   }
64982
64983   isExterior() {
64984     return this.holeOf == null;
64985   }
64986
64987 }
64988
64989 /**
64990  * @param  {Array.<SweepEvent>} sortedEvents
64991  * @return {Array.<SweepEvent>}
64992  */
64993 function orderEvents(sortedEvents) {
64994   let event, i, len, tmp;
64995   const resultEvents = [];
64996   for (i = 0, len = sortedEvents.length; i < len; i++) {
64997     event = sortedEvents[i];
64998     if ((event.left && event.inResult) ||
64999       (!event.left && event.otherEvent.inResult)) {
65000       resultEvents.push(event);
65001     }
65002   }
65003   // Due to overlapping edges the resultEvents array can be not wholly sorted
65004   let sorted = false;
65005   while (!sorted) {
65006     sorted = true;
65007     for (i = 0, len = resultEvents.length; i < len; i++) {
65008       if ((i + 1) < len &&
65009         compareEvents(resultEvents[i], resultEvents[i + 1]) === 1) {
65010         tmp = resultEvents[i];
65011         resultEvents[i] = resultEvents[i + 1];
65012         resultEvents[i + 1] = tmp;
65013         sorted = false;
65014       }
65015     }
65016   }
65017
65018
65019   for (i = 0, len = resultEvents.length; i < len; i++) {
65020     event = resultEvents[i];
65021     event.otherPos = i;
65022   }
65023
65024   // imagine, the right event is found in the beginning of the queue,
65025   // when his left counterpart is not marked yet
65026   for (i = 0, len = resultEvents.length; i < len; i++) {
65027     event = resultEvents[i];
65028     if (!event.left) {
65029       tmp = event.otherPos;
65030       event.otherPos = event.otherEvent.otherPos;
65031       event.otherEvent.otherPos = tmp;
65032     }
65033   }
65034
65035   return resultEvents;
65036 }
65037
65038
65039 /**
65040  * @param  {Number} pos
65041  * @param  {Array.<SweepEvent>} resultEvents
65042  * @param  {Object>}    processed
65043  * @return {Number}
65044  */
65045 function nextPos(pos, resultEvents, processed, origPos) {
65046   let newPos = pos + 1,
65047       p = resultEvents[pos].point,
65048       p1;
65049   const length = resultEvents.length;
65050
65051   if (newPos < length)
65052     p1 = resultEvents[newPos].point;
65053
65054   while (newPos < length && p1[0] === p[0] && p1[1] === p[1]) {
65055     if (!processed[newPos]) {
65056       return newPos;
65057     } else   {
65058       newPos++;
65059     }
65060     p1 = resultEvents[newPos].point;
65061   }
65062
65063   newPos = pos - 1;
65064
65065   while (processed[newPos] && newPos > origPos) {
65066     newPos--;
65067   }
65068
65069   return newPos;
65070 }
65071
65072
65073 function initializeContourFromContext(event, contours, contourId) {
65074   const contour = new Contour();
65075   if (event.prevInResult != null) {
65076     const prevInResult = event.prevInResult;
65077     // Note that it is valid to query the "previous in result" for its output contour id,
65078     // because we must have already processed it (i.e., assigned an output contour id)
65079     // in an earlier iteration, otherwise it wouldn't be possible that it is "previous in
65080     // result".
65081     const lowerContourId = prevInResult.outputContourId;
65082     const lowerResultTransition = prevInResult.resultTransition;
65083     if (lowerResultTransition > 0) {
65084       // We are inside. Now we have to check if the thing below us is another hole or
65085       // an exterior contour.
65086       const lowerContour = contours[lowerContourId];
65087       if (lowerContour.holeOf != null) {
65088         // The lower contour is a hole => Connect the new contour as a hole to its parent,
65089         // and use same depth.
65090         const parentContourId = lowerContour.holeOf;
65091         contours[parentContourId].holeIds.push(contourId);
65092         contour.holeOf = parentContourId;
65093         contour.depth = contours[lowerContourId].depth;
65094       } else {
65095         // The lower contour is an exterior contour => Connect the new contour as a hole,
65096         // and increment depth.
65097         contours[lowerContourId].holeIds.push(contourId);
65098         contour.holeOf = lowerContourId;
65099         contour.depth = contours[lowerContourId].depth + 1;
65100       }
65101     } else {
65102       // We are outside => this contour is an exterior contour of same depth.
65103       contour.holeOf = null;
65104       contour.depth = contours[lowerContourId].depth;
65105     }
65106   } else {
65107     // There is no lower/previous contour => this contour is an exterior contour of depth 0.
65108     contour.holeOf = null;
65109     contour.depth = 0;
65110   }
65111   return contour;
65112 }
65113
65114 /**
65115  * @param  {Array.<SweepEvent>} sortedEvents
65116  * @return {Array.<*>} polygons
65117  */
65118 function connectEdges(sortedEvents) {
65119   let i, len;
65120   const resultEvents = orderEvents(sortedEvents);
65121
65122   // "false"-filled array
65123   const processed = {};
65124   const contours = [];
65125
65126   for (i = 0, len = resultEvents.length; i < len; i++) {
65127
65128     if (processed[i]) {
65129       continue;
65130     }
65131
65132     const contourId = contours.length;
65133     const contour = initializeContourFromContext(resultEvents[i], contours, contourId);
65134
65135     // Helper function that combines marking an event as processed with assigning its output contour ID
65136     const markAsProcessed = (pos) => {
65137       processed[pos] = true;
65138       resultEvents[pos].outputContourId = contourId;
65139     };
65140
65141     let pos = i;
65142     let origPos = i;
65143
65144     const initial = resultEvents[i].point;
65145     contour.points.push(initial);
65146
65147     /* eslint no-constant-condition: "off" */
65148     while (true) {
65149       markAsProcessed(pos);
65150
65151       pos = resultEvents[pos].otherPos;
65152
65153       markAsProcessed(pos);
65154       contour.points.push(resultEvents[pos].point);
65155
65156       pos = nextPos(pos, resultEvents, processed, origPos);
65157
65158       if (pos == origPos) {
65159         break;
65160       }
65161     }
65162
65163     contours.push(contour);
65164   }
65165
65166   return contours;
65167 }
65168
65169 var tinyqueue = {exports: {}};
65170
65171 tinyqueue.exports = TinyQueue;
65172 tinyqueue.exports.default = TinyQueue;
65173
65174 function TinyQueue(data, compare) {
65175     if (!(this instanceof TinyQueue)) return new TinyQueue(data, compare);
65176
65177     this.data = data || [];
65178     this.length = this.data.length;
65179     this.compare = compare || defaultCompare;
65180
65181     if (this.length > 0) {
65182         for (var i = (this.length >> 1) - 1; i >= 0; i--) this._down(i);
65183     }
65184 }
65185
65186 function defaultCompare(a, b) {
65187     return a < b ? -1 : a > b ? 1 : 0;
65188 }
65189
65190 TinyQueue.prototype = {
65191
65192     push: function (item) {
65193         this.data.push(item);
65194         this.length++;
65195         this._up(this.length - 1);
65196     },
65197
65198     pop: function () {
65199         if (this.length === 0) return undefined;
65200
65201         var top = this.data[0];
65202         this.length--;
65203
65204         if (this.length > 0) {
65205             this.data[0] = this.data[this.length];
65206             this._down(0);
65207         }
65208         this.data.pop();
65209
65210         return top;
65211     },
65212
65213     peek: function () {
65214         return this.data[0];
65215     },
65216
65217     _up: function (pos) {
65218         var data = this.data;
65219         var compare = this.compare;
65220         var item = data[pos];
65221
65222         while (pos > 0) {
65223             var parent = (pos - 1) >> 1;
65224             var current = data[parent];
65225             if (compare(item, current) >= 0) break;
65226             data[pos] = current;
65227             pos = parent;
65228         }
65229
65230         data[pos] = item;
65231     },
65232
65233     _down: function (pos) {
65234         var data = this.data;
65235         var compare = this.compare;
65236         var halfLength = this.length >> 1;
65237         var item = data[pos];
65238
65239         while (pos < halfLength) {
65240             var left = (pos << 1) + 1;
65241             var right = left + 1;
65242             var best = data[left];
65243
65244             if (right < this.length && compare(data[right], best) < 0) {
65245                 left = right;
65246                 best = data[right];
65247             }
65248             if (compare(best, item) >= 0) break;
65249
65250             data[pos] = best;
65251             pos = left;
65252         }
65253
65254         data[pos] = item;
65255     }
65256 };
65257
65258 var Queue = tinyqueue.exports;
65259
65260 const max = Math.max;
65261 const min = Math.min;
65262
65263 let contourId = 0;
65264
65265
65266 function processPolygon(contourOrHole, isSubject, depth, Q, bbox, isExteriorRing) {
65267   let i, len, s1, s2, e1, e2;
65268   for (i = 0, len = contourOrHole.length - 1; i < len; i++) {
65269     s1 = contourOrHole[i];
65270     s2 = contourOrHole[i + 1];
65271     e1 = new SweepEvent(s1, false, undefined, isSubject);
65272     e2 = new SweepEvent(s2, false, e1,        isSubject);
65273     e1.otherEvent = e2;
65274
65275     if (s1[0] === s2[0] && s1[1] === s2[1]) {
65276       continue; // skip collapsed edges, or it breaks
65277     }
65278
65279     e1.contourId = e2.contourId = depth;
65280     if (!isExteriorRing) {
65281       e1.isExteriorRing = false;
65282       e2.isExteriorRing = false;
65283     }
65284     if (compareEvents(e1, e2) > 0) {
65285       e2.left = true;
65286     } else {
65287       e1.left = true;
65288     }
65289
65290     const x = s1[0], y = s1[1];
65291     bbox[0] = min(bbox[0], x);
65292     bbox[1] = min(bbox[1], y);
65293     bbox[2] = max(bbox[2], x);
65294     bbox[3] = max(bbox[3], y);
65295
65296     // Pushing it so the queue is sorted from left to right,
65297     // with object on the left having the highest priority.
65298     Q.push(e1);
65299     Q.push(e2);
65300   }
65301 }
65302
65303
65304 function fillQueue(subject, clipping, sbbox, cbbox, operation) {
65305   const eventQueue = new Queue(null, compareEvents);
65306   let polygonSet, isExteriorRing, i, ii, j, jj; //, k, kk;
65307
65308   for (i = 0, ii = subject.length; i < ii; i++) {
65309     polygonSet = subject[i];
65310     for (j = 0, jj = polygonSet.length; j < jj; j++) {
65311       isExteriorRing = j === 0;
65312       if (isExteriorRing) contourId++;
65313       processPolygon(polygonSet[j], true, contourId, eventQueue, sbbox, isExteriorRing);
65314     }
65315   }
65316
65317   for (i = 0, ii = clipping.length; i < ii; i++) {
65318     polygonSet = clipping[i];
65319     for (j = 0, jj = polygonSet.length; j < jj; j++) {
65320       isExteriorRing = j === 0;
65321       if (operation === DIFFERENCE) isExteriorRing = false;
65322       if (isExteriorRing) contourId++;
65323       processPolygon(polygonSet[j], false, contourId, eventQueue, cbbox, isExteriorRing);
65324     }
65325   }
65326
65327   return eventQueue;
65328 }
65329
65330 const EMPTY = [];
65331
65332
65333 function trivialOperation(subject, clipping, operation) {
65334   let result = null;
65335   if (subject.length * clipping.length === 0) {
65336     if        (operation === INTERSECTION) {
65337       result = EMPTY;
65338     } else if (operation === DIFFERENCE) {
65339       result = subject;
65340     } else if (operation === UNION ||
65341                operation === XOR) {
65342       result = (subject.length === 0) ? clipping : subject;
65343     }
65344   }
65345   return result;
65346 }
65347
65348
65349 function compareBBoxes(subject, clipping, sbbox, cbbox, operation) {
65350   let result = null;
65351   if (sbbox[0] > cbbox[2] ||
65352       cbbox[0] > sbbox[2] ||
65353       sbbox[1] > cbbox[3] ||
65354       cbbox[1] > sbbox[3]) {
65355     if        (operation === INTERSECTION) {
65356       result = EMPTY;
65357     } else if (operation === DIFFERENCE) {
65358       result = subject;
65359     } else if (operation === UNION ||
65360                operation === XOR) {
65361       result = subject.concat(clipping);
65362     }
65363   }
65364   return result;
65365 }
65366
65367
65368 function boolean(subject, clipping, operation) {
65369   if (typeof subject[0][0][0] === 'number') {
65370     subject = [subject];
65371   }
65372   if (typeof clipping[0][0][0] === 'number') {
65373     clipping = [clipping];
65374   }
65375   let trivial = trivialOperation(subject, clipping, operation);
65376   if (trivial) {
65377     return trivial === EMPTY ? null : trivial;
65378   }
65379   const sbbox = [Infinity, Infinity, -Infinity, -Infinity];
65380   const cbbox = [Infinity, Infinity, -Infinity, -Infinity];
65381
65382   // console.time('fill queue');
65383   const eventQueue = fillQueue(subject, clipping, sbbox, cbbox, operation);
65384   //console.timeEnd('fill queue');
65385
65386   trivial = compareBBoxes(subject, clipping, sbbox, cbbox, operation);
65387   if (trivial) {
65388     return trivial === EMPTY ? null : trivial;
65389   }
65390   // console.time('subdivide edges');
65391   const sortedEvents = subdivide(eventQueue, subject, clipping, sbbox, cbbox, operation);
65392   //console.timeEnd('subdivide edges');
65393
65394   // console.time('connect vertices');
65395   const contours = connectEdges(sortedEvents);
65396   //console.timeEnd('connect vertices');
65397
65398   // Convert contours to polygons
65399   const polygons = [];
65400   for (let i = 0; i < contours.length; i++) {
65401     let contour = contours[i];
65402     if (contour.isExterior()) {
65403       // The exterior ring goes first
65404       let rings = [contour.points];
65405       // Followed by holes if any
65406       for (let j = 0; j < contour.holeIds.length; j++) {
65407         let holeId = contour.holeIds[j];
65408         rings.push(contours[holeId].points);
65409       }
65410       polygons.push(rings);
65411     }
65412   }
65413
65414   return polygons;
65415 }
65416
65417 function intersection (subject, clipping) {
65418   return boolean(subject, clipping, INTERSECTION);
65419 }
65420
65421 /**
65422  * @class VertexGeometry
65423  * @abstract
65424  * @classdesc Represents a vertex geometry.
65425  */
65426 class VertexGeometry extends Geometry {
65427     /**
65428      * Create a vertex geometry.
65429      *
65430      * @constructor
65431      * @ignore
65432      */
65433     constructor() {
65434         super();
65435         this._subsampleThreshold = 0.005;
65436     }
65437     /**
65438      * Finds the polygon pole of inaccessibility, the most distant internal
65439      * point from the polygon outline.
65440      *
65441      * @param {Array<Array<number>>} points2d - 2d points of outline to triangulate.
65442      * @returns {Array<number>} Point of inaccessibility.
65443      * @ignore
65444      */
65445     _getPoleOfInaccessibility2d(points2d) {
65446         let pole2d = polylabel$1([points2d], 3e-2);
65447         return pole2d;
65448     }
65449     _project(points2d, transform) {
65450         const camera = this._createCamera(transform.upVector().toArray(), transform.unprojectSfM([0, 0], 0), transform.unprojectSfM([0, 0], 10));
65451         return this._deunproject(points2d, transform, camera);
65452     }
65453     _subsample(points2d, threshold = this._subsampleThreshold) {
65454         const subsampled = [];
65455         const length = points2d.length;
65456         for (let index = 0; index < length; index++) {
65457             const p1 = points2d[index];
65458             const p2 = points2d[(index + 1) % length];
65459             subsampled.push(p1);
65460             const dist = Math.sqrt(Math.pow((p2[0] - p1[0]), 2) + Math.pow((p2[1] - p1[1]), 2));
65461             const subsamples = Math.floor(dist / threshold);
65462             const coeff = 1 / (subsamples + 1);
65463             for (let i = 1; i <= subsamples; i++) {
65464                 const alpha = i * coeff;
65465                 const subsample = [
65466                     (1 - alpha) * p1[0] + alpha * p2[0],
65467                     (1 - alpha) * p1[1] + alpha * p2[1],
65468                 ];
65469                 subsampled.push(subsample);
65470             }
65471         }
65472         return subsampled;
65473     }
65474     /**
65475      * Triangulates a 2d polygon and returns the triangle
65476      * representation as a flattened array of 3d points.
65477      *
65478      * @param {Array<Array<number>>} points2d - 2d points of outline to triangulate.
65479      * @param {Array<Array<number>>} points3d - 3d points of outline corresponding to the 2d points.
65480      * @param {Array<Array<Array<number>>>} [holes2d] - 2d points of holes to triangulate.
65481      * @param {Array<Array<Array<number>>>} [holes3d] - 3d points of holes corresponding to the 2d points.
65482      * @returns {Array<number>} Flattened array of 3d points ordered based on the triangles.
65483      * @ignore
65484      */
65485     _triangulate(points2d, points3d, holes2d, holes3d) {
65486         let data = [points2d.slice(0, -1)];
65487         for (let hole2d of holes2d != null ? holes2d : []) {
65488             data.push(hole2d.slice(0, -1));
65489         }
65490         let points = points3d.slice(0, -1);
65491         for (let hole3d of holes3d != null ? holes3d : []) {
65492             points = points.concat(hole3d.slice(0, -1));
65493         }
65494         let flattened = earcut$1.flatten(data);
65495         let indices = earcut$1(flattened.vertices, flattened.holes, flattened.dimensions);
65496         let triangles = [];
65497         for (let i = 0; i < indices.length; ++i) {
65498             let point = points[indices[i]];
65499             triangles.push(point[0]);
65500             triangles.push(point[1]);
65501             triangles.push(point[2]);
65502         }
65503         return triangles;
65504     }
65505     _triangulateSpherical(points2d, holes2d, transform) {
65506         const triangles = [];
65507         const epsilon = 1e-9;
65508         const subareasX = 3;
65509         const subareasY = 3;
65510         for (let x = 0; x < subareasX; x++) {
65511             for (let y = 0; y < subareasY; y++) {
65512                 const epsilonX0 = x === 0 ? -epsilon : epsilon;
65513                 const epsilonY0 = y === 0 ? -epsilon : epsilon;
65514                 const x0 = x / subareasX + epsilonX0;
65515                 const y0 = y / subareasY + epsilonY0;
65516                 const x1 = (x + 1) / subareasX + epsilon;
65517                 const y1 = (y + 1) / subareasY + epsilon;
65518                 const bbox2d = [
65519                     [x0, y0],
65520                     [x0, y1],
65521                     [x1, y1],
65522                     [x1, y0],
65523                     [x0, y0],
65524                 ];
65525                 const lookat2d = [
65526                     (2 * x + 1) / (2 * subareasX),
65527                     (2 * y + 1) / (2 * subareasY),
65528                 ];
65529                 triangles.push(...this._triangulateSubarea(points2d, holes2d, bbox2d, lookat2d, transform));
65530             }
65531         }
65532         return triangles;
65533     }
65534     _unproject(points2d, transform, distance = 200) {
65535         return points2d
65536             .map((point) => {
65537             return transform.unprojectBasic(point, distance);
65538         });
65539     }
65540     _createCamera(upVector, position, lookAt) {
65541         const camera = new Camera$1();
65542         camera.up.copy(new Vector3().fromArray(upVector));
65543         camera.position.copy(new Vector3().fromArray(position));
65544         camera.lookAt(new Vector3().fromArray(lookAt));
65545         camera.updateMatrix();
65546         camera.updateMatrixWorld(true);
65547         return camera;
65548     }
65549     _deunproject(points2d, transform, camera) {
65550         return points2d
65551             .map((point2d) => {
65552             const pointWorld = transform.unprojectBasic(point2d, 10000);
65553             const pointCamera = new Vector3(pointWorld[0], pointWorld[1], pointWorld[2])
65554                 .applyMatrix4(camera.matrixWorldInverse);
65555             return [pointCamera.x / pointCamera.z, pointCamera.y / pointCamera.z];
65556         });
65557     }
65558     _triangulateSubarea(points2d, holes2d, bbox2d, lookat2d, transform) {
65559         const intersections = intersection([points2d, ...holes2d], [bbox2d]);
65560         if (!intersections) {
65561             return [];
65562         }
65563         const triangles = [];
65564         const threshold = this._subsampleThreshold;
65565         const camera = this._createCamera(transform.upVector().toArray(), transform.unprojectSfM([0, 0], 0), transform.unprojectBasic(lookat2d, 10));
65566         for (const intersection of intersections) {
65567             const subsampledPolygon2d = this._subsample(intersection[0], threshold);
65568             const polygon2d = this._deunproject(subsampledPolygon2d, transform, camera);
65569             const polygon3d = this._unproject(subsampledPolygon2d, transform);
65570             const polygonHoles2d = [];
65571             const polygonHoles3d = [];
65572             for (let i = 1; i < intersection.length; i++) {
65573                 let subsampledHole2d = this._subsample(intersection[i], threshold);
65574                 const hole2d = this._deunproject(subsampledHole2d, transform, camera);
65575                 const hole3d = this._unproject(subsampledHole2d, transform);
65576                 polygonHoles2d.push(hole2d);
65577                 polygonHoles3d.push(hole3d);
65578             }
65579             triangles.push(...this._triangulate(polygon2d, polygon3d, polygonHoles2d, polygonHoles3d));
65580         }
65581         return triangles;
65582     }
65583 }
65584
65585 /**
65586  * @class RectGeometry
65587  *
65588  * @classdesc Represents a rectangle geometry in the 2D basic image coordinate system.
65589  *
65590  * @example
65591  * ```js
65592  * var basicRect = [0.5, 0.3, 0.7, 0.4];
65593  * var rectGeometry = new RectGeometry(basicRect);
65594  * ```
65595  */
65596 class RectGeometry extends VertexGeometry {
65597     /**
65598      * Create a rectangle geometry.
65599      *
65600      * @constructor
65601      * @param {Array<number>} rect - An array representing the top-left and bottom-right
65602      * corners of the rectangle in basic coordinates. Ordered according to [x0, y0, x1, y1].
65603      *
65604      * @throws {GeometryTagError} Rectangle coordinates must be valid basic coordinates.
65605      */
65606     constructor(rect) {
65607         super();
65608         if (rect.length !== 4) {
65609             throw new GeometryTagError("Rectangle needs to have four values.");
65610         }
65611         if (rect[1] > rect[3]) {
65612             throw new GeometryTagError("Basic Y coordinates values can not be inverted.");
65613         }
65614         for (let coord of rect) {
65615             if (coord < 0 || coord > 1) {
65616                 throw new GeometryTagError("Basic coordinates must be on the interval [0, 1].");
65617             }
65618         }
65619         this._anchorIndex = undefined;
65620         this._rect = rect.slice(0, 4);
65621         this._inverted = this._rect[0] > this._rect[2];
65622     }
65623     /**
65624      * Get anchor index property.
65625      *
65626      * @returns {number} Index representing the current anchor property if
65627      * achoring indexing has been initialized. If anchor indexing has not been
65628      * initialized or has been terminated undefined will be returned.
65629      * @ignore
65630      */
65631     get anchorIndex() {
65632         return this._anchorIndex;
65633     }
65634     /**
65635      * Get inverted property.
65636      *
65637      * @returns {boolean} Boolean determining whether the rect geometry is
65638      * inverted. For spherical the rect geometrye may be inverted.
65639      * @ignore
65640      */
65641     get inverted() {
65642         return this._inverted;
65643     }
65644     /**
65645      * Get rect property.
65646      *
65647      * @returns {Array<number>} Array representing the top-left and bottom-right
65648      * corners of the rectangle in basic coordinates.
65649      */
65650     get rect() {
65651         return this._rect;
65652     }
65653     /**
65654      * Initialize anchor indexing to enable setting opposite vertex.
65655      *
65656      * @param {number} [index] - The index of the vertex to use as anchor.
65657      *
65658      * @throws {GeometryTagError} If anchor indexing has already been initialized.
65659      * @throws {GeometryTagError} If index is not valid (0 to 3).
65660      * @ignore
65661      */
65662     initializeAnchorIndexing(index) {
65663         if (this._anchorIndex !== undefined) {
65664             throw new GeometryTagError("Anchor indexing is already initialized.");
65665         }
65666         if (index < 0 || index > 3) {
65667             throw new GeometryTagError(`Invalid anchor index: ${index}.`);
65668         }
65669         this._anchorIndex = index === undefined ? 0 : index;
65670     }
65671     /**
65672      * Terminate anchor indexing to disable setting pposite vertex.
65673      * @ignore
65674      */
65675     terminateAnchorIndexing() {
65676         this._anchorIndex = undefined;
65677     }
65678     /**
65679      * Set the value of the vertex opposite to the anchor in the polygon
65680      * representation of the rectangle.
65681      *
65682      * @description Setting the opposite vertex may change the anchor index.
65683      *
65684      * @param {Array<number>} opposite - The new value of the vertex opposite to the anchor.
65685      * @param {Transform} transform - The transform of the image related to the rectangle.
65686      *
65687      * @throws {GeometryTagError} When anchor indexing has not been initialized.
65688      * @ignore
65689      */
65690     setOppositeVertex2d(opposite, transform) {
65691         if (this._anchorIndex === undefined) {
65692             throw new GeometryTagError("Anchor indexing needs to be initialized.");
65693         }
65694         const changed = [
65695             Math.max(0, Math.min(1, opposite[0])),
65696             Math.max(0, Math.min(1, opposite[1])),
65697         ];
65698         const original = this._rect.slice();
65699         const anchor = this._anchorIndex === 0 ? [original[0], original[3]] :
65700             this._anchorIndex === 1 ? [original[0], original[1]] :
65701                 this._anchorIndex === 2 ? [original[2], original[1]] :
65702                     [original[2], original[3]];
65703         if (isSpherical(transform.cameraType)) {
65704             const deltaX = this._anchorIndex < 2 ?
65705                 changed[0] - original[2] :
65706                 changed[0] - original[0];
65707             if (!this._inverted && this._anchorIndex < 2 && changed[0] < 0.25 && original[2] > 0.75 && deltaX < -0.5) {
65708                 // right side passes boundary rightward
65709                 this._inverted = true;
65710                 this._anchorIndex = anchor[1] > changed[1] ? 0 : 1;
65711             }
65712             else if (!this._inverted && this._anchorIndex >= 2 && changed[0] < 0.25 && original[2] > 0.75 && deltaX < -0.5) {
65713                 // left side passes right side and boundary rightward
65714                 this._inverted = true;
65715                 this._anchorIndex = anchor[1] > changed[1] ? 0 : 1;
65716             }
65717             else if (this._inverted && this._anchorIndex >= 2 && changed[0] < 0.25 && original[0] > 0.75 && deltaX < -0.5) {
65718                 this._inverted = false;
65719                 if (anchor[0] > changed[0]) {
65720                     // left side passes boundary rightward
65721                     this._anchorIndex = anchor[1] > changed[1] ? 3 : 2;
65722                 }
65723                 else {
65724                     // left side passes right side and boundary rightward
65725                     this._anchorIndex = anchor[1] > changed[1] ? 0 : 1;
65726                 }
65727             }
65728             else if (!this._inverted && this._anchorIndex >= 2 && changed[0] > 0.75 && original[0] < 0.25 && deltaX > 0.5) {
65729                 // left side passes boundary leftward
65730                 this._inverted = true;
65731                 this._anchorIndex = anchor[1] > changed[1] ? 3 : 2;
65732             }
65733             else if (!this._inverted && this._anchorIndex < 2 && changed[0] > 0.75 && original[0] < 0.25 && deltaX > 0.5) {
65734                 // right side passes left side and boundary leftward
65735                 this._inverted = true;
65736                 this._anchorIndex = anchor[1] > changed[1] ? 3 : 2;
65737             }
65738             else if (this._inverted && this._anchorIndex < 2 && changed[0] > 0.75 && original[2] < 0.25 && deltaX > 0.5) {
65739                 this._inverted = false;
65740                 if (anchor[0] > changed[0]) {
65741                     // right side passes boundary leftward
65742                     this._anchorIndex = anchor[1] > changed[1] ? 3 : 2;
65743                 }
65744                 else {
65745                     // right side passes left side and boundary leftward
65746                     this._anchorIndex = anchor[1] > changed[1] ? 0 : 1;
65747                 }
65748             }
65749             else if (this._inverted && this._anchorIndex < 2 && changed[0] > original[0]) {
65750                 // inverted and right side passes left side completing a loop
65751                 this._inverted = false;
65752                 this._anchorIndex = anchor[1] > changed[1] ? 0 : 1;
65753             }
65754             else if (this._inverted && this._anchorIndex >= 2 && changed[0] < original[2]) {
65755                 // inverted and left side passes right side completing a loop
65756                 this._inverted = false;
65757                 this._anchorIndex = anchor[1] > changed[1] ? 3 : 2;
65758             }
65759             else if (this._inverted) {
65760                 // if still inverted only top and bottom can switch
65761                 if (this._anchorIndex < 2) {
65762                     this._anchorIndex = anchor[1] > changed[1] ? 0 : 1;
65763                 }
65764                 else {
65765                     this._anchorIndex = anchor[1] > changed[1] ? 3 : 2;
65766                 }
65767             }
65768             else {
65769                 // if still not inverted treat as non spherical
65770                 if (anchor[0] <= changed[0] && anchor[1] > changed[1]) {
65771                     this._anchorIndex = 0;
65772                 }
65773                 else if (anchor[0] <= changed[0] && anchor[1] <= changed[1]) {
65774                     this._anchorIndex = 1;
65775                 }
65776                 else if (anchor[0] > changed[0] && anchor[1] <= changed[1]) {
65777                     this._anchorIndex = 2;
65778                 }
65779                 else {
65780                     this._anchorIndex = 3;
65781                 }
65782             }
65783             const rect = [];
65784             if (this._anchorIndex === 0) {
65785                 rect[0] = anchor[0];
65786                 rect[1] = changed[1];
65787                 rect[2] = changed[0];
65788                 rect[3] = anchor[1];
65789             }
65790             else if (this._anchorIndex === 1) {
65791                 rect[0] = anchor[0];
65792                 rect[1] = anchor[1];
65793                 rect[2] = changed[0];
65794                 rect[3] = changed[1];
65795             }
65796             else if (this._anchorIndex === 2) {
65797                 rect[0] = changed[0];
65798                 rect[1] = anchor[1];
65799                 rect[2] = anchor[0];
65800                 rect[3] = changed[1];
65801             }
65802             else {
65803                 rect[0] = changed[0];
65804                 rect[1] = changed[1];
65805                 rect[2] = anchor[0];
65806                 rect[3] = anchor[1];
65807             }
65808             if (!this._inverted && rect[0] > rect[2] ||
65809                 this._inverted && rect[0] < rect[2]) {
65810                 rect[0] = original[0];
65811                 rect[2] = original[2];
65812             }
65813             if (rect[1] > rect[3]) {
65814                 rect[1] = original[1];
65815                 rect[3] = original[3];
65816             }
65817             this._rect[0] = rect[0];
65818             this._rect[1] = rect[1];
65819             this._rect[2] = rect[2];
65820             this._rect[3] = rect[3];
65821         }
65822         else {
65823             if (anchor[0] <= changed[0] && anchor[1] > changed[1]) {
65824                 this._anchorIndex = 0;
65825             }
65826             else if (anchor[0] <= changed[0] && anchor[1] <= changed[1]) {
65827                 this._anchorIndex = 1;
65828             }
65829             else if (anchor[0] > changed[0] && anchor[1] <= changed[1]) {
65830                 this._anchorIndex = 2;
65831             }
65832             else {
65833                 this._anchorIndex = 3;
65834             }
65835             const rect = [];
65836             if (this._anchorIndex === 0) {
65837                 rect[0] = anchor[0];
65838                 rect[1] = changed[1];
65839                 rect[2] = changed[0];
65840                 rect[3] = anchor[1];
65841             }
65842             else if (this._anchorIndex === 1) {
65843                 rect[0] = anchor[0];
65844                 rect[1] = anchor[1];
65845                 rect[2] = changed[0];
65846                 rect[3] = changed[1];
65847             }
65848             else if (this._anchorIndex === 2) {
65849                 rect[0] = changed[0];
65850                 rect[1] = anchor[1];
65851                 rect[2] = anchor[0];
65852                 rect[3] = changed[1];
65853             }
65854             else {
65855                 rect[0] = changed[0];
65856                 rect[1] = changed[1];
65857                 rect[2] = anchor[0];
65858                 rect[3] = anchor[1];
65859             }
65860             if (rect[0] > rect[2]) {
65861                 rect[0] = original[0];
65862                 rect[2] = original[2];
65863             }
65864             if (rect[1] > rect[3]) {
65865                 rect[1] = original[1];
65866                 rect[3] = original[3];
65867             }
65868             this._rect[0] = rect[0];
65869             this._rect[1] = rect[1];
65870             this._rect[2] = rect[2];
65871             this._rect[3] = rect[3];
65872         }
65873         this._notifyChanged$.next(this);
65874     }
65875     /**
65876      * Set the value of a vertex in the polygon representation of the rectangle.
65877      *
65878      * @description The polygon is defined to have the first vertex at the
65879      * bottom-left corner with the rest of the vertices following in clockwise order.
65880      *
65881      * @param {number} index - The index of the vertex to be set.
65882      * @param {Array<number>} value - The new value of the vertex.
65883      * @param {Transform} transform - The transform of the image related to the rectangle.
65884      * @ignore
65885      */
65886     setVertex2d(index, value, transform) {
65887         let original = this._rect.slice();
65888         let changed = [
65889             Math.max(0, Math.min(1, value[0])),
65890             Math.max(0, Math.min(1, value[1])),
65891         ];
65892         let rect = [];
65893         if (index === 0) {
65894             rect[0] = changed[0];
65895             rect[1] = original[1];
65896             rect[2] = original[2];
65897             rect[3] = changed[1];
65898         }
65899         else if (index === 1) {
65900             rect[0] = changed[0];
65901             rect[1] = changed[1];
65902             rect[2] = original[2];
65903             rect[3] = original[3];
65904         }
65905         else if (index === 2) {
65906             rect[0] = original[0];
65907             rect[1] = changed[1];
65908             rect[2] = changed[0];
65909             rect[3] = original[3];
65910         }
65911         else if (index === 3) {
65912             rect[0] = original[0];
65913             rect[1] = original[1];
65914             rect[2] = changed[0];
65915             rect[3] = changed[1];
65916         }
65917         if (isSpherical(transform.cameraType)) {
65918             let passingBoundaryLeftward = index < 2 && changed[0] > 0.75 && original[0] < 0.25 ||
65919                 index >= 2 && this._inverted && changed[0] > 0.75 && original[2] < 0.25;
65920             let passingBoundaryRightward = index < 2 && this._inverted && changed[0] < 0.25 && original[0] > 0.75 ||
65921                 index >= 2 && changed[0] < 0.25 && original[2] > 0.75;
65922             if (passingBoundaryLeftward || passingBoundaryRightward) {
65923                 this._inverted = !this._inverted;
65924             }
65925             else {
65926                 if (rect[0] - original[0] < -0.25) {
65927                     rect[0] = original[0];
65928                 }
65929                 if (rect[2] - original[2] > 0.25) {
65930                     rect[2] = original[2];
65931                 }
65932             }
65933             if (!this._inverted && rect[0] > rect[2] ||
65934                 this._inverted && rect[0] < rect[2]) {
65935                 rect[0] = original[0];
65936                 rect[2] = original[2];
65937             }
65938         }
65939         else {
65940             if (rect[0] > rect[2]) {
65941                 rect[0] = original[0];
65942                 rect[2] = original[2];
65943             }
65944         }
65945         if (rect[1] > rect[3]) {
65946             rect[1] = original[1];
65947             rect[3] = original[3];
65948         }
65949         this._rect[0] = rect[0];
65950         this._rect[1] = rect[1];
65951         this._rect[2] = rect[2];
65952         this._rect[3] = rect[3];
65953         this._notifyChanged$.next(this);
65954     }
65955     /** @ignore */
65956     setCentroid2d(value, transform) {
65957         let original = this._rect.slice();
65958         let x0 = original[0];
65959         let x1 = this._inverted ? original[2] + 1 : original[2];
65960         let y0 = original[1];
65961         let y1 = original[3];
65962         let centerX = x0 + (x1 - x0) / 2;
65963         let centerY = y0 + (y1 - y0) / 2;
65964         let translationX = 0;
65965         if (isSpherical(transform.cameraType)) {
65966             translationX = this._inverted ? value[0] + 1 - centerX : value[0] - centerX;
65967         }
65968         else {
65969             let minTranslationX = -x0;
65970             let maxTranslationX = 1 - x1;
65971             translationX = Math.max(minTranslationX, Math.min(maxTranslationX, value[0] - centerX));
65972         }
65973         let minTranslationY = -y0;
65974         let maxTranslationY = 1 - y1;
65975         let translationY = Math.max(minTranslationY, Math.min(maxTranslationY, value[1] - centerY));
65976         this._rect[0] = original[0] + translationX;
65977         this._rect[1] = original[1] + translationY;
65978         this._rect[2] = original[2] + translationX;
65979         this._rect[3] = original[3] + translationY;
65980         if (this._rect[0] < 0) {
65981             this._rect[0] += 1;
65982             this._inverted = !this._inverted;
65983         }
65984         else if (this._rect[0] > 1) {
65985             this._rect[0] -= 1;
65986             this._inverted = !this._inverted;
65987         }
65988         if (this._rect[2] < 0) {
65989             this._rect[2] += 1;
65990             this._inverted = !this._inverted;
65991         }
65992         else if (this._rect[2] > 1) {
65993             this._rect[2] -= 1;
65994             this._inverted = !this._inverted;
65995         }
65996         this._notifyChanged$.next(this);
65997     }
65998     /**
65999      * Get the 3D coordinates for the vertices of the rectangle with
66000      * interpolated points along the lines.
66001      *
66002      * @param {Transform} transform - The transform of the image related to
66003      * the rectangle.
66004      * @returns {Array<Array<number>>} Polygon array of 3D world coordinates
66005      * representing the rectangle.
66006      * @ignore
66007      */
66008     getPoints3d(transform) {
66009         return this._getPoints2d()
66010             .map((point) => {
66011             return transform.unprojectBasic(point, 200);
66012         });
66013     }
66014     /**
66015      * Get the coordinates of a vertex from the polygon representation of the geometry.
66016      *
66017      * @description The first vertex represents the bottom-left corner with the rest of
66018      * the vertices following in clockwise order. The method shifts the right side
66019      * coordinates of the rectangle by one unit to ensure that the vertices are ordered
66020      * clockwise.
66021      *
66022      * @param {number} index - Vertex index.
66023      * @returns {Array<number>} Array representing the 2D basic coordinates of the vertex.
66024      * @ignore
66025      */
66026     getVertex2d(index) {
66027         return this._rectToVertices2d(this._rect)[index];
66028     }
66029     /**
66030      * Get the coordinates of a vertex from the polygon representation of the geometry.
66031      *
66032      * @description The first vertex represents the bottom-left corner with the rest of
66033      * the vertices following in clockwise order. The coordinates will not be shifted
66034      * so they may not appear in clockwise order when layed out on the plane.
66035      *
66036      * @param {number} index - Vertex index.
66037      * @returns {Array<number>} Array representing the 2D basic coordinates of the vertex.
66038      * @ignore
66039      */
66040     getNonAdjustedVertex2d(index) {
66041         return this._rectToNonAdjustedVertices2d(this._rect)[index];
66042     }
66043     /**
66044      * Get a vertex from the polygon representation of the 3D coordinates for the
66045      * vertices of the geometry.
66046      *
66047      * @description The first vertex represents the bottom-left corner with the rest of
66048      * the vertices following in clockwise order.
66049      *
66050      * @param {number} index - Vertex index.
66051      * @param {Transform} transform - The transform of the image related to the geometry.
66052      * @returns {Array<Array<number>>} Polygon array of 3D world coordinates representing
66053      * the vertices of the geometry.
66054      * @ignore
66055      */
66056     getVertex3d(index, transform) {
66057         return transform.unprojectBasic(this._rectToVertices2d(this._rect)[index], 200);
66058     }
66059     /**
66060      * Get a polygon representation of the 2D basic coordinates for the vertices of the rectangle.
66061      *
66062      * @description The first vertex represents the bottom-left corner with the rest of
66063      * the vertices following in clockwise order.
66064      *
66065      * @returns {Array<Array<number>>} Polygon array of 2D basic coordinates representing
66066      * the rectangle vertices.
66067      * @ignore
66068      */
66069     getVertices2d() {
66070         return this._rectToVertices2d(this._rect);
66071     }
66072     /**
66073      * Get a polygon representation of the 3D coordinates for the vertices of the rectangle.
66074      *
66075      * @description The first vertex represents the bottom-left corner with the rest of
66076      * the vertices following in clockwise order.
66077      *
66078      * @param {Transform} transform - The transform of the image related to the rectangle.
66079      * @returns {Array<Array<number>>} Polygon array of 3D world coordinates representing
66080      * the rectangle vertices.
66081      * @ignore
66082      */
66083     getVertices3d(transform) {
66084         return this._rectToVertices2d(this._rect)
66085             .map((vertex) => {
66086             return transform.unprojectBasic(vertex, 200);
66087         });
66088     }
66089     /** @ignore */
66090     getCentroid2d() {
66091         const rect = this._rect;
66092         const x0 = rect[0];
66093         const x1 = this._inverted ? rect[2] + 1 : rect[2];
66094         const y0 = rect[1];
66095         const y1 = rect[3];
66096         const centroidX = (x0 + x1) / 2;
66097         const centroidY = (y0 + y1) / 2;
66098         return [centroidX, centroidY];
66099     }
66100     /** @ignore */
66101     getCentroid3d(transform) {
66102         const centroid2d = this.getCentroid2d();
66103         return transform.unprojectBasic(centroid2d, 200);
66104     }
66105     /**
66106      * @ignore
66107      */
66108     getPoleOfInaccessibility2d() {
66109         return this._getPoleOfInaccessibility2d(this._rectToVertices2d(this._rect));
66110     }
66111     /** @ignore */
66112     getPoleOfInaccessibility3d(transform) {
66113         let pole2d = this._getPoleOfInaccessibility2d(this._rectToVertices2d(this._rect));
66114         return transform.unprojectBasic(pole2d, 200);
66115     }
66116     /** @ignore */
66117     getTriangles3d(transform) {
66118         return isSpherical(transform.cameraType) ?
66119             [] :
66120             this._triangulate(this._project(this._getPoints2d(), transform), this.getPoints3d(transform));
66121     }
66122     /**
66123      * Check if a particular bottom-right value is valid according to the current
66124      * rectangle coordinates.
66125      *
66126      * @param {Array<number>} bottomRight - The bottom-right coordinates to validate
66127      * @returns {boolean} Value indicating whether the provided bottom-right coordinates
66128      * are valid.
66129      * @ignore
66130      */
66131     validate(bottomRight) {
66132         let rect = this._rect;
66133         if (!this._inverted && bottomRight[0] < rect[0] ||
66134             bottomRight[0] - rect[2] > 0.25 ||
66135             bottomRight[1] < rect[1]) {
66136             return false;
66137         }
66138         return true;
66139     }
66140     /**
66141      * Get the 2D coordinates for the vertices of the rectangle with
66142      * interpolated points along the lines.
66143      *
66144      * @returns {Array<Array<number>>} Polygon array of 2D basic coordinates
66145      * representing the rectangle.
66146      */
66147     _getPoints2d() {
66148         let vertices2d = this._rectToVertices2d(this._rect);
66149         let sides = vertices2d.length - 1;
66150         let sections = 10;
66151         let points2d = [];
66152         for (let i = 0; i < sides; ++i) {
66153             let startX = vertices2d[i][0];
66154             let startY = vertices2d[i][1];
66155             let endX = vertices2d[i + 1][0];
66156             let endY = vertices2d[i + 1][1];
66157             let intervalX = (endX - startX) / (sections - 1);
66158             let intervalY = (endY - startY) / (sections - 1);
66159             for (let j = 0; j < sections; ++j) {
66160                 let point = [
66161                     startX + j * intervalX,
66162                     startY + j * intervalY,
66163                 ];
66164                 points2d.push(point);
66165             }
66166         }
66167         return points2d;
66168     }
66169     /**
66170      * Convert the top-left, bottom-right representation of a rectangle to a polygon
66171      * representation of the vertices starting at the bottom-left corner going
66172      * clockwise.
66173      *
66174      * @description The method shifts the right side coordinates of the rectangle
66175      * by one unit to ensure that the vertices are ordered clockwise.
66176      *
66177      * @param {Array<number>} rect - Top-left, bottom-right representation of a
66178      * rectangle.
66179      * @returns {Array<Array<number>>} Polygon representation of the vertices of the
66180      * rectangle.
66181      */
66182     _rectToVertices2d(rect) {
66183         return [
66184             [rect[0], rect[3]],
66185             [rect[0], rect[1]],
66186             [this._inverted ? rect[2] + 1 : rect[2], rect[1]],
66187             [this._inverted ? rect[2] + 1 : rect[2], rect[3]],
66188             [rect[0], rect[3]],
66189         ];
66190     }
66191     /**
66192      * Convert the top-left, bottom-right representation of a rectangle to a polygon
66193      * representation of the vertices starting at the bottom-left corner going
66194      * clockwise.
66195      *
66196      * @description The first vertex represents the bottom-left corner with the rest of
66197      * the vertices following in clockwise order. The coordinates will not be shifted
66198      * to ensure that the vertices are ordered clockwise when layed out on the plane.
66199      *
66200      * @param {Array<number>} rect - Top-left, bottom-right representation of a
66201      * rectangle.
66202      * @returns {Array<Array<number>>} Polygon representation of the vertices of the
66203      * rectangle.
66204      */
66205     _rectToNonAdjustedVertices2d(rect) {
66206         return [
66207             [rect[0], rect[3]],
66208             [rect[0], rect[1]],
66209             [rect[2], rect[1]],
66210             [rect[2], rect[3]],
66211             [rect[0], rect[3]],
66212         ];
66213     }
66214 }
66215
66216 class ExtremePointCreateTag extends CreateTag {
66217     constructor(geometry, options, transform, viewportCoords) {
66218         super(geometry, transform, viewportCoords);
66219         this._options = {
66220             color: options.color == null ? 0xFFFFFF : options.color,
66221             indicateCompleter: options.indicateCompleter == null ? true : options.indicateCompleter,
66222         };
66223         this._rectGeometry = new RectGeometry(this._geometry.getRect2d(transform));
66224         this._createGlObjects();
66225     }
66226     create() {
66227         if (this._geometry.points.length < 3) {
66228             return;
66229         }
66230         this._geometry.removePoint2d(this._geometry.points.length - 1);
66231         this._created$.next(this);
66232     }
66233     dispose() {
66234         super.dispose();
66235         this._disposeObjects();
66236     }
66237     getDOMObjects(camera, size) {
66238         const container = {
66239             offsetHeight: size.height, offsetWidth: size.width,
66240         };
66241         const vNodes = [];
66242         const points2d = this._geometry.getPoints2d();
66243         const length = points2d.length;
66244         for (let index = 0; index < length - 1; index++) {
66245             const nonModifiedIndex = index;
66246             const [pointX, pointY] = points2d[index];
66247             const pointCanvas = this._viewportCoords.basicToCanvasSafe(pointX, pointY, container, this._transform, camera);
66248             if (!pointCanvas) {
66249                 continue;
66250             }
66251             const abort = (e) => {
66252                 e.stopPropagation();
66253                 this._aborted$.next(this);
66254             };
66255             const remove = (e) => {
66256                 e.stopPropagation();
66257                 this._geometry.removePoint2d(nonModifiedIndex);
66258             };
66259             const transform = this._canvasToTransform(pointCanvas);
66260             const completerProperties = {
66261                 onclick: index === 0 && length < 3 ? abort : remove,
66262                 style: { transform: transform },
66263             };
66264             vNodes.push(virtualDom.h("div.mapillary-tag-interactor", completerProperties, []));
66265             const background = this._colorToBackground(this._options.color);
66266             const pointProperties = {
66267                 style: {
66268                     background: background,
66269                     transform: transform,
66270                 },
66271             };
66272             vNodes.push(virtualDom.h("div.mapillary-tag-vertex", pointProperties, []));
66273         }
66274         if (length > 2 && this._options.indicateCompleter === true) {
66275             const [centroidX, centroidY] = this._geometry.getCentroid2d(this._transform);
66276             const centroidCanvas = this._viewportCoords.basicToCanvasSafe(centroidX, centroidY, container, this._transform, camera);
66277             if (!!centroidCanvas) {
66278                 const complete = (e) => {
66279                     e.stopPropagation();
66280                     this._geometry.removePoint2d(this._geometry.points.length - 1);
66281                     this._created$.next(this);
66282                 };
66283                 const transform = this._canvasToTransform(centroidCanvas);
66284                 const completerProperties = {
66285                     onclick: complete,
66286                     style: { transform: transform },
66287                 };
66288                 vNodes.push(virtualDom.h("div.mapillary-tag-completer.mapillary-tag-larger", completerProperties, []));
66289                 const pointProperties = {
66290                     style: {
66291                         background: this._colorToBackground(this._options.color),
66292                         transform: transform,
66293                     },
66294                 };
66295                 vNodes.push(virtualDom.h("div.mapillary-tag-vertex.mapillary-tag-larger", pointProperties, []));
66296                 const dotProperties = {
66297                     style: {
66298                         transform: transform,
66299                     },
66300                 };
66301                 vNodes.push(virtualDom.h("div.mapillary-tag-dot", dotProperties, []));
66302             }
66303         }
66304         return vNodes;
66305     }
66306     _onGeometryChanged() {
66307         this._disposeObjects();
66308         this._rectGeometry = new RectGeometry(this._geometry.getRect2d(this._transform));
66309         this._createGlObjects();
66310     }
66311     _createGlObjects() {
66312         this._glObjects = [];
66313         const polygon3d = this._rectGeometry.getPoints3d(this._transform);
66314         this._outline = this._createOutine(polygon3d, this._options.color);
66315         this._glObjects.push(this._outline);
66316     }
66317     _disposeObjects() {
66318         this._disposeLine(this._outline);
66319         this._outline = null;
66320         this._glObjects = null;
66321     }
66322 }
66323
66324 /**
66325  * @class PolygonGeometry
66326  *
66327  * @classdesc Represents a polygon geometry in the 2D basic image coordinate system.
66328  * All polygons and holes provided to the constructor needs to be closed.
66329  *
66330  * @example
66331  * ```js
66332  * var basicPolygon = [[0.5, 0.3], [0.7, 0.3], [0.6, 0.5], [0.5, 0.3]];
66333  * var polygonGeometry = new PolygonGeometry(basicPolygon);
66334  * ```
66335  */
66336 class PolygonGeometry extends VertexGeometry {
66337     /**
66338      * Create a polygon geometry.
66339      *
66340      * @constructor
66341      * @param {Array<Array<number>>} polygon - Array of polygon vertices. Must be closed.
66342      * @param {Array<Array<Array<number>>>} [holes] - Array of arrays of hole vertices.
66343      * Each array of holes vertices must be closed.
66344      *
66345      * @throws {GeometryTagError} Polygon coordinates must be valid basic coordinates.
66346      */
66347     constructor(polygon, holes) {
66348         super();
66349         let polygonLength = polygon.length;
66350         if (polygonLength < 3) {
66351             throw new GeometryTagError("A polygon must have three or more positions.");
66352         }
66353         if (polygon[0][0] !== polygon[polygonLength - 1][0] ||
66354             polygon[0][1] !== polygon[polygonLength - 1][1]) {
66355             throw new GeometryTagError("First and last positions must be equivalent.");
66356         }
66357         this._polygon = [];
66358         for (let vertex of polygon) {
66359             if (vertex[0] < 0 || vertex[0] > 1 ||
66360                 vertex[1] < 0 || vertex[1] > 1) {
66361                 throw new GeometryTagError("Basic coordinates of polygon must be on the interval [0, 1].");
66362             }
66363             this._polygon.push(vertex.slice());
66364         }
66365         this._holes = [];
66366         if (holes == null) {
66367             return;
66368         }
66369         for (let i = 0; i < holes.length; i++) {
66370             let hole = holes[i];
66371             let holeLength = hole.length;
66372             if (holeLength < 3) {
66373                 throw new GeometryTagError("A polygon hole must have three or more positions.");
66374             }
66375             if (hole[0][0] !== hole[holeLength - 1][0] ||
66376                 hole[0][1] !== hole[holeLength - 1][1]) {
66377                 throw new GeometryTagError("First and last positions of hole must be equivalent.");
66378             }
66379             this._holes.push([]);
66380             for (let vertex of hole) {
66381                 if (vertex[0] < 0 || vertex[0] > 1 ||
66382                     vertex[1] < 0 || vertex[1] > 1) {
66383                     throw new GeometryTagError("Basic coordinates of hole must be on the interval [0, 1].");
66384                 }
66385                 this._holes[i].push(vertex.slice());
66386             }
66387         }
66388     }
66389     /**
66390      * Get polygon property.
66391      * @returns {Array<Array<number>>} Closed 2d polygon.
66392      */
66393     get polygon() {
66394         return this._polygon;
66395     }
66396     /**
66397      * Get holes property.
66398      * @returns {Array<Array<Array<number>>>} Holes of 2d polygon.
66399      */
66400     get holes() {
66401         return this._holes;
66402     }
66403     /**
66404      * Add a vertex to the polygon by appending it after the last vertex.
66405      *
66406      * @param {Array<number>} vertex - Vertex to add.
66407      * @ignore
66408      */
66409     addVertex2d(vertex) {
66410         let clamped = [
66411             Math.max(0, Math.min(1, vertex[0])),
66412             Math.max(0, Math.min(1, vertex[1])),
66413         ];
66414         this._polygon.splice(this._polygon.length - 1, 0, clamped);
66415         this._notifyChanged$.next(this);
66416     }
66417     /**
66418      * Get the coordinates of a vertex from the polygon representation of the geometry.
66419      *
66420      * @param {number} index - Vertex index.
66421      * @returns {Array<number>} Array representing the 2D basic coordinates of the vertex.
66422      * @ignore
66423      */
66424     getVertex2d(index) {
66425         return this._polygon[index].slice();
66426     }
66427     /**
66428      * Remove a vertex from the polygon.
66429      *
66430      * @param {number} index - The index of the vertex to remove.
66431      * @ignore
66432      */
66433     removeVertex2d(index) {
66434         if (index < 0 ||
66435             index >= this._polygon.length ||
66436             this._polygon.length < 4) {
66437             throw new GeometryTagError("Index for removed vertex must be valid.");
66438         }
66439         if (index > 0 && index < this._polygon.length - 1) {
66440             this._polygon.splice(index, 1);
66441         }
66442         else {
66443             this._polygon.splice(0, 1);
66444             this._polygon.pop();
66445             let closing = this._polygon[0].slice();
66446             this._polygon.push(closing);
66447         }
66448         this._notifyChanged$.next(this);
66449     }
66450     /** @ignore */
66451     setVertex2d(index, value, transform) {
66452         let changed = [
66453             Math.max(0, Math.min(1, value[0])),
66454             Math.max(0, Math.min(1, value[1])),
66455         ];
66456         if (index === 0 || index === this._polygon.length - 1) {
66457             this._polygon[0] = changed.slice();
66458             this._polygon[this._polygon.length - 1] = changed.slice();
66459         }
66460         else {
66461             this._polygon[index] = changed.slice();
66462         }
66463         this._notifyChanged$.next(this);
66464     }
66465     /** @ignore */
66466     setCentroid2d(value, transform) {
66467         let xs = this._polygon.map((point) => { return point[0]; });
66468         let ys = this._polygon.map((point) => { return point[1]; });
66469         let minX = Math.min.apply(Math, xs);
66470         let maxX = Math.max.apply(Math, xs);
66471         let minY = Math.min.apply(Math, ys);
66472         let maxY = Math.max.apply(Math, ys);
66473         let centroid = this.getCentroid2d();
66474         let minTranslationX = -minX;
66475         let maxTranslationX = 1 - maxX;
66476         let minTranslationY = -minY;
66477         let maxTranslationY = 1 - maxY;
66478         let translationX = Math.max(minTranslationX, Math.min(maxTranslationX, value[0] - centroid[0]));
66479         let translationY = Math.max(minTranslationY, Math.min(maxTranslationY, value[1] - centroid[1]));
66480         for (let point of this._polygon) {
66481             point[0] += translationX;
66482             point[1] += translationY;
66483         }
66484         this._notifyChanged$.next(this);
66485     }
66486     /** @ignore */
66487     getPoints3d(transform) {
66488         return this._getPoints3d(this._subsample(this._polygon), transform);
66489     }
66490     /** @ignore */
66491     getVertex3d(index, transform) {
66492         return transform.unprojectBasic(this._polygon[index], 200);
66493     }
66494     /** @ignore */
66495     getVertices2d() {
66496         return this._polygon.slice();
66497     }
66498     /** @ignore */
66499     getVertices3d(transform) {
66500         return this._getPoints3d(this._polygon, transform);
66501     }
66502     /**
66503      * Get a polygon representation of the 3D coordinates for the vertices of each hole
66504      * of the geometry. Line segments between vertices will possibly be subsampled
66505      * resulting in a larger number of points than the total number of vertices.
66506      *
66507      * @param {Transform} transform - The transform of the image related to the geometry.
66508      * @returns {Array<Array<Array<number>>>} Array of hole polygons in 3D world coordinates
66509      * representing the vertices of each hole of the geometry.
66510      * @ignore
66511      */
66512     getHolePoints3d(transform) {
66513         return this._holes
66514             .map((hole2d) => {
66515             return this._getPoints3d(this._subsample(hole2d), transform);
66516         });
66517     }
66518     /**
66519      * Get a polygon representation of the 3D coordinates for the vertices of each hole
66520      * of the geometry.
66521      *
66522      * @param {Transform} transform - The transform of the image related to the geometry.
66523      * @returns {Array<Array<Array<number>>>} Array of hole polygons in 3D world coordinates
66524      * representing the vertices of each hole of the geometry.
66525      * @ignore
66526      */
66527     getHoleVertices3d(transform) {
66528         return this._holes
66529             .map((hole2d) => {
66530             return this._getPoints3d(hole2d, transform);
66531         });
66532     }
66533     /** @ignore */
66534     getCentroid2d() {
66535         let polygon = this._polygon;
66536         let area = 0;
66537         let centroidX = 0;
66538         let centroidY = 0;
66539         for (let i = 0; i < polygon.length - 1; i++) {
66540             let xi = polygon[i][0];
66541             let yi = polygon[i][1];
66542             let xi1 = polygon[i + 1][0];
66543             let yi1 = polygon[i + 1][1];
66544             let a = xi * yi1 - xi1 * yi;
66545             area += a;
66546             centroidX += (xi + xi1) * a;
66547             centroidY += (yi + yi1) * a;
66548         }
66549         area /= 2;
66550         centroidX /= 6 * area;
66551         centroidY /= 6 * area;
66552         return [centroidX, centroidY];
66553     }
66554     /** @ignore */
66555     getCentroid3d(transform) {
66556         let centroid2d = this.getCentroid2d();
66557         return transform.unprojectBasic(centroid2d, 200);
66558     }
66559     /** @ignore */
66560     get3dDomainTriangles3d(transform) {
66561         return this._triangulate(this._project(this._polygon, transform), this.getVertices3d(transform), this._holes
66562             .map((hole2d) => {
66563             return this._project(hole2d, transform);
66564         }), this.getHoleVertices3d(transform));
66565     }
66566     /** @ignore */
66567     getTriangles3d(transform) {
66568         if (isSpherical(transform.cameraType)) {
66569             return this._triangulateSpherical(this._polygon.slice(), this.holes.slice(), transform);
66570         }
66571         const points2d = this._project(this._subsample(this._polygon), transform);
66572         const points3d = this.getPoints3d(transform);
66573         const holes2d = this._holes
66574             .map((hole) => {
66575             return this._project(this._subsample(hole), transform);
66576         });
66577         const holes3d = this.getHolePoints3d(transform);
66578         return this._triangulate(points2d, points3d, holes2d, holes3d);
66579     }
66580     /** @ignore */
66581     getPoleOfInaccessibility2d() {
66582         return this._getPoleOfInaccessibility2d(this._polygon.slice());
66583     }
66584     /** @ignore */
66585     getPoleOfInaccessibility3d(transform) {
66586         let pole2d = this._getPoleOfInaccessibility2d(this._polygon.slice());
66587         return transform.unprojectBasic(pole2d, 200);
66588     }
66589     _getPoints3d(points2d, transform) {
66590         return points2d
66591             .map((point) => {
66592             return transform.unprojectBasic(point, 200);
66593         });
66594     }
66595 }
66596
66597 class OutlineCreateTag extends CreateTag {
66598     constructor(geometry, options, transform, viewportCoords) {
66599         super(geometry, transform, viewportCoords);
66600         this._options = { color: options.color == null ? 0xFFFFFF : options.color };
66601         this._createGlObjects();
66602     }
66603     create() {
66604         if (this._geometry instanceof RectGeometry) {
66605             this._created$.next(this);
66606         }
66607         else if (this._geometry instanceof PolygonGeometry) {
66608             const polygonGeometry = this._geometry;
66609             polygonGeometry.removeVertex2d(polygonGeometry.polygon.length - 2);
66610             this._created$.next(this);
66611         }
66612     }
66613     dispose() {
66614         super.dispose();
66615         this._disposeLine(this._outline);
66616         this._disposeObjects();
66617     }
66618     getDOMObjects(camera, size) {
66619         const vNodes = [];
66620         const container = {
66621             offsetHeight: size.height, offsetWidth: size.width,
66622         };
66623         const abort = (e) => {
66624             e.stopPropagation();
66625             this._aborted$.next(this);
66626         };
66627         if (this._geometry instanceof RectGeometry) {
66628             const anchorIndex = this._geometry.anchorIndex;
66629             const vertexIndex = anchorIndex === undefined ? 1 : anchorIndex;
66630             const [basicX, basicY] = this._geometry.getVertex2d(vertexIndex);
66631             const canvasPoint = this._viewportCoords.basicToCanvasSafe(basicX, basicY, container, this._transform, camera);
66632             if (canvasPoint != null) {
66633                 const background = this._colorToBackground(this._options.color);
66634                 const transform = this._canvasToTransform(canvasPoint);
66635                 const pointProperties = {
66636                     style: { background: background, transform: transform },
66637                 };
66638                 const completerProperties = {
66639                     onclick: abort,
66640                     style: { transform: transform },
66641                 };
66642                 vNodes.push(virtualDom.h("div.mapillary-tag-interactor", completerProperties, []));
66643                 vNodes.push(virtualDom.h("div.mapillary-tag-vertex", pointProperties, []));
66644             }
66645         }
66646         else if (this._geometry instanceof PolygonGeometry) {
66647             const polygonGeometry = this._geometry;
66648             const [firstVertexBasicX, firstVertexBasicY] = polygonGeometry.getVertex2d(0);
66649             const firstVertexCanvas = this._viewportCoords.basicToCanvasSafe(firstVertexBasicX, firstVertexBasicY, container, this._transform, camera);
66650             if (firstVertexCanvas != null) {
66651                 const firstOnclick = polygonGeometry.polygon.length > 4 ?
66652                     (e) => {
66653                         e.stopPropagation();
66654                         polygonGeometry.removeVertex2d(polygonGeometry.polygon.length - 2);
66655                         this._created$.next(this);
66656                     } :
66657                     abort;
66658                 const transform = this._canvasToTransform(firstVertexCanvas);
66659                 const completerProperties = {
66660                     onclick: firstOnclick,
66661                     style: { transform: transform },
66662                 };
66663                 const firstClass = polygonGeometry.polygon.length > 4 ?
66664                     "mapillary-tag-completer" :
66665                     "mapillary-tag-interactor";
66666                 vNodes.push(virtualDom.h("div." + firstClass, completerProperties, []));
66667             }
66668             if (polygonGeometry.polygon.length > 3) {
66669                 const [lastVertexBasicX, lastVertexBasicY] = polygonGeometry.getVertex2d(polygonGeometry.polygon.length - 3);
66670                 const lastVertexCanvas = this._viewportCoords.basicToCanvasSafe(lastVertexBasicX, lastVertexBasicY, container, this._transform, camera);
66671                 if (lastVertexCanvas != null) {
66672                     const remove = (e) => {
66673                         e.stopPropagation();
66674                         polygonGeometry.removeVertex2d(polygonGeometry.polygon.length - 3);
66675                     };
66676                     const transform = this._canvasToTransform(lastVertexCanvas);
66677                     const completerProperties = {
66678                         onclick: remove,
66679                         style: { transform: transform },
66680                     };
66681                     vNodes.push(virtualDom.h("div.mapillary-tag-interactor", completerProperties, []));
66682                 }
66683             }
66684             const verticesBasic = polygonGeometry.polygon.slice();
66685             verticesBasic.splice(-2, 2);
66686             for (const vertexBasic of verticesBasic) {
66687                 const vertexCanvas = this._viewportCoords.basicToCanvasSafe(vertexBasic[0], vertexBasic[1], container, this._transform, camera);
66688                 if (vertexCanvas != null) {
66689                     const background = this._colorToBackground(this._options.color);
66690                     const transform = this._canvasToTransform(vertexCanvas);
66691                     const pointProperties = {
66692                         style: {
66693                             background: background,
66694                             transform: transform,
66695                         },
66696                     };
66697                     vNodes.push(virtualDom.h("div.mapillary-tag-vertex", pointProperties, []));
66698                 }
66699             }
66700         }
66701         return vNodes;
66702     }
66703     addPoint(point) {
66704         if (this._geometry instanceof RectGeometry) {
66705             const rectGeometry = this._geometry;
66706             if (!rectGeometry.validate(point)) {
66707                 return;
66708             }
66709             this._created$.next(this);
66710         }
66711         else if (this._geometry instanceof PolygonGeometry) {
66712             const polygonGeometry = this._geometry;
66713             polygonGeometry.addVertex2d(point);
66714         }
66715     }
66716     _onGeometryChanged() {
66717         this._disposeLine(this._outline);
66718         this._disposeObjects();
66719         this._createGlObjects();
66720     }
66721     _disposeObjects() {
66722         this._outline = null;
66723         this._glObjects = [];
66724     }
66725     _createGlObjects() {
66726         const polygon3d = this._geometry instanceof RectGeometry ?
66727             this._geometry.getPoints3d(this._transform) :
66728             this._geometry.getVertices3d(this._transform);
66729         this._outline = this._createOutine(polygon3d, this._options.color);
66730         this._glObjects = [this._outline];
66731     }
66732 }
66733
66734 class TagCreator {
66735     constructor(component, navigator) {
66736         this._component = component;
66737         this._navigator = navigator;
66738         this._tagOperation$ = new Subject();
66739         this._createPoints$ = new Subject();
66740         this._createPolygon$ = new Subject();
66741         this._createRect$ = new Subject();
66742         this._delete$ = new Subject();
66743         this._tag$ = this._tagOperation$.pipe(scan((tag, operation) => {
66744             return operation(tag);
66745         }, null), share());
66746         this._replayedTag$ = this._tag$.pipe(publishReplay(1), refCount());
66747         this._replayedTag$.subscribe();
66748         this._createPoints$.pipe(withLatestFrom(this._component.configuration$, this._navigator.stateService.currentTransform$), map(([coord, conf, transform]) => {
66749             return () => {
66750                 const geometry = new PointsGeometry([
66751                     [coord[0], coord[1]],
66752                     [coord[0], coord[1]],
66753                 ]);
66754                 return new ExtremePointCreateTag(geometry, {
66755                     color: conf.createColor,
66756                     indicateCompleter: conf.indicatePointsCompleter,
66757                 }, transform);
66758             };
66759         }))
66760             .subscribe(this._tagOperation$);
66761         this._createRect$.pipe(withLatestFrom(this._component.configuration$, this._navigator.stateService.currentTransform$), map(([coord, conf, transform]) => {
66762             return () => {
66763                 const geometry = new RectGeometry([
66764                     coord[0],
66765                     coord[1],
66766                     coord[0],
66767                     coord[1],
66768                 ]);
66769                 return new OutlineCreateTag(geometry, { color: conf.createColor }, transform);
66770             };
66771         }))
66772             .subscribe(this._tagOperation$);
66773         this._createPolygon$.pipe(withLatestFrom(this._component.configuration$, this._navigator.stateService.currentTransform$), map(([coord, conf, transform]) => {
66774             return () => {
66775                 const geometry = new PolygonGeometry([
66776                     [coord[0], coord[1]],
66777                     [coord[0], coord[1]],
66778                     [coord[0], coord[1]],
66779                 ]);
66780                 return new OutlineCreateTag(geometry, { color: conf.createColor }, transform);
66781             };
66782         }))
66783             .subscribe(this._tagOperation$);
66784         this._delete$.pipe(map(() => {
66785             return () => {
66786                 return null;
66787             };
66788         }))
66789             .subscribe(this._tagOperation$);
66790     }
66791     get createRect$() {
66792         return this._createRect$;
66793     }
66794     get createPolygon$() {
66795         return this._createPolygon$;
66796     }
66797     get createPoints$() {
66798         return this._createPoints$;
66799     }
66800     get delete$() {
66801         return this._delete$;
66802     }
66803     get tag$() {
66804         return this._tag$;
66805     }
66806     get replayedTag$() {
66807         return this._replayedTag$;
66808     }
66809 }
66810
66811 class TagDOMRenderer {
66812     render(tags, createTag, atlas, camera, size) {
66813         let vNodes = [];
66814         for (const tag of tags) {
66815             vNodes = vNodes.concat(tag.getDOMObjects(atlas, camera, size));
66816         }
66817         if (createTag != null) {
66818             vNodes = vNodes.concat(createTag.getDOMObjects(camera, size));
66819         }
66820         return virtualDom.h("div.mapillary-tag-container", {}, vNodes);
66821     }
66822     clear() {
66823         return virtualDom.h("div", {}, []);
66824     }
66825 }
66826
66827 class TagScene {
66828     constructor(scene, raycaster) {
66829         this._createTag = null;
66830         this._needsRender = false;
66831         this._raycaster = !!raycaster ? raycaster : new Raycaster();
66832         this._scene = !!scene ? scene : new Scene();
66833         this._objectTags = {};
66834         this._retrievableObjects = [];
66835         this._tags = {};
66836     }
66837     get needsRender() {
66838         return this._needsRender;
66839     }
66840     add(tags) {
66841         for (let tag of tags) {
66842             if (tag.tag.id in this._tags) {
66843                 this._remove(tag.tag.id);
66844             }
66845             this._add(tag);
66846         }
66847         this._needsRender = true;
66848     }
66849     addCreateTag(tag) {
66850         for (const object of tag.glObjects) {
66851             this._scene.add(object);
66852         }
66853         this._createTag = { tag: tag, objects: tag.glObjects };
66854         this._needsRender = true;
66855     }
66856     clear() {
66857         for (const id of Object.keys(this._tags)) {
66858             this._remove(id);
66859         }
66860         this._needsRender = false;
66861     }
66862     get(id) {
66863         return this.has(id) ? this._tags[id].tag : undefined;
66864     }
66865     has(id) {
66866         return id in this._tags;
66867     }
66868     hasCreateTag() {
66869         return this._createTag != null;
66870     }
66871     intersectObjects([viewportX, viewportY], camera) {
66872         this._raycaster.setFromCamera(new Vector2(viewportX, viewportY), camera);
66873         const intersects = this._raycaster.intersectObjects(this._retrievableObjects);
66874         const intersectedIds = [];
66875         for (const intersect of intersects) {
66876             if (intersect.object.uuid in this._objectTags) {
66877                 intersectedIds.push(this._objectTags[intersect.object.uuid]);
66878             }
66879         }
66880         return intersectedIds;
66881     }
66882     remove(ids) {
66883         for (const id of ids) {
66884             this._remove(id);
66885         }
66886         this._needsRender = true;
66887     }
66888     removeAll() {
66889         for (const id of Object.keys(this._tags)) {
66890             this._remove(id);
66891         }
66892         this._needsRender = true;
66893     }
66894     removeCreateTag() {
66895         if (this._createTag == null) {
66896             return;
66897         }
66898         for (const object of this._createTag.objects) {
66899             this._scene.remove(object);
66900         }
66901         this._createTag.tag.dispose();
66902         this._createTag = null;
66903         this._needsRender = true;
66904     }
66905     render(perspectiveCamera, renderer) {
66906         renderer.render(this._scene, perspectiveCamera);
66907         this._needsRender = false;
66908     }
66909     update() {
66910         this._needsRender = true;
66911     }
66912     updateCreateTagObjects(tag) {
66913         if (this._createTag.tag !== tag) {
66914             throw new Error("Create tags do not have the same reference.");
66915         }
66916         for (let object of this._createTag.objects) {
66917             this._scene.remove(object);
66918         }
66919         for (const object of tag.glObjects) {
66920             this._scene.add(object);
66921         }
66922         this._createTag.objects = tag.glObjects;
66923         this._needsRender = true;
66924     }
66925     updateObjects(tag) {
66926         const id = tag.tag.id;
66927         if (this._tags[id].tag !== tag) {
66928             throw new Error("Tags do not have the same reference.");
66929         }
66930         const tagObjects = this._tags[id];
66931         this._removeObjects(tagObjects);
66932         delete this._tags[id];
66933         this._add(tag);
66934         this._needsRender = true;
66935     }
66936     _add(tag) {
66937         const id = tag.tag.id;
66938         const tagObjects = { tag: tag, objects: [], retrievableObjects: [] };
66939         this._tags[id] = tagObjects;
66940         for (const object of tag.getGLObjects()) {
66941             tagObjects.objects.push(object);
66942             this._scene.add(object);
66943         }
66944         for (const retrievableObject of tag.getRetrievableObjects()) {
66945             tagObjects.retrievableObjects.push(retrievableObject);
66946             this._retrievableObjects.push(retrievableObject);
66947             this._objectTags[retrievableObject.uuid] = tag.tag.id;
66948         }
66949     }
66950     _remove(id) {
66951         const tagObjects = this._tags[id];
66952         this._removeObjects(tagObjects);
66953         tagObjects.tag.dispose();
66954         delete this._tags[id];
66955     }
66956     _removeObjects(tagObjects) {
66957         for (const object of tagObjects.objects) {
66958             this._scene.remove(object);
66959         }
66960         for (const retrievableObject of tagObjects.retrievableObjects) {
66961             const index = this._retrievableObjects.indexOf(retrievableObject);
66962             if (index !== -1) {
66963                 this._retrievableObjects.splice(index, 1);
66964             }
66965         }
66966     }
66967 }
66968
66969 /**
66970  * Enumeration for tag modes
66971  * @enum {number}
66972  * @readonly
66973  * @description Modes for the interaction in the tag component.
66974  */
66975 var TagMode;
66976 (function (TagMode) {
66977     /**
66978      * Disables creating tags.
66979      */
66980     TagMode[TagMode["Default"] = 0] = "Default";
66981     /**
66982      * Create a point geometry through a click.
66983      */
66984     TagMode[TagMode["CreatePoint"] = 1] = "CreatePoint";
66985     /**
66986      * Create a points geometry through clicks.
66987      */
66988     TagMode[TagMode["CreatePoints"] = 2] = "CreatePoints";
66989     /**
66990      * Create a polygon geometry through clicks.
66991      */
66992     TagMode[TagMode["CreatePolygon"] = 3] = "CreatePolygon";
66993     /**
66994      * Create a rect geometry through clicks.
66995      */
66996     TagMode[TagMode["CreateRect"] = 4] = "CreateRect";
66997     /**
66998      * Create a rect geometry through drag.
66999      *
67000      * @description Claims the mouse which results in mouse handlers like
67001      * drag pan and scroll zoom becoming inactive.
67002      */
67003     TagMode[TagMode["CreateRectDrag"] = 5] = "CreateRectDrag";
67004 })(TagMode || (TagMode = {}));
67005
67006 var TagOperation;
67007 (function (TagOperation) {
67008     TagOperation[TagOperation["None"] = 0] = "None";
67009     TagOperation[TagOperation["Centroid"] = 1] = "Centroid";
67010     TagOperation[TagOperation["Vertex"] = 2] = "Vertex";
67011 })(TagOperation || (TagOperation = {}));
67012
67013 class RenderTag {
67014     constructor(tag, transform, viewportCoords) {
67015         this._tag = tag;
67016         this._transform = transform;
67017         this._viewportCoords = !!viewportCoords ? viewportCoords : new ViewportCoords();
67018         this._glObjectsChanged$ = new Subject();
67019         this._interact$ = new Subject();
67020     }
67021     get glObjectsChanged$() {
67022         return this._glObjectsChanged$;
67023     }
67024     get interact$() {
67025         return this._interact$;
67026     }
67027     get tag() {
67028         return this._tag;
67029     }
67030 }
67031
67032 class OutlineRenderTagBase extends RenderTag {
67033     constructor(tag, transform) {
67034         super(tag, transform);
67035         this._geometryChangedSubscription = this._tag.geometry.changed$
67036             .subscribe(() => {
67037             this._onGeometryChanged();
67038         });
67039         this._changedSubscription = this._tag.changed$
67040             .subscribe(() => {
67041             const glObjectsChanged = this._onTagChanged();
67042             if (glObjectsChanged) {
67043                 this._glObjectsChanged$.next(this);
67044             }
67045         });
67046     }
67047     dispose() {
67048         this._changedSubscription.unsubscribe();
67049         this._geometryChangedSubscription.unsubscribe();
67050     }
67051     _colorToCss(color) {
67052         return "#" + ("000000" + color.toString(16)).substr(-6);
67053     }
67054     _createFill() {
67055         let triangles = this._getTriangles();
67056         let positions = new Float32Array(triangles);
67057         let geometry = new BufferGeometry();
67058         geometry.setAttribute("position", new BufferAttribute(positions, 3));
67059         geometry.computeBoundingSphere();
67060         let material = new MeshBasicMaterial({ side: DoubleSide, transparent: true });
67061         this._updateFillMaterial(material);
67062         return new Mesh(geometry, material);
67063     }
67064     _createLine(points3d) {
67065         let positions = this._getLinePositions(points3d);
67066         let geometry = new BufferGeometry();
67067         geometry.setAttribute("position", new BufferAttribute(positions, 3));
67068         geometry.computeBoundingSphere();
67069         let material = new LineBasicMaterial();
67070         this._updateLineBasicMaterial(material);
67071         const line = new Line(geometry, material);
67072         line.renderOrder = 1;
67073         return line;
67074     }
67075     _createOutline() {
67076         return this._createLine(this._getPoints3d());
67077     }
67078     _disposeFill() {
67079         if (this._fill == null) {
67080             return;
67081         }
67082         this._fill.geometry.dispose();
67083         this._fill.material.dispose();
67084         this._fill = null;
67085     }
67086     _disposeOutline() {
67087         if (this._outline == null) {
67088             return;
67089         }
67090         this._outline.geometry.dispose();
67091         this._outline.material.dispose();
67092         this._outline = null;
67093     }
67094     _getLinePositions(points3d) {
67095         let length = points3d.length;
67096         let positions = new Float32Array(length * 3);
67097         for (let i = 0; i < length; ++i) {
67098             let index = 3 * i;
67099             let position = points3d[i];
67100             positions[index + 0] = position[0];
67101             positions[index + 1] = position[1];
67102             positions[index + 2] = position[2];
67103         }
67104         return positions;
67105     }
67106     _interact(operation, cursor, vertexIndex) {
67107         return (e) => {
67108             let offsetX = e.offsetX - e.target.offsetWidth / 2;
67109             let offsetY = e.offsetY - e.target.offsetHeight / 2;
67110             this._interact$.next({
67111                 cursor: cursor,
67112                 offsetX: offsetX,
67113                 offsetY: offsetY,
67114                 operation: operation,
67115                 tag: this._tag,
67116                 vertexIndex: vertexIndex,
67117             });
67118         };
67119     }
67120     _updateFillGeometry() {
67121         let triangles = this._getTriangles();
67122         let positions = new Float32Array(triangles);
67123         let geometry = this._fill.geometry;
67124         let attribute = geometry.getAttribute("position");
67125         if (attribute.array.length === positions.length) {
67126             attribute.set(positions);
67127             attribute.needsUpdate = true;
67128         }
67129         else {
67130             geometry.deleteAttribute("position");
67131             geometry.setAttribute("position", new BufferAttribute(positions, 3));
67132         }
67133         geometry.computeBoundingSphere();
67134     }
67135     _updateLine(line, points3d) {
67136         let positions = this._getLinePositions(points3d);
67137         let geometry = line.geometry;
67138         let attribute = geometry.getAttribute("position");
67139         attribute.set(positions);
67140         attribute.needsUpdate = true;
67141         geometry.computeBoundingSphere();
67142     }
67143     _updateOulineGeometry() {
67144         this._updateLine(this._outline, this._getPoints3d());
67145     }
67146 }
67147
67148 /**
67149  * @class OutlineRenderTag
67150  * @classdesc Tag visualizing the properties of an OutlineTag.
67151  */
67152 class ExtremePointRenderTag extends OutlineRenderTagBase {
67153     constructor(tag, transform) {
67154         super(tag, transform);
67155         this._rectGeometry = new RectGeometry(this._tag.geometry.getRect2d(transform));
67156         this._fill = !isSpherical(transform.cameraType) ?
67157             this._createFill() : null;
67158         this._outline = this._tag.lineWidth >= 1 ?
67159             this._createOutline() :
67160             null;
67161     }
67162     dispose() {
67163         super.dispose();
67164         this._disposeFill();
67165         this._disposeOutline();
67166     }
67167     getDOMObjects(atlas, camera, size) {
67168         const vNodes = [];
67169         const container = {
67170             offsetHeight: size.height, offsetWidth: size.width,
67171         };
67172         if (!this._tag.editable) {
67173             return vNodes;
67174         }
67175         const lineColor = this._colorToCss(this._tag.lineColor);
67176         const points2d = this._tag.geometry.getPoints2d();
67177         for (let i = 0; i < points2d.length; i++) {
67178             const [vertexBasicX, vertexBasicY] = points2d[i];
67179             const vertexCanvas = this._viewportCoords.basicToCanvasSafe(vertexBasicX, vertexBasicY, container, this._transform, camera);
67180             if (vertexCanvas == null) {
67181                 continue;
67182             }
67183             const cursor = "crosshair";
67184             const interact = this._interact(TagOperation.Vertex, cursor, i);
67185             const vertexCanvasX = Math.round(vertexCanvas[0]);
67186             const vertexCanvasY = Math.round(vertexCanvas[1]);
67187             const transform = `translate(-50%, -50%) translate(${vertexCanvasX}px,${vertexCanvasY}px)`;
67188             const properties = {
67189                 onpointerdown: interact,
67190                 style: { background: lineColor, transform: transform, cursor: cursor },
67191             };
67192             vNodes.push(virtualDom.h("div.mapillary-tag-resizer", properties, []));
67193             if (!this._tag.indicateVertices) {
67194                 continue;
67195             }
67196             const pointProperties = {
67197                 style: { background: lineColor, transform: transform },
67198             };
67199             vNodes.push(virtualDom.h("div.mapillary-tag-vertex", pointProperties, []));
67200         }
67201         return vNodes;
67202     }
67203     getGLObjects() {
67204         const glObjects = [];
67205         if (this._fill != null) {
67206             glObjects.push(this._fill);
67207         }
67208         if (this._outline != null) {
67209             glObjects.push(this._outline);
67210         }
67211         return glObjects;
67212     }
67213     getRetrievableObjects() {
67214         return this._fill != null ? [this._fill] : [];
67215     }
67216     _onGeometryChanged() {
67217         this._rectGeometry = new RectGeometry(this._tag.geometry.getRect2d(this._transform));
67218         if (this._fill != null) {
67219             this._updateFillGeometry();
67220         }
67221         if (this._outline != null) {
67222             this._updateOulineGeometry();
67223         }
67224     }
67225     _onTagChanged() {
67226         let glObjectsChanged = false;
67227         if (this._fill != null) {
67228             this._updateFillMaterial(this._fill.material);
67229         }
67230         if (this._outline == null) {
67231             if (this._tag.lineWidth >= 1) {
67232                 this._outline = this._createOutline();
67233                 glObjectsChanged = true;
67234             }
67235         }
67236         else {
67237             this._updateOutlineMaterial();
67238         }
67239         return glObjectsChanged;
67240     }
67241     _getPoints3d() {
67242         return this._rectGeometry.getPoints3d(this._transform);
67243     }
67244     _getTriangles() {
67245         return this._rectGeometry.getTriangles3d(this._transform);
67246     }
67247     _updateFillMaterial(material) {
67248         material.color = new Color(this._tag.fillColor);
67249         material.opacity = this._tag.fillOpacity;
67250         material.needsUpdate = true;
67251     }
67252     _updateLineBasicMaterial(material) {
67253         material.color = new Color(this._tag.lineColor);
67254         material.linewidth = Math.max(this._tag.lineWidth, 1);
67255         material.visible = this._tag.lineWidth >= 1 && this._tag.lineOpacity > 0;
67256         material.opacity = this._tag.lineOpacity;
67257         material.transparent = this._tag.lineOpacity < 1;
67258         material.needsUpdate = true;
67259     }
67260     _updateOutlineMaterial() {
67261         let material = this._outline.material;
67262         this._updateLineBasicMaterial(material);
67263     }
67264 }
67265
67266 /**
67267  * @class Tag
67268  * @abstract
67269  * @classdesc Abstract class representing the basic functionality of for a tag.
67270  */
67271 class Tag extends EventEmitter {
67272     /**
67273      * Create a tag.
67274      *
67275      * @constructor
67276      * @param {string} id
67277      * @param {Geometry} geometry
67278      */
67279     constructor(id, geometry) {
67280         super();
67281         this._id = id;
67282         this._geometry = geometry;
67283         this._notifyChanged$ = new Subject();
67284         this._notifyChanged$
67285             .subscribe((t) => {
67286             const type = "tag";
67287             const event = {
67288                 target: this,
67289                 type,
67290             };
67291             this.fire(type, event);
67292         });
67293         this._geometry.changed$
67294             .subscribe((g) => {
67295             const type = "geometry";
67296             const event = {
67297                 target: this,
67298                 type,
67299             };
67300             this.fire(type, event);
67301         });
67302     }
67303     /**
67304      * Get id property.
67305      * @returns {string}
67306      */
67307     get id() {
67308         return this._id;
67309     }
67310     /**
67311      * Get geometry property.
67312      * @returns {Geometry} The geometry of the tag.
67313      */
67314     get geometry() {
67315         return this._geometry;
67316     }
67317     /**
67318      * Get changed observable.
67319      * @returns {Observable<Tag>}
67320      * @ignore
67321      */
67322     get changed$() {
67323         return this._notifyChanged$;
67324     }
67325     /**
67326      * Get geometry changed observable.
67327      * @returns {Observable<Tag>}
67328      * @ignore
67329      */
67330     get geometryChanged$() {
67331         return this._geometry.changed$.pipe(map(() => {
67332             return this;
67333         }), share());
67334     }
67335     fire(type, event) {
67336         super.fire(type, event);
67337     }
67338     off(type, handler) {
67339         super.off(type, handler);
67340     }
67341     on(type, handler) {
67342         super.on(type, handler);
67343     }
67344 }
67345
67346 /**
67347  * @class ExtremePointTag
67348  *
67349  * @classdesc Tag holding properties for visualizing a extreme points
67350  * and their outline.
67351  *
67352  * @example
67353  * ```js
67354  * var geometry = new PointsGeometry([[0.3, 0.3], [0.5, 0.4]]);
67355  * var tag = new ExtremePointTag(
67356  *     "id-1",
67357  *     geometry
67358  *     { editable: true, lineColor: 0xff0000 });
67359  *
67360  * tagComponent.add([tag]);
67361  * ```
67362  */
67363 class ExtremePointTag extends Tag {
67364     /**
67365      * Create an extreme point tag.
67366      *
67367      * @override
67368      * @constructor
67369      * @param {string} id - Unique identifier of the tag.
67370      * @param {PointsGeometry} geometry - Geometry defining points of tag.
67371      * @param {ExtremePointTagOptions} options - Options defining the visual appearance and
67372      * behavior of the extreme point tag.
67373      */
67374     constructor(id, geometry, options) {
67375         super(id, geometry);
67376         options = !!options ? options : {};
67377         this._editable = options.editable == null ? false : options.editable;
67378         this._fillColor = options.fillColor == null ? 0xFFFFFF : options.fillColor;
67379         this._fillOpacity = options.fillOpacity == null ? 0.0 : options.fillOpacity;
67380         this._indicateVertices = options.indicateVertices == null ? true : options.indicateVertices;
67381         this._lineColor = options.lineColor == null ? 0xFFFFFF : options.lineColor;
67382         this._lineOpacity = options.lineOpacity == null ? 1 : options.lineOpacity;
67383         this._lineWidth = options.lineWidth == null ? 1 : options.lineWidth;
67384     }
67385     /**
67386      * Get editable property.
67387      * @returns {boolean} Value indicating if tag is editable.
67388      */
67389     get editable() {
67390         return this._editable;
67391     }
67392     /**
67393      * Set editable property.
67394      * @param {boolean}
67395      *
67396      * @fires changed
67397      */
67398     set editable(value) {
67399         this._editable = value;
67400         this._notifyChanged$.next(this);
67401     }
67402     /**
67403      * Get fill color property.
67404      * @returns {number}
67405      */
67406     get fillColor() {
67407         return this._fillColor;
67408     }
67409     /**
67410      * Set fill color property.
67411      * @param {number}
67412      *
67413      * @fires changed
67414      */
67415     set fillColor(value) {
67416         this._fillColor = value;
67417         this._notifyChanged$.next(this);
67418     }
67419     /**
67420      * Get fill opacity property.
67421      * @returns {number}
67422      */
67423     get fillOpacity() {
67424         return this._fillOpacity;
67425     }
67426     /**
67427      * Set fill opacity property.
67428      * @param {number}
67429      *
67430      * @fires changed
67431      */
67432     set fillOpacity(value) {
67433         this._fillOpacity = value;
67434         this._notifyChanged$.next(this);
67435     }
67436     /** @inheritdoc */
67437     get geometry() {
67438         return this._geometry;
67439     }
67440     /**
67441      * Get indicate vertices property.
67442      * @returns {boolean} Value indicating if vertices should be indicated
67443      * when tag is editable.
67444      */
67445     get indicateVertices() {
67446         return this._indicateVertices;
67447     }
67448     /**
67449      * Set indicate vertices property.
67450      * @param {boolean}
67451      *
67452      * @fires changed
67453      */
67454     set indicateVertices(value) {
67455         this._indicateVertices = value;
67456         this._notifyChanged$.next(this);
67457     }
67458     /**
67459      * Get line color property.
67460      * @returns {number}
67461      */
67462     get lineColor() {
67463         return this._lineColor;
67464     }
67465     /**
67466      * Set line color property.
67467      * @param {number}
67468      *
67469      * @fires changed
67470      */
67471     set lineColor(value) {
67472         this._lineColor = value;
67473         this._notifyChanged$.next(this);
67474     }
67475     /**
67476      * Get line opacity property.
67477      * @returns {number}
67478      */
67479     get lineOpacity() {
67480         return this._lineOpacity;
67481     }
67482     /**
67483      * Set line opacity property.
67484      * @param {number}
67485      *
67486      * @fires changed
67487      */
67488     set lineOpacity(value) {
67489         this._lineOpacity = value;
67490         this._notifyChanged$.next(this);
67491     }
67492     /**
67493      * Get line width property.
67494      * @returns {number}
67495      */
67496     get lineWidth() {
67497         return this._lineWidth;
67498     }
67499     /**
67500      * Set line width property.
67501      * @param {number}
67502      *
67503      * @fires changed
67504      */
67505     set lineWidth(value) {
67506         this._lineWidth = value;
67507         this._notifyChanged$.next(this);
67508     }
67509     /**
67510      * Set options for tag.
67511      *
67512      * @description Sets all the option properties provided and keeps
67513      * the rest of the values as is.
67514      *
67515      * @param {ExtremePointTagOptions} options - Extreme point tag options
67516      *
67517      * @fires changed
67518      */
67519     setOptions(options) {
67520         this._editable = options.editable == null ? this._editable : options.editable;
67521         this._indicateVertices = options.indicateVertices == null ? this._indicateVertices : options.indicateVertices;
67522         this._lineColor = options.lineColor == null ? this._lineColor : options.lineColor;
67523         this._lineWidth = options.lineWidth == null ? this._lineWidth : options.lineWidth;
67524         this._fillColor = options.fillColor == null ? this._fillColor : options.fillColor;
67525         this._fillOpacity = options.fillOpacity == null ? this._fillOpacity : options.fillOpacity;
67526         this._notifyChanged$.next(this);
67527     }
67528 }
67529
67530 /**
67531  * Enumeration for tag domains.
67532  * @enum {number}
67533  * @readonly
67534  * @description Defines where lines between two vertices are treated
67535  * as straight.
67536  *
67537  * Only applicable for polygons. For rectangles lines between
67538  * vertices are always treated as straight in the distorted 2D
67539  * projection and bended in the undistorted 3D space.
67540  */
67541 var TagDomain;
67542 (function (TagDomain) {
67543     /**
67544      * Treats lines between two vertices as straight in the
67545      * distorted 2D projection, i.e. on the image. If the image
67546      * is distorted this will result in bended lines when rendered
67547      * in the undistorted 3D space.
67548      */
67549     TagDomain[TagDomain["TwoDimensional"] = 0] = "TwoDimensional";
67550     /**
67551      * Treats lines as straight in the undistorted 3D space. If the
67552      * image is distorted this will result in bended lines when rendered
67553      * on the distorted 2D projection of the image.
67554      */
67555     TagDomain[TagDomain["ThreeDimensional"] = 1] = "ThreeDimensional";
67556 })(TagDomain || (TagDomain = {}));
67557
67558 /**
67559  * @class OutlineRenderTag
67560  * @classdesc Tag visualizing the properties of an OutlineTag.
67561  */
67562 class OutlineRenderTag extends OutlineRenderTagBase {
67563     constructor(tag, transform) {
67564         super(tag, transform);
67565         this._fill = !isSpherical(transform.cameraType) ?
67566             this._createFill() :
67567             tag.domain === TagDomain.TwoDimensional &&
67568                 tag.geometry instanceof PolygonGeometry ?
67569                 this._createFill() :
67570                 null;
67571         this._holes = this._tag.lineWidth >= 1 ?
67572             this._createHoles() :
67573             [];
67574         this._outline = this._tag.lineWidth >= 1 ?
67575             this._createOutline() :
67576             null;
67577     }
67578     dispose() {
67579         super.dispose();
67580         this._disposeFill();
67581         this._disposeHoles();
67582         this._disposeOutline();
67583     }
67584     getDOMObjects(atlas, camera, size) {
67585         const vNodes = [];
67586         const isRect = this._tag.geometry instanceof RectGeometry;
67587         const isPerspective = !isSpherical(this._transform.cameraType);
67588         const container = {
67589             offsetHeight: size.height, offsetWidth: size.width,
67590         };
67591         if (this._tag.icon != null && (isRect || isPerspective)) {
67592             const [iconBasicX, iconBasicY] = this._tag.geometry instanceof RectGeometry ?
67593                 this._tag.geometry.getVertex2d(this._tag.iconIndex) :
67594                 this._tag.geometry.getPoleOfInaccessibility2d();
67595             const iconCanvas = this._viewportCoords.basicToCanvasSafe(iconBasicX, iconBasicY, container, this._transform, camera);
67596             if (iconCanvas != null) {
67597                 const interact = () => {
67598                     this._interact$.next({ offsetX: 0, offsetY: 0, operation: TagOperation.None, tag: this._tag });
67599                 };
67600                 if (atlas.loaded) {
67601                     const sprite = atlas.getDOMSprite(this._tag.icon, this._tag.iconFloat);
67602                     const iconCanvasX = Math.round(iconCanvas[0]);
67603                     const iconCanvasY = Math.round(iconCanvas[1]);
67604                     const transform = `translate(${iconCanvasX}px,${iconCanvasY}px)`;
67605                     const click = (e) => {
67606                         e.stopPropagation();
67607                         this._tag.click$.next(this._tag);
67608                     };
67609                     const properties = {
67610                         onclick: click,
67611                         onpointerdown: interact,
67612                         style: { transform: transform },
67613                     };
67614                     vNodes.push(virtualDom.h("div.mapillary-tag-symbol", properties, [sprite]));
67615                 }
67616             }
67617         }
67618         else if (this._tag.text != null && (isRect || isPerspective)) {
67619             const [textBasicX, textBasicY] = this._tag.geometry instanceof RectGeometry ?
67620                 this._tag.geometry.getVertex2d(3) :
67621                 this._tag.geometry.getPoleOfInaccessibility2d();
67622             const textCanvas = this._viewportCoords.basicToCanvasSafe(textBasicX, textBasicY, container, this._transform, camera);
67623             if (textCanvas != null) {
67624                 const textCanvasX = Math.round(textCanvas[0]);
67625                 const textCanvasY = Math.round(textCanvas[1]);
67626                 const transform = this._tag.geometry instanceof RectGeometry ?
67627                     `translate(${textCanvasX}px,${textCanvasY}px)` :
67628                     `translate(-50%, -50%) translate(${textCanvasX}px,${textCanvasY}px)`;
67629                 const interact = () => {
67630                     this._interact$.next({ offsetX: 0, offsetY: 0, operation: TagOperation.None, tag: this._tag });
67631                 };
67632                 const properties = {
67633                     onpointerdown: interact,
67634                     style: {
67635                         color: this._colorToCss(this._tag.textColor),
67636                         transform: transform,
67637                     },
67638                     textContent: this._tag.text,
67639                 };
67640                 vNodes.push(virtualDom.h("span.mapillary-tag-symbol", properties, []));
67641             }
67642         }
67643         if (!this._tag.editable) {
67644             return vNodes;
67645         }
67646         const lineColor = this._colorToCss(this._tag.lineColor);
67647         if (this._tag.geometry instanceof RectGeometry) {
67648             const [centroidBasicX, centroidBasicY] = this._tag.geometry.getCentroid2d();
67649             const centroidCanvas = this._viewportCoords.basicToCanvasSafe(centroidBasicX, centroidBasicY, container, this._transform, camera);
67650             if (centroidCanvas != null) {
67651                 const interact = this._interact(TagOperation.Centroid, "move");
67652                 const centroidCanvasX = Math.round(centroidCanvas[0]);
67653                 const centroidCanvasY = Math.round(centroidCanvas[1]);
67654                 const transform = `translate(-50%, -50%) translate(${centroidCanvasX}px,${centroidCanvasY}px)`;
67655                 const properties = {
67656                     onpointerdown: interact,
67657                     style: { background: lineColor, transform: transform },
67658                 };
67659                 vNodes.push(virtualDom.h("div.mapillary-tag-mover", properties, []));
67660             }
67661         }
67662         const vertices2d = this._tag.geometry.getVertices2d();
67663         for (let i = 0; i < vertices2d.length - 1; i++) {
67664             if (isRect &&
67665                 ((this._tag.icon != null && i === this._tag.iconIndex) ||
67666                     (this._tag.icon == null && this._tag.text != null && i === 3))) {
67667                 continue;
67668             }
67669             const [vertexBasicX, vertexBasicY] = vertices2d[i];
67670             const vertexCanvas = this._viewportCoords.basicToCanvasSafe(vertexBasicX, vertexBasicY, container, this._transform, camera);
67671             if (vertexCanvas == null) {
67672                 continue;
67673             }
67674             const cursor = isRect ?
67675                 i % 2 === 0 ? "nesw-resize" : "nwse-resize" :
67676                 "crosshair";
67677             const interact = this._interact(TagOperation.Vertex, cursor, i);
67678             const vertexCanvasX = Math.round(vertexCanvas[0]);
67679             const vertexCanvasY = Math.round(vertexCanvas[1]);
67680             const transform = `translate(-50%, -50%) translate(${vertexCanvasX}px,${vertexCanvasY}px)`;
67681             const properties = {
67682                 onpointerdown: interact,
67683                 style: { background: lineColor, transform: transform, cursor: cursor },
67684             };
67685             vNodes.push(virtualDom.h("div.mapillary-tag-resizer", properties, []));
67686             if (!this._tag.indicateVertices) {
67687                 continue;
67688             }
67689             const pointProperties = {
67690                 style: { background: lineColor, transform: transform },
67691             };
67692             vNodes.push(virtualDom.h("div.mapillary-tag-vertex", pointProperties, []));
67693         }
67694         return vNodes;
67695     }
67696     getGLObjects() {
67697         const glObjects = [];
67698         if (this._fill != null) {
67699             glObjects.push(this._fill);
67700         }
67701         for (const hole of this._holes) {
67702             glObjects.push(hole);
67703         }
67704         if (this._outline != null) {
67705             glObjects.push(this._outline);
67706         }
67707         return glObjects;
67708     }
67709     getRetrievableObjects() {
67710         return this._fill != null ? [this._fill] : [];
67711     }
67712     _onGeometryChanged() {
67713         if (this._fill != null) {
67714             this._updateFillGeometry();
67715         }
67716         if (this._holes.length > 0) {
67717             this._updateHoleGeometries();
67718         }
67719         if (this._outline != null) {
67720             this._updateOulineGeometry();
67721         }
67722     }
67723     _onTagChanged() {
67724         let glObjectsChanged = false;
67725         if (this._fill != null) {
67726             this._updateFillMaterial(this._fill.material);
67727         }
67728         if (this._outline == null) {
67729             if (this._tag.lineWidth >= 1) {
67730                 this._holes = this._createHoles();
67731                 this._outline = this._createOutline();
67732                 glObjectsChanged = true;
67733             }
67734         }
67735         else {
67736             this._updateHoleMaterials();
67737             this._updateOutlineMaterial();
67738         }
67739         return glObjectsChanged;
67740     }
67741     _getPoints3d() {
67742         return this._in3dDomain() ?
67743             this._tag.geometry.getVertices3d(this._transform) :
67744             this._tag.geometry.getPoints3d(this._transform);
67745     }
67746     _getTriangles() {
67747         return this._in3dDomain() ?
67748             this._tag.geometry.get3dDomainTriangles3d(this._transform) :
67749             this._tag.geometry.getTriangles3d(this._transform);
67750     }
67751     _updateFillMaterial(material) {
67752         material.color = new Color(this._tag.fillColor);
67753         material.opacity = this._tag.fillOpacity;
67754         material.needsUpdate = true;
67755     }
67756     _updateLineBasicMaterial(material) {
67757         material.color = new Color(this._tag.lineColor);
67758         material.linewidth = Math.max(this._tag.lineWidth, 1);
67759         material.visible = this._tag.lineWidth >= 1 && this._tag.lineOpacity > 0;
67760         material.opacity = this._tag.lineOpacity;
67761         material.transparent = this._tag.lineOpacity < 1;
67762         material.needsUpdate = true;
67763     }
67764     _createHoles() {
67765         let holes = [];
67766         if (this._tag.geometry instanceof PolygonGeometry) {
67767             let holes3d = this._getHoles3d();
67768             for (let holePoints3d of holes3d) {
67769                 let hole = this._createLine(holePoints3d);
67770                 holes.push(hole);
67771             }
67772         }
67773         return holes;
67774     }
67775     _disposeHoles() {
67776         for (let hole of this._holes) {
67777             hole.geometry.dispose();
67778             hole.material.dispose();
67779         }
67780         this._holes = [];
67781     }
67782     _getHoles3d() {
67783         const polygonGeometry = this._tag.geometry;
67784         return this._in3dDomain() ?
67785             polygonGeometry.getHoleVertices3d(this._transform) :
67786             polygonGeometry.getHolePoints3d(this._transform);
67787     }
67788     _in3dDomain() {
67789         return this._tag.geometry instanceof PolygonGeometry && this._tag.domain === TagDomain.ThreeDimensional;
67790     }
67791     _updateHoleGeometries() {
67792         let holes3d = this._getHoles3d();
67793         if (holes3d.length !== this._holes.length) {
67794             throw new Error("Changing the number of holes is not supported.");
67795         }
67796         for (let i = 0; i < this._holes.length; i++) {
67797             let holePoints3d = holes3d[i];
67798             let hole = this._holes[i];
67799             this._updateLine(hole, holePoints3d);
67800         }
67801     }
67802     _updateHoleMaterials() {
67803         for (const hole of this._holes) {
67804             this._updateLineBasicMaterial(hole.material);
67805         }
67806     }
67807     _updateOutlineMaterial() {
67808         this._updateLineBasicMaterial(this._outline.material);
67809     }
67810 }
67811
67812 /**
67813  * Enumeration for alignments
67814  * @enum {number}
67815  * @readonly
67816  */
67817 var Alignment;
67818 (function (Alignment) {
67819     /**
67820      * Align to bottom
67821      */
67822     Alignment[Alignment["Bottom"] = 0] = "Bottom";
67823     /**
67824      * Align to bottom left
67825      */
67826     Alignment[Alignment["BottomLeft"] = 1] = "BottomLeft";
67827     /**
67828      * Align to bottom right
67829      */
67830     Alignment[Alignment["BottomRight"] = 2] = "BottomRight";
67831     /**
67832      * Align to center
67833      */
67834     Alignment[Alignment["Center"] = 3] = "Center";
67835     /**
67836      * Align to left
67837      */
67838     Alignment[Alignment["Left"] = 4] = "Left";
67839     /**
67840      * Align to right
67841      */
67842     Alignment[Alignment["Right"] = 5] = "Right";
67843     /**
67844      * Align to top
67845      */
67846     Alignment[Alignment["Top"] = 6] = "Top";
67847     /**
67848      * Align to top left
67849      */
67850     Alignment[Alignment["TopLeft"] = 7] = "TopLeft";
67851     /**
67852      * Align to top right
67853      */
67854     Alignment[Alignment["TopRight"] = 8] = "TopRight";
67855 })(Alignment || (Alignment = {}));
67856
67857 /**
67858  * @class OutlineTag
67859  *
67860  * @classdesc Tag holding properties for visualizing a geometry outline.
67861  *
67862  * @example
67863  * ```js
67864  * var geometry = new RectGeometry([0.3, 0.3, 0.5, 0.4]);
67865  * var tag = new OutlineTag(
67866  *     "id-1",
67867  *     geometry
67868  *     { editable: true, lineColor: 0xff0000 });
67869  *
67870  * tagComponent.add([tag]);
67871  * ```
67872  */
67873 class OutlineTag extends Tag {
67874     /**
67875      * Create an outline tag.
67876      *
67877      * @override
67878      * @constructor
67879      * @param {string} id - Unique identifier of the tag.
67880      * @param {VertexGeometry} geometry - Geometry defining vertices of tag.
67881      * @param {OutlineTagOptions} options - Options defining the visual appearance and
67882      * behavior of the outline tag.
67883      */
67884     constructor(id, geometry, options) {
67885         super(id, geometry);
67886         options = !!options ? options : {};
67887         const domain = options.domain != null && geometry instanceof PolygonGeometry ?
67888             options.domain : TagDomain.TwoDimensional;
67889         const twoDimensionalPolygon = this._twoDimensionalPolygon(domain, geometry);
67890         this._domain = domain;
67891         this._editable = options.editable == null || twoDimensionalPolygon ? false : options.editable;
67892         this._fillColor = options.fillColor == null ? 0xFFFFFF : options.fillColor;
67893         this._fillOpacity = options.fillOpacity == null ? 0.0 : options.fillOpacity;
67894         this._icon = options.icon === undefined ? null : options.icon;
67895         this._iconFloat = options.iconFloat == null ? Alignment.Center : options.iconFloat;
67896         this._iconIndex = options.iconIndex == null ? 3 : options.iconIndex;
67897         this._indicateVertices = options.indicateVertices == null ? true : options.indicateVertices;
67898         this._lineColor = options.lineColor == null ? 0xFFFFFF : options.lineColor;
67899         this._lineOpacity = options.lineOpacity == null ? 1 : options.lineOpacity;
67900         this._lineWidth = options.lineWidth == null ? 1 : options.lineWidth;
67901         this._text = options.text === undefined ? null : options.text;
67902         this._textColor = options.textColor == null ? 0xFFFFFF : options.textColor;
67903         this._click$ = new Subject();
67904         this._click$
67905             .subscribe(() => {
67906             const type = "click";
67907             const event = {
67908                 target: this,
67909                 type,
67910             };
67911             this.fire(type, event);
67912         });
67913     }
67914     /**
67915      * Click observable.
67916      *
67917      * @description An observable emitting the tag when the icon of the
67918      * tag has been clicked.
67919      *
67920      * @returns {Observable<Tag>}
67921      */
67922     get click$() {
67923         return this._click$;
67924     }
67925     /**
67926      * Get domain property.
67927      *
67928      * @description Readonly property that can only be set in constructor.
67929      *
67930      * @returns Value indicating the domain of the tag.
67931      */
67932     get domain() {
67933         return this._domain;
67934     }
67935     /**
67936      * Get editable property.
67937      * @returns {boolean} Value indicating if tag is editable.
67938      */
67939     get editable() {
67940         return this._editable;
67941     }
67942     /**
67943      * Set editable property.
67944      * @param {boolean}
67945      *
67946      * @fires changed
67947      */
67948     set editable(value) {
67949         if (this._twoDimensionalPolygon(this._domain, this._geometry)) {
67950             return;
67951         }
67952         this._editable = value;
67953         this._notifyChanged$.next(this);
67954     }
67955     /**
67956      * Get fill color property.
67957      * @returns {number}
67958      */
67959     get fillColor() {
67960         return this._fillColor;
67961     }
67962     /**
67963      * Set fill color property.
67964      * @param {number}
67965      *
67966      * @fires changed
67967      */
67968     set fillColor(value) {
67969         this._fillColor = value;
67970         this._notifyChanged$.next(this);
67971     }
67972     /**
67973      * Get fill opacity property.
67974      * @returns {number}
67975      */
67976     get fillOpacity() {
67977         return this._fillOpacity;
67978     }
67979     /**
67980      * Set fill opacity property.
67981      * @param {number}
67982      *
67983      * @fires changed
67984      */
67985     set fillOpacity(value) {
67986         this._fillOpacity = value;
67987         this._notifyChanged$.next(this);
67988     }
67989     /** @inheritdoc */
67990     get geometry() {
67991         return this._geometry;
67992     }
67993     /**
67994      * Get icon property.
67995      * @returns {string}
67996      */
67997     get icon() {
67998         return this._icon;
67999     }
68000     /**
68001      * Set icon property.
68002      * @param {string}
68003      *
68004      * @fires changed
68005      */
68006     set icon(value) {
68007         this._icon = value;
68008         this._notifyChanged$.next(this);
68009     }
68010     /**
68011      * Get icon float property.
68012      * @returns {Alignment}
68013      */
68014     get iconFloat() {
68015         return this._iconFloat;
68016     }
68017     /**
68018      * Set icon float property.
68019      * @param {Alignment}
68020      *
68021      * @fires changed
68022      */
68023     set iconFloat(value) {
68024         this._iconFloat = value;
68025         this._notifyChanged$.next(this);
68026     }
68027     /**
68028      * Get icon index property.
68029      * @returns {number}
68030      */
68031     get iconIndex() {
68032         return this._iconIndex;
68033     }
68034     /**
68035      * Set icon index property.
68036      * @param {number}
68037      *
68038      * @fires changed
68039      */
68040     set iconIndex(value) {
68041         this._iconIndex = value;
68042         this._notifyChanged$.next(this);
68043     }
68044     /**
68045      * Get indicate vertices property.
68046      * @returns {boolean} Value indicating if vertices should be indicated
68047      * when tag is editable.
68048      */
68049     get indicateVertices() {
68050         return this._indicateVertices;
68051     }
68052     /**
68053      * Set indicate vertices property.
68054      * @param {boolean}
68055      *
68056      * @fires changed
68057      */
68058     set indicateVertices(value) {
68059         this._indicateVertices = value;
68060         this._notifyChanged$.next(this);
68061     }
68062     /**
68063      * Get line color property.
68064      * @returns {number}
68065      */
68066     get lineColor() {
68067         return this._lineColor;
68068     }
68069     /**
68070      * Set line color property.
68071      * @param {number}
68072      *
68073      * @fires changed
68074      */
68075     set lineColor(value) {
68076         this._lineColor = value;
68077         this._notifyChanged$.next(this);
68078     }
68079     /**
68080      * Get line opacity property.
68081      * @returns {number}
68082      */
68083     get lineOpacity() {
68084         return this._lineOpacity;
68085     }
68086     /**
68087      * Set line opacity property.
68088      * @param {number}
68089      *
68090      * @fires changed
68091      */
68092     set lineOpacity(value) {
68093         this._lineOpacity = value;
68094         this._notifyChanged$.next(this);
68095     }
68096     /**
68097      * Get line width property.
68098      * @returns {number}
68099      */
68100     get lineWidth() {
68101         return this._lineWidth;
68102     }
68103     /**
68104      * Set line width property.
68105      * @param {number}
68106      *
68107      * @fires changed
68108      */
68109     set lineWidth(value) {
68110         this._lineWidth = value;
68111         this._notifyChanged$.next(this);
68112     }
68113     /**
68114      * Get text property.
68115      * @returns {string}
68116      */
68117     get text() {
68118         return this._text;
68119     }
68120     /**
68121      * Set text property.
68122      * @param {string}
68123      *
68124      * @fires changed
68125      */
68126     set text(value) {
68127         this._text = value;
68128         this._notifyChanged$.next(this);
68129     }
68130     /**
68131      * Get text color property.
68132      * @returns {number}
68133      */
68134     get textColor() {
68135         return this._textColor;
68136     }
68137     /**
68138      * Set text color property.
68139      * @param {number}
68140      *
68141      * @fires changed
68142      */
68143     set textColor(value) {
68144         this._textColor = value;
68145         this._notifyChanged$.next(this);
68146     }
68147     fire(type, event) {
68148         super.fire(type, event);
68149     }
68150     off(type, handler) {
68151         super.off(type, handler);
68152     }
68153     on(type, handler) {
68154         super.on(type, handler);
68155     }
68156     /**
68157      * Set options for tag.
68158      *
68159      * @description Sets all the option properties provided and keeps
68160      * the rest of the values as is.
68161      *
68162      * @param {OutlineTagOptions} options - Outline tag options
68163      *
68164      * @fires changed
68165      */
68166     setOptions(options) {
68167         const twoDimensionalPolygon = this._twoDimensionalPolygon(this._domain, this._geometry);
68168         this._editable = twoDimensionalPolygon || options.editable == null ? this._editable : options.editable;
68169         this._icon = options.icon === undefined ? this._icon : options.icon;
68170         this._iconFloat = options.iconFloat == null ? this._iconFloat : options.iconFloat;
68171         this._iconIndex = options.iconIndex == null ? this._iconIndex : options.iconIndex;
68172         this._indicateVertices = options.indicateVertices == null ? this._indicateVertices : options.indicateVertices;
68173         this._lineColor = options.lineColor == null ? this._lineColor : options.lineColor;
68174         this._lineWidth = options.lineWidth == null ? this._lineWidth : options.lineWidth;
68175         this._fillColor = options.fillColor == null ? this._fillColor : options.fillColor;
68176         this._fillOpacity = options.fillOpacity == null ? this._fillOpacity : options.fillOpacity;
68177         this._text = options.text === undefined ? this._text : options.text;
68178         this._textColor = options.textColor == null ? this._textColor : options.textColor;
68179         this._notifyChanged$.next(this);
68180     }
68181     _twoDimensionalPolygon(domain, geometry) {
68182         return domain !== TagDomain.ThreeDimensional && geometry instanceof PolygonGeometry;
68183     }
68184 }
68185
68186 /**
68187  * @class SpotRenderTag
68188  * @classdesc Tag visualizing the properties of a SpotTag.
68189  */
68190 class SpotRenderTag extends RenderTag {
68191     dispose() { }
68192     getDOMObjects(atlas, camera, size) {
68193         const tag = this._tag;
68194         const container = {
68195             offsetHeight: size.height, offsetWidth: size.width,
68196         };
68197         const vNodes = [];
68198         const [centroidBasicX, centroidBasicY] = tag.geometry.getCentroid2d();
68199         const centroidCanvas = this._viewportCoords.basicToCanvasSafe(centroidBasicX, centroidBasicY, container, this._transform, camera);
68200         if (centroidCanvas != null) {
68201             const interactNone = (e) => {
68202                 this._interact$.next({ offsetX: 0, offsetY: 0, operation: TagOperation.None, tag: tag });
68203             };
68204             const canvasX = Math.round(centroidCanvas[0]);
68205             const canvasY = Math.round(centroidCanvas[1]);
68206             if (tag.icon != null) {
68207                 if (atlas.loaded) {
68208                     const sprite = atlas.getDOMSprite(tag.icon, Alignment.Bottom);
68209                     const iconTransform = `translate(${canvasX}px,${canvasY + 8}px)`;
68210                     const properties = {
68211                         onpointerdown: interactNone,
68212                         style: {
68213                             pointerEvents: "all",
68214                             transform: iconTransform,
68215                         },
68216                     };
68217                     vNodes.push(virtualDom.h("div", properties, [sprite]));
68218                 }
68219             }
68220             else if (tag.text != null) {
68221                 const textTransform = `translate(-50%,0%) translate(${canvasX}px,${canvasY + 8}px)`;
68222                 const properties = {
68223                     onpointerdown: interactNone,
68224                     style: {
68225                         color: this._colorToCss(tag.textColor),
68226                         transform: textTransform,
68227                     },
68228                     textContent: tag.text,
68229                 };
68230                 vNodes.push(virtualDom.h("span.mapillary-tag-symbol", properties, []));
68231             }
68232             const interact = this._interact(TagOperation.Centroid, tag, "move");
68233             const background = this._colorToCss(tag.color);
68234             const transform = `translate(-50%,-50%) translate(${canvasX}px,${canvasY}px)`;
68235             if (tag.editable) {
68236                 let interactorProperties = {
68237                     onpointerdown: interact,
68238                     style: {
68239                         background: background,
68240                         transform: transform,
68241                     },
68242                 };
68243                 vNodes.push(virtualDom.h("div.mapillary-tag-spot-interactor", interactorProperties, []));
68244             }
68245             const pointProperties = {
68246                 style: {
68247                     background: background,
68248                     transform: transform,
68249                 },
68250             };
68251             vNodes.push(virtualDom.h("div.mapillary-tag-vertex", pointProperties, []));
68252         }
68253         return vNodes;
68254     }
68255     getGLObjects() { return []; }
68256     getRetrievableObjects() { return []; }
68257     _colorToCss(color) {
68258         return "#" + ("000000" + color.toString(16)).substr(-6);
68259     }
68260     _interact(operation, tag, cursor, vertexIndex) {
68261         return (e) => {
68262             const offsetX = e.offsetX - e.target.offsetWidth / 2;
68263             const offsetY = e.offsetY - e.target.offsetHeight / 2;
68264             this._interact$.next({
68265                 cursor: cursor,
68266                 offsetX: offsetX,
68267                 offsetY: offsetY,
68268                 operation: operation,
68269                 tag: tag,
68270                 vertexIndex: vertexIndex,
68271             });
68272         };
68273     }
68274 }
68275
68276 /**
68277  * @class SpotTag
68278  *
68279  * @classdesc Tag holding properties for visualizing the centroid of a geometry.
68280  *
68281  * @example
68282  * ```js
68283  * var geometry = new PointGeometry([0.3, 0.3]);
68284  * var tag = new SpotTag(
68285  *     "id-1",
68286  *     geometry
68287  *     { editable: true, color: 0xff0000 });
68288  *
68289  * tagComponent.add([tag]);
68290  * ```
68291  */
68292 class SpotTag extends Tag {
68293     /**
68294      * Create a spot tag.
68295      *
68296      * @override
68297      * @constructor
68298      * @param {string} id
68299      * @param {Geometry} geometry
68300      * @param {IOutlineTagOptions} options - Options defining the visual appearance and
68301      * behavior of the spot tag.
68302      */
68303     constructor(id, geometry, options) {
68304         super(id, geometry);
68305         options = !!options ? options : {};
68306         this._color = options.color == null ? 0xFFFFFF : options.color;
68307         this._editable = options.editable == null ? false : options.editable;
68308         this._icon = options.icon === undefined ? null : options.icon;
68309         this._text = options.text === undefined ? null : options.text;
68310         this._textColor = options.textColor == null ? 0xFFFFFF : options.textColor;
68311     }
68312     /**
68313      * Get color property.
68314      * @returns {number} The color of the spot as a hexagonal number;
68315      */
68316     get color() {
68317         return this._color;
68318     }
68319     /**
68320      * Set color property.
68321      * @param {number}
68322      *
68323      * @fires changed
68324      */
68325     set color(value) {
68326         this._color = value;
68327         this._notifyChanged$.next(this);
68328     }
68329     /**
68330      * Get editable property.
68331      * @returns {boolean} Value indicating if tag is editable.
68332      */
68333     get editable() {
68334         return this._editable;
68335     }
68336     /**
68337      * Set editable property.
68338      * @param {boolean}
68339      *
68340      * @fires changed
68341      */
68342     set editable(value) {
68343         this._editable = value;
68344         this._notifyChanged$.next(this);
68345     }
68346     /**
68347      * Get icon property.
68348      * @returns {string}
68349      */
68350     get icon() {
68351         return this._icon;
68352     }
68353     /**
68354      * Set icon property.
68355      * @param {string}
68356      *
68357      * @fires changed
68358      */
68359     set icon(value) {
68360         this._icon = value;
68361         this._notifyChanged$.next(this);
68362     }
68363     /**
68364      * Get text property.
68365      * @returns {string}
68366      */
68367     get text() {
68368         return this._text;
68369     }
68370     /**
68371      * Set text property.
68372      * @param {string}
68373      *
68374      * @fires changed
68375      */
68376     set text(value) {
68377         this._text = value;
68378         this._notifyChanged$.next(this);
68379     }
68380     /**
68381      * Get text color property.
68382      * @returns {number}
68383      */
68384     get textColor() {
68385         return this._textColor;
68386     }
68387     /**
68388      * Set text color property.
68389      * @param {number}
68390      *
68391      * @fires changed
68392      */
68393     set textColor(value) {
68394         this._textColor = value;
68395         this._notifyChanged$.next(this);
68396     }
68397     /**
68398      * Set options for tag.
68399      *
68400      * @description Sets all the option properties provided and keps
68401      * the rest of the values as is.
68402      *
68403      * @param {SpotTagOptions} options - Spot tag options
68404      *
68405      * @fires changed
68406      */
68407     setOptions(options) {
68408         this._color = options.color == null ? this._color : options.color;
68409         this._editable = options.editable == null ? this._editable : options.editable;
68410         this._icon = options.icon === undefined ? this._icon : options.icon;
68411         this._text = options.text === undefined ? this._text : options.text;
68412         this._textColor = options.textColor == null ? this._textColor : options.textColor;
68413         this._notifyChanged$.next(this);
68414     }
68415 }
68416
68417 class TagSet {
68418     constructor() {
68419         this._active = false;
68420         this._hash = {};
68421         this._hashDeactivated = {};
68422         this._notifyChanged$ = new Subject();
68423     }
68424     get active() {
68425         return this._active;
68426     }
68427     get changed$() {
68428         return this._notifyChanged$;
68429     }
68430     activate(transform) {
68431         if (this._active) {
68432             return;
68433         }
68434         for (const id in this._hashDeactivated) {
68435             if (!this._hashDeactivated.hasOwnProperty(id)) {
68436                 continue;
68437             }
68438             const tag = this._hashDeactivated[id];
68439             this._add(tag, transform);
68440         }
68441         this._hashDeactivated = {};
68442         this._active = true;
68443         this._notifyChanged$.next(this);
68444     }
68445     deactivate() {
68446         if (!this._active) {
68447             return;
68448         }
68449         for (const id in this._hash) {
68450             if (!this._hash.hasOwnProperty(id)) {
68451                 continue;
68452             }
68453             this._hashDeactivated[id] = this._hash[id].tag;
68454         }
68455         this._hash = {};
68456         this._active = false;
68457     }
68458     add(tags, transform) {
68459         this._assertActivationState(true);
68460         for (const tag of tags) {
68461             this._add(tag, transform);
68462         }
68463         this._notifyChanged$.next(this);
68464     }
68465     addDeactivated(tags) {
68466         this._assertActivationState(false);
68467         for (const tag of tags) {
68468             if (!(tag instanceof OutlineTag ||
68469                 tag instanceof SpotTag ||
68470                 tag instanceof ExtremePointTag)) {
68471                 throw new Error("Tag type not supported");
68472             }
68473             this._hashDeactivated[tag.id] = tag;
68474         }
68475     }
68476     get(id) {
68477         return this.has(id) ? this._hash[id] : undefined;
68478     }
68479     getAll() {
68480         const hash = this._hash;
68481         return Object.keys(hash)
68482             .map((id) => {
68483             return hash[id];
68484         });
68485     }
68486     getAllDeactivated() {
68487         const hashDeactivated = this._hashDeactivated;
68488         return Object.keys(hashDeactivated)
68489             .map((id) => {
68490             return hashDeactivated[id];
68491         });
68492     }
68493     getDeactivated(id) {
68494         return this.hasDeactivated(id) ? this._hashDeactivated[id] : undefined;
68495     }
68496     has(id) {
68497         return id in this._hash;
68498     }
68499     hasDeactivated(id) {
68500         return id in this._hashDeactivated;
68501     }
68502     remove(ids) {
68503         this._assertActivationState(true);
68504         const hash = this._hash;
68505         for (const id of ids) {
68506             if (!(id in hash)) {
68507                 continue;
68508             }
68509             delete hash[id];
68510         }
68511         this._notifyChanged$.next(this);
68512     }
68513     removeAll() {
68514         this._assertActivationState(true);
68515         this._hash = {};
68516         this._notifyChanged$.next(this);
68517     }
68518     removeAllDeactivated() {
68519         this._assertActivationState(false);
68520         this._hashDeactivated = {};
68521     }
68522     removeDeactivated(ids) {
68523         this._assertActivationState(false);
68524         const hashDeactivated = this._hashDeactivated;
68525         for (const id of ids) {
68526             if (!(id in hashDeactivated)) {
68527                 continue;
68528             }
68529             delete hashDeactivated[id];
68530         }
68531     }
68532     _add(tag, transform) {
68533         if (tag instanceof OutlineTag) {
68534             this._hash[tag.id] = new OutlineRenderTag(tag, transform);
68535         }
68536         else if (tag instanceof SpotTag) {
68537             this._hash[tag.id] = new SpotRenderTag(tag, transform);
68538         }
68539         else if (tag instanceof ExtremePointTag) {
68540             this._hash[tag.id] = new ExtremePointRenderTag(tag, transform);
68541         }
68542         else {
68543             throw new Error("Tag type not supported");
68544         }
68545     }
68546     _assertActivationState(should) {
68547         if (should !== this._active) {
68548             throw new Error("Tag set not in correct state for operation.");
68549         }
68550     }
68551 }
68552
68553 /**
68554  * @class PointGeometry
68555  *
68556  * @classdesc Represents a point geometry in the 2D basic image coordinate system.
68557  *
68558  * @example
68559  * ```js
68560  * var basicPoint = [0.5, 0.7];
68561  * var pointGeometry = new PointGeometry(basicPoint);
68562  * ```
68563  */
68564 class PointGeometry extends Geometry {
68565     /**
68566      * Create a point geometry.
68567      *
68568      * @constructor
68569      * @param {Array<number>} point - An array representing the basic coordinates of
68570      * the point.
68571      *
68572      * @throws {GeometryTagError} Point coordinates must be valid basic coordinates.
68573      */
68574     constructor(point) {
68575         super();
68576         let x = point[0];
68577         let y = point[1];
68578         if (x < 0 || x > 1 || y < 0 || y > 1) {
68579             throw new GeometryTagError("Basic coordinates must be on the interval [0, 1].");
68580         }
68581         this._point = point.slice();
68582     }
68583     /**
68584      * Get point property.
68585      * @returns {Array<number>} Array representing the basic coordinates of the point.
68586      */
68587     get point() {
68588         return this._point;
68589     }
68590     /**
68591      * Get the 2D basic coordinates for the centroid of the point, i.e. the 2D
68592      * basic coordinates of the point itself.
68593      *
68594      * @returns {Array<number>} 2D basic coordinates representing the centroid.
68595      * @ignore
68596      */
68597     getCentroid2d() {
68598         return this._point.slice();
68599     }
68600     /**
68601      * Get the 3D world coordinates for the centroid of the point, i.e. the 3D
68602      * world coordinates of the point itself.
68603      *
68604      * @param {Transform} transform - The transform of the image related to the point.
68605      * @returns {Array<number>} 3D world coordinates representing the centroid.
68606      * @ignore
68607      */
68608     getCentroid3d(transform) {
68609         return transform.unprojectBasic(this._point, 200);
68610     }
68611     /**
68612      * Set the centroid of the point, i.e. the point coordinates.
68613      *
68614      * @param {Array<number>} value - The new value of the centroid.
68615      * @param {Transform} transform - The transform of the image related to the point.
68616      * @ignore
68617      */
68618     setCentroid2d(value, transform) {
68619         let changed = [
68620             Math.max(0, Math.min(1, value[0])),
68621             Math.max(0, Math.min(1, value[1])),
68622         ];
68623         this._point[0] = changed[0];
68624         this._point[1] = changed[1];
68625         this._notifyChanged$.next(this);
68626     }
68627 }
68628
68629 class TagHandlerBase extends HandlerBase {
68630     constructor(component, container, navigator, viewportCoords) {
68631         super(component, container, navigator);
68632         this._name = `${this._component.name}-${this._getNameExtension()}`;
68633         this._viewportCoords = viewportCoords;
68634     }
68635     _getConfiguration(enable) {
68636         return {};
68637     }
68638     _mouseEventToBasic(event, element, camera, transform, offsetX, offsetY) {
68639         offsetX = offsetX != null ? offsetX : 0;
68640         offsetY = offsetY != null ? offsetY : 0;
68641         const [canvasX, canvasY] = this._viewportCoords.canvasPosition(event, element);
68642         const basic = this._viewportCoords.canvasToBasic(canvasX - offsetX, canvasY - offsetY, element, transform, camera.perspective);
68643         return basic;
68644     }
68645 }
68646
68647 class CreateHandlerBase extends TagHandlerBase {
68648     constructor(component, container, navigator, viewportCoords, tagCreator) {
68649         super(component, container, navigator, viewportCoords);
68650         this._tagCreator = tagCreator;
68651         this._geometryCreated$ = new Subject();
68652     }
68653     get geometryCreated$() {
68654         return this._geometryCreated$;
68655     }
68656     _enable() {
68657         this._enableCreate();
68658         this._container.container.classList.add("component-tag-create");
68659     }
68660     _disable() {
68661         this._container.container.classList.remove("component-tag-create");
68662         this._disableCreate();
68663     }
68664     _validateBasic(basic) {
68665         const x = basic[0];
68666         const y = basic[1];
68667         return 0 <= x && x <= 1 && 0 <= y && y <= 1;
68668     }
68669     _mouseEventToBasic$(mouseEvent$) {
68670         return mouseEvent$.pipe(withLatestFrom(this._container.renderService.renderCamera$, this._navigator.stateService.currentTransform$), map(([event, camera, transform]) => {
68671             return this._mouseEventToBasic(event, this._container.container, camera, transform);
68672         }));
68673     }
68674 }
68675
68676 class CreatePointHandler extends CreateHandlerBase {
68677     _enableCreate() {
68678         this._container.mouseService.deferPixels(this._name, 4);
68679         this._geometryCreatedSubscription = this._mouseEventToBasic$(this._container.mouseService.proximateClick$).pipe(filter(this._validateBasic), map((basic) => {
68680             return new PointGeometry(basic);
68681         }))
68682             .subscribe(this._geometryCreated$);
68683     }
68684     _disableCreate() {
68685         this._container.mouseService.undeferPixels(this._name);
68686         this._geometryCreatedSubscription.unsubscribe();
68687     }
68688     _getNameExtension() {
68689         return "create-point";
68690     }
68691 }
68692
68693 class CreateVertexHandler extends CreateHandlerBase {
68694     _enableCreate() {
68695         this._container.mouseService.deferPixels(this._name, 4);
68696         const transformChanged$ = this._navigator.stateService.currentTransform$.pipe(map(() => { }), publishReplay(1), refCount());
68697         this._deleteSubscription = transformChanged$.pipe(skip(1))
68698             .subscribe(this._tagCreator.delete$);
68699         const basicClick$ = this._mouseEventToBasic$(this._container.mouseService.proximateClick$).pipe(share());
68700         this._createSubscription = transformChanged$.pipe(switchMap(() => {
68701             return basicClick$.pipe(filter(this._validateBasic), take(1));
68702         }))
68703             .subscribe(this._create$);
68704         this._setVertexSubscription = this._tagCreator.tag$.pipe(switchMap((tag) => {
68705             return !!tag ?
68706                 combineLatest(of(tag), merge(this._container.mouseService.mouseMove$, this._container.mouseService.domMouseMove$), this._container.renderService.renderCamera$, this._navigator.stateService.currentTransform$) :
68707                 empty();
68708         }))
68709             .subscribe(([tag, event, camera, transform]) => {
68710             const basicPoint = this._mouseEventToBasic(event, this._container.container, camera, transform);
68711             this._setVertex2d(tag, basicPoint, transform);
68712         });
68713         this._addPointSubscription = this._tagCreator.tag$.pipe(switchMap((tag) => {
68714             return !!tag ?
68715                 combineLatest(of(tag), basicClick$) :
68716                 empty();
68717         }))
68718             .subscribe(([tag, basicPoint]) => {
68719             this._addPoint(tag, basicPoint);
68720         });
68721         this._geometryCreateSubscription = this._tagCreator.tag$.pipe(switchMap((tag) => {
68722             return !!tag ?
68723                 tag.created$.pipe(map((t) => {
68724                     return t.geometry;
68725                 })) :
68726                 empty();
68727         }))
68728             .subscribe(this._geometryCreated$);
68729     }
68730     _disableCreate() {
68731         this._container.mouseService.undeferPixels(this._name);
68732         this._tagCreator.delete$.next(null);
68733         this._addPointSubscription.unsubscribe();
68734         this._createSubscription.unsubscribe();
68735         this._deleteSubscription.unsubscribe();
68736         this._geometryCreateSubscription.unsubscribe();
68737         this._setVertexSubscription.unsubscribe();
68738     }
68739 }
68740
68741 class CreatePointsHandler extends CreateVertexHandler {
68742     get _create$() {
68743         return this._tagCreator.createPoints$;
68744     }
68745     _addPoint(tag, basicPoint) {
68746         tag.geometry.addPoint2d(basicPoint);
68747     }
68748     _getNameExtension() {
68749         return "create-points";
68750     }
68751     _setVertex2d(tag, basicPoint, transform) {
68752         tag.geometry.setPoint2d((tag.geometry).points.length - 1, basicPoint, transform);
68753     }
68754 }
68755
68756 class CreatePolygonHandler extends CreateVertexHandler {
68757     get _create$() {
68758         return this._tagCreator.createPolygon$;
68759     }
68760     _addPoint(tag, basicPoint) {
68761         tag.addPoint(basicPoint);
68762     }
68763     _getNameExtension() {
68764         return "create-polygon";
68765     }
68766     _setVertex2d(tag, basicPoint, transform) {
68767         tag.geometry.setVertex2d(tag.geometry.polygon.length - 2, basicPoint, transform);
68768     }
68769 }
68770
68771 class CreateRectHandler extends CreateVertexHandler {
68772     get _create$() {
68773         return this._tagCreator.createRect$;
68774     }
68775     _addPoint(tag, basicPoint) {
68776         const rectGeometry = tag.geometry;
68777         if (!rectGeometry.validate(basicPoint)) {
68778             basicPoint = rectGeometry.getNonAdjustedVertex2d(3);
68779         }
68780         tag.addPoint(basicPoint);
68781     }
68782     _enable() {
68783         super._enable();
68784         this._initializeAnchorIndexingSubscription = this._tagCreator.tag$.pipe(filter((tag) => {
68785             return !!tag;
68786         }))
68787             .subscribe((tag) => {
68788             tag.geometry.initializeAnchorIndexing();
68789         });
68790     }
68791     _disable() {
68792         super._disable();
68793         this._initializeAnchorIndexingSubscription.unsubscribe();
68794     }
68795     _getNameExtension() {
68796         return "create-rect";
68797     }
68798     _setVertex2d(tag, basicPoint, transform) {
68799         tag.geometry.setOppositeVertex2d(basicPoint, transform);
68800     }
68801 }
68802
68803 class CreateRectDragHandler extends CreateHandlerBase {
68804     _enableCreate() {
68805         this._container.mouseService.claimMouse(this._name, 2);
68806         this._deleteSubscription = this._navigator.stateService.currentTransform$.pipe(map((transform) => { return null; }), skip(1))
68807             .subscribe(this._tagCreator.delete$);
68808         this._createSubscription = this._mouseEventToBasic$(this._container.mouseService.filtered$(this._name, this._container.mouseService.mouseDragStart$)).pipe(filter(this._validateBasic))
68809             .subscribe(this._tagCreator.createRect$);
68810         this._initializeAnchorIndexingSubscription = this._tagCreator.tag$.pipe(filter((tag) => {
68811             return !!tag;
68812         }))
68813             .subscribe((tag) => {
68814             tag.geometry.initializeAnchorIndexing();
68815         });
68816         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]) => {
68817             return this._mouseEventToBasic(event, this._container.container, camera, transform);
68818         }));
68819         this._setVertexSubscription = this._tagCreator.tag$.pipe(switchMap((tag) => {
68820             return !!tag ?
68821                 combineLatest(of(tag), basicMouse$, this._navigator.stateService.currentTransform$) :
68822                 empty();
68823         }))
68824             .subscribe(([tag, basicPoint, transform]) => {
68825             tag.geometry.setOppositeVertex2d(basicPoint, transform);
68826         });
68827         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) => {
68828             return basicPoint;
68829         }), share());
68830         this._addPointSubscription = this._tagCreator.tag$.pipe(switchMap((tag) => {
68831             return !!tag ?
68832                 combineLatest(of(tag), basicMouseDragEnd$) :
68833                 empty();
68834         }))
68835             .subscribe(([tag, basicPoint]) => {
68836             const rectGeometry = tag.geometry;
68837             if (!rectGeometry.validate(basicPoint)) {
68838                 basicPoint = rectGeometry.getNonAdjustedVertex2d(3);
68839             }
68840             tag.addPoint(basicPoint);
68841         });
68842         this._geometryCreatedSubscription = this._tagCreator.tag$.pipe(switchMap((tag) => {
68843             return !!tag ?
68844                 tag.created$.pipe(map((t) => {
68845                     return t.geometry;
68846                 })) :
68847                 empty();
68848         }))
68849             .subscribe(this._geometryCreated$);
68850     }
68851     _disableCreate() {
68852         this._container.mouseService.unclaimMouse(this._name);
68853         this._tagCreator.delete$.next(null);
68854         this._addPointSubscription.unsubscribe();
68855         this._createSubscription.unsubscribe();
68856         this._deleteSubscription.unsubscribe();
68857         this._geometryCreatedSubscription.unsubscribe();
68858         this._initializeAnchorIndexingSubscription.unsubscribe();
68859         this._setVertexSubscription.unsubscribe();
68860     }
68861     _getNameExtension() {
68862         return "create-rect-drag";
68863     }
68864 }
68865
68866 class EditVertexHandler extends TagHandlerBase {
68867     constructor(component, container, navigator, viewportCoords, tagSet) {
68868         super(component, container, navigator, viewportCoords);
68869         this._tagSet = tagSet;
68870     }
68871     _enable() {
68872         const interaction$ = this._tagSet.changed$.pipe(map((tagSet) => {
68873             return tagSet.getAll();
68874         }), switchMap((tags) => {
68875             return from(tags).pipe(mergeMap((tag) => {
68876                 return tag.interact$;
68877             }));
68878         }), switchMap((interaction) => {
68879             return concat(of(interaction), this._container.mouseService.documentMouseUp$.pipe(map(() => {
68880                 return { offsetX: 0, offsetY: 0, operation: TagOperation.None, tag: null };
68881             }), first()));
68882         }), share());
68883         merge(this._container.mouseService.mouseMove$, this._container.mouseService.domMouseMove$).pipe(share());
68884         this._claimMouseSubscription = interaction$.pipe(switchMap((interaction) => {
68885             return !!interaction.tag ? this._container.mouseService.domMouseDragStart$ : empty();
68886         }))
68887             .subscribe(() => {
68888             this._container.mouseService.claimMouse(this._name, 3);
68889         });
68890         this._cursorSubscription = interaction$.pipe(map((interaction) => {
68891             return interaction.cursor;
68892         }), distinctUntilChanged())
68893             .subscribe((cursor) => {
68894             const interactionCursors = ["crosshair", "move", "nesw-resize", "nwse-resize"];
68895             for (const interactionCursor of interactionCursors) {
68896                 this._container.container.classList.remove(`component-tag-edit-${interactionCursor}`);
68897             }
68898             if (!!cursor) {
68899                 this._container.container.classList.add(`component-tag-edit-${cursor}`);
68900             }
68901         });
68902         this._unclaimMouseSubscription = this._container.mouseService
68903             .filtered$(this._name, this._container.mouseService.domMouseDragEnd$)
68904             .subscribe((e) => {
68905             this._container.mouseService.unclaimMouse(this._name);
68906         });
68907         this._preventDefaultSubscription = interaction$.pipe(switchMap((interaction) => {
68908             return !!interaction.tag ?
68909                 this._container.mouseService.documentMouseMove$ :
68910                 empty();
68911         }))
68912             .subscribe((event) => {
68913             event.preventDefault(); // prevent selection of content outside the viewer
68914         });
68915         this._updateGeometrySubscription = interaction$.pipe(switchMap((interaction) => {
68916             if (interaction.operation === TagOperation.None || !interaction.tag) {
68917                 return empty();
68918             }
68919             const mouseDrag$ = this._container.mouseService
68920                 .filtered$(this._name, this._container.mouseService.domMouseDrag$).pipe(filter((event) => {
68921                 return this._viewportCoords.insideElement(event, this._container.container);
68922             }));
68923             return combineLatest(mouseDrag$, this._container.renderService.renderCamera$).pipe(withLatestFrom(of(interaction), this._navigator.stateService.currentTransform$, ([event, render], i, transform) => {
68924                 return [event, render, i, transform];
68925             }));
68926         }))
68927             .subscribe(([mouseEvent, renderCamera, interaction, transform]) => {
68928             const basic = this._mouseEventToBasic(mouseEvent, this._container.container, renderCamera, transform, interaction.offsetX, interaction.offsetY);
68929             const geometry = interaction.tag.geometry;
68930             if (interaction.operation === TagOperation.Centroid) {
68931                 geometry.setCentroid2d(basic, transform);
68932             }
68933             else if (interaction.operation === TagOperation.Vertex) {
68934                 geometry.setVertex2d(interaction.vertexIndex, basic, transform);
68935             }
68936         });
68937     }
68938     _disable() {
68939         this._claimMouseSubscription.unsubscribe();
68940         this._cursorSubscription.unsubscribe();
68941         this._preventDefaultSubscription.unsubscribe();
68942         this._unclaimMouseSubscription.unsubscribe();
68943         this._updateGeometrySubscription.unsubscribe();
68944     }
68945     _getNameExtension() {
68946         return "edit-vertex";
68947     }
68948 }
68949
68950 /**
68951  * @class TagComponent
68952  *
68953  * @classdesc Component for showing and editing tags with different
68954  * geometries composed from 2D basic image coordinates (see the
68955  * {@link Viewer} class documentation for more information about coordinate
68956  * systems).
68957  *
68958  * The `add` method is used for adding new tags or replacing
68959  * tags already in the set. Tags are removed by id.
68960  *
68961  * If a tag already in the set has the same
68962  * id as one of the tags added, the old tag will be removed and
68963  * the added tag will take its place.
68964  *
68965  * The tag component mode can be set to either be non interactive or
68966  * to be in creating mode of a certain geometry type.
68967  *
68968  * The tag properties can be updated at any time and the change will
68969  * be visibile immediately.
68970  *
68971  * Tags are only relevant to a single image because they are based on
68972  * 2D basic image coordinates. Tags related to a certain image should
68973  * be removed when the viewer is moved to another image.
68974  *
68975  * To retrive and use the tag component
68976  *
68977  * @example
68978  * ```js
68979  * var viewer = new Viewer({ component: { tag: true } }, ...);
68980  *
68981  * var tagComponent = viewer.getComponent("tag");
68982  * ```
68983  */
68984 class TagComponent extends Component {
68985     /** @ignore */
68986     constructor(name, container, navigator) {
68987         super(name, container, navigator);
68988         this._tagDomRenderer = new TagDOMRenderer();
68989         this._tagScene = new TagScene();
68990         this._tagSet = new TagSet();
68991         this._tagCreator = new TagCreator(this, navigator);
68992         this._viewportCoords = new ViewportCoords();
68993         this._createHandlers = {
68994             "CreatePoint": new CreatePointHandler(this, container, navigator, this._viewportCoords, this._tagCreator),
68995             "CreatePoints": new CreatePointsHandler(this, container, navigator, this._viewportCoords, this._tagCreator),
68996             "CreatePolygon": new CreatePolygonHandler(this, container, navigator, this._viewportCoords, this._tagCreator),
68997             "CreateRect": new CreateRectHandler(this, container, navigator, this._viewportCoords, this._tagCreator),
68998             "CreateRectDrag": new CreateRectDragHandler(this, container, navigator, this._viewportCoords, this._tagCreator),
68999             "Default": undefined,
69000         };
69001         this._editVertexHandler =
69002             new EditVertexHandler(this, container, navigator, this._viewportCoords, this._tagSet);
69003         this._renderTags$ = this._tagSet.changed$.pipe(map((tagSet) => {
69004             const tags = tagSet.getAll();
69005             // ensure that tags are always rendered in the same order
69006             // to avoid hover tracking problems on first resize.
69007             tags.sort((t1, t2) => {
69008                 const id1 = t1.tag.id;
69009                 const id2 = t2.tag.id;
69010                 if (id1 < id2) {
69011                     return -1;
69012                 }
69013                 if (id1 > id2) {
69014                     return 1;
69015                 }
69016                 return 0;
69017             });
69018             return tags;
69019         }), share());
69020         this._tagChanged$ = this._renderTags$.pipe(switchMap((tags) => {
69021             return from(tags).pipe(mergeMap((tag) => {
69022                 return merge(tag.tag.changed$, tag.tag.geometryChanged$);
69023             }));
69024         }), share());
69025         this._renderTagGLChanged$ = this._renderTags$.pipe(switchMap((tags) => {
69026             return from(tags).pipe(mergeMap((tag) => {
69027                 return tag.glObjectsChanged$;
69028             }));
69029         }), share());
69030         this._createGeometryChanged$ = this._tagCreator.tag$.pipe(switchMap((tag) => {
69031             return tag != null ?
69032                 tag.geometryChanged$ :
69033                 empty();
69034         }), share());
69035         this._createGLObjectsChanged$ = this._tagCreator.tag$.pipe(switchMap((tag) => {
69036             return tag != null ?
69037                 tag.glObjectsChanged$ :
69038                 empty();
69039         }), share());
69040         this._creatingConfiguration$ = this._configuration$.pipe(distinctUntilChanged((c1, c2) => {
69041             return c1.mode === c2.mode;
69042         }, (configuration) => {
69043             return {
69044                 createColor: configuration.createColor,
69045                 mode: configuration.mode,
69046             };
69047         }), publishReplay(1), refCount());
69048         this._creatingConfiguration$
69049             .subscribe((configuration) => {
69050             const type = "tagmode";
69051             const event = {
69052                 mode: configuration.mode,
69053                 target: this,
69054                 type,
69055             };
69056             this.fire(type, event);
69057         });
69058     }
69059     /**
69060      * Add tags to the tag set or replace tags in the tag set.
69061      *
69062      * @description If a tag already in the set has the same
69063      * id as one of the tags added, the old tag will be removed
69064      * the added tag will take its place.
69065      *
69066      * @param {Array<Tag>} tags - Tags to add.
69067      *
69068      * @example
69069      * ```js
69070      * tagComponent.add([tag1, tag2]);
69071      * ```
69072      */
69073     add(tags) {
69074         if (this._activated) {
69075             this._navigator.stateService.currentTransform$.pipe(first())
69076                 .subscribe((transform) => {
69077                 this._tagSet.add(tags, transform);
69078                 const renderTags = tags
69079                     .map((tag) => {
69080                     return this._tagSet.get(tag.id);
69081                 });
69082                 this._tagScene.add(renderTags);
69083             });
69084         }
69085         else {
69086             this._tagSet.addDeactivated(tags);
69087         }
69088     }
69089     /**
69090      * Calculate the smallest rectangle containing all the points
69091      * in the points geometry.
69092      *
69093      * @description The result may be different depending on if the
69094      * current image is an spherical or not. If the
69095      * current image is an spherical the rectangle may
69096      * wrap the horizontal border of the image.
69097      *
69098      * @returns {Promise<Array<number>>} Promise to the rectangle
69099      * on the format specified for the {@link RectGeometry} in basic
69100      * coordinates.
69101      */
69102     calculateRect(geometry) {
69103         return new Promise((resolve, reject) => {
69104             this._navigator.stateService.currentTransform$.pipe(first(), map((transform) => {
69105                 return geometry.getRect2d(transform);
69106             }))
69107                 .subscribe((rect) => {
69108                 resolve(rect);
69109             }, (error) => {
69110                 reject(error);
69111             });
69112         });
69113     }
69114     /**
69115      * Force the creation of a geometry programatically using its
69116      * current vertices.
69117      *
69118      * @description The method only has an effect when the tag
69119      * mode is either of the following modes:
69120      *
69121      * {@link TagMode.CreatePoints}
69122      * {@link TagMode.CreatePolygon}
69123      * {@link TagMode.CreateRect}
69124      * {@link TagMode.CreateRectDrag}
69125      *
69126      * In the case of points or polygon creation, only the created
69127      * vertices are used, i.e. the mouse position is disregarded.
69128      *
69129      * In the case of rectangle creation the position of the mouse
69130      * at the time of the method call is used as one of the vertices
69131      * defining the rectangle.
69132      *
69133      * @fires geometrycreate
69134      *
69135      * @example
69136      * ```js
69137      * tagComponent.on("geometrycreate", function(geometry) {
69138      *     console.log(geometry);
69139      * });
69140      *
69141      * tagComponent.create();
69142      * ```
69143      */
69144     create() {
69145         this._tagCreator.replayedTag$.pipe(first(), filter((tag) => {
69146             return !!tag;
69147         }))
69148             .subscribe((tag) => {
69149             tag.create();
69150         });
69151     }
69152     /**
69153      * Change the current tag mode.
69154      *
69155      * @description Change the tag mode to one of the create modes for creating new geometries.
69156      *
69157      * @param {TagMode} mode - New tag mode.
69158      *
69159      * @fires tagmode
69160      *
69161      * @example
69162      * ```js
69163      * tagComponent.changeMode(TagMode.CreateRect);
69164      * ```
69165      */
69166     changeMode(mode) {
69167         this.configure({ mode: mode });
69168     }
69169     fire(type, event) {
69170         super.fire(type, event);
69171     }
69172     /**
69173      * Returns the tag in the tag set with the specified id, or
69174      * undefined if the id matches no tag.
69175      *
69176      * @param {string} tagId - Id of the tag.
69177      *
69178      * @example
69179      * ```js
69180      * var tag = tagComponent.get("tagId");
69181      * ```
69182      */
69183     get(tagId) {
69184         if (this._activated) {
69185             const renderTag = this._tagSet.get(tagId);
69186             return renderTag !== undefined ? renderTag.tag : undefined;
69187         }
69188         else {
69189             return this._tagSet.getDeactivated(tagId);
69190         }
69191     }
69192     /**
69193      * Returns an array of all tags.
69194      *
69195      * @example
69196      * ```js
69197      * var tags = tagComponent.getAll();
69198      * ```
69199      */
69200     getAll() {
69201         if (this.activated) {
69202             return this._tagSet
69203                 .getAll()
69204                 .map((renderTag) => {
69205                 return renderTag.tag;
69206             });
69207         }
69208         else {
69209             return this._tagSet.getAllDeactivated();
69210         }
69211     }
69212     /**
69213      * Returns an array of tag ids for tags that contain the specified point.
69214      *
69215      * @description The pixel point must lie inside the polygon or rectangle
69216      * of an added tag for the tag id to be returned. Tag ids for
69217      * tags that do not have a fill will also be returned if the point is inside
69218      * the geometry of the tag. Tags with point geometries can not be retrieved.
69219      *
69220      * No tag ids will be returned for polygons rendered in cropped spherical or
69221      * rectangles rendered in spherical.
69222      *
69223      * Notice that the pixelPoint argument requires x, y coordinates from pixel space.
69224      *
69225      * With this function, you can use the coordinates provided by mouse
69226      * events to get information out of the tag component.
69227      *
69228      * If no tag at exist the pixel point, an empty array will be returned.
69229      *
69230      * @param {Array<number>} pixelPoint - Pixel coordinates on the viewer element.
69231      * @returns {Promise<Array<string>>} Promise to the ids of the tags that
69232      * contain the specified pixel point.
69233      *
69234      * @example
69235      * ```js
69236      * tagComponent.getTagIdsAt([100, 100])
69237      *     .then((tagIds) => { console.log(tagIds); });
69238      * ```
69239      */
69240     getTagIdsAt(pixelPoint) {
69241         return new Promise((resolve, reject) => {
69242             this._container.renderService.renderCamera$.pipe(first(), map((render) => {
69243                 const viewport = this._viewportCoords
69244                     .canvasToViewport(pixelPoint[0], pixelPoint[1], this._container.container);
69245                 const ids = this._tagScene.intersectObjects(viewport, render.perspective);
69246                 return ids;
69247             }))
69248                 .subscribe((ids) => {
69249                 resolve(ids);
69250             }, (error) => {
69251                 reject(error);
69252             });
69253         });
69254     }
69255     /**
69256      * Check if a tag exist in the tag set.
69257      *
69258      * @param {string} tagId - Id of the tag.
69259      *
69260      * @example
69261      * ```js
69262      * var tagExists = tagComponent.has("tagId");
69263      * ```
69264      */
69265     has(tagId) {
69266         return this._activated ? this._tagSet.has(tagId) : this._tagSet.hasDeactivated(tagId);
69267     }
69268     off(type, handler) {
69269         super.off(type, handler);
69270     }
69271     on(type, handler) {
69272         super.on(type, handler);
69273     }
69274     /**
69275      * Remove tags with the specified ids from the tag set.
69276      *
69277      * @param {Array<string>} tagIds - Ids for tags to remove.
69278      *
69279      * @example
69280      * ```js
69281      * tagComponent.remove(["id-1", "id-2"]);
69282      * ```
69283      */
69284     remove(tagIds) {
69285         if (this._activated) {
69286             this._tagSet.remove(tagIds);
69287             this._tagScene.remove(tagIds);
69288         }
69289         else {
69290             this._tagSet.removeDeactivated(tagIds);
69291         }
69292     }
69293     /**
69294      * Remove all tags from the tag set.
69295      *
69296      * @example
69297      * ```js
69298      * tagComponent.removeAll();
69299      * ```
69300      */
69301     removeAll() {
69302         if (this._activated) {
69303             this._tagSet.removeAll();
69304             this._tagScene.removeAll();
69305         }
69306         else {
69307             this._tagSet.removeAllDeactivated();
69308         }
69309     }
69310     _activate() {
69311         this._editVertexHandler.enable();
69312         const handlerGeometryCreated$ = from(Object.keys(this._createHandlers)).pipe(map((key) => {
69313             return this._createHandlers[key];
69314         }), filter((handler) => {
69315             return !!handler;
69316         }), mergeMap((handler) => {
69317             return handler.geometryCreated$;
69318         }), share());
69319         const subs = this._subscriptions;
69320         subs.push(handlerGeometryCreated$
69321             .subscribe((geometry) => {
69322             const type = "geometrycreate";
69323             const event = {
69324                 geometry,
69325                 target: this,
69326                 type,
69327             };
69328             this.fire(type, event);
69329         }));
69330         subs.push(this._tagCreator.tag$.pipe(skipWhile((tag) => {
69331             return tag == null;
69332         }), distinctUntilChanged())
69333             .subscribe((tag) => {
69334             const type = tag != null ?
69335                 "tagcreatestart" :
69336                 "tagcreateend";
69337             const event = {
69338                 target: this,
69339                 type,
69340             };
69341             this.fire(type, event);
69342         }));
69343         subs.push(handlerGeometryCreated$
69344             .subscribe(() => {
69345             this.changeMode(TagMode.Default);
69346         }));
69347         subs.push(this._creatingConfiguration$
69348             .subscribe((configuration) => {
69349             this._disableCreateHandlers();
69350             const mode = TagMode[configuration.mode];
69351             const handler = this._createHandlers[mode];
69352             if (!!handler) {
69353                 handler.enable();
69354             }
69355         }));
69356         subs.push(this._renderTags$
69357             .subscribe(() => {
69358             const type = "tags";
69359             const event = {
69360                 target: this,
69361                 type,
69362             };
69363             this.fire(type, event);
69364         }));
69365         subs.push(this._tagCreator.tag$.pipe(switchMap((tag) => {
69366             return tag != null ?
69367                 tag.aborted$.pipe(map(() => { return null; })) :
69368                 empty();
69369         }))
69370             .subscribe(() => { this.changeMode(TagMode.Default); }));
69371         subs.push(this._tagCreator.tag$
69372             .subscribe((tag) => {
69373             if (this._tagScene.hasCreateTag()) {
69374                 this._tagScene.removeCreateTag();
69375             }
69376             if (tag != null) {
69377                 this._tagScene.addCreateTag(tag);
69378             }
69379         }));
69380         subs.push(this._createGLObjectsChanged$
69381             .subscribe((tag) => {
69382             this._tagScene.updateCreateTagObjects(tag);
69383         }));
69384         subs.push(this._renderTagGLChanged$
69385             .subscribe((tag) => {
69386             this._tagScene.updateObjects(tag);
69387         }));
69388         subs.push(this._tagChanged$
69389             .subscribe(() => {
69390             this._tagScene.update();
69391         }));
69392         subs.push(combineLatest(this._renderTags$.pipe(startWith([]), tap(() => {
69393             this._container.domRenderer.render$.next({
69394                 name: this._name,
69395                 vNode: this._tagDomRenderer.clear(),
69396             });
69397         })), 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]) => {
69398             return {
69399                 name: this._name,
69400                 vNode: this._tagDomRenderer.render(renderTags, ct, atlas, rc.perspective, size),
69401             };
69402         }))
69403             .subscribe(this._container.domRenderer.render$));
69404         subs.push(this._navigator.stateService.currentState$.pipe(map((frame) => {
69405             const tagScene = this._tagScene;
69406             return {
69407                 name: this._name,
69408                 renderer: {
69409                     frameId: frame.id,
69410                     needsRender: tagScene.needsRender,
69411                     render: tagScene.render.bind(tagScene),
69412                     pass: RenderPass$1.Opaque,
69413                 },
69414             };
69415         }))
69416             .subscribe(this._container.glRenderer.render$));
69417         this._navigator.stateService.currentTransform$.pipe(first())
69418             .subscribe((transform) => {
69419             this._tagSet.activate(transform);
69420             this._tagScene.add(this._tagSet.getAll());
69421         });
69422     }
69423     _deactivate() {
69424         this._editVertexHandler.disable();
69425         this._disableCreateHandlers();
69426         this._tagScene.clear();
69427         this._tagSet.deactivate();
69428         this._tagCreator.delete$.next(null);
69429         this._subscriptions.unsubscribe();
69430         this._container.container.classList.remove("component-tag-create");
69431     }
69432     _getDefaultConfiguration() {
69433         return {
69434             createColor: 0xFFFFFF,
69435             indicatePointsCompleter: true,
69436             mode: TagMode.Default,
69437         };
69438     }
69439     _disableCreateHandlers() {
69440         const createHandlers = this._createHandlers;
69441         for (const key in createHandlers) {
69442             if (!createHandlers.hasOwnProperty(key)) {
69443                 continue;
69444             }
69445             const handler = createHandlers[key];
69446             if (!!handler) {
69447                 handler.disable();
69448             }
69449         }
69450     }
69451 }
69452 /** @inheritdoc */
69453 TagComponent.componentName = "tag";
69454
69455 /**
69456  * @class ZoomComponent
69457  *
69458  * @classdesc Component rendering UI elements used for zooming.
69459  *
69460  * @example
69461  * ```js
69462  * var viewer = new Viewer({ ... });
69463  *
69464  * var zoomComponent = viewer.getComponent("zoom");
69465  * zoomComponent.configure({ size: ComponentSize.Small });
69466  * ```
69467  */
69468 class ZoomComponent extends Component {
69469     constructor(name, container, navigator) {
69470         super(name, container, navigator);
69471         this._viewportCoords = new ViewportCoords();
69472         this._zoomDelta$ = new Subject();
69473     }
69474     _activate() {
69475         const subs = this._subscriptions;
69476         subs.push(combineLatest(this._navigator.stateService.currentState$, this._navigator.stateService.state$, this._configuration$, this._container.renderService.size$).pipe(map(([frame, state, configuration, size]) => {
69477             const zoom = frame.state.zoom;
69478             const zoomInIcon = virtualDom.h("div.mapillary-zoom-in-icon", []);
69479             const zoomInButton = zoom >= 3 || state === State.Waiting ?
69480                 virtualDom.h("div.mapillary-zoom-in-button-inactive", [zoomInIcon]) :
69481                 virtualDom.h("div.mapillary-zoom-in-button", { onclick: () => { this._zoomDelta$.next(1); } }, [zoomInIcon]);
69482             const zoomOutIcon = virtualDom.h("div.mapillary-zoom-out-icon", []);
69483             const zoomOutButton = zoom <= 0 || state === State.Waiting ?
69484                 virtualDom.h("div.mapillary-zoom-out-button-inactive", [zoomOutIcon]) :
69485                 virtualDom.h("div.mapillary-zoom-out-button", { onclick: () => { this._zoomDelta$.next(-1); } }, [zoomOutIcon]);
69486             const compact = configuration.size === ComponentSize.Small ||
69487                 configuration.size === ComponentSize.Automatic && size.width < 640 ?
69488                 ".mapillary-zoom-compact" : "";
69489             return {
69490                 name: this._name,
69491                 vNode: virtualDom.h("div.mapillary-zoom-container" + compact, { oncontextmenu: (event) => { event.preventDefault(); } }, [zoomInButton, zoomOutButton]),
69492             };
69493         }))
69494             .subscribe(this._container.domRenderer.render$));
69495         subs.push(this._zoomDelta$.pipe(withLatestFrom(this._container.renderService.renderCamera$, this._navigator.stateService.currentTransform$))
69496             .subscribe(([zoomDelta, render, transform]) => {
69497             const unprojected = this._viewportCoords.unprojectFromViewport(0, 0, render.perspective);
69498             const reference = transform.projectBasic(unprojected.toArray());
69499             this._navigator.stateService.zoomIn(zoomDelta, reference);
69500         }));
69501     }
69502     _deactivate() {
69503         this._subscriptions.unsubscribe();
69504     }
69505     _getDefaultConfiguration() {
69506         return { size: ComponentSize.Automatic };
69507     }
69508 }
69509 ZoomComponent.componentName = "zoom";
69510
69511 class ImageFallbackComponent extends Component {
69512     constructor(name, container, navigator, dom) {
69513         super(name, container, navigator);
69514         this._canvasId = `${container.id}-${this._name}`;
69515         this._dom = !!dom ? dom : new DOM();
69516     }
69517     _activate() {
69518         const canvasSize$ = this._container.domRenderer.element$.pipe(map(() => {
69519             return this._dom.document.getElementById(this._canvasId);
69520         }), filter((canvas) => {
69521             return !!canvas;
69522         }), map((canvas) => {
69523             const adaptableDomRenderer = canvas.parentElement;
69524             const width = adaptableDomRenderer.offsetWidth;
69525             const height = adaptableDomRenderer.offsetHeight;
69526             return [canvas, { height: height, width: width }];
69527         }), distinctUntilChanged((s1, s2) => {
69528             return s1.height === s2.height && s1.width === s2.width;
69529         }, ([, size]) => {
69530             return size;
69531         }));
69532         this._subscriptions.push(combineLatest(canvasSize$, this._navigator.stateService.currentImage$)
69533             .subscribe(([[canvas, size], image]) => {
69534             canvas.width = size.width;
69535             canvas.height = size.height;
69536             canvas
69537                 .getContext("2d")
69538                 .drawImage(image.image, 0, 0, size.width, size.height);
69539         }));
69540         this._container.domRenderer.renderAdaptive$.next({ name: this._name, vNode: virtualDom.h(`canvas#${this._canvasId}`, []) });
69541     }
69542     _deactivate() {
69543         this._subscriptions.unsubscribe();
69544     }
69545     _getDefaultConfiguration() {
69546         return {};
69547     }
69548 }
69549 ImageFallbackComponent.componentName = "imagefallback";
69550
69551 /**
69552  * @class NavigationFallbackComponent
69553  *
69554  * @classdesc Fallback navigation component for environments without WebGL support.
69555  *
69556  * Replaces the functionality in the Direction and Sequence components.
69557  */
69558 class NavigationFallbackComponent extends Component {
69559     /** @ignore */
69560     constructor(name, container, navigator) {
69561         super(name, container, navigator);
69562         this._seqNames = {};
69563         this._seqNames[NavigationDirection[NavigationDirection.Prev]] = "-prev";
69564         this._seqNames[NavigationDirection[NavigationDirection.Next]] = "-next";
69565         this._spaTopNames = {};
69566         this._spaTopNames[NavigationDirection[NavigationDirection.TurnLeft]] = "-turn-left";
69567         this._spaTopNames[NavigationDirection[NavigationDirection.StepLeft]] = "-left";
69568         this._spaTopNames[NavigationDirection[NavigationDirection.StepForward]] = "-forward";
69569         this._spaTopNames[NavigationDirection[NavigationDirection.StepRight]] = "-right";
69570         this._spaTopNames[NavigationDirection[NavigationDirection.TurnRight]] = "-turn-right";
69571         this._spaBottomNames = {};
69572         this._spaBottomNames[NavigationDirection[NavigationDirection.TurnU]] = "-turn-around";
69573         this._spaBottomNames[NavigationDirection[NavigationDirection.StepBackward]] = "-backward";
69574     }
69575     _activate() {
69576         this._subscriptions.push(combineLatest(this._navigator.stateService.currentImage$, this._configuration$).pipe(switchMap(([image, configuration]) => {
69577             const sequenceEdges$ = configuration.sequence ?
69578                 image.sequenceEdges$.pipe(map((status) => {
69579                     return status.edges
69580                         .map((edge) => {
69581                         return edge.data.direction;
69582                     });
69583                 })) :
69584                 of([]);
69585             const spatialEdges$ = !isSpherical(image.cameraType) &&
69586                 configuration.spatial ?
69587                 image.spatialEdges$.pipe(map((status) => {
69588                     return status.edges
69589                         .map((edge) => {
69590                         return edge.data.direction;
69591                     });
69592                 })) :
69593                 of([]);
69594             return combineLatest(sequenceEdges$, spatialEdges$).pipe(map(([seq, spa]) => {
69595                 return seq.concat(spa);
69596             }));
69597         }), map((edgeDirections) => {
69598             const seqs = this._createArrowRow(this._seqNames, edgeDirections);
69599             const spaTops = this._createArrowRow(this._spaTopNames, edgeDirections);
69600             const spaBottoms = this._createArrowRow(this._spaBottomNames, edgeDirections);
69601             const seqContainer = virtualDom.h(`div.mapillary-navigation-sequence`, seqs);
69602             const spaTopContainer = virtualDom.h(`div.NavigationSpatialTop`, spaTops);
69603             const spaBottomContainer = virtualDom.h(`div.mapillary-navigation-spatial-bottom`, spaBottoms);
69604             const spaContainer = virtualDom.h(`div.mapillary-navigation-spatial`, [spaTopContainer, spaBottomContainer]);
69605             return { name: this._name, vNode: virtualDom.h(`div.NavigationContainer`, [seqContainer, spaContainer]) };
69606         }))
69607             .subscribe(this._container.domRenderer.render$));
69608     }
69609     _deactivate() {
69610         this._subscriptions.unsubscribe();
69611     }
69612     _getDefaultConfiguration() {
69613         return { sequence: true, spatial: true };
69614     }
69615     _createArrowRow(arrowNames, edgeDirections) {
69616         const arrows = [];
69617         for (const arrowName in arrowNames) {
69618             if (!(arrowNames.hasOwnProperty(arrowName))) {
69619                 continue;
69620             }
69621             const direction = NavigationDirection[arrowName];
69622             if (edgeDirections.indexOf(direction) !== -1) {
69623                 arrows.push(this._createVNode(direction, arrowNames[arrowName], "visible"));
69624             }
69625             else {
69626                 arrows.push(this._createVNode(direction, arrowNames[arrowName], "hidden"));
69627             }
69628         }
69629         return arrows;
69630     }
69631     _createVNode(direction, name, visibility) {
69632         return virtualDom.h(`span.mapillary-navigation-button.mapillary-navigation${name}`, {
69633             onclick: () => {
69634                 this._navigator.moveDir$(direction)
69635                     .subscribe(undefined, (error) => {
69636                     if (!(error instanceof CancelMapillaryError)) {
69637                         console.error(error);
69638                     }
69639                 });
69640             },
69641             style: {
69642                 visibility: visibility,
69643             },
69644         }, []);
69645     }
69646 }
69647 NavigationFallbackComponent.componentName = "navigationfallback";
69648
69649 /*! pako 2.0.4 https://github.com/nodeca/pako @license (MIT AND Zlib) */
69650 // (C) 1995-2013 Jean-loup Gailly and Mark Adler
69651 // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
69652 //
69653 // This software is provided 'as-is', without any express or implied
69654 // warranty. In no event will the authors be held liable for any damages
69655 // arising from the use of this software.
69656 //
69657 // Permission is granted to anyone to use this software for any purpose,
69658 // including commercial applications, and to alter it and redistribute it
69659 // freely, subject to the following restrictions:
69660 //
69661 // 1. The origin of this software must not be misrepresented; you must not
69662 //   claim that you wrote the original software. If you use this software
69663 //   in a product, an acknowledgment in the product documentation would be
69664 //   appreciated but is not required.
69665 // 2. Altered source versions must be plainly marked as such, and must not be
69666 //   misrepresented as being the original software.
69667 // 3. This notice may not be removed or altered from any source distribution.
69668
69669 /* eslint-disable space-unary-ops */
69670
69671 /* Public constants ==========================================================*/
69672 /* ===========================================================================*/
69673
69674
69675 //const Z_FILTERED          = 1;
69676 //const Z_HUFFMAN_ONLY      = 2;
69677 //const Z_RLE               = 3;
69678 const Z_FIXED$1               = 4;
69679 //const Z_DEFAULT_STRATEGY  = 0;
69680
69681 /* Possible values of the data_type field (though see inflate()) */
69682 const Z_BINARY              = 0;
69683 const Z_TEXT                = 1;
69684 //const Z_ASCII             = 1; // = Z_TEXT
69685 const Z_UNKNOWN$1             = 2;
69686
69687 /*============================================================================*/
69688
69689
69690 function zero$1(buf) { let len = buf.length; while (--len >= 0) { buf[len] = 0; } }
69691
69692 // From zutil.h
69693
69694 const STORED_BLOCK = 0;
69695 const STATIC_TREES = 1;
69696 const DYN_TREES    = 2;
69697 /* The three kinds of block type */
69698
69699 const MIN_MATCH$1    = 3;
69700 const MAX_MATCH$1    = 258;
69701 /* The minimum and maximum match lengths */
69702
69703 // From deflate.h
69704 /* ===========================================================================
69705  * Internal compression state.
69706  */
69707
69708 const LENGTH_CODES$1  = 29;
69709 /* number of length codes, not counting the special END_BLOCK code */
69710
69711 const LITERALS$1      = 256;
69712 /* number of literal bytes 0..255 */
69713
69714 const L_CODES$1       = LITERALS$1 + 1 + LENGTH_CODES$1;
69715 /* number of Literal or Length codes, including the END_BLOCK code */
69716
69717 const D_CODES$1       = 30;
69718 /* number of distance codes */
69719
69720 const BL_CODES$1      = 19;
69721 /* number of codes used to transfer the bit lengths */
69722
69723 const HEAP_SIZE$1     = 2 * L_CODES$1 + 1;
69724 /* maximum heap size */
69725
69726 const MAX_BITS$1      = 15;
69727 /* All codes must not exceed MAX_BITS bits */
69728
69729 const Buf_size      = 16;
69730 /* size of bit buffer in bi_buf */
69731
69732
69733 /* ===========================================================================
69734  * Constants
69735  */
69736
69737 const MAX_BL_BITS = 7;
69738 /* Bit length codes must not exceed MAX_BL_BITS bits */
69739
69740 const END_BLOCK   = 256;
69741 /* end of block literal code */
69742
69743 const REP_3_6     = 16;
69744 /* repeat previous bit length 3-6 times (2 bits of repeat count) */
69745
69746 const REPZ_3_10   = 17;
69747 /* repeat a zero length 3-10 times  (3 bits of repeat count) */
69748
69749 const REPZ_11_138 = 18;
69750 /* repeat a zero length 11-138 times  (7 bits of repeat count) */
69751
69752 /* eslint-disable comma-spacing,array-bracket-spacing */
69753 const extra_lbits =   /* extra bits for each length code */
69754   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]);
69755
69756 const extra_dbits =   /* extra bits for each distance code */
69757   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]);
69758
69759 const extra_blbits =  /* extra bits for each bit length code */
69760   new Uint8Array([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7]);
69761
69762 const bl_order =
69763   new Uint8Array([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]);
69764 /* eslint-enable comma-spacing,array-bracket-spacing */
69765
69766 /* The lengths of the bit length codes are sent in order of decreasing
69767  * probability, to avoid transmitting the lengths for unused bit length codes.
69768  */
69769
69770 /* ===========================================================================
69771  * Local data. These are initialized only once.
69772  */
69773
69774 // We pre-fill arrays with 0 to avoid uninitialized gaps
69775
69776 const DIST_CODE_LEN = 512; /* see definition of array dist_code below */
69777
69778 // !!!! Use flat array instead of structure, Freq = i*2, Len = i*2+1
69779 const static_ltree  = new Array((L_CODES$1 + 2) * 2);
69780 zero$1(static_ltree);
69781 /* The static literal tree. Since the bit lengths are imposed, there is no
69782  * need for the L_CODES extra codes used during heap construction. However
69783  * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
69784  * below).
69785  */
69786
69787 const static_dtree  = new Array(D_CODES$1 * 2);
69788 zero$1(static_dtree);
69789 /* The static distance tree. (Actually a trivial tree since all codes use
69790  * 5 bits.)
69791  */
69792
69793 const _dist_code    = new Array(DIST_CODE_LEN);
69794 zero$1(_dist_code);
69795 /* Distance codes. The first 256 values correspond to the distances
69796  * 3 .. 258, the last 256 values correspond to the top 8 bits of
69797  * the 15 bit distances.
69798  */
69799
69800 const _length_code  = new Array(MAX_MATCH$1 - MIN_MATCH$1 + 1);
69801 zero$1(_length_code);
69802 /* length code for each normalized match length (0 == MIN_MATCH) */
69803
69804 const base_length   = new Array(LENGTH_CODES$1);
69805 zero$1(base_length);
69806 /* First normalized length for each code (0 = MIN_MATCH) */
69807
69808 const base_dist     = new Array(D_CODES$1);
69809 zero$1(base_dist);
69810 /* First normalized distance for each code (0 = distance of 1) */
69811
69812
69813 function StaticTreeDesc(static_tree, extra_bits, extra_base, elems, max_length) {
69814
69815   this.static_tree  = static_tree;  /* static tree or NULL */
69816   this.extra_bits   = extra_bits;   /* extra bits for each code or NULL */
69817   this.extra_base   = extra_base;   /* base index for extra_bits */
69818   this.elems        = elems;        /* max number of elements in the tree */
69819   this.max_length   = max_length;   /* max bit length for the codes */
69820
69821   // show if `static_tree` has data or dummy - needed for monomorphic objects
69822   this.has_stree    = static_tree && static_tree.length;
69823 }
69824
69825
69826 let static_l_desc;
69827 let static_d_desc;
69828 let static_bl_desc;
69829
69830
69831 function TreeDesc(dyn_tree, stat_desc) {
69832   this.dyn_tree = dyn_tree;     /* the dynamic tree */
69833   this.max_code = 0;            /* largest code with non zero frequency */
69834   this.stat_desc = stat_desc;   /* the corresponding static tree */
69835 }
69836
69837
69838
69839 const d_code = (dist) => {
69840
69841   return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)];
69842 };
69843
69844
69845 /* ===========================================================================
69846  * Output a short LSB first on the stream.
69847  * IN assertion: there is enough room in pendingBuf.
69848  */
69849 const put_short = (s, w) => {
69850 //    put_byte(s, (uch)((w) & 0xff));
69851 //    put_byte(s, (uch)((ush)(w) >> 8));
69852   s.pending_buf[s.pending++] = (w) & 0xff;
69853   s.pending_buf[s.pending++] = (w >>> 8) & 0xff;
69854 };
69855
69856
69857 /* ===========================================================================
69858  * Send a value on a given number of bits.
69859  * IN assertion: length <= 16 and value fits in length bits.
69860  */
69861 const send_bits = (s, value, length) => {
69862
69863   if (s.bi_valid > (Buf_size - length)) {
69864     s.bi_buf |= (value << s.bi_valid) & 0xffff;
69865     put_short(s, s.bi_buf);
69866     s.bi_buf = value >> (Buf_size - s.bi_valid);
69867     s.bi_valid += length - Buf_size;
69868   } else {
69869     s.bi_buf |= (value << s.bi_valid) & 0xffff;
69870     s.bi_valid += length;
69871   }
69872 };
69873
69874
69875 const send_code = (s, c, tree) => {
69876
69877   send_bits(s, tree[c * 2]/*.Code*/, tree[c * 2 + 1]/*.Len*/);
69878 };
69879
69880
69881 /* ===========================================================================
69882  * Reverse the first len bits of a code, using straightforward code (a faster
69883  * method would use a table)
69884  * IN assertion: 1 <= len <= 15
69885  */
69886 const bi_reverse = (code, len) => {
69887
69888   let res = 0;
69889   do {
69890     res |= code & 1;
69891     code >>>= 1;
69892     res <<= 1;
69893   } while (--len > 0);
69894   return res >>> 1;
69895 };
69896
69897
69898 /* ===========================================================================
69899  * Flush the bit buffer, keeping at most 7 bits in it.
69900  */
69901 const bi_flush = (s) => {
69902
69903   if (s.bi_valid === 16) {
69904     put_short(s, s.bi_buf);
69905     s.bi_buf = 0;
69906     s.bi_valid = 0;
69907
69908   } else if (s.bi_valid >= 8) {
69909     s.pending_buf[s.pending++] = s.bi_buf & 0xff;
69910     s.bi_buf >>= 8;
69911     s.bi_valid -= 8;
69912   }
69913 };
69914
69915
69916 /* ===========================================================================
69917  * Compute the optimal bit lengths for a tree and update the total bit length
69918  * for the current block.
69919  * IN assertion: the fields freq and dad are set, heap[heap_max] and
69920  *    above are the tree nodes sorted by increasing frequency.
69921  * OUT assertions: the field len is set to the optimal bit length, the
69922  *     array bl_count contains the frequencies for each bit length.
69923  *     The length opt_len is updated; static_len is also updated if stree is
69924  *     not null.
69925  */
69926 const gen_bitlen = (s, desc) =>
69927 //    deflate_state *s;
69928 //    tree_desc *desc;    /* the tree descriptor */
69929 {
69930   const tree            = desc.dyn_tree;
69931   const max_code        = desc.max_code;
69932   const stree           = desc.stat_desc.static_tree;
69933   const has_stree       = desc.stat_desc.has_stree;
69934   const extra           = desc.stat_desc.extra_bits;
69935   const base            = desc.stat_desc.extra_base;
69936   const max_length      = desc.stat_desc.max_length;
69937   let h;              /* heap index */
69938   let n, m;           /* iterate over the tree elements */
69939   let bits;           /* bit length */
69940   let xbits;          /* extra bits */
69941   let f;              /* frequency */
69942   let overflow = 0;   /* number of elements with bit length too large */
69943
69944   for (bits = 0; bits <= MAX_BITS$1; bits++) {
69945     s.bl_count[bits] = 0;
69946   }
69947
69948   /* In a first pass, compute the optimal bit lengths (which may
69949    * overflow in the case of the bit length tree).
69950    */
69951   tree[s.heap[s.heap_max] * 2 + 1]/*.Len*/ = 0; /* root of the heap */
69952
69953   for (h = s.heap_max + 1; h < HEAP_SIZE$1; h++) {
69954     n = s.heap[h];
69955     bits = tree[tree[n * 2 + 1]/*.Dad*/ * 2 + 1]/*.Len*/ + 1;
69956     if (bits > max_length) {
69957       bits = max_length;
69958       overflow++;
69959     }
69960     tree[n * 2 + 1]/*.Len*/ = bits;
69961     /* We overwrite tree[n].Dad which is no longer needed */
69962
69963     if (n > max_code) { continue; } /* not a leaf node */
69964
69965     s.bl_count[bits]++;
69966     xbits = 0;
69967     if (n >= base) {
69968       xbits = extra[n - base];
69969     }
69970     f = tree[n * 2]/*.Freq*/;
69971     s.opt_len += f * (bits + xbits);
69972     if (has_stree) {
69973       s.static_len += f * (stree[n * 2 + 1]/*.Len*/ + xbits);
69974     }
69975   }
69976   if (overflow === 0) { return; }
69977
69978   // Trace((stderr,"\nbit length overflow\n"));
69979   /* This happens for example on obj2 and pic of the Calgary corpus */
69980
69981   /* Find the first bit length which could increase: */
69982   do {
69983     bits = max_length - 1;
69984     while (s.bl_count[bits] === 0) { bits--; }
69985     s.bl_count[bits]--;      /* move one leaf down the tree */
69986     s.bl_count[bits + 1] += 2; /* move one overflow item as its brother */
69987     s.bl_count[max_length]--;
69988     /* The brother of the overflow item also moves one step up,
69989      * but this does not affect bl_count[max_length]
69990      */
69991     overflow -= 2;
69992   } while (overflow > 0);
69993
69994   /* Now recompute all bit lengths, scanning in increasing frequency.
69995    * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
69996    * lengths instead of fixing only the wrong ones. This idea is taken
69997    * from 'ar' written by Haruhiko Okumura.)
69998    */
69999   for (bits = max_length; bits !== 0; bits--) {
70000     n = s.bl_count[bits];
70001     while (n !== 0) {
70002       m = s.heap[--h];
70003       if (m > max_code) { continue; }
70004       if (tree[m * 2 + 1]/*.Len*/ !== bits) {
70005         // Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
70006         s.opt_len += (bits - tree[m * 2 + 1]/*.Len*/) * tree[m * 2]/*.Freq*/;
70007         tree[m * 2 + 1]/*.Len*/ = bits;
70008       }
70009       n--;
70010     }
70011   }
70012 };
70013
70014
70015 /* ===========================================================================
70016  * Generate the codes for a given tree and bit counts (which need not be
70017  * optimal).
70018  * IN assertion: the array bl_count contains the bit length statistics for
70019  * the given tree and the field len is set for all tree elements.
70020  * OUT assertion: the field code is set for all tree elements of non
70021  *     zero code length.
70022  */
70023 const gen_codes = (tree, max_code, bl_count) =>
70024 //    ct_data *tree;             /* the tree to decorate */
70025 //    int max_code;              /* largest code with non zero frequency */
70026 //    ushf *bl_count;            /* number of codes at each bit length */
70027 {
70028   const next_code = new Array(MAX_BITS$1 + 1); /* next code value for each bit length */
70029   let code = 0;              /* running code value */
70030   let bits;                  /* bit index */
70031   let n;                     /* code index */
70032
70033   /* The distribution counts are first used to generate the code values
70034    * without bit reversal.
70035    */
70036   for (bits = 1; bits <= MAX_BITS$1; bits++) {
70037     next_code[bits] = code = (code + bl_count[bits - 1]) << 1;
70038   }
70039   /* Check that the bit counts in bl_count are consistent. The last code
70040    * must be all ones.
70041    */
70042   //Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
70043   //        "inconsistent bit counts");
70044   //Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
70045
70046   for (n = 0;  n <= max_code; n++) {
70047     let len = tree[n * 2 + 1]/*.Len*/;
70048     if (len === 0) { continue; }
70049     /* Now reverse the bits */
70050     tree[n * 2]/*.Code*/ = bi_reverse(next_code[len]++, len);
70051
70052     //Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
70053     //     n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
70054   }
70055 };
70056
70057
70058 /* ===========================================================================
70059  * Initialize the various 'constant' tables.
70060  */
70061 const tr_static_init = () => {
70062
70063   let n;        /* iterates over tree elements */
70064   let bits;     /* bit counter */
70065   let length;   /* length value */
70066   let code;     /* code value */
70067   let dist;     /* distance index */
70068   const bl_count = new Array(MAX_BITS$1 + 1);
70069   /* number of codes at each bit length for an optimal tree */
70070
70071   // do check in _tr_init()
70072   //if (static_init_done) return;
70073
70074   /* For some embedded targets, global variables are not initialized: */
70075 /*#ifdef NO_INIT_GLOBAL_POINTERS
70076   static_l_desc.static_tree = static_ltree;
70077   static_l_desc.extra_bits = extra_lbits;
70078   static_d_desc.static_tree = static_dtree;
70079   static_d_desc.extra_bits = extra_dbits;
70080   static_bl_desc.extra_bits = extra_blbits;
70081 #endif*/
70082
70083   /* Initialize the mapping length (0..255) -> length code (0..28) */
70084   length = 0;
70085   for (code = 0; code < LENGTH_CODES$1 - 1; code++) {
70086     base_length[code] = length;
70087     for (n = 0; n < (1 << extra_lbits[code]); n++) {
70088       _length_code[length++] = code;
70089     }
70090   }
70091   //Assert (length == 256, "tr_static_init: length != 256");
70092   /* Note that the length 255 (match length 258) can be represented
70093    * in two different ways: code 284 + 5 bits or code 285, so we
70094    * overwrite length_code[255] to use the best encoding:
70095    */
70096   _length_code[length - 1] = code;
70097
70098   /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
70099   dist = 0;
70100   for (code = 0; code < 16; code++) {
70101     base_dist[code] = dist;
70102     for (n = 0; n < (1 << extra_dbits[code]); n++) {
70103       _dist_code[dist++] = code;
70104     }
70105   }
70106   //Assert (dist == 256, "tr_static_init: dist != 256");
70107   dist >>= 7; /* from now on, all distances are divided by 128 */
70108   for (; code < D_CODES$1; code++) {
70109     base_dist[code] = dist << 7;
70110     for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) {
70111       _dist_code[256 + dist++] = code;
70112     }
70113   }
70114   //Assert (dist == 256, "tr_static_init: 256+dist != 512");
70115
70116   /* Construct the codes of the static literal tree */
70117   for (bits = 0; bits <= MAX_BITS$1; bits++) {
70118     bl_count[bits] = 0;
70119   }
70120
70121   n = 0;
70122   while (n <= 143) {
70123     static_ltree[n * 2 + 1]/*.Len*/ = 8;
70124     n++;
70125     bl_count[8]++;
70126   }
70127   while (n <= 255) {
70128     static_ltree[n * 2 + 1]/*.Len*/ = 9;
70129     n++;
70130     bl_count[9]++;
70131   }
70132   while (n <= 279) {
70133     static_ltree[n * 2 + 1]/*.Len*/ = 7;
70134     n++;
70135     bl_count[7]++;
70136   }
70137   while (n <= 287) {
70138     static_ltree[n * 2 + 1]/*.Len*/ = 8;
70139     n++;
70140     bl_count[8]++;
70141   }
70142   /* Codes 286 and 287 do not exist, but we must include them in the
70143    * tree construction to get a canonical Huffman tree (longest code
70144    * all ones)
70145    */
70146   gen_codes(static_ltree, L_CODES$1 + 1, bl_count);
70147
70148   /* The static distance tree is trivial: */
70149   for (n = 0; n < D_CODES$1; n++) {
70150     static_dtree[n * 2 + 1]/*.Len*/ = 5;
70151     static_dtree[n * 2]/*.Code*/ = bi_reverse(n, 5);
70152   }
70153
70154   // Now data ready and we can init static trees
70155   static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS$1 + 1, L_CODES$1, MAX_BITS$1);
70156   static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0,          D_CODES$1, MAX_BITS$1);
70157   static_bl_desc = new StaticTreeDesc(new Array(0), extra_blbits, 0,         BL_CODES$1, MAX_BL_BITS);
70158
70159   //static_init_done = true;
70160 };
70161
70162
70163 /* ===========================================================================
70164  * Initialize a new block.
70165  */
70166 const init_block = (s) => {
70167
70168   let n; /* iterates over tree elements */
70169
70170   /* Initialize the trees. */
70171   for (n = 0; n < L_CODES$1;  n++) { s.dyn_ltree[n * 2]/*.Freq*/ = 0; }
70172   for (n = 0; n < D_CODES$1;  n++) { s.dyn_dtree[n * 2]/*.Freq*/ = 0; }
70173   for (n = 0; n < BL_CODES$1; n++) { s.bl_tree[n * 2]/*.Freq*/ = 0; }
70174
70175   s.dyn_ltree[END_BLOCK * 2]/*.Freq*/ = 1;
70176   s.opt_len = s.static_len = 0;
70177   s.last_lit = s.matches = 0;
70178 };
70179
70180
70181 /* ===========================================================================
70182  * Flush the bit buffer and align the output on a byte boundary
70183  */
70184 const bi_windup = (s) =>
70185 {
70186   if (s.bi_valid > 8) {
70187     put_short(s, s.bi_buf);
70188   } else if (s.bi_valid > 0) {
70189     //put_byte(s, (Byte)s->bi_buf);
70190     s.pending_buf[s.pending++] = s.bi_buf;
70191   }
70192   s.bi_buf = 0;
70193   s.bi_valid = 0;
70194 };
70195
70196 /* ===========================================================================
70197  * Copy a stored block, storing first the length and its
70198  * one's complement if requested.
70199  */
70200 const copy_block = (s, buf, len, header) =>
70201 //DeflateState *s;
70202 //charf    *buf;    /* the input data */
70203 //unsigned len;     /* its length */
70204 //int      header;  /* true if block header must be written */
70205 {
70206   bi_windup(s);        /* align on byte boundary */
70207
70208   if (header) {
70209     put_short(s, len);
70210     put_short(s, ~len);
70211   }
70212 //  while (len--) {
70213 //    put_byte(s, *buf++);
70214 //  }
70215   s.pending_buf.set(s.window.subarray(buf, buf + len), s.pending);
70216   s.pending += len;
70217 };
70218
70219 /* ===========================================================================
70220  * Compares to subtrees, using the tree depth as tie breaker when
70221  * the subtrees have equal frequency. This minimizes the worst case length.
70222  */
70223 const smaller = (tree, n, m, depth) => {
70224
70225   const _n2 = n * 2;
70226   const _m2 = m * 2;
70227   return (tree[_n2]/*.Freq*/ < tree[_m2]/*.Freq*/ ||
70228          (tree[_n2]/*.Freq*/ === tree[_m2]/*.Freq*/ && depth[n] <= depth[m]));
70229 };
70230
70231 /* ===========================================================================
70232  * Restore the heap property by moving down the tree starting at node k,
70233  * exchanging a node with the smallest of its two sons if necessary, stopping
70234  * when the heap property is re-established (each father smaller than its
70235  * two sons).
70236  */
70237 const pqdownheap = (s, tree, k) =>
70238 //    deflate_state *s;
70239 //    ct_data *tree;  /* the tree to restore */
70240 //    int k;               /* node to move down */
70241 {
70242   const v = s.heap[k];
70243   let j = k << 1;  /* left son of k */
70244   while (j <= s.heap_len) {
70245     /* Set j to the smallest of the two sons: */
70246     if (j < s.heap_len &&
70247       smaller(tree, s.heap[j + 1], s.heap[j], s.depth)) {
70248       j++;
70249     }
70250     /* Exit if v is smaller than both sons */
70251     if (smaller(tree, v, s.heap[j], s.depth)) { break; }
70252
70253     /* Exchange v with the smallest son */
70254     s.heap[k] = s.heap[j];
70255     k = j;
70256
70257     /* And continue down the tree, setting j to the left son of k */
70258     j <<= 1;
70259   }
70260   s.heap[k] = v;
70261 };
70262
70263
70264 // inlined manually
70265 // const SMALLEST = 1;
70266
70267 /* ===========================================================================
70268  * Send the block data compressed using the given Huffman trees
70269  */
70270 const compress_block = (s, ltree, dtree) =>
70271 //    deflate_state *s;
70272 //    const ct_data *ltree; /* literal tree */
70273 //    const ct_data *dtree; /* distance tree */
70274 {
70275   let dist;           /* distance of matched string */
70276   let lc;             /* match length or unmatched char (if dist == 0) */
70277   let lx = 0;         /* running index in l_buf */
70278   let code;           /* the code to send */
70279   let extra;          /* number of extra bits to send */
70280
70281   if (s.last_lit !== 0) {
70282     do {
70283       dist = (s.pending_buf[s.d_buf + lx * 2] << 8) | (s.pending_buf[s.d_buf + lx * 2 + 1]);
70284       lc = s.pending_buf[s.l_buf + lx];
70285       lx++;
70286
70287       if (dist === 0) {
70288         send_code(s, lc, ltree); /* send a literal byte */
70289         //Tracecv(isgraph(lc), (stderr," '%c' ", lc));
70290       } else {
70291         /* Here, lc is the match length - MIN_MATCH */
70292         code = _length_code[lc];
70293         send_code(s, code + LITERALS$1 + 1, ltree); /* send the length code */
70294         extra = extra_lbits[code];
70295         if (extra !== 0) {
70296           lc -= base_length[code];
70297           send_bits(s, lc, extra);       /* send the extra length bits */
70298         }
70299         dist--; /* dist is now the match distance - 1 */
70300         code = d_code(dist);
70301         //Assert (code < D_CODES, "bad d_code");
70302
70303         send_code(s, code, dtree);       /* send the distance code */
70304         extra = extra_dbits[code];
70305         if (extra !== 0) {
70306           dist -= base_dist[code];
70307           send_bits(s, dist, extra);   /* send the extra distance bits */
70308         }
70309       } /* literal or match pair ? */
70310
70311       /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
70312       //Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
70313       //       "pendingBuf overflow");
70314
70315     } while (lx < s.last_lit);
70316   }
70317
70318   send_code(s, END_BLOCK, ltree);
70319 };
70320
70321
70322 /* ===========================================================================
70323  * Construct one Huffman tree and assigns the code bit strings and lengths.
70324  * Update the total bit length for the current block.
70325  * IN assertion: the field freq is set for all tree elements.
70326  * OUT assertions: the fields len and code are set to the optimal bit length
70327  *     and corresponding code. The length opt_len is updated; static_len is
70328  *     also updated if stree is not null. The field max_code is set.
70329  */
70330 const build_tree = (s, desc) =>
70331 //    deflate_state *s;
70332 //    tree_desc *desc; /* the tree descriptor */
70333 {
70334   const tree     = desc.dyn_tree;
70335   const stree    = desc.stat_desc.static_tree;
70336   const has_stree = desc.stat_desc.has_stree;
70337   const elems    = desc.stat_desc.elems;
70338   let n, m;          /* iterate over heap elements */
70339   let max_code = -1; /* largest code with non zero frequency */
70340   let node;          /* new node being created */
70341
70342   /* Construct the initial heap, with least frequent element in
70343    * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
70344    * heap[0] is not used.
70345    */
70346   s.heap_len = 0;
70347   s.heap_max = HEAP_SIZE$1;
70348
70349   for (n = 0; n < elems; n++) {
70350     if (tree[n * 2]/*.Freq*/ !== 0) {
70351       s.heap[++s.heap_len] = max_code = n;
70352       s.depth[n] = 0;
70353
70354     } else {
70355       tree[n * 2 + 1]/*.Len*/ = 0;
70356     }
70357   }
70358
70359   /* The pkzip format requires that at least one distance code exists,
70360    * and that at least one bit should be sent even if there is only one
70361    * possible code. So to avoid special checks later on we force at least
70362    * two codes of non zero frequency.
70363    */
70364   while (s.heap_len < 2) {
70365     node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0);
70366     tree[node * 2]/*.Freq*/ = 1;
70367     s.depth[node] = 0;
70368     s.opt_len--;
70369
70370     if (has_stree) {
70371       s.static_len -= stree[node * 2 + 1]/*.Len*/;
70372     }
70373     /* node is 0 or 1 so it does not have extra bits */
70374   }
70375   desc.max_code = max_code;
70376
70377   /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
70378    * establish sub-heaps of increasing lengths:
70379    */
70380   for (n = (s.heap_len >> 1/*int /2*/); n >= 1; n--) { pqdownheap(s, tree, n); }
70381
70382   /* Construct the Huffman tree by repeatedly combining the least two
70383    * frequent nodes.
70384    */
70385   node = elems;              /* next internal node of the tree */
70386   do {
70387     //pqremove(s, tree, n);  /* n = node of least frequency */
70388     /*** pqremove ***/
70389     n = s.heap[1/*SMALLEST*/];
70390     s.heap[1/*SMALLEST*/] = s.heap[s.heap_len--];
70391     pqdownheap(s, tree, 1/*SMALLEST*/);
70392     /***/
70393
70394     m = s.heap[1/*SMALLEST*/]; /* m = node of next least frequency */
70395
70396     s.heap[--s.heap_max] = n; /* keep the nodes sorted by frequency */
70397     s.heap[--s.heap_max] = m;
70398
70399     /* Create a new node father of n and m */
70400     tree[node * 2]/*.Freq*/ = tree[n * 2]/*.Freq*/ + tree[m * 2]/*.Freq*/;
70401     s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1;
70402     tree[n * 2 + 1]/*.Dad*/ = tree[m * 2 + 1]/*.Dad*/ = node;
70403
70404     /* and insert the new node in the heap */
70405     s.heap[1/*SMALLEST*/] = node++;
70406     pqdownheap(s, tree, 1/*SMALLEST*/);
70407
70408   } while (s.heap_len >= 2);
70409
70410   s.heap[--s.heap_max] = s.heap[1/*SMALLEST*/];
70411
70412   /* At this point, the fields freq and dad are set. We can now
70413    * generate the bit lengths.
70414    */
70415   gen_bitlen(s, desc);
70416
70417   /* The field len is now set, we can generate the bit codes */
70418   gen_codes(tree, max_code, s.bl_count);
70419 };
70420
70421
70422 /* ===========================================================================
70423  * Scan a literal or distance tree to determine the frequencies of the codes
70424  * in the bit length tree.
70425  */
70426 const scan_tree = (s, tree, max_code) =>
70427 //    deflate_state *s;
70428 //    ct_data *tree;   /* the tree to be scanned */
70429 //    int max_code;    /* and its largest code of non zero frequency */
70430 {
70431   let n;                     /* iterates over all tree elements */
70432   let prevlen = -1;          /* last emitted length */
70433   let curlen;                /* length of current code */
70434
70435   let nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */
70436
70437   let count = 0;             /* repeat count of the current code */
70438   let max_count = 7;         /* max repeat count */
70439   let min_count = 4;         /* min repeat count */
70440
70441   if (nextlen === 0) {
70442     max_count = 138;
70443     min_count = 3;
70444   }
70445   tree[(max_code + 1) * 2 + 1]/*.Len*/ = 0xffff; /* guard */
70446
70447   for (n = 0; n <= max_code; n++) {
70448     curlen = nextlen;
70449     nextlen = tree[(n + 1) * 2 + 1]/*.Len*/;
70450
70451     if (++count < max_count && curlen === nextlen) {
70452       continue;
70453
70454     } else if (count < min_count) {
70455       s.bl_tree[curlen * 2]/*.Freq*/ += count;
70456
70457     } else if (curlen !== 0) {
70458
70459       if (curlen !== prevlen) { s.bl_tree[curlen * 2]/*.Freq*/++; }
70460       s.bl_tree[REP_3_6 * 2]/*.Freq*/++;
70461
70462     } else if (count <= 10) {
70463       s.bl_tree[REPZ_3_10 * 2]/*.Freq*/++;
70464
70465     } else {
70466       s.bl_tree[REPZ_11_138 * 2]/*.Freq*/++;
70467     }
70468
70469     count = 0;
70470     prevlen = curlen;
70471
70472     if (nextlen === 0) {
70473       max_count = 138;
70474       min_count = 3;
70475
70476     } else if (curlen === nextlen) {
70477       max_count = 6;
70478       min_count = 3;
70479
70480     } else {
70481       max_count = 7;
70482       min_count = 4;
70483     }
70484   }
70485 };
70486
70487
70488 /* ===========================================================================
70489  * Send a literal or distance tree in compressed form, using the codes in
70490  * bl_tree.
70491  */
70492 const send_tree = (s, tree, max_code) =>
70493 //    deflate_state *s;
70494 //    ct_data *tree; /* the tree to be scanned */
70495 //    int max_code;       /* and its largest code of non zero frequency */
70496 {
70497   let n;                     /* iterates over all tree elements */
70498   let prevlen = -1;          /* last emitted length */
70499   let curlen;                /* length of current code */
70500
70501   let nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */
70502
70503   let count = 0;             /* repeat count of the current code */
70504   let max_count = 7;         /* max repeat count */
70505   let min_count = 4;         /* min repeat count */
70506
70507   /* tree[max_code+1].Len = -1; */  /* guard already set */
70508   if (nextlen === 0) {
70509     max_count = 138;
70510     min_count = 3;
70511   }
70512
70513   for (n = 0; n <= max_code; n++) {
70514     curlen = nextlen;
70515     nextlen = tree[(n + 1) * 2 + 1]/*.Len*/;
70516
70517     if (++count < max_count && curlen === nextlen) {
70518       continue;
70519
70520     } else if (count < min_count) {
70521       do { send_code(s, curlen, s.bl_tree); } while (--count !== 0);
70522
70523     } else if (curlen !== 0) {
70524       if (curlen !== prevlen) {
70525         send_code(s, curlen, s.bl_tree);
70526         count--;
70527       }
70528       //Assert(count >= 3 && count <= 6, " 3_6?");
70529       send_code(s, REP_3_6, s.bl_tree);
70530       send_bits(s, count - 3, 2);
70531
70532     } else if (count <= 10) {
70533       send_code(s, REPZ_3_10, s.bl_tree);
70534       send_bits(s, count - 3, 3);
70535
70536     } else {
70537       send_code(s, REPZ_11_138, s.bl_tree);
70538       send_bits(s, count - 11, 7);
70539     }
70540
70541     count = 0;
70542     prevlen = curlen;
70543     if (nextlen === 0) {
70544       max_count = 138;
70545       min_count = 3;
70546
70547     } else if (curlen === nextlen) {
70548       max_count = 6;
70549       min_count = 3;
70550
70551     } else {
70552       max_count = 7;
70553       min_count = 4;
70554     }
70555   }
70556 };
70557
70558
70559 /* ===========================================================================
70560  * Construct the Huffman tree for the bit lengths and return the index in
70561  * bl_order of the last bit length code to send.
70562  */
70563 const build_bl_tree = (s) => {
70564
70565   let max_blindex;  /* index of last bit length code of non zero freq */
70566
70567   /* Determine the bit length frequencies for literal and distance trees */
70568   scan_tree(s, s.dyn_ltree, s.l_desc.max_code);
70569   scan_tree(s, s.dyn_dtree, s.d_desc.max_code);
70570
70571   /* Build the bit length tree: */
70572   build_tree(s, s.bl_desc);
70573   /* opt_len now includes the length of the tree representations, except
70574    * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
70575    */
70576
70577   /* Determine the number of bit length codes to send. The pkzip format
70578    * requires that at least 4 bit length codes be sent. (appnote.txt says
70579    * 3 but the actual value used is 4.)
70580    */
70581   for (max_blindex = BL_CODES$1 - 1; max_blindex >= 3; max_blindex--) {
70582     if (s.bl_tree[bl_order[max_blindex] * 2 + 1]/*.Len*/ !== 0) {
70583       break;
70584     }
70585   }
70586   /* Update opt_len to include the bit length tree and counts */
70587   s.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;
70588   //Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
70589   //        s->opt_len, s->static_len));
70590
70591   return max_blindex;
70592 };
70593
70594
70595 /* ===========================================================================
70596  * Send the header for a block using dynamic Huffman trees: the counts, the
70597  * lengths of the bit length codes, the literal tree and the distance tree.
70598  * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
70599  */
70600 const send_all_trees = (s, lcodes, dcodes, blcodes) =>
70601 //    deflate_state *s;
70602 //    int lcodes, dcodes, blcodes; /* number of codes for each tree */
70603 {
70604   let rank;                    /* index in bl_order */
70605
70606   //Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
70607   //Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
70608   //        "too many codes");
70609   //Tracev((stderr, "\nbl counts: "));
70610   send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */
70611   send_bits(s, dcodes - 1,   5);
70612   send_bits(s, blcodes - 4,  4); /* not -3 as stated in appnote.txt */
70613   for (rank = 0; rank < blcodes; rank++) {
70614     //Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
70615     send_bits(s, s.bl_tree[bl_order[rank] * 2 + 1]/*.Len*/, 3);
70616   }
70617   //Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
70618
70619   send_tree(s, s.dyn_ltree, lcodes - 1); /* literal tree */
70620   //Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
70621
70622   send_tree(s, s.dyn_dtree, dcodes - 1); /* distance tree */
70623   //Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
70624 };
70625
70626
70627 /* ===========================================================================
70628  * Check if the data type is TEXT or BINARY, using the following algorithm:
70629  * - TEXT if the two conditions below are satisfied:
70630  *    a) There are no non-portable control characters belonging to the
70631  *       "black list" (0..6, 14..25, 28..31).
70632  *    b) There is at least one printable character belonging to the
70633  *       "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).
70634  * - BINARY otherwise.
70635  * - The following partially-portable control characters form a
70636  *   "gray list" that is ignored in this detection algorithm:
70637  *   (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).
70638  * IN assertion: the fields Freq of dyn_ltree are set.
70639  */
70640 const detect_data_type = (s) => {
70641   /* black_mask is the bit mask of black-listed bytes
70642    * set bits 0..6, 14..25, and 28..31
70643    * 0xf3ffc07f = binary 11110011111111111100000001111111
70644    */
70645   let black_mask = 0xf3ffc07f;
70646   let n;
70647
70648   /* Check for non-textual ("black-listed") bytes. */
70649   for (n = 0; n <= 31; n++, black_mask >>>= 1) {
70650     if ((black_mask & 1) && (s.dyn_ltree[n * 2]/*.Freq*/ !== 0)) {
70651       return Z_BINARY;
70652     }
70653   }
70654
70655   /* Check for textual ("white-listed") bytes. */
70656   if (s.dyn_ltree[9 * 2]/*.Freq*/ !== 0 || s.dyn_ltree[10 * 2]/*.Freq*/ !== 0 ||
70657       s.dyn_ltree[13 * 2]/*.Freq*/ !== 0) {
70658     return Z_TEXT;
70659   }
70660   for (n = 32; n < LITERALS$1; n++) {
70661     if (s.dyn_ltree[n * 2]/*.Freq*/ !== 0) {
70662       return Z_TEXT;
70663     }
70664   }
70665
70666   /* There are no "black-listed" or "white-listed" bytes:
70667    * this stream either is empty or has tolerated ("gray-listed") bytes only.
70668    */
70669   return Z_BINARY;
70670 };
70671
70672
70673 let static_init_done = false;
70674
70675 /* ===========================================================================
70676  * Initialize the tree data structures for a new zlib stream.
70677  */
70678 const _tr_init$1 = (s) =>
70679 {
70680
70681   if (!static_init_done) {
70682     tr_static_init();
70683     static_init_done = true;
70684   }
70685
70686   s.l_desc  = new TreeDesc(s.dyn_ltree, static_l_desc);
70687   s.d_desc  = new TreeDesc(s.dyn_dtree, static_d_desc);
70688   s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc);
70689
70690   s.bi_buf = 0;
70691   s.bi_valid = 0;
70692
70693   /* Initialize the first block of the first file: */
70694   init_block(s);
70695 };
70696
70697
70698 /* ===========================================================================
70699  * Send a stored block
70700  */
70701 const _tr_stored_block$1 = (s, buf, stored_len, last) =>
70702 //DeflateState *s;
70703 //charf *buf;       /* input block */
70704 //ulg stored_len;   /* length of input block */
70705 //int last;         /* one if this is the last block for a file */
70706 {
70707   send_bits(s, (STORED_BLOCK << 1) + (last ? 1 : 0), 3);    /* send block type */
70708   copy_block(s, buf, stored_len, true); /* with header */
70709 };
70710
70711
70712 /* ===========================================================================
70713  * Send one empty static block to give enough lookahead for inflate.
70714  * This takes 10 bits, of which 7 may remain in the bit buffer.
70715  */
70716 const _tr_align$1 = (s) => {
70717   send_bits(s, STATIC_TREES << 1, 3);
70718   send_code(s, END_BLOCK, static_ltree);
70719   bi_flush(s);
70720 };
70721
70722
70723 /* ===========================================================================
70724  * Determine the best encoding for the current block: dynamic trees, static
70725  * trees or store, and output the encoded block to the zip file.
70726  */
70727 const _tr_flush_block$1 = (s, buf, stored_len, last) =>
70728 //DeflateState *s;
70729 //charf *buf;       /* input block, or NULL if too old */
70730 //ulg stored_len;   /* length of input block */
70731 //int last;         /* one if this is the last block for a file */
70732 {
70733   let opt_lenb, static_lenb;  /* opt_len and static_len in bytes */
70734   let max_blindex = 0;        /* index of last bit length code of non zero freq */
70735
70736   /* Build the Huffman trees unless a stored block is forced */
70737   if (s.level > 0) {
70738
70739     /* Check if the file is binary or text */
70740     if (s.strm.data_type === Z_UNKNOWN$1) {
70741       s.strm.data_type = detect_data_type(s);
70742     }
70743
70744     /* Construct the literal and distance trees */
70745     build_tree(s, s.l_desc);
70746     // Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
70747     //        s->static_len));
70748
70749     build_tree(s, s.d_desc);
70750     // Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
70751     //        s->static_len));
70752     /* At this point, opt_len and static_len are the total bit lengths of
70753      * the compressed block data, excluding the tree representations.
70754      */
70755
70756     /* Build the bit length tree for the above two trees, and get the index
70757      * in bl_order of the last bit length code to send.
70758      */
70759     max_blindex = build_bl_tree(s);
70760
70761     /* Determine the best encoding. Compute the block lengths in bytes. */
70762     opt_lenb = (s.opt_len + 3 + 7) >>> 3;
70763     static_lenb = (s.static_len + 3 + 7) >>> 3;
70764
70765     // Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
70766     //        opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
70767     //        s->last_lit));
70768
70769     if (static_lenb <= opt_lenb) { opt_lenb = static_lenb; }
70770
70771   } else {
70772     // Assert(buf != (char*)0, "lost buf");
70773     opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
70774   }
70775
70776   if ((stored_len + 4 <= opt_lenb) && (buf !== -1)) {
70777     /* 4: two words for the lengths */
70778
70779     /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
70780      * Otherwise we can't have processed more than WSIZE input bytes since
70781      * the last block flush, because compression would have been
70782      * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
70783      * transform a block into a stored block.
70784      */
70785     _tr_stored_block$1(s, buf, stored_len, last);
70786
70787   } else if (s.strategy === Z_FIXED$1 || static_lenb === opt_lenb) {
70788
70789     send_bits(s, (STATIC_TREES << 1) + (last ? 1 : 0), 3);
70790     compress_block(s, static_ltree, static_dtree);
70791
70792   } else {
70793     send_bits(s, (DYN_TREES << 1) + (last ? 1 : 0), 3);
70794     send_all_trees(s, s.l_desc.max_code + 1, s.d_desc.max_code + 1, max_blindex + 1);
70795     compress_block(s, s.dyn_ltree, s.dyn_dtree);
70796   }
70797   // Assert (s->compressed_len == s->bits_sent, "bad compressed size");
70798   /* The above check is made mod 2^32, for files larger than 512 MB
70799    * and uLong implemented on 32 bits.
70800    */
70801   init_block(s);
70802
70803   if (last) {
70804     bi_windup(s);
70805   }
70806   // Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
70807   //       s->compressed_len-7*last));
70808 };
70809
70810 /* ===========================================================================
70811  * Save the match info and tally the frequency counts. Return true if
70812  * the current block must be flushed.
70813  */
70814 const _tr_tally$1 = (s, dist, lc) =>
70815 //    deflate_state *s;
70816 //    unsigned dist;  /* distance of matched string */
70817 //    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
70818 {
70819   //let out_length, in_length, dcode;
70820
70821   s.pending_buf[s.d_buf + s.last_lit * 2]     = (dist >>> 8) & 0xff;
70822   s.pending_buf[s.d_buf + s.last_lit * 2 + 1] = dist & 0xff;
70823
70824   s.pending_buf[s.l_buf + s.last_lit] = lc & 0xff;
70825   s.last_lit++;
70826
70827   if (dist === 0) {
70828     /* lc is the unmatched char */
70829     s.dyn_ltree[lc * 2]/*.Freq*/++;
70830   } else {
70831     s.matches++;
70832     /* Here, lc is the match length - MIN_MATCH */
70833     dist--;             /* dist = match distance - 1 */
70834     //Assert((ush)dist < (ush)MAX_DIST(s) &&
70835     //       (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
70836     //       (ush)d_code(dist) < (ush)D_CODES,  "_tr_tally: bad match");
70837
70838     s.dyn_ltree[(_length_code[lc] + LITERALS$1 + 1) * 2]/*.Freq*/++;
70839     s.dyn_dtree[d_code(dist) * 2]/*.Freq*/++;
70840   }
70841
70842 // (!) This block is disabled in zlib defaults,
70843 // don't enable it for binary compatibility
70844
70845 //#ifdef TRUNCATE_BLOCK
70846 //  /* Try to guess if it is profitable to stop the current block here */
70847 //  if ((s.last_lit & 0x1fff) === 0 && s.level > 2) {
70848 //    /* Compute an upper bound for the compressed length */
70849 //    out_length = s.last_lit*8;
70850 //    in_length = s.strstart - s.block_start;
70851 //
70852 //    for (dcode = 0; dcode < D_CODES; dcode++) {
70853 //      out_length += s.dyn_dtree[dcode*2]/*.Freq*/ * (5 + extra_dbits[dcode]);
70854 //    }
70855 //    out_length >>>= 3;
70856 //    //Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
70857 //    //       s->last_lit, in_length, out_length,
70858 //    //       100L - out_length*100L/in_length));
70859 //    if (s.matches < (s.last_lit>>1)/*int /2*/ && out_length < (in_length>>1)/*int /2*/) {
70860 //      return true;
70861 //    }
70862 //  }
70863 //#endif
70864
70865   return (s.last_lit === s.lit_bufsize - 1);
70866   /* We avoid equality with lit_bufsize because of wraparound at 64K
70867    * on 16 bit machines and because stored blocks are restricted to
70868    * 64K-1 bytes.
70869    */
70870 };
70871
70872 var _tr_init_1  = _tr_init$1;
70873 var _tr_stored_block_1 = _tr_stored_block$1;
70874 var _tr_flush_block_1  = _tr_flush_block$1;
70875 var _tr_tally_1 = _tr_tally$1;
70876 var _tr_align_1 = _tr_align$1;
70877
70878 var trees = {
70879         _tr_init: _tr_init_1,
70880         _tr_stored_block: _tr_stored_block_1,
70881         _tr_flush_block: _tr_flush_block_1,
70882         _tr_tally: _tr_tally_1,
70883         _tr_align: _tr_align_1
70884 };
70885
70886 // Note: adler32 takes 12% for level 0 and 2% for level 6.
70887 // It isn't worth it to make additional optimizations as in original.
70888 // Small size is preferable.
70889
70890 // (C) 1995-2013 Jean-loup Gailly and Mark Adler
70891 // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
70892 //
70893 // This software is provided 'as-is', without any express or implied
70894 // warranty. In no event will the authors be held liable for any damages
70895 // arising from the use of this software.
70896 //
70897 // Permission is granted to anyone to use this software for any purpose,
70898 // including commercial applications, and to alter it and redistribute it
70899 // freely, subject to the following restrictions:
70900 //
70901 // 1. The origin of this software must not be misrepresented; you must not
70902 //   claim that you wrote the original software. If you use this software
70903 //   in a product, an acknowledgment in the product documentation would be
70904 //   appreciated but is not required.
70905 // 2. Altered source versions must be plainly marked as such, and must not be
70906 //   misrepresented as being the original software.
70907 // 3. This notice may not be removed or altered from any source distribution.
70908
70909 const adler32 = (adler, buf, len, pos) => {
70910   let s1 = (adler & 0xffff) |0,
70911       s2 = ((adler >>> 16) & 0xffff) |0,
70912       n = 0;
70913
70914   while (len !== 0) {
70915     // Set limit ~ twice less than 5552, to keep
70916     // s2 in 31-bits, because we force signed ints.
70917     // in other case %= will fail.
70918     n = len > 2000 ? 2000 : len;
70919     len -= n;
70920
70921     do {
70922       s1 = (s1 + buf[pos++]) |0;
70923       s2 = (s2 + s1) |0;
70924     } while (--n);
70925
70926     s1 %= 65521;
70927     s2 %= 65521;
70928   }
70929
70930   return (s1 | (s2 << 16)) |0;
70931 };
70932
70933
70934 var adler32_1 = adler32;
70935
70936 // Note: we can't get significant speed boost here.
70937 // So write code to minimize size - no pregenerated tables
70938 // and array tools dependencies.
70939
70940 // (C) 1995-2013 Jean-loup Gailly and Mark Adler
70941 // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
70942 //
70943 // This software is provided 'as-is', without any express or implied
70944 // warranty. In no event will the authors be held liable for any damages
70945 // arising from the use of this software.
70946 //
70947 // Permission is granted to anyone to use this software for any purpose,
70948 // including commercial applications, and to alter it and redistribute it
70949 // freely, subject to the following restrictions:
70950 //
70951 // 1. The origin of this software must not be misrepresented; you must not
70952 //   claim that you wrote the original software. If you use this software
70953 //   in a product, an acknowledgment in the product documentation would be
70954 //   appreciated but is not required.
70955 // 2. Altered source versions must be plainly marked as such, and must not be
70956 //   misrepresented as being the original software.
70957 // 3. This notice may not be removed or altered from any source distribution.
70958
70959 // Use ordinary array, since untyped makes no boost here
70960 const makeTable = () => {
70961   let c, table = [];
70962
70963   for (var n = 0; n < 256; n++) {
70964     c = n;
70965     for (var k = 0; k < 8; k++) {
70966       c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));
70967     }
70968     table[n] = c;
70969   }
70970
70971   return table;
70972 };
70973
70974 // Create table on load. Just 255 signed longs. Not a problem.
70975 const crcTable = new Uint32Array(makeTable());
70976
70977
70978 const crc32 = (crc, buf, len, pos) => {
70979   const t = crcTable;
70980   const end = pos + len;
70981
70982   crc ^= -1;
70983
70984   for (let i = pos; i < end; i++) {
70985     crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF];
70986   }
70987
70988   return (crc ^ (-1)); // >>> 0;
70989 };
70990
70991
70992 var crc32_1 = crc32;
70993
70994 // (C) 1995-2013 Jean-loup Gailly and Mark Adler
70995 // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
70996 //
70997 // This software is provided 'as-is', without any express or implied
70998 // warranty. In no event will the authors be held liable for any damages
70999 // arising from the use of this software.
71000 //
71001 // Permission is granted to anyone to use this software for any purpose,
71002 // including commercial applications, and to alter it and redistribute it
71003 // freely, subject to the following restrictions:
71004 //
71005 // 1. The origin of this software must not be misrepresented; you must not
71006 //   claim that you wrote the original software. If you use this software
71007 //   in a product, an acknowledgment in the product documentation would be
71008 //   appreciated but is not required.
71009 // 2. Altered source versions must be plainly marked as such, and must not be
71010 //   misrepresented as being the original software.
71011 // 3. This notice may not be removed or altered from any source distribution.
71012
71013 var messages = {
71014   2:      'need dictionary',     /* Z_NEED_DICT       2  */
71015   1:      'stream end',          /* Z_STREAM_END      1  */
71016   0:      '',                    /* Z_OK              0  */
71017   '-1':   'file error',          /* Z_ERRNO         (-1) */
71018   '-2':   'stream error',        /* Z_STREAM_ERROR  (-2) */
71019   '-3':   'data error',          /* Z_DATA_ERROR    (-3) */
71020   '-4':   'insufficient memory', /* Z_MEM_ERROR     (-4) */
71021   '-5':   'buffer error',        /* Z_BUF_ERROR     (-5) */
71022   '-6':   'incompatible version' /* Z_VERSION_ERROR (-6) */
71023 };
71024
71025 // (C) 1995-2013 Jean-loup Gailly and Mark Adler
71026 // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
71027 //
71028 // This software is provided 'as-is', without any express or implied
71029 // warranty. In no event will the authors be held liable for any damages
71030 // arising from the use of this software.
71031 //
71032 // Permission is granted to anyone to use this software for any purpose,
71033 // including commercial applications, and to alter it and redistribute it
71034 // freely, subject to the following restrictions:
71035 //
71036 // 1. The origin of this software must not be misrepresented; you must not
71037 //   claim that you wrote the original software. If you use this software
71038 //   in a product, an acknowledgment in the product documentation would be
71039 //   appreciated but is not required.
71040 // 2. Altered source versions must be plainly marked as such, and must not be
71041 //   misrepresented as being the original software.
71042 // 3. This notice may not be removed or altered from any source distribution.
71043
71044 var constants$2 = {
71045
71046   /* Allowed flush values; see deflate() and inflate() below for details */
71047   Z_NO_FLUSH:         0,
71048   Z_PARTIAL_FLUSH:    1,
71049   Z_SYNC_FLUSH:       2,
71050   Z_FULL_FLUSH:       3,
71051   Z_FINISH:           4,
71052   Z_BLOCK:            5,
71053   Z_TREES:            6,
71054
71055   /* Return codes for the compression/decompression functions. Negative values
71056   * are errors, positive values are used for special but normal events.
71057   */
71058   Z_OK:               0,
71059   Z_STREAM_END:       1,
71060   Z_NEED_DICT:        2,
71061   Z_ERRNO:           -1,
71062   Z_STREAM_ERROR:    -2,
71063   Z_DATA_ERROR:      -3,
71064   Z_MEM_ERROR:       -4,
71065   Z_BUF_ERROR:       -5,
71066   //Z_VERSION_ERROR: -6,
71067
71068   /* compression levels */
71069   Z_NO_COMPRESSION:         0,
71070   Z_BEST_SPEED:             1,
71071   Z_BEST_COMPRESSION:       9,
71072   Z_DEFAULT_COMPRESSION:   -1,
71073
71074
71075   Z_FILTERED:               1,
71076   Z_HUFFMAN_ONLY:           2,
71077   Z_RLE:                    3,
71078   Z_FIXED:                  4,
71079   Z_DEFAULT_STRATEGY:       0,
71080
71081   /* Possible values of the data_type field (though see inflate()) */
71082   Z_BINARY:                 0,
71083   Z_TEXT:                   1,
71084   //Z_ASCII:                1, // = Z_TEXT (deprecated)
71085   Z_UNKNOWN:                2,
71086
71087   /* The deflate compression method */
71088   Z_DEFLATED:               8
71089   //Z_NULL:                 null // Use -1 or null inline, depending on var type
71090 };
71091
71092 // (C) 1995-2013 Jean-loup Gailly and Mark Adler
71093 // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
71094 //
71095 // This software is provided 'as-is', without any express or implied
71096 // warranty. In no event will the authors be held liable for any damages
71097 // arising from the use of this software.
71098 //
71099 // Permission is granted to anyone to use this software for any purpose,
71100 // including commercial applications, and to alter it and redistribute it
71101 // freely, subject to the following restrictions:
71102 //
71103 // 1. The origin of this software must not be misrepresented; you must not
71104 //   claim that you wrote the original software. If you use this software
71105 //   in a product, an acknowledgment in the product documentation would be
71106 //   appreciated but is not required.
71107 // 2. Altered source versions must be plainly marked as such, and must not be
71108 //   misrepresented as being the original software.
71109 // 3. This notice may not be removed or altered from any source distribution.
71110
71111 const { _tr_init, _tr_stored_block, _tr_flush_block, _tr_tally, _tr_align } = trees;
71112
71113
71114
71115
71116 /* Public constants ==========================================================*/
71117 /* ===========================================================================*/
71118
71119 const {
71120   Z_NO_FLUSH: Z_NO_FLUSH$2, Z_PARTIAL_FLUSH, Z_FULL_FLUSH: Z_FULL_FLUSH$1, Z_FINISH: Z_FINISH$3, Z_BLOCK: Z_BLOCK$1,
71121   Z_OK: Z_OK$3, Z_STREAM_END: Z_STREAM_END$3, Z_STREAM_ERROR: Z_STREAM_ERROR$2, Z_DATA_ERROR: Z_DATA_ERROR$2, Z_BUF_ERROR: Z_BUF_ERROR$1,
71122   Z_DEFAULT_COMPRESSION: Z_DEFAULT_COMPRESSION$1,
71123   Z_FILTERED, Z_HUFFMAN_ONLY, Z_RLE, Z_FIXED, Z_DEFAULT_STRATEGY: Z_DEFAULT_STRATEGY$1,
71124   Z_UNKNOWN,
71125   Z_DEFLATED: Z_DEFLATED$2
71126 } = constants$2;
71127
71128 /*============================================================================*/
71129
71130
71131 const MAX_MEM_LEVEL = 9;
71132 /* Maximum value for memLevel in deflateInit2 */
71133 const MAX_WBITS$1 = 15;
71134 /* 32K LZ77 window */
71135 const DEF_MEM_LEVEL = 8;
71136
71137
71138 const LENGTH_CODES  = 29;
71139 /* number of length codes, not counting the special END_BLOCK code */
71140 const LITERALS      = 256;
71141 /* number of literal bytes 0..255 */
71142 const L_CODES       = LITERALS + 1 + LENGTH_CODES;
71143 /* number of Literal or Length codes, including the END_BLOCK code */
71144 const D_CODES       = 30;
71145 /* number of distance codes */
71146 const BL_CODES      = 19;
71147 /* number of codes used to transfer the bit lengths */
71148 const HEAP_SIZE     = 2 * L_CODES + 1;
71149 /* maximum heap size */
71150 const MAX_BITS  = 15;
71151 /* All codes must not exceed MAX_BITS bits */
71152
71153 const MIN_MATCH = 3;
71154 const MAX_MATCH = 258;
71155 const MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1);
71156
71157 const PRESET_DICT = 0x20;
71158
71159 const INIT_STATE = 42;
71160 const EXTRA_STATE = 69;
71161 const NAME_STATE = 73;
71162 const COMMENT_STATE = 91;
71163 const HCRC_STATE = 103;
71164 const BUSY_STATE = 113;
71165 const FINISH_STATE = 666;
71166
71167 const BS_NEED_MORE      = 1; /* block not completed, need more input or more output */
71168 const BS_BLOCK_DONE     = 2; /* block flush performed */
71169 const BS_FINISH_STARTED = 3; /* finish started, need only more output at next deflate */
71170 const BS_FINISH_DONE    = 4; /* finish done, accept no more input or output */
71171
71172 const OS_CODE = 0x03; // Unix :) . Don't detect, use this default.
71173
71174 const err = (strm, errorCode) => {
71175   strm.msg = messages[errorCode];
71176   return errorCode;
71177 };
71178
71179 const rank = (f) => {
71180   return ((f) << 1) - ((f) > 4 ? 9 : 0);
71181 };
71182
71183 const zero = (buf) => {
71184   let len = buf.length; while (--len >= 0) { buf[len] = 0; }
71185 };
71186
71187
71188 /* eslint-disable new-cap */
71189 let HASH_ZLIB = (s, prev, data) => ((prev << s.hash_shift) ^ data) & s.hash_mask;
71190 // This hash causes less collisions, https://github.com/nodeca/pako/issues/135
71191 // But breaks binary compatibility
71192 //let HASH_FAST = (s, prev, data) => ((prev << 8) + (prev >> 8) + (data << 4)) & s.hash_mask;
71193 let HASH = HASH_ZLIB;
71194
71195 /* =========================================================================
71196  * Flush as much pending output as possible. All deflate() output goes
71197  * through this function so some applications may wish to modify it
71198  * to avoid allocating a large strm->output buffer and copying into it.
71199  * (See also read_buf()).
71200  */
71201 const flush_pending = (strm) => {
71202   const s = strm.state;
71203
71204   //_tr_flush_bits(s);
71205   let len = s.pending;
71206   if (len > strm.avail_out) {
71207     len = strm.avail_out;
71208   }
71209   if (len === 0) { return; }
71210
71211   strm.output.set(s.pending_buf.subarray(s.pending_out, s.pending_out + len), strm.next_out);
71212   strm.next_out += len;
71213   s.pending_out += len;
71214   strm.total_out += len;
71215   strm.avail_out -= len;
71216   s.pending -= len;
71217   if (s.pending === 0) {
71218     s.pending_out = 0;
71219   }
71220 };
71221
71222
71223 const flush_block_only = (s, last) => {
71224   _tr_flush_block(s, (s.block_start >= 0 ? s.block_start : -1), s.strstart - s.block_start, last);
71225   s.block_start = s.strstart;
71226   flush_pending(s.strm);
71227 };
71228
71229
71230 const put_byte = (s, b) => {
71231   s.pending_buf[s.pending++] = b;
71232 };
71233
71234
71235 /* =========================================================================
71236  * Put a short in the pending buffer. The 16-bit value is put in MSB order.
71237  * IN assertion: the stream state is correct and there is enough room in
71238  * pending_buf.
71239  */
71240 const putShortMSB = (s, b) => {
71241
71242   //  put_byte(s, (Byte)(b >> 8));
71243 //  put_byte(s, (Byte)(b & 0xff));
71244   s.pending_buf[s.pending++] = (b >>> 8) & 0xff;
71245   s.pending_buf[s.pending++] = b & 0xff;
71246 };
71247
71248
71249 /* ===========================================================================
71250  * Read a new buffer from the current input stream, update the adler32
71251  * and total number of bytes read.  All deflate() input goes through
71252  * this function so some applications may wish to modify it to avoid
71253  * allocating a large strm->input buffer and copying from it.
71254  * (See also flush_pending()).
71255  */
71256 const read_buf = (strm, buf, start, size) => {
71257
71258   let len = strm.avail_in;
71259
71260   if (len > size) { len = size; }
71261   if (len === 0) { return 0; }
71262
71263   strm.avail_in -= len;
71264
71265   // zmemcpy(buf, strm->next_in, len);
71266   buf.set(strm.input.subarray(strm.next_in, strm.next_in + len), start);
71267   if (strm.state.wrap === 1) {
71268     strm.adler = adler32_1(strm.adler, buf, len, start);
71269   }
71270
71271   else if (strm.state.wrap === 2) {
71272     strm.adler = crc32_1(strm.adler, buf, len, start);
71273   }
71274
71275   strm.next_in += len;
71276   strm.total_in += len;
71277
71278   return len;
71279 };
71280
71281
71282 /* ===========================================================================
71283  * Set match_start to the longest match starting at the given string and
71284  * return its length. Matches shorter or equal to prev_length are discarded,
71285  * in which case the result is equal to prev_length and match_start is
71286  * garbage.
71287  * IN assertions: cur_match is the head of the hash chain for the current
71288  *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
71289  * OUT assertion: the match length is not greater than s->lookahead.
71290  */
71291 const longest_match = (s, cur_match) => {
71292
71293   let chain_length = s.max_chain_length;      /* max hash chain length */
71294   let scan = s.strstart; /* current string */
71295   let match;                       /* matched string */
71296   let len;                           /* length of current match */
71297   let best_len = s.prev_length;              /* best match length so far */
71298   let nice_match = s.nice_match;             /* stop if match long enough */
71299   const limit = (s.strstart > (s.w_size - MIN_LOOKAHEAD)) ?
71300       s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0/*NIL*/;
71301
71302   const _win = s.window; // shortcut
71303
71304   const wmask = s.w_mask;
71305   const prev  = s.prev;
71306
71307   /* Stop when cur_match becomes <= limit. To simplify the code,
71308    * we prevent matches with the string of window index 0.
71309    */
71310
71311   const strend = s.strstart + MAX_MATCH;
71312   let scan_end1  = _win[scan + best_len - 1];
71313   let scan_end   = _win[scan + best_len];
71314
71315   /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
71316    * It is easy to get rid of this optimization if necessary.
71317    */
71318   // Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
71319
71320   /* Do not waste too much time if we already have a good match: */
71321   if (s.prev_length >= s.good_match) {
71322     chain_length >>= 2;
71323   }
71324   /* Do not look for matches beyond the end of the input. This is necessary
71325    * to make deflate deterministic.
71326    */
71327   if (nice_match > s.lookahead) { nice_match = s.lookahead; }
71328
71329   // Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
71330
71331   do {
71332     // Assert(cur_match < s->strstart, "no future");
71333     match = cur_match;
71334
71335     /* Skip to next match if the match length cannot increase
71336      * or if the match length is less than 2.  Note that the checks below
71337      * for insufficient lookahead only occur occasionally for performance
71338      * reasons.  Therefore uninitialized memory will be accessed, and
71339      * conditional jumps will be made that depend on those values.
71340      * However the length of the match is limited to the lookahead, so
71341      * the output of deflate is not affected by the uninitialized values.
71342      */
71343
71344     if (_win[match + best_len]     !== scan_end  ||
71345         _win[match + best_len - 1] !== scan_end1 ||
71346         _win[match]                !== _win[scan] ||
71347         _win[++match]              !== _win[scan + 1]) {
71348       continue;
71349     }
71350
71351     /* The check at best_len-1 can be removed because it will be made
71352      * again later. (This heuristic is not always a win.)
71353      * It is not necessary to compare scan[2] and match[2] since they
71354      * are always equal when the other bytes match, given that
71355      * the hash keys are equal and that HASH_BITS >= 8.
71356      */
71357     scan += 2;
71358     match++;
71359     // Assert(*scan == *match, "match[2]?");
71360
71361     /* We check for insufficient lookahead only every 8th comparison;
71362      * the 256th check will be made at strstart+258.
71363      */
71364     do {
71365       /*jshint noempty:false*/
71366     } while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
71367              _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
71368              _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
71369              _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
71370              scan < strend);
71371
71372     // Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
71373
71374     len = MAX_MATCH - (strend - scan);
71375     scan = strend - MAX_MATCH;
71376
71377     if (len > best_len) {
71378       s.match_start = cur_match;
71379       best_len = len;
71380       if (len >= nice_match) {
71381         break;
71382       }
71383       scan_end1  = _win[scan + best_len - 1];
71384       scan_end   = _win[scan + best_len];
71385     }
71386   } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0);
71387
71388   if (best_len <= s.lookahead) {
71389     return best_len;
71390   }
71391   return s.lookahead;
71392 };
71393
71394
71395 /* ===========================================================================
71396  * Fill the window when the lookahead becomes insufficient.
71397  * Updates strstart and lookahead.
71398  *
71399  * IN assertion: lookahead < MIN_LOOKAHEAD
71400  * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
71401  *    At least one byte has been read, or avail_in == 0; reads are
71402  *    performed for at least two bytes (required for the zip translate_eol
71403  *    option -- not supported here).
71404  */
71405 const fill_window = (s) => {
71406
71407   const _w_size = s.w_size;
71408   let p, n, m, more, str;
71409
71410   //Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead");
71411
71412   do {
71413     more = s.window_size - s.lookahead - s.strstart;
71414
71415     // JS ints have 32 bit, block below not needed
71416     /* Deal with !@#$% 64K limit: */
71417     //if (sizeof(int) <= 2) {
71418     //    if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
71419     //        more = wsize;
71420     //
71421     //  } else if (more == (unsigned)(-1)) {
71422     //        /* Very unlikely, but possible on 16 bit machine if
71423     //         * strstart == 0 && lookahead == 1 (input done a byte at time)
71424     //         */
71425     //        more--;
71426     //    }
71427     //}
71428
71429
71430     /* If the window is almost full and there is insufficient lookahead,
71431      * move the upper half to the lower one to make room in the upper half.
71432      */
71433     if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) {
71434
71435       s.window.set(s.window.subarray(_w_size, _w_size + _w_size), 0);
71436       s.match_start -= _w_size;
71437       s.strstart -= _w_size;
71438       /* we now have strstart >= MAX_DIST */
71439       s.block_start -= _w_size;
71440
71441       /* Slide the hash table (could be avoided with 32 bit values
71442        at the expense of memory usage). We slide even when level == 0
71443        to keep the hash table consistent if we switch back to level > 0
71444        later. (Using level 0 permanently is not an optimal usage of
71445        zlib, so we don't care about this pathological case.)
71446        */
71447
71448       n = s.hash_size;
71449       p = n;
71450
71451       do {
71452         m = s.head[--p];
71453         s.head[p] = (m >= _w_size ? m - _w_size : 0);
71454       } while (--n);
71455
71456       n = _w_size;
71457       p = n;
71458
71459       do {
71460         m = s.prev[--p];
71461         s.prev[p] = (m >= _w_size ? m - _w_size : 0);
71462         /* If n is not on any hash chain, prev[n] is garbage but
71463          * its value will never be used.
71464          */
71465       } while (--n);
71466
71467       more += _w_size;
71468     }
71469     if (s.strm.avail_in === 0) {
71470       break;
71471     }
71472
71473     /* If there was no sliding:
71474      *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
71475      *    more == window_size - lookahead - strstart
71476      * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
71477      * => more >= window_size - 2*WSIZE + 2
71478      * In the BIG_MEM or MMAP case (not yet supported),
71479      *   window_size == input_size + MIN_LOOKAHEAD  &&
71480      *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
71481      * Otherwise, window_size == 2*WSIZE so more >= 2.
71482      * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
71483      */
71484     //Assert(more >= 2, "more < 2");
71485     n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more);
71486     s.lookahead += n;
71487
71488     /* Initialize the hash value now that we have some input: */
71489     if (s.lookahead + s.insert >= MIN_MATCH) {
71490       str = s.strstart - s.insert;
71491       s.ins_h = s.window[str];
71492
71493       /* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */
71494       s.ins_h = HASH(s, s.ins_h, s.window[str + 1]);
71495 //#if MIN_MATCH != 3
71496 //        Call update_hash() MIN_MATCH-3 more times
71497 //#endif
71498       while (s.insert) {
71499         /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */
71500         s.ins_h = HASH(s, s.ins_h, s.window[str + MIN_MATCH - 1]);
71501
71502         s.prev[str & s.w_mask] = s.head[s.ins_h];
71503         s.head[s.ins_h] = str;
71504         str++;
71505         s.insert--;
71506         if (s.lookahead + s.insert < MIN_MATCH) {
71507           break;
71508         }
71509       }
71510     }
71511     /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
71512      * but this is not important since only literal bytes will be emitted.
71513      */
71514
71515   } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0);
71516
71517   /* If the WIN_INIT bytes after the end of the current data have never been
71518    * written, then zero those bytes in order to avoid memory check reports of
71519    * the use of uninitialized (or uninitialised as Julian writes) bytes by
71520    * the longest match routines.  Update the high water mark for the next
71521    * time through here.  WIN_INIT is set to MAX_MATCH since the longest match
71522    * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.
71523    */
71524 //  if (s.high_water < s.window_size) {
71525 //    const curr = s.strstart + s.lookahead;
71526 //    let init = 0;
71527 //
71528 //    if (s.high_water < curr) {
71529 //      /* Previous high water mark below current data -- zero WIN_INIT
71530 //       * bytes or up to end of window, whichever is less.
71531 //       */
71532 //      init = s.window_size - curr;
71533 //      if (init > WIN_INIT)
71534 //        init = WIN_INIT;
71535 //      zmemzero(s->window + curr, (unsigned)init);
71536 //      s->high_water = curr + init;
71537 //    }
71538 //    else if (s->high_water < (ulg)curr + WIN_INIT) {
71539 //      /* High water mark at or above current data, but below current data
71540 //       * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up
71541 //       * to end of window, whichever is less.
71542 //       */
71543 //      init = (ulg)curr + WIN_INIT - s->high_water;
71544 //      if (init > s->window_size - s->high_water)
71545 //        init = s->window_size - s->high_water;
71546 //      zmemzero(s->window + s->high_water, (unsigned)init);
71547 //      s->high_water += init;
71548 //    }
71549 //  }
71550 //
71551 //  Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,
71552 //    "not enough room for search");
71553 };
71554
71555 /* ===========================================================================
71556  * Copy without compression as much as possible from the input stream, return
71557  * the current block state.
71558  * This function does not insert new strings in the dictionary since
71559  * uncompressible data is probably not useful. This function is used
71560  * only for the level=0 compression option.
71561  * NOTE: this function should be optimized to avoid extra copying from
71562  * window to pending_buf.
71563  */
71564 const deflate_stored = (s, flush) => {
71565
71566   /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
71567    * to pending_buf_size, and each stored block has a 5 byte header:
71568    */
71569   let max_block_size = 0xffff;
71570
71571   if (max_block_size > s.pending_buf_size - 5) {
71572     max_block_size = s.pending_buf_size - 5;
71573   }
71574
71575   /* Copy as much as possible from input to output: */
71576   for (;;) {
71577     /* Fill the window as much as possible: */
71578     if (s.lookahead <= 1) {
71579
71580       //Assert(s->strstart < s->w_size+MAX_DIST(s) ||
71581       //  s->block_start >= (long)s->w_size, "slide too late");
71582 //      if (!(s.strstart < s.w_size + (s.w_size - MIN_LOOKAHEAD) ||
71583 //        s.block_start >= s.w_size)) {
71584 //        throw  new Error("slide too late");
71585 //      }
71586
71587       fill_window(s);
71588       if (s.lookahead === 0 && flush === Z_NO_FLUSH$2) {
71589         return BS_NEED_MORE;
71590       }
71591
71592       if (s.lookahead === 0) {
71593         break;
71594       }
71595       /* flush the current block */
71596     }
71597     //Assert(s->block_start >= 0L, "block gone");
71598 //    if (s.block_start < 0) throw new Error("block gone");
71599
71600     s.strstart += s.lookahead;
71601     s.lookahead = 0;
71602
71603     /* Emit a stored block if pending_buf will be full: */
71604     const max_start = s.block_start + max_block_size;
71605
71606     if (s.strstart === 0 || s.strstart >= max_start) {
71607       /* strstart == 0 is possible when wraparound on 16-bit machine */
71608       s.lookahead = s.strstart - max_start;
71609       s.strstart = max_start;
71610       /*** FLUSH_BLOCK(s, 0); ***/
71611       flush_block_only(s, false);
71612       if (s.strm.avail_out === 0) {
71613         return BS_NEED_MORE;
71614       }
71615       /***/
71616
71617
71618     }
71619     /* Flush if we may have to slide, otherwise block_start may become
71620      * negative and the data will be gone:
71621      */
71622     if (s.strstart - s.block_start >= (s.w_size - MIN_LOOKAHEAD)) {
71623       /*** FLUSH_BLOCK(s, 0); ***/
71624       flush_block_only(s, false);
71625       if (s.strm.avail_out === 0) {
71626         return BS_NEED_MORE;
71627       }
71628       /***/
71629     }
71630   }
71631
71632   s.insert = 0;
71633
71634   if (flush === Z_FINISH$3) {
71635     /*** FLUSH_BLOCK(s, 1); ***/
71636     flush_block_only(s, true);
71637     if (s.strm.avail_out === 0) {
71638       return BS_FINISH_STARTED;
71639     }
71640     /***/
71641     return BS_FINISH_DONE;
71642   }
71643
71644   if (s.strstart > s.block_start) {
71645     /*** FLUSH_BLOCK(s, 0); ***/
71646     flush_block_only(s, false);
71647     if (s.strm.avail_out === 0) {
71648       return BS_NEED_MORE;
71649     }
71650     /***/
71651   }
71652
71653   return BS_NEED_MORE;
71654 };
71655
71656 /* ===========================================================================
71657  * Compress as much as possible from the input stream, return the current
71658  * block state.
71659  * This function does not perform lazy evaluation of matches and inserts
71660  * new strings in the dictionary only for unmatched strings or for short
71661  * matches. It is used only for the fast compression options.
71662  */
71663 const deflate_fast = (s, flush) => {
71664
71665   let hash_head;        /* head of the hash chain */
71666   let bflush;           /* set if current block must be flushed */
71667
71668   for (;;) {
71669     /* Make sure that we always have enough lookahead, except
71670      * at the end of the input file. We need MAX_MATCH bytes
71671      * for the next match, plus MIN_MATCH bytes to insert the
71672      * string following the next match.
71673      */
71674     if (s.lookahead < MIN_LOOKAHEAD) {
71675       fill_window(s);
71676       if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH$2) {
71677         return BS_NEED_MORE;
71678       }
71679       if (s.lookahead === 0) {
71680         break; /* flush the current block */
71681       }
71682     }
71683
71684     /* Insert the string window[strstart .. strstart+2] in the
71685      * dictionary, and set hash_head to the head of the hash chain:
71686      */
71687     hash_head = 0/*NIL*/;
71688     if (s.lookahead >= MIN_MATCH) {
71689       /*** INSERT_STRING(s, s.strstart, hash_head); ***/
71690       s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH - 1]);
71691       hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
71692       s.head[s.ins_h] = s.strstart;
71693       /***/
71694     }
71695
71696     /* Find the longest match, discarding those <= prev_length.
71697      * At this point we have always match_length < MIN_MATCH
71698      */
71699     if (hash_head !== 0/*NIL*/ && ((s.strstart - hash_head) <= (s.w_size - MIN_LOOKAHEAD))) {
71700       /* To simplify the code, we prevent matches with the string
71701        * of window index 0 (in particular we have to avoid a match
71702        * of the string with itself at the start of the input file).
71703        */
71704       s.match_length = longest_match(s, hash_head);
71705       /* longest_match() sets match_start */
71706     }
71707     if (s.match_length >= MIN_MATCH) {
71708       // check_match(s, s.strstart, s.match_start, s.match_length); // for debug only
71709
71710       /*** _tr_tally_dist(s, s.strstart - s.match_start,
71711                      s.match_length - MIN_MATCH, bflush); ***/
71712       bflush = _tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH);
71713
71714       s.lookahead -= s.match_length;
71715
71716       /* Insert new strings in the hash table only if the match length
71717        * is not too large. This saves time but degrades compression.
71718        */
71719       if (s.match_length <= s.max_lazy_match/*max_insert_length*/ && s.lookahead >= MIN_MATCH) {
71720         s.match_length--; /* string at strstart already in table */
71721         do {
71722           s.strstart++;
71723           /*** INSERT_STRING(s, s.strstart, hash_head); ***/
71724           s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH - 1]);
71725           hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
71726           s.head[s.ins_h] = s.strstart;
71727           /***/
71728           /* strstart never exceeds WSIZE-MAX_MATCH, so there are
71729            * always MIN_MATCH bytes ahead.
71730            */
71731         } while (--s.match_length !== 0);
71732         s.strstart++;
71733       } else
71734       {
71735         s.strstart += s.match_length;
71736         s.match_length = 0;
71737         s.ins_h = s.window[s.strstart];
71738         /* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */
71739         s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + 1]);
71740
71741 //#if MIN_MATCH != 3
71742 //                Call UPDATE_HASH() MIN_MATCH-3 more times
71743 //#endif
71744         /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
71745          * matter since it will be recomputed at next deflate call.
71746          */
71747       }
71748     } else {
71749       /* No match, output a literal byte */
71750       //Tracevv((stderr,"%c", s.window[s.strstart]));
71751       /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
71752       bflush = _tr_tally(s, 0, s.window[s.strstart]);
71753
71754       s.lookahead--;
71755       s.strstart++;
71756     }
71757     if (bflush) {
71758       /*** FLUSH_BLOCK(s, 0); ***/
71759       flush_block_only(s, false);
71760       if (s.strm.avail_out === 0) {
71761         return BS_NEED_MORE;
71762       }
71763       /***/
71764     }
71765   }
71766   s.insert = ((s.strstart < (MIN_MATCH - 1)) ? s.strstart : MIN_MATCH - 1);
71767   if (flush === Z_FINISH$3) {
71768     /*** FLUSH_BLOCK(s, 1); ***/
71769     flush_block_only(s, true);
71770     if (s.strm.avail_out === 0) {
71771       return BS_FINISH_STARTED;
71772     }
71773     /***/
71774     return BS_FINISH_DONE;
71775   }
71776   if (s.last_lit) {
71777     /*** FLUSH_BLOCK(s, 0); ***/
71778     flush_block_only(s, false);
71779     if (s.strm.avail_out === 0) {
71780       return BS_NEED_MORE;
71781     }
71782     /***/
71783   }
71784   return BS_BLOCK_DONE;
71785 };
71786
71787 /* ===========================================================================
71788  * Same as above, but achieves better compression. We use a lazy
71789  * evaluation for matches: a match is finally adopted only if there is
71790  * no better match at the next window position.
71791  */
71792 const deflate_slow = (s, flush) => {
71793
71794   let hash_head;          /* head of hash chain */
71795   let bflush;              /* set if current block must be flushed */
71796
71797   let max_insert;
71798
71799   /* Process the input block. */
71800   for (;;) {
71801     /* Make sure that we always have enough lookahead, except
71802      * at the end of the input file. We need MAX_MATCH bytes
71803      * for the next match, plus MIN_MATCH bytes to insert the
71804      * string following the next match.
71805      */
71806     if (s.lookahead < MIN_LOOKAHEAD) {
71807       fill_window(s);
71808       if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH$2) {
71809         return BS_NEED_MORE;
71810       }
71811       if (s.lookahead === 0) { break; } /* flush the current block */
71812     }
71813
71814     /* Insert the string window[strstart .. strstart+2] in the
71815      * dictionary, and set hash_head to the head of the hash chain:
71816      */
71817     hash_head = 0/*NIL*/;
71818     if (s.lookahead >= MIN_MATCH) {
71819       /*** INSERT_STRING(s, s.strstart, hash_head); ***/
71820       s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH - 1]);
71821       hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
71822       s.head[s.ins_h] = s.strstart;
71823       /***/
71824     }
71825
71826     /* Find the longest match, discarding those <= prev_length.
71827      */
71828     s.prev_length = s.match_length;
71829     s.prev_match = s.match_start;
71830     s.match_length = MIN_MATCH - 1;
71831
71832     if (hash_head !== 0/*NIL*/ && s.prev_length < s.max_lazy_match &&
71833         s.strstart - hash_head <= (s.w_size - MIN_LOOKAHEAD)/*MAX_DIST(s)*/) {
71834       /* To simplify the code, we prevent matches with the string
71835        * of window index 0 (in particular we have to avoid a match
71836        * of the string with itself at the start of the input file).
71837        */
71838       s.match_length = longest_match(s, hash_head);
71839       /* longest_match() sets match_start */
71840
71841       if (s.match_length <= 5 &&
71842          (s.strategy === Z_FILTERED || (s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096/*TOO_FAR*/))) {
71843
71844         /* If prev_match is also MIN_MATCH, match_start is garbage
71845          * but we will ignore the current match anyway.
71846          */
71847         s.match_length = MIN_MATCH - 1;
71848       }
71849     }
71850     /* If there was a match at the previous step and the current
71851      * match is not better, output the previous match:
71852      */
71853     if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) {
71854       max_insert = s.strstart + s.lookahead - MIN_MATCH;
71855       /* Do not insert strings in hash table beyond this. */
71856
71857       //check_match(s, s.strstart-1, s.prev_match, s.prev_length);
71858
71859       /***_tr_tally_dist(s, s.strstart - 1 - s.prev_match,
71860                      s.prev_length - MIN_MATCH, bflush);***/
71861       bflush = _tr_tally(s, s.strstart - 1 - s.prev_match, s.prev_length - MIN_MATCH);
71862       /* Insert in hash table all strings up to the end of the match.
71863        * strstart-1 and strstart are already inserted. If there is not
71864        * enough lookahead, the last two strings are not inserted in
71865        * the hash table.
71866        */
71867       s.lookahead -= s.prev_length - 1;
71868       s.prev_length -= 2;
71869       do {
71870         if (++s.strstart <= max_insert) {
71871           /*** INSERT_STRING(s, s.strstart, hash_head); ***/
71872           s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH - 1]);
71873           hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
71874           s.head[s.ins_h] = s.strstart;
71875           /***/
71876         }
71877       } while (--s.prev_length !== 0);
71878       s.match_available = 0;
71879       s.match_length = MIN_MATCH - 1;
71880       s.strstart++;
71881
71882       if (bflush) {
71883         /*** FLUSH_BLOCK(s, 0); ***/
71884         flush_block_only(s, false);
71885         if (s.strm.avail_out === 0) {
71886           return BS_NEED_MORE;
71887         }
71888         /***/
71889       }
71890
71891     } else if (s.match_available) {
71892       /* If there was no match at the previous position, output a
71893        * single literal. If there was a match but the current match
71894        * is longer, truncate the previous match to a single literal.
71895        */
71896       //Tracevv((stderr,"%c", s->window[s->strstart-1]));
71897       /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/
71898       bflush = _tr_tally(s, 0, s.window[s.strstart - 1]);
71899
71900       if (bflush) {
71901         /*** FLUSH_BLOCK_ONLY(s, 0) ***/
71902         flush_block_only(s, false);
71903         /***/
71904       }
71905       s.strstart++;
71906       s.lookahead--;
71907       if (s.strm.avail_out === 0) {
71908         return BS_NEED_MORE;
71909       }
71910     } else {
71911       /* There is no previous match to compare with, wait for
71912        * the next step to decide.
71913        */
71914       s.match_available = 1;
71915       s.strstart++;
71916       s.lookahead--;
71917     }
71918   }
71919   //Assert (flush != Z_NO_FLUSH, "no flush?");
71920   if (s.match_available) {
71921     //Tracevv((stderr,"%c", s->window[s->strstart-1]));
71922     /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/
71923     bflush = _tr_tally(s, 0, s.window[s.strstart - 1]);
71924
71925     s.match_available = 0;
71926   }
71927   s.insert = s.strstart < MIN_MATCH - 1 ? s.strstart : MIN_MATCH - 1;
71928   if (flush === Z_FINISH$3) {
71929     /*** FLUSH_BLOCK(s, 1); ***/
71930     flush_block_only(s, true);
71931     if (s.strm.avail_out === 0) {
71932       return BS_FINISH_STARTED;
71933     }
71934     /***/
71935     return BS_FINISH_DONE;
71936   }
71937   if (s.last_lit) {
71938     /*** FLUSH_BLOCK(s, 0); ***/
71939     flush_block_only(s, false);
71940     if (s.strm.avail_out === 0) {
71941       return BS_NEED_MORE;
71942     }
71943     /***/
71944   }
71945
71946   return BS_BLOCK_DONE;
71947 };
71948
71949
71950 /* ===========================================================================
71951  * For Z_RLE, simply look for runs of bytes, generate matches only of distance
71952  * one.  Do not maintain a hash table.  (It will be regenerated if this run of
71953  * deflate switches away from Z_RLE.)
71954  */
71955 const deflate_rle = (s, flush) => {
71956
71957   let bflush;            /* set if current block must be flushed */
71958   let prev;              /* byte at distance one to match */
71959   let scan, strend;      /* scan goes up to strend for length of run */
71960
71961   const _win = s.window;
71962
71963   for (;;) {
71964     /* Make sure that we always have enough lookahead, except
71965      * at the end of the input file. We need MAX_MATCH bytes
71966      * for the longest run, plus one for the unrolled loop.
71967      */
71968     if (s.lookahead <= MAX_MATCH) {
71969       fill_window(s);
71970       if (s.lookahead <= MAX_MATCH && flush === Z_NO_FLUSH$2) {
71971         return BS_NEED_MORE;
71972       }
71973       if (s.lookahead === 0) { break; } /* flush the current block */
71974     }
71975
71976     /* See how many times the previous byte repeats */
71977     s.match_length = 0;
71978     if (s.lookahead >= MIN_MATCH && s.strstart > 0) {
71979       scan = s.strstart - 1;
71980       prev = _win[scan];
71981       if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) {
71982         strend = s.strstart + MAX_MATCH;
71983         do {
71984           /*jshint noempty:false*/
71985         } while (prev === _win[++scan] && prev === _win[++scan] &&
71986                  prev === _win[++scan] && prev === _win[++scan] &&
71987                  prev === _win[++scan] && prev === _win[++scan] &&
71988                  prev === _win[++scan] && prev === _win[++scan] &&
71989                  scan < strend);
71990         s.match_length = MAX_MATCH - (strend - scan);
71991         if (s.match_length > s.lookahead) {
71992           s.match_length = s.lookahead;
71993         }
71994       }
71995       //Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan");
71996     }
71997
71998     /* Emit match if have run of MIN_MATCH or longer, else emit literal */
71999     if (s.match_length >= MIN_MATCH) {
72000       //check_match(s, s.strstart, s.strstart - 1, s.match_length);
72001
72002       /*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/
72003       bflush = _tr_tally(s, 1, s.match_length - MIN_MATCH);
72004
72005       s.lookahead -= s.match_length;
72006       s.strstart += s.match_length;
72007       s.match_length = 0;
72008     } else {
72009       /* No match, output a literal byte */
72010       //Tracevv((stderr,"%c", s->window[s->strstart]));
72011       /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
72012       bflush = _tr_tally(s, 0, s.window[s.strstart]);
72013
72014       s.lookahead--;
72015       s.strstart++;
72016     }
72017     if (bflush) {
72018       /*** FLUSH_BLOCK(s, 0); ***/
72019       flush_block_only(s, false);
72020       if (s.strm.avail_out === 0) {
72021         return BS_NEED_MORE;
72022       }
72023       /***/
72024     }
72025   }
72026   s.insert = 0;
72027   if (flush === Z_FINISH$3) {
72028     /*** FLUSH_BLOCK(s, 1); ***/
72029     flush_block_only(s, true);
72030     if (s.strm.avail_out === 0) {
72031       return BS_FINISH_STARTED;
72032     }
72033     /***/
72034     return BS_FINISH_DONE;
72035   }
72036   if (s.last_lit) {
72037     /*** FLUSH_BLOCK(s, 0); ***/
72038     flush_block_only(s, false);
72039     if (s.strm.avail_out === 0) {
72040       return BS_NEED_MORE;
72041     }
72042     /***/
72043   }
72044   return BS_BLOCK_DONE;
72045 };
72046
72047 /* ===========================================================================
72048  * For Z_HUFFMAN_ONLY, do not look for matches.  Do not maintain a hash table.
72049  * (It will be regenerated if this run of deflate switches away from Huffman.)
72050  */
72051 const deflate_huff = (s, flush) => {
72052
72053   let bflush;             /* set if current block must be flushed */
72054
72055   for (;;) {
72056     /* Make sure that we have a literal to write. */
72057     if (s.lookahead === 0) {
72058       fill_window(s);
72059       if (s.lookahead === 0) {
72060         if (flush === Z_NO_FLUSH$2) {
72061           return BS_NEED_MORE;
72062         }
72063         break;      /* flush the current block */
72064       }
72065     }
72066
72067     /* Output a literal byte */
72068     s.match_length = 0;
72069     //Tracevv((stderr,"%c", s->window[s->strstart]));
72070     /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
72071     bflush = _tr_tally(s, 0, s.window[s.strstart]);
72072     s.lookahead--;
72073     s.strstart++;
72074     if (bflush) {
72075       /*** FLUSH_BLOCK(s, 0); ***/
72076       flush_block_only(s, false);
72077       if (s.strm.avail_out === 0) {
72078         return BS_NEED_MORE;
72079       }
72080       /***/
72081     }
72082   }
72083   s.insert = 0;
72084   if (flush === Z_FINISH$3) {
72085     /*** FLUSH_BLOCK(s, 1); ***/
72086     flush_block_only(s, true);
72087     if (s.strm.avail_out === 0) {
72088       return BS_FINISH_STARTED;
72089     }
72090     /***/
72091     return BS_FINISH_DONE;
72092   }
72093   if (s.last_lit) {
72094     /*** FLUSH_BLOCK(s, 0); ***/
72095     flush_block_only(s, false);
72096     if (s.strm.avail_out === 0) {
72097       return BS_NEED_MORE;
72098     }
72099     /***/
72100   }
72101   return BS_BLOCK_DONE;
72102 };
72103
72104 /* Values for max_lazy_match, good_match and max_chain_length, depending on
72105  * the desired pack level (0..9). The values given below have been tuned to
72106  * exclude worst case performance for pathological files. Better values may be
72107  * found for specific files.
72108  */
72109 function Config(good_length, max_lazy, nice_length, max_chain, func) {
72110
72111   this.good_length = good_length;
72112   this.max_lazy = max_lazy;
72113   this.nice_length = nice_length;
72114   this.max_chain = max_chain;
72115   this.func = func;
72116 }
72117
72118 const configuration_table = [
72119   /*      good lazy nice chain */
72120   new Config(0, 0, 0, 0, deflate_stored),          /* 0 store only */
72121   new Config(4, 4, 8, 4, deflate_fast),            /* 1 max speed, no lazy matches */
72122   new Config(4, 5, 16, 8, deflate_fast),           /* 2 */
72123   new Config(4, 6, 32, 32, deflate_fast),          /* 3 */
72124
72125   new Config(4, 4, 16, 16, deflate_slow),          /* 4 lazy matches */
72126   new Config(8, 16, 32, 32, deflate_slow),         /* 5 */
72127   new Config(8, 16, 128, 128, deflate_slow),       /* 6 */
72128   new Config(8, 32, 128, 256, deflate_slow),       /* 7 */
72129   new Config(32, 128, 258, 1024, deflate_slow),    /* 8 */
72130   new Config(32, 258, 258, 4096, deflate_slow)     /* 9 max compression */
72131 ];
72132
72133
72134 /* ===========================================================================
72135  * Initialize the "longest match" routines for a new zlib stream
72136  */
72137 const lm_init = (s) => {
72138
72139   s.window_size = 2 * s.w_size;
72140
72141   /*** CLEAR_HASH(s); ***/
72142   zero(s.head); // Fill with NIL (= 0);
72143
72144   /* Set the default configuration parameters:
72145    */
72146   s.max_lazy_match = configuration_table[s.level].max_lazy;
72147   s.good_match = configuration_table[s.level].good_length;
72148   s.nice_match = configuration_table[s.level].nice_length;
72149   s.max_chain_length = configuration_table[s.level].max_chain;
72150
72151   s.strstart = 0;
72152   s.block_start = 0;
72153   s.lookahead = 0;
72154   s.insert = 0;
72155   s.match_length = s.prev_length = MIN_MATCH - 1;
72156   s.match_available = 0;
72157   s.ins_h = 0;
72158 };
72159
72160
72161 function DeflateState() {
72162   this.strm = null;            /* pointer back to this zlib stream */
72163   this.status = 0;            /* as the name implies */
72164   this.pending_buf = null;      /* output still pending */
72165   this.pending_buf_size = 0;  /* size of pending_buf */
72166   this.pending_out = 0;       /* next pending byte to output to the stream */
72167   this.pending = 0;           /* nb of bytes in the pending buffer */
72168   this.wrap = 0;              /* bit 0 true for zlib, bit 1 true for gzip */
72169   this.gzhead = null;         /* gzip header information to write */
72170   this.gzindex = 0;           /* where in extra, name, or comment */
72171   this.method = Z_DEFLATED$2; /* can only be DEFLATED */
72172   this.last_flush = -1;   /* value of flush param for previous deflate call */
72173
72174   this.w_size = 0;  /* LZ77 window size (32K by default) */
72175   this.w_bits = 0;  /* log2(w_size)  (8..16) */
72176   this.w_mask = 0;  /* w_size - 1 */
72177
72178   this.window = null;
72179   /* Sliding window. Input bytes are read into the second half of the window,
72180    * and move to the first half later to keep a dictionary of at least wSize
72181    * bytes. With this organization, matches are limited to a distance of
72182    * wSize-MAX_MATCH bytes, but this ensures that IO is always
72183    * performed with a length multiple of the block size.
72184    */
72185
72186   this.window_size = 0;
72187   /* Actual size of window: 2*wSize, except when the user input buffer
72188    * is directly used as sliding window.
72189    */
72190
72191   this.prev = null;
72192   /* Link to older string with same hash index. To limit the size of this
72193    * array to 64K, this link is maintained only for the last 32K strings.
72194    * An index in this array is thus a window index modulo 32K.
72195    */
72196
72197   this.head = null;   /* Heads of the hash chains or NIL. */
72198
72199   this.ins_h = 0;       /* hash index of string to be inserted */
72200   this.hash_size = 0;   /* number of elements in hash table */
72201   this.hash_bits = 0;   /* log2(hash_size) */
72202   this.hash_mask = 0;   /* hash_size-1 */
72203
72204   this.hash_shift = 0;
72205   /* Number of bits by which ins_h must be shifted at each input
72206    * step. It must be such that after MIN_MATCH steps, the oldest
72207    * byte no longer takes part in the hash key, that is:
72208    *   hash_shift * MIN_MATCH >= hash_bits
72209    */
72210
72211   this.block_start = 0;
72212   /* Window position at the beginning of the current output block. Gets
72213    * negative when the window is moved backwards.
72214    */
72215
72216   this.match_length = 0;      /* length of best match */
72217   this.prev_match = 0;        /* previous match */
72218   this.match_available = 0;   /* set if previous match exists */
72219   this.strstart = 0;          /* start of string to insert */
72220   this.match_start = 0;       /* start of matching string */
72221   this.lookahead = 0;         /* number of valid bytes ahead in window */
72222
72223   this.prev_length = 0;
72224   /* Length of the best match at previous step. Matches not greater than this
72225    * are discarded. This is used in the lazy match evaluation.
72226    */
72227
72228   this.max_chain_length = 0;
72229   /* To speed up deflation, hash chains are never searched beyond this
72230    * length.  A higher limit improves compression ratio but degrades the
72231    * speed.
72232    */
72233
72234   this.max_lazy_match = 0;
72235   /* Attempt to find a better match only when the current match is strictly
72236    * smaller than this value. This mechanism is used only for compression
72237    * levels >= 4.
72238    */
72239   // That's alias to max_lazy_match, don't use directly
72240   //this.max_insert_length = 0;
72241   /* Insert new strings in the hash table only if the match length is not
72242    * greater than this length. This saves time but degrades compression.
72243    * max_insert_length is used only for compression levels <= 3.
72244    */
72245
72246   this.level = 0;     /* compression level (1..9) */
72247   this.strategy = 0;  /* favor or force Huffman coding*/
72248
72249   this.good_match = 0;
72250   /* Use a faster search when the previous match is longer than this */
72251
72252   this.nice_match = 0; /* Stop searching when current match exceeds this */
72253
72254               /* used by trees.c: */
72255
72256   /* Didn't use ct_data typedef below to suppress compiler warning */
72257
72258   // struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
72259   // struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
72260   // struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */
72261
72262   // Use flat array of DOUBLE size, with interleaved fata,
72263   // because JS does not support effective
72264   this.dyn_ltree  = new Uint16Array(HEAP_SIZE * 2);
72265   this.dyn_dtree  = new Uint16Array((2 * D_CODES + 1) * 2);
72266   this.bl_tree    = new Uint16Array((2 * BL_CODES + 1) * 2);
72267   zero(this.dyn_ltree);
72268   zero(this.dyn_dtree);
72269   zero(this.bl_tree);
72270
72271   this.l_desc   = null;         /* desc. for literal tree */
72272   this.d_desc   = null;         /* desc. for distance tree */
72273   this.bl_desc  = null;         /* desc. for bit length tree */
72274
72275   //ush bl_count[MAX_BITS+1];
72276   this.bl_count = new Uint16Array(MAX_BITS + 1);
72277   /* number of codes at each bit length for an optimal tree */
72278
72279   //int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */
72280   this.heap = new Uint16Array(2 * L_CODES + 1);  /* heap used to build the Huffman trees */
72281   zero(this.heap);
72282
72283   this.heap_len = 0;               /* number of elements in the heap */
72284   this.heap_max = 0;               /* element of largest frequency */
72285   /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
72286    * The same heap array is used to build all trees.
72287    */
72288
72289   this.depth = new Uint16Array(2 * L_CODES + 1); //uch depth[2*L_CODES+1];
72290   zero(this.depth);
72291   /* Depth of each subtree used as tie breaker for trees of equal frequency
72292    */
72293
72294   this.l_buf = 0;          /* buffer index for literals or lengths */
72295
72296   this.lit_bufsize = 0;
72297   /* Size of match buffer for literals/lengths.  There are 4 reasons for
72298    * limiting lit_bufsize to 64K:
72299    *   - frequencies can be kept in 16 bit counters
72300    *   - if compression is not successful for the first block, all input
72301    *     data is still in the window so we can still emit a stored block even
72302    *     when input comes from standard input.  (This can also be done for
72303    *     all blocks if lit_bufsize is not greater than 32K.)
72304    *   - if compression is not successful for a file smaller than 64K, we can
72305    *     even emit a stored file instead of a stored block (saving 5 bytes).
72306    *     This is applicable only for zip (not gzip or zlib).
72307    *   - creating new Huffman trees less frequently may not provide fast
72308    *     adaptation to changes in the input data statistics. (Take for
72309    *     example a binary file with poorly compressible code followed by
72310    *     a highly compressible string table.) Smaller buffer sizes give
72311    *     fast adaptation but have of course the overhead of transmitting
72312    *     trees more frequently.
72313    *   - I can't count above 4
72314    */
72315
72316   this.last_lit = 0;      /* running index in l_buf */
72317
72318   this.d_buf = 0;
72319   /* Buffer index for distances. To simplify the code, d_buf and l_buf have
72320    * the same number of elements. To use different lengths, an extra flag
72321    * array would be necessary.
72322    */
72323
72324   this.opt_len = 0;       /* bit length of current block with optimal trees */
72325   this.static_len = 0;    /* bit length of current block with static trees */
72326   this.matches = 0;       /* number of string matches in current block */
72327   this.insert = 0;        /* bytes at end of window left to insert */
72328
72329
72330   this.bi_buf = 0;
72331   /* Output buffer. bits are inserted starting at the bottom (least
72332    * significant bits).
72333    */
72334   this.bi_valid = 0;
72335   /* Number of valid bits in bi_buf.  All bits above the last valid bit
72336    * are always zero.
72337    */
72338
72339   // Used for window memory init. We safely ignore it for JS. That makes
72340   // sense only for pointers and memory check tools.
72341   //this.high_water = 0;
72342   /* High water mark offset in window for initialized bytes -- bytes above
72343    * this are set to zero in order to avoid memory check warnings when
72344    * longest match routines access bytes past the input.  This is then
72345    * updated to the new high water mark.
72346    */
72347 }
72348
72349
72350 const deflateResetKeep = (strm) => {
72351
72352   if (!strm || !strm.state) {
72353     return err(strm, Z_STREAM_ERROR$2);
72354   }
72355
72356   strm.total_in = strm.total_out = 0;
72357   strm.data_type = Z_UNKNOWN;
72358
72359   const s = strm.state;
72360   s.pending = 0;
72361   s.pending_out = 0;
72362
72363   if (s.wrap < 0) {
72364     s.wrap = -s.wrap;
72365     /* was made negative by deflate(..., Z_FINISH); */
72366   }
72367   s.status = (s.wrap ? INIT_STATE : BUSY_STATE);
72368   strm.adler = (s.wrap === 2) ?
72369     0  // crc32(0, Z_NULL, 0)
72370   :
72371     1; // adler32(0, Z_NULL, 0)
72372   s.last_flush = Z_NO_FLUSH$2;
72373   _tr_init(s);
72374   return Z_OK$3;
72375 };
72376
72377
72378 const deflateReset = (strm) => {
72379
72380   const ret = deflateResetKeep(strm);
72381   if (ret === Z_OK$3) {
72382     lm_init(strm.state);
72383   }
72384   return ret;
72385 };
72386
72387
72388 const deflateSetHeader = (strm, head) => {
72389
72390   if (!strm || !strm.state) { return Z_STREAM_ERROR$2; }
72391   if (strm.state.wrap !== 2) { return Z_STREAM_ERROR$2; }
72392   strm.state.gzhead = head;
72393   return Z_OK$3;
72394 };
72395
72396
72397 const deflateInit2 = (strm, level, method, windowBits, memLevel, strategy) => {
72398
72399   if (!strm) { // === Z_NULL
72400     return Z_STREAM_ERROR$2;
72401   }
72402   let wrap = 1;
72403
72404   if (level === Z_DEFAULT_COMPRESSION$1) {
72405     level = 6;
72406   }
72407
72408   if (windowBits < 0) { /* suppress zlib wrapper */
72409     wrap = 0;
72410     windowBits = -windowBits;
72411   }
72412
72413   else if (windowBits > 15) {
72414     wrap = 2;           /* write gzip wrapper instead */
72415     windowBits -= 16;
72416   }
72417
72418
72419   if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED$2 ||
72420     windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
72421     strategy < 0 || strategy > Z_FIXED) {
72422     return err(strm, Z_STREAM_ERROR$2);
72423   }
72424
72425
72426   if (windowBits === 8) {
72427     windowBits = 9;
72428   }
72429   /* until 256-byte window bug fixed */
72430
72431   const s = new DeflateState();
72432
72433   strm.state = s;
72434   s.strm = strm;
72435
72436   s.wrap = wrap;
72437   s.gzhead = null;
72438   s.w_bits = windowBits;
72439   s.w_size = 1 << s.w_bits;
72440   s.w_mask = s.w_size - 1;
72441
72442   s.hash_bits = memLevel + 7;
72443   s.hash_size = 1 << s.hash_bits;
72444   s.hash_mask = s.hash_size - 1;
72445   s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH);
72446
72447   s.window = new Uint8Array(s.w_size * 2);
72448   s.head = new Uint16Array(s.hash_size);
72449   s.prev = new Uint16Array(s.w_size);
72450
72451   // Don't need mem init magic for JS.
72452   //s.high_water = 0;  /* nothing written to s->window yet */
72453
72454   s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
72455
72456   s.pending_buf_size = s.lit_bufsize * 4;
72457
72458   //overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
72459   //s->pending_buf = (uchf *) overlay;
72460   s.pending_buf = new Uint8Array(s.pending_buf_size);
72461
72462   // It is offset from `s.pending_buf` (size is `s.lit_bufsize * 2`)
72463   //s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
72464   s.d_buf = 1 * s.lit_bufsize;
72465
72466   //s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
72467   s.l_buf = (1 + 2) * s.lit_bufsize;
72468
72469   s.level = level;
72470   s.strategy = strategy;
72471   s.method = method;
72472
72473   return deflateReset(strm);
72474 };
72475
72476 const deflateInit = (strm, level) => {
72477
72478   return deflateInit2(strm, level, Z_DEFLATED$2, MAX_WBITS$1, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY$1);
72479 };
72480
72481
72482 const deflate$2 = (strm, flush) => {
72483
72484   let beg, val; // for gzip header write only
72485
72486   if (!strm || !strm.state ||
72487     flush > Z_BLOCK$1 || flush < 0) {
72488     return strm ? err(strm, Z_STREAM_ERROR$2) : Z_STREAM_ERROR$2;
72489   }
72490
72491   const s = strm.state;
72492
72493   if (!strm.output ||
72494       (!strm.input && strm.avail_in !== 0) ||
72495       (s.status === FINISH_STATE && flush !== Z_FINISH$3)) {
72496     return err(strm, (strm.avail_out === 0) ? Z_BUF_ERROR$1 : Z_STREAM_ERROR$2);
72497   }
72498
72499   s.strm = strm; /* just in case */
72500   const old_flush = s.last_flush;
72501   s.last_flush = flush;
72502
72503   /* Write the header */
72504   if (s.status === INIT_STATE) {
72505
72506     if (s.wrap === 2) { // GZIP header
72507       strm.adler = 0;  //crc32(0L, Z_NULL, 0);
72508       put_byte(s, 31);
72509       put_byte(s, 139);
72510       put_byte(s, 8);
72511       if (!s.gzhead) { // s->gzhead == Z_NULL
72512         put_byte(s, 0);
72513         put_byte(s, 0);
72514         put_byte(s, 0);
72515         put_byte(s, 0);
72516         put_byte(s, 0);
72517         put_byte(s, s.level === 9 ? 2 :
72518                     (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?
72519                      4 : 0));
72520         put_byte(s, OS_CODE);
72521         s.status = BUSY_STATE;
72522       }
72523       else {
72524         put_byte(s, (s.gzhead.text ? 1 : 0) +
72525                     (s.gzhead.hcrc ? 2 : 0) +
72526                     (!s.gzhead.extra ? 0 : 4) +
72527                     (!s.gzhead.name ? 0 : 8) +
72528                     (!s.gzhead.comment ? 0 : 16)
72529         );
72530         put_byte(s, s.gzhead.time & 0xff);
72531         put_byte(s, (s.gzhead.time >> 8) & 0xff);
72532         put_byte(s, (s.gzhead.time >> 16) & 0xff);
72533         put_byte(s, (s.gzhead.time >> 24) & 0xff);
72534         put_byte(s, s.level === 9 ? 2 :
72535                     (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?
72536                      4 : 0));
72537         put_byte(s, s.gzhead.os & 0xff);
72538         if (s.gzhead.extra && s.gzhead.extra.length) {
72539           put_byte(s, s.gzhead.extra.length & 0xff);
72540           put_byte(s, (s.gzhead.extra.length >> 8) & 0xff);
72541         }
72542         if (s.gzhead.hcrc) {
72543           strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending, 0);
72544         }
72545         s.gzindex = 0;
72546         s.status = EXTRA_STATE;
72547       }
72548     }
72549     else // DEFLATE header
72550     {
72551       let header = (Z_DEFLATED$2 + ((s.w_bits - 8) << 4)) << 8;
72552       let level_flags = -1;
72553
72554       if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) {
72555         level_flags = 0;
72556       } else if (s.level < 6) {
72557         level_flags = 1;
72558       } else if (s.level === 6) {
72559         level_flags = 2;
72560       } else {
72561         level_flags = 3;
72562       }
72563       header |= (level_flags << 6);
72564       if (s.strstart !== 0) { header |= PRESET_DICT; }
72565       header += 31 - (header % 31);
72566
72567       s.status = BUSY_STATE;
72568       putShortMSB(s, header);
72569
72570       /* Save the adler32 of the preset dictionary: */
72571       if (s.strstart !== 0) {
72572         putShortMSB(s, strm.adler >>> 16);
72573         putShortMSB(s, strm.adler & 0xffff);
72574       }
72575       strm.adler = 1; // adler32(0L, Z_NULL, 0);
72576     }
72577   }
72578
72579 //#ifdef GZIP
72580   if (s.status === EXTRA_STATE) {
72581     if (s.gzhead.extra/* != Z_NULL*/) {
72582       beg = s.pending;  /* start of bytes to update crc */
72583
72584       while (s.gzindex < (s.gzhead.extra.length & 0xffff)) {
72585         if (s.pending === s.pending_buf_size) {
72586           if (s.gzhead.hcrc && s.pending > beg) {
72587             strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg);
72588           }
72589           flush_pending(strm);
72590           beg = s.pending;
72591           if (s.pending === s.pending_buf_size) {
72592             break;
72593           }
72594         }
72595         put_byte(s, s.gzhead.extra[s.gzindex] & 0xff);
72596         s.gzindex++;
72597       }
72598       if (s.gzhead.hcrc && s.pending > beg) {
72599         strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg);
72600       }
72601       if (s.gzindex === s.gzhead.extra.length) {
72602         s.gzindex = 0;
72603         s.status = NAME_STATE;
72604       }
72605     }
72606     else {
72607       s.status = NAME_STATE;
72608     }
72609   }
72610   if (s.status === NAME_STATE) {
72611     if (s.gzhead.name/* != Z_NULL*/) {
72612       beg = s.pending;  /* start of bytes to update crc */
72613       //int val;
72614
72615       do {
72616         if (s.pending === s.pending_buf_size) {
72617           if (s.gzhead.hcrc && s.pending > beg) {
72618             strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg);
72619           }
72620           flush_pending(strm);
72621           beg = s.pending;
72622           if (s.pending === s.pending_buf_size) {
72623             val = 1;
72624             break;
72625           }
72626         }
72627         // JS specific: little magic to add zero terminator to end of string
72628         if (s.gzindex < s.gzhead.name.length) {
72629           val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff;
72630         } else {
72631           val = 0;
72632         }
72633         put_byte(s, val);
72634       } while (val !== 0);
72635
72636       if (s.gzhead.hcrc && s.pending > beg) {
72637         strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg);
72638       }
72639       if (val === 0) {
72640         s.gzindex = 0;
72641         s.status = COMMENT_STATE;
72642       }
72643     }
72644     else {
72645       s.status = COMMENT_STATE;
72646     }
72647   }
72648   if (s.status === COMMENT_STATE) {
72649     if (s.gzhead.comment/* != Z_NULL*/) {
72650       beg = s.pending;  /* start of bytes to update crc */
72651       //int val;
72652
72653       do {
72654         if (s.pending === s.pending_buf_size) {
72655           if (s.gzhead.hcrc && s.pending > beg) {
72656             strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg);
72657           }
72658           flush_pending(strm);
72659           beg = s.pending;
72660           if (s.pending === s.pending_buf_size) {
72661             val = 1;
72662             break;
72663           }
72664         }
72665         // JS specific: little magic to add zero terminator to end of string
72666         if (s.gzindex < s.gzhead.comment.length) {
72667           val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff;
72668         } else {
72669           val = 0;
72670         }
72671         put_byte(s, val);
72672       } while (val !== 0);
72673
72674       if (s.gzhead.hcrc && s.pending > beg) {
72675         strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg);
72676       }
72677       if (val === 0) {
72678         s.status = HCRC_STATE;
72679       }
72680     }
72681     else {
72682       s.status = HCRC_STATE;
72683     }
72684   }
72685   if (s.status === HCRC_STATE) {
72686     if (s.gzhead.hcrc) {
72687       if (s.pending + 2 > s.pending_buf_size) {
72688         flush_pending(strm);
72689       }
72690       if (s.pending + 2 <= s.pending_buf_size) {
72691         put_byte(s, strm.adler & 0xff);
72692         put_byte(s, (strm.adler >> 8) & 0xff);
72693         strm.adler = 0; //crc32(0L, Z_NULL, 0);
72694         s.status = BUSY_STATE;
72695       }
72696     }
72697     else {
72698       s.status = BUSY_STATE;
72699     }
72700   }
72701 //#endif
72702
72703   /* Flush as much pending output as possible */
72704   if (s.pending !== 0) {
72705     flush_pending(strm);
72706     if (strm.avail_out === 0) {
72707       /* Since avail_out is 0, deflate will be called again with
72708        * more output space, but possibly with both pending and
72709        * avail_in equal to zero. There won't be anything to do,
72710        * but this is not an error situation so make sure we
72711        * return OK instead of BUF_ERROR at next call of deflate:
72712        */
72713       s.last_flush = -1;
72714       return Z_OK$3;
72715     }
72716
72717     /* Make sure there is something to do and avoid duplicate consecutive
72718      * flushes. For repeated and useless calls with Z_FINISH, we keep
72719      * returning Z_STREAM_END instead of Z_BUF_ERROR.
72720      */
72721   } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) &&
72722     flush !== Z_FINISH$3) {
72723     return err(strm, Z_BUF_ERROR$1);
72724   }
72725
72726   /* User must not provide more input after the first FINISH: */
72727   if (s.status === FINISH_STATE && strm.avail_in !== 0) {
72728     return err(strm, Z_BUF_ERROR$1);
72729   }
72730
72731   /* Start a new block or continue the current one.
72732    */
72733   if (strm.avail_in !== 0 || s.lookahead !== 0 ||
72734     (flush !== Z_NO_FLUSH$2 && s.status !== FINISH_STATE)) {
72735     let bstate = (s.strategy === Z_HUFFMAN_ONLY) ? deflate_huff(s, flush) :
72736       (s.strategy === Z_RLE ? deflate_rle(s, flush) :
72737         configuration_table[s.level].func(s, flush));
72738
72739     if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) {
72740       s.status = FINISH_STATE;
72741     }
72742     if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) {
72743       if (strm.avail_out === 0) {
72744         s.last_flush = -1;
72745         /* avoid BUF_ERROR next call, see above */
72746       }
72747       return Z_OK$3;
72748       /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
72749        * of deflate should use the same flush parameter to make sure
72750        * that the flush is complete. So we don't have to output an
72751        * empty block here, this will be done at next call. This also
72752        * ensures that for a very small output buffer, we emit at most
72753        * one empty block.
72754        */
72755     }
72756     if (bstate === BS_BLOCK_DONE) {
72757       if (flush === Z_PARTIAL_FLUSH) {
72758         _tr_align(s);
72759       }
72760       else if (flush !== Z_BLOCK$1) { /* FULL_FLUSH or SYNC_FLUSH */
72761
72762         _tr_stored_block(s, 0, 0, false);
72763         /* For a full flush, this empty block will be recognized
72764          * as a special marker by inflate_sync().
72765          */
72766         if (flush === Z_FULL_FLUSH$1) {
72767           /*** CLEAR_HASH(s); ***/             /* forget history */
72768           zero(s.head); // Fill with NIL (= 0);
72769
72770           if (s.lookahead === 0) {
72771             s.strstart = 0;
72772             s.block_start = 0;
72773             s.insert = 0;
72774           }
72775         }
72776       }
72777       flush_pending(strm);
72778       if (strm.avail_out === 0) {
72779         s.last_flush = -1; /* avoid BUF_ERROR at next call, see above */
72780         return Z_OK$3;
72781       }
72782     }
72783   }
72784   //Assert(strm->avail_out > 0, "bug2");
72785   //if (strm.avail_out <= 0) { throw new Error("bug2");}
72786
72787   if (flush !== Z_FINISH$3) { return Z_OK$3; }
72788   if (s.wrap <= 0) { return Z_STREAM_END$3; }
72789
72790   /* Write the trailer */
72791   if (s.wrap === 2) {
72792     put_byte(s, strm.adler & 0xff);
72793     put_byte(s, (strm.adler >> 8) & 0xff);
72794     put_byte(s, (strm.adler >> 16) & 0xff);
72795     put_byte(s, (strm.adler >> 24) & 0xff);
72796     put_byte(s, strm.total_in & 0xff);
72797     put_byte(s, (strm.total_in >> 8) & 0xff);
72798     put_byte(s, (strm.total_in >> 16) & 0xff);
72799     put_byte(s, (strm.total_in >> 24) & 0xff);
72800   }
72801   else
72802   {
72803     putShortMSB(s, strm.adler >>> 16);
72804     putShortMSB(s, strm.adler & 0xffff);
72805   }
72806
72807   flush_pending(strm);
72808   /* If avail_out is zero, the application will call deflate again
72809    * to flush the rest.
72810    */
72811   if (s.wrap > 0) { s.wrap = -s.wrap; }
72812   /* write the trailer only once! */
72813   return s.pending !== 0 ? Z_OK$3 : Z_STREAM_END$3;
72814 };
72815
72816
72817 const deflateEnd = (strm) => {
72818
72819   if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) {
72820     return Z_STREAM_ERROR$2;
72821   }
72822
72823   const status = strm.state.status;
72824   if (status !== INIT_STATE &&
72825     status !== EXTRA_STATE &&
72826     status !== NAME_STATE &&
72827     status !== COMMENT_STATE &&
72828     status !== HCRC_STATE &&
72829     status !== BUSY_STATE &&
72830     status !== FINISH_STATE
72831   ) {
72832     return err(strm, Z_STREAM_ERROR$2);
72833   }
72834
72835   strm.state = null;
72836
72837   return status === BUSY_STATE ? err(strm, Z_DATA_ERROR$2) : Z_OK$3;
72838 };
72839
72840
72841 /* =========================================================================
72842  * Initializes the compression dictionary from the given byte
72843  * sequence without producing any compressed output.
72844  */
72845 const deflateSetDictionary = (strm, dictionary) => {
72846
72847   let dictLength = dictionary.length;
72848
72849   if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) {
72850     return Z_STREAM_ERROR$2;
72851   }
72852
72853   const s = strm.state;
72854   const wrap = s.wrap;
72855
72856   if (wrap === 2 || (wrap === 1 && s.status !== INIT_STATE) || s.lookahead) {
72857     return Z_STREAM_ERROR$2;
72858   }
72859
72860   /* when using zlib wrappers, compute Adler-32 for provided dictionary */
72861   if (wrap === 1) {
72862     /* adler32(strm->adler, dictionary, dictLength); */
72863     strm.adler = adler32_1(strm.adler, dictionary, dictLength, 0);
72864   }
72865
72866   s.wrap = 0;   /* avoid computing Adler-32 in read_buf */
72867
72868   /* if dictionary would fill window, just replace the history */
72869   if (dictLength >= s.w_size) {
72870     if (wrap === 0) {            /* already empty otherwise */
72871       /*** CLEAR_HASH(s); ***/
72872       zero(s.head); // Fill with NIL (= 0);
72873       s.strstart = 0;
72874       s.block_start = 0;
72875       s.insert = 0;
72876     }
72877     /* use the tail */
72878     // dictionary = dictionary.slice(dictLength - s.w_size);
72879     let tmpDict = new Uint8Array(s.w_size);
72880     tmpDict.set(dictionary.subarray(dictLength - s.w_size, dictLength), 0);
72881     dictionary = tmpDict;
72882     dictLength = s.w_size;
72883   }
72884   /* insert dictionary into window and hash */
72885   const avail = strm.avail_in;
72886   const next = strm.next_in;
72887   const input = strm.input;
72888   strm.avail_in = dictLength;
72889   strm.next_in = 0;
72890   strm.input = dictionary;
72891   fill_window(s);
72892   while (s.lookahead >= MIN_MATCH) {
72893     let str = s.strstart;
72894     let n = s.lookahead - (MIN_MATCH - 1);
72895     do {
72896       /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */
72897       s.ins_h = HASH(s, s.ins_h, s.window[str + MIN_MATCH - 1]);
72898
72899       s.prev[str & s.w_mask] = s.head[s.ins_h];
72900
72901       s.head[s.ins_h] = str;
72902       str++;
72903     } while (--n);
72904     s.strstart = str;
72905     s.lookahead = MIN_MATCH - 1;
72906     fill_window(s);
72907   }
72908   s.strstart += s.lookahead;
72909   s.block_start = s.strstart;
72910   s.insert = s.lookahead;
72911   s.lookahead = 0;
72912   s.match_length = s.prev_length = MIN_MATCH - 1;
72913   s.match_available = 0;
72914   strm.next_in = next;
72915   strm.input = input;
72916   strm.avail_in = avail;
72917   s.wrap = wrap;
72918   return Z_OK$3;
72919 };
72920
72921
72922 var deflateInit_1 = deflateInit;
72923 var deflateInit2_1 = deflateInit2;
72924 var deflateReset_1 = deflateReset;
72925 var deflateResetKeep_1 = deflateResetKeep;
72926 var deflateSetHeader_1 = deflateSetHeader;
72927 var deflate_2$1 = deflate$2;
72928 var deflateEnd_1 = deflateEnd;
72929 var deflateSetDictionary_1 = deflateSetDictionary;
72930 var deflateInfo = 'pako deflate (from Nodeca project)';
72931
72932 /* Not implemented
72933 module.exports.deflateBound = deflateBound;
72934 module.exports.deflateCopy = deflateCopy;
72935 module.exports.deflateParams = deflateParams;
72936 module.exports.deflatePending = deflatePending;
72937 module.exports.deflatePrime = deflatePrime;
72938 module.exports.deflateTune = deflateTune;
72939 */
72940
72941 var deflate_1$2 = {
72942         deflateInit: deflateInit_1,
72943         deflateInit2: deflateInit2_1,
72944         deflateReset: deflateReset_1,
72945         deflateResetKeep: deflateResetKeep_1,
72946         deflateSetHeader: deflateSetHeader_1,
72947         deflate: deflate_2$1,
72948         deflateEnd: deflateEnd_1,
72949         deflateSetDictionary: deflateSetDictionary_1,
72950         deflateInfo: deflateInfo
72951 };
72952
72953 const _has = (obj, key) => {
72954   return Object.prototype.hasOwnProperty.call(obj, key);
72955 };
72956
72957 var assign = function (obj /*from1, from2, from3, ...*/) {
72958   const sources = Array.prototype.slice.call(arguments, 1);
72959   while (sources.length) {
72960     const source = sources.shift();
72961     if (!source) { continue; }
72962
72963     if (typeof source !== 'object') {
72964       throw new TypeError(source + 'must be non-object');
72965     }
72966
72967     for (const p in source) {
72968       if (_has(source, p)) {
72969         obj[p] = source[p];
72970       }
72971     }
72972   }
72973
72974   return obj;
72975 };
72976
72977
72978 // Join array of chunks to single array.
72979 var flattenChunks = (chunks) => {
72980   // calculate data length
72981   let len = 0;
72982
72983   for (let i = 0, l = chunks.length; i < l; i++) {
72984     len += chunks[i].length;
72985   }
72986
72987   // join chunks
72988   const result = new Uint8Array(len);
72989
72990   for (let i = 0, pos = 0, l = chunks.length; i < l; i++) {
72991     let chunk = chunks[i];
72992     result.set(chunk, pos);
72993     pos += chunk.length;
72994   }
72995
72996   return result;
72997 };
72998
72999 var common = {
73000         assign: assign,
73001         flattenChunks: flattenChunks
73002 };
73003
73004 // String encode/decode helpers
73005
73006
73007 // Quick check if we can use fast array to bin string conversion
73008 //
73009 // - apply(Array) can fail on Android 2.2
73010 // - apply(Uint8Array) can fail on iOS 5.1 Safari
73011 //
73012 let STR_APPLY_UIA_OK = true;
73013
73014 try { String.fromCharCode.apply(null, new Uint8Array(1)); } catch (__) { STR_APPLY_UIA_OK = false; }
73015
73016
73017 // Table with utf8 lengths (calculated by first byte of sequence)
73018 // Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS,
73019 // because max possible codepoint is 0x10ffff
73020 const _utf8len = new Uint8Array(256);
73021 for (let q = 0; q < 256; q++) {
73022   _utf8len[q] = (q >= 252 ? 6 : q >= 248 ? 5 : q >= 240 ? 4 : q >= 224 ? 3 : q >= 192 ? 2 : 1);
73023 }
73024 _utf8len[254] = _utf8len[254] = 1; // Invalid sequence start
73025
73026
73027 // convert string to array (typed, when possible)
73028 var string2buf = (str) => {
73029   if (typeof TextEncoder === 'function' && TextEncoder.prototype.encode) {
73030     return new TextEncoder().encode(str);
73031   }
73032
73033   let buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0;
73034
73035   // count binary size
73036   for (m_pos = 0; m_pos < str_len; m_pos++) {
73037     c = str.charCodeAt(m_pos);
73038     if ((c & 0xfc00) === 0xd800 && (m_pos + 1 < str_len)) {
73039       c2 = str.charCodeAt(m_pos + 1);
73040       if ((c2 & 0xfc00) === 0xdc00) {
73041         c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
73042         m_pos++;
73043       }
73044     }
73045     buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4;
73046   }
73047
73048   // allocate buffer
73049   buf = new Uint8Array(buf_len);
73050
73051   // convert
73052   for (i = 0, m_pos = 0; i < buf_len; m_pos++) {
73053     c = str.charCodeAt(m_pos);
73054     if ((c & 0xfc00) === 0xd800 && (m_pos + 1 < str_len)) {
73055       c2 = str.charCodeAt(m_pos + 1);
73056       if ((c2 & 0xfc00) === 0xdc00) {
73057         c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
73058         m_pos++;
73059       }
73060     }
73061     if (c < 0x80) {
73062       /* one byte */
73063       buf[i++] = c;
73064     } else if (c < 0x800) {
73065       /* two bytes */
73066       buf[i++] = 0xC0 | (c >>> 6);
73067       buf[i++] = 0x80 | (c & 0x3f);
73068     } else if (c < 0x10000) {
73069       /* three bytes */
73070       buf[i++] = 0xE0 | (c >>> 12);
73071       buf[i++] = 0x80 | (c >>> 6 & 0x3f);
73072       buf[i++] = 0x80 | (c & 0x3f);
73073     } else {
73074       /* four bytes */
73075       buf[i++] = 0xf0 | (c >>> 18);
73076       buf[i++] = 0x80 | (c >>> 12 & 0x3f);
73077       buf[i++] = 0x80 | (c >>> 6 & 0x3f);
73078       buf[i++] = 0x80 | (c & 0x3f);
73079     }
73080   }
73081
73082   return buf;
73083 };
73084
73085 // Helper
73086 const buf2binstring = (buf, len) => {
73087   // On Chrome, the arguments in a function call that are allowed is `65534`.
73088   // If the length of the buffer is smaller than that, we can use this optimization,
73089   // otherwise we will take a slower path.
73090   if (len < 65534) {
73091     if (buf.subarray && STR_APPLY_UIA_OK) {
73092       return String.fromCharCode.apply(null, buf.length === len ? buf : buf.subarray(0, len));
73093     }
73094   }
73095
73096   let result = '';
73097   for (let i = 0; i < len; i++) {
73098     result += String.fromCharCode(buf[i]);
73099   }
73100   return result;
73101 };
73102
73103
73104 // convert array to string
73105 var buf2string = (buf, max) => {
73106   const len = max || buf.length;
73107
73108   if (typeof TextDecoder === 'function' && TextDecoder.prototype.decode) {
73109     return new TextDecoder().decode(buf.subarray(0, max));
73110   }
73111
73112   let i, out;
73113
73114   // Reserve max possible length (2 words per char)
73115   // NB: by unknown reasons, Array is significantly faster for
73116   //     String.fromCharCode.apply than Uint16Array.
73117   const utf16buf = new Array(len * 2);
73118
73119   for (out = 0, i = 0; i < len;) {
73120     let c = buf[i++];
73121     // quick process ascii
73122     if (c < 0x80) { utf16buf[out++] = c; continue; }
73123
73124     let c_len = _utf8len[c];
73125     // skip 5 & 6 byte codes
73126     if (c_len > 4) { utf16buf[out++] = 0xfffd; i += c_len - 1; continue; }
73127
73128     // apply mask on first byte
73129     c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07;
73130     // join the rest
73131     while (c_len > 1 && i < len) {
73132       c = (c << 6) | (buf[i++] & 0x3f);
73133       c_len--;
73134     }
73135
73136     // terminated by end of string?
73137     if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; }
73138
73139     if (c < 0x10000) {
73140       utf16buf[out++] = c;
73141     } else {
73142       c -= 0x10000;
73143       utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff);
73144       utf16buf[out++] = 0xdc00 | (c & 0x3ff);
73145     }
73146   }
73147
73148   return buf2binstring(utf16buf, out);
73149 };
73150
73151
73152 // Calculate max possible position in utf8 buffer,
73153 // that will not break sequence. If that's not possible
73154 // - (very small limits) return max size as is.
73155 //
73156 // buf[] - utf8 bytes array
73157 // max   - length limit (mandatory);
73158 var utf8border = (buf, max) => {
73159
73160   max = max || buf.length;
73161   if (max > buf.length) { max = buf.length; }
73162
73163   // go back from last position, until start of sequence found
73164   let pos = max - 1;
73165   while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; }
73166
73167   // Very small and broken sequence,
73168   // return max, because we should return something anyway.
73169   if (pos < 0) { return max; }
73170
73171   // If we came to start of buffer - that means buffer is too small,
73172   // return max too.
73173   if (pos === 0) { return max; }
73174
73175   return (pos + _utf8len[buf[pos]] > max) ? pos : max;
73176 };
73177
73178 var strings = {
73179         string2buf: string2buf,
73180         buf2string: buf2string,
73181         utf8border: utf8border
73182 };
73183
73184 // (C) 1995-2013 Jean-loup Gailly and Mark Adler
73185 // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
73186 //
73187 // This software is provided 'as-is', without any express or implied
73188 // warranty. In no event will the authors be held liable for any damages
73189 // arising from the use of this software.
73190 //
73191 // Permission is granted to anyone to use this software for any purpose,
73192 // including commercial applications, and to alter it and redistribute it
73193 // freely, subject to the following restrictions:
73194 //
73195 // 1. The origin of this software must not be misrepresented; you must not
73196 //   claim that you wrote the original software. If you use this software
73197 //   in a product, an acknowledgment in the product documentation would be
73198 //   appreciated but is not required.
73199 // 2. Altered source versions must be plainly marked as such, and must not be
73200 //   misrepresented as being the original software.
73201 // 3. This notice may not be removed or altered from any source distribution.
73202
73203 function ZStream() {
73204   /* next input byte */
73205   this.input = null; // JS specific, because we have no pointers
73206   this.next_in = 0;
73207   /* number of bytes available at input */
73208   this.avail_in = 0;
73209   /* total number of input bytes read so far */
73210   this.total_in = 0;
73211   /* next output byte should be put there */
73212   this.output = null; // JS specific, because we have no pointers
73213   this.next_out = 0;
73214   /* remaining free space at output */
73215   this.avail_out = 0;
73216   /* total number of bytes output so far */
73217   this.total_out = 0;
73218   /* last error message, NULL if no error */
73219   this.msg = ''/*Z_NULL*/;
73220   /* not visible by applications */
73221   this.state = null;
73222   /* best guess about the data type: binary or text */
73223   this.data_type = 2/*Z_UNKNOWN*/;
73224   /* adler32 value of the uncompressed data */
73225   this.adler = 0;
73226 }
73227
73228 var zstream = ZStream;
73229
73230 const toString$1 = Object.prototype.toString;
73231
73232 /* Public constants ==========================================================*/
73233 /* ===========================================================================*/
73234
73235 const {
73236   Z_NO_FLUSH: Z_NO_FLUSH$1, Z_SYNC_FLUSH, Z_FULL_FLUSH, Z_FINISH: Z_FINISH$2,
73237   Z_OK: Z_OK$2, Z_STREAM_END: Z_STREAM_END$2,
73238   Z_DEFAULT_COMPRESSION,
73239   Z_DEFAULT_STRATEGY,
73240   Z_DEFLATED: Z_DEFLATED$1
73241 } = constants$2;
73242
73243 /* ===========================================================================*/
73244
73245
73246 /**
73247  * class Deflate
73248  *
73249  * Generic JS-style wrapper for zlib calls. If you don't need
73250  * streaming behaviour - use more simple functions: [[deflate]],
73251  * [[deflateRaw]] and [[gzip]].
73252  **/
73253
73254 /* internal
73255  * Deflate.chunks -> Array
73256  *
73257  * Chunks of output data, if [[Deflate#onData]] not overridden.
73258  **/
73259
73260 /**
73261  * Deflate.result -> Uint8Array
73262  *
73263  * Compressed result, generated by default [[Deflate#onData]]
73264  * and [[Deflate#onEnd]] handlers. Filled after you push last chunk
73265  * (call [[Deflate#push]] with `Z_FINISH` / `true` param).
73266  **/
73267
73268 /**
73269  * Deflate.err -> Number
73270  *
73271  * Error code after deflate finished. 0 (Z_OK) on success.
73272  * You will not need it in real life, because deflate errors
73273  * are possible only on wrong options or bad `onData` / `onEnd`
73274  * custom handlers.
73275  **/
73276
73277 /**
73278  * Deflate.msg -> String
73279  *
73280  * Error message, if [[Deflate.err]] != 0
73281  **/
73282
73283
73284 /**
73285  * new Deflate(options)
73286  * - options (Object): zlib deflate options.
73287  *
73288  * Creates new deflator instance with specified params. Throws exception
73289  * on bad params. Supported options:
73290  *
73291  * - `level`
73292  * - `windowBits`
73293  * - `memLevel`
73294  * - `strategy`
73295  * - `dictionary`
73296  *
73297  * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
73298  * for more information on these.
73299  *
73300  * Additional options, for internal needs:
73301  *
73302  * - `chunkSize` - size of generated data chunks (16K by default)
73303  * - `raw` (Boolean) - do raw deflate
73304  * - `gzip` (Boolean) - create gzip wrapper
73305  * - `header` (Object) - custom header for gzip
73306  *   - `text` (Boolean) - true if compressed data believed to be text
73307  *   - `time` (Number) - modification time, unix timestamp
73308  *   - `os` (Number) - operation system code
73309  *   - `extra` (Array) - array of bytes with extra data (max 65536)
73310  *   - `name` (String) - file name (binary string)
73311  *   - `comment` (String) - comment (binary string)
73312  *   - `hcrc` (Boolean) - true if header crc should be added
73313  *
73314  * ##### Example:
73315  *
73316  * ```javascript
73317  * const pako = require('pako')
73318  *   , chunk1 = new Uint8Array([1,2,3,4,5,6,7,8,9])
73319  *   , chunk2 = new Uint8Array([10,11,12,13,14,15,16,17,18,19]);
73320  *
73321  * const deflate = new pako.Deflate({ level: 3});
73322  *
73323  * deflate.push(chunk1, false);
73324  * deflate.push(chunk2, true);  // true -> last chunk
73325  *
73326  * if (deflate.err) { throw new Error(deflate.err); }
73327  *
73328  * console.log(deflate.result);
73329  * ```
73330  **/
73331 function Deflate$1(options) {
73332   this.options = common.assign({
73333     level: Z_DEFAULT_COMPRESSION,
73334     method: Z_DEFLATED$1,
73335     chunkSize: 16384,
73336     windowBits: 15,
73337     memLevel: 8,
73338     strategy: Z_DEFAULT_STRATEGY
73339   }, options || {});
73340
73341   let opt = this.options;
73342
73343   if (opt.raw && (opt.windowBits > 0)) {
73344     opt.windowBits = -opt.windowBits;
73345   }
73346
73347   else if (opt.gzip && (opt.windowBits > 0) && (opt.windowBits < 16)) {
73348     opt.windowBits += 16;
73349   }
73350
73351   this.err    = 0;      // error code, if happens (0 = Z_OK)
73352   this.msg    = '';     // error message
73353   this.ended  = false;  // used to avoid multiple onEnd() calls
73354   this.chunks = [];     // chunks of compressed data
73355
73356   this.strm = new zstream();
73357   this.strm.avail_out = 0;
73358
73359   let status = deflate_1$2.deflateInit2(
73360     this.strm,
73361     opt.level,
73362     opt.method,
73363     opt.windowBits,
73364     opt.memLevel,
73365     opt.strategy
73366   );
73367
73368   if (status !== Z_OK$2) {
73369     throw new Error(messages[status]);
73370   }
73371
73372   if (opt.header) {
73373     deflate_1$2.deflateSetHeader(this.strm, opt.header);
73374   }
73375
73376   if (opt.dictionary) {
73377     let dict;
73378     // Convert data if needed
73379     if (typeof opt.dictionary === 'string') {
73380       // If we need to compress text, change encoding to utf8.
73381       dict = strings.string2buf(opt.dictionary);
73382     } else if (toString$1.call(opt.dictionary) === '[object ArrayBuffer]') {
73383       dict = new Uint8Array(opt.dictionary);
73384     } else {
73385       dict = opt.dictionary;
73386     }
73387
73388     status = deflate_1$2.deflateSetDictionary(this.strm, dict);
73389
73390     if (status !== Z_OK$2) {
73391       throw new Error(messages[status]);
73392     }
73393
73394     this._dict_set = true;
73395   }
73396 }
73397
73398 /**
73399  * Deflate#push(data[, flush_mode]) -> Boolean
73400  * - data (Uint8Array|ArrayBuffer|String): input data. Strings will be
73401  *   converted to utf8 byte sequence.
73402  * - flush_mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes.
73403  *   See constants. Skipped or `false` means Z_NO_FLUSH, `true` means Z_FINISH.
73404  *
73405  * Sends input data to deflate pipe, generating [[Deflate#onData]] calls with
73406  * new compressed chunks. Returns `true` on success. The last data block must
73407  * have `flush_mode` Z_FINISH (or `true`). That will flush internal pending
73408  * buffers and call [[Deflate#onEnd]].
73409  *
73410  * On fail call [[Deflate#onEnd]] with error code and return false.
73411  *
73412  * ##### Example
73413  *
73414  * ```javascript
73415  * push(chunk, false); // push one of data chunks
73416  * ...
73417  * push(chunk, true);  // push last chunk
73418  * ```
73419  **/
73420 Deflate$1.prototype.push = function (data, flush_mode) {
73421   const strm = this.strm;
73422   const chunkSize = this.options.chunkSize;
73423   let status, _flush_mode;
73424
73425   if (this.ended) { return false; }
73426
73427   if (flush_mode === ~~flush_mode) _flush_mode = flush_mode;
73428   else _flush_mode = flush_mode === true ? Z_FINISH$2 : Z_NO_FLUSH$1;
73429
73430   // Convert data if needed
73431   if (typeof data === 'string') {
73432     // If we need to compress text, change encoding to utf8.
73433     strm.input = strings.string2buf(data);
73434   } else if (toString$1.call(data) === '[object ArrayBuffer]') {
73435     strm.input = new Uint8Array(data);
73436   } else {
73437     strm.input = data;
73438   }
73439
73440   strm.next_in = 0;
73441   strm.avail_in = strm.input.length;
73442
73443   for (;;) {
73444     if (strm.avail_out === 0) {
73445       strm.output = new Uint8Array(chunkSize);
73446       strm.next_out = 0;
73447       strm.avail_out = chunkSize;
73448     }
73449
73450     // Make sure avail_out > 6 to avoid repeating markers
73451     if ((_flush_mode === Z_SYNC_FLUSH || _flush_mode === Z_FULL_FLUSH) && strm.avail_out <= 6) {
73452       this.onData(strm.output.subarray(0, strm.next_out));
73453       strm.avail_out = 0;
73454       continue;
73455     }
73456
73457     status = deflate_1$2.deflate(strm, _flush_mode);
73458
73459     // Ended => flush and finish
73460     if (status === Z_STREAM_END$2) {
73461       if (strm.next_out > 0) {
73462         this.onData(strm.output.subarray(0, strm.next_out));
73463       }
73464       status = deflate_1$2.deflateEnd(this.strm);
73465       this.onEnd(status);
73466       this.ended = true;
73467       return status === Z_OK$2;
73468     }
73469
73470     // Flush if out buffer full
73471     if (strm.avail_out === 0) {
73472       this.onData(strm.output);
73473       continue;
73474     }
73475
73476     // Flush if requested and has data
73477     if (_flush_mode > 0 && strm.next_out > 0) {
73478       this.onData(strm.output.subarray(0, strm.next_out));
73479       strm.avail_out = 0;
73480       continue;
73481     }
73482
73483     if (strm.avail_in === 0) break;
73484   }
73485
73486   return true;
73487 };
73488
73489
73490 /**
73491  * Deflate#onData(chunk) -> Void
73492  * - chunk (Uint8Array): output data.
73493  *
73494  * By default, stores data blocks in `chunks[]` property and glue
73495  * those in `onEnd`. Override this handler, if you need another behaviour.
73496  **/
73497 Deflate$1.prototype.onData = function (chunk) {
73498   this.chunks.push(chunk);
73499 };
73500
73501
73502 /**
73503  * Deflate#onEnd(status) -> Void
73504  * - status (Number): deflate status. 0 (Z_OK) on success,
73505  *   other if not.
73506  *
73507  * Called once after you tell deflate that the input stream is
73508  * complete (Z_FINISH). By default - join collected chunks,
73509  * free memory and fill `results` / `err` properties.
73510  **/
73511 Deflate$1.prototype.onEnd = function (status) {
73512   // On success - join
73513   if (status === Z_OK$2) {
73514     this.result = common.flattenChunks(this.chunks);
73515   }
73516   this.chunks = [];
73517   this.err = status;
73518   this.msg = this.strm.msg;
73519 };
73520
73521 // (C) 1995-2013 Jean-loup Gailly and Mark Adler
73522 // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
73523 //
73524 // This software is provided 'as-is', without any express or implied
73525 // warranty. In no event will the authors be held liable for any damages
73526 // arising from the use of this software.
73527 //
73528 // Permission is granted to anyone to use this software for any purpose,
73529 // including commercial applications, and to alter it and redistribute it
73530 // freely, subject to the following restrictions:
73531 //
73532 // 1. The origin of this software must not be misrepresented; you must not
73533 //   claim that you wrote the original software. If you use this software
73534 //   in a product, an acknowledgment in the product documentation would be
73535 //   appreciated but is not required.
73536 // 2. Altered source versions must be plainly marked as such, and must not be
73537 //   misrepresented as being the original software.
73538 // 3. This notice may not be removed or altered from any source distribution.
73539
73540 // See state defs from inflate.js
73541 const BAD$1 = 30;       /* got a data error -- remain here until reset */
73542 const TYPE$1 = 12;      /* i: waiting for type bits, including last-flag bit */
73543
73544 /*
73545    Decode literal, length, and distance codes and write out the resulting
73546    literal and match bytes until either not enough input or output is
73547    available, an end-of-block is encountered, or a data error is encountered.
73548    When large enough input and output buffers are supplied to inflate(), for
73549    example, a 16K input buffer and a 64K output buffer, more than 95% of the
73550    inflate execution time is spent in this routine.
73551
73552    Entry assumptions:
73553
73554         state.mode === LEN
73555         strm.avail_in >= 6
73556         strm.avail_out >= 258
73557         start >= strm.avail_out
73558         state.bits < 8
73559
73560    On return, state.mode is one of:
73561
73562         LEN -- ran out of enough output space or enough available input
73563         TYPE -- reached end of block code, inflate() to interpret next block
73564         BAD -- error in block data
73565
73566    Notes:
73567
73568     - The maximum input bits used by a length/distance pair is 15 bits for the
73569       length code, 5 bits for the length extra, 15 bits for the distance code,
73570       and 13 bits for the distance extra.  This totals 48 bits, or six bytes.
73571       Therefore if strm.avail_in >= 6, then there is enough input to avoid
73572       checking for available input while decoding.
73573
73574     - The maximum bytes that a single length/distance pair can output is 258
73575       bytes, which is the maximum length that can be coded.  inflate_fast()
73576       requires strm.avail_out >= 258 for each loop to avoid checking for
73577       output space.
73578  */
73579 var inffast = function inflate_fast(strm, start) {
73580   let _in;                    /* local strm.input */
73581   let last;                   /* have enough input while in < last */
73582   let _out;                   /* local strm.output */
73583   let beg;                    /* inflate()'s initial strm.output */
73584   let end;                    /* while out < end, enough space available */
73585 //#ifdef INFLATE_STRICT
73586   let dmax;                   /* maximum distance from zlib header */
73587 //#endif
73588   let wsize;                  /* window size or zero if not using window */
73589   let whave;                  /* valid bytes in the window */
73590   let wnext;                  /* window write index */
73591   // Use `s_window` instead `window`, avoid conflict with instrumentation tools
73592   let s_window;               /* allocated sliding window, if wsize != 0 */
73593   let hold;                   /* local strm.hold */
73594   let bits;                   /* local strm.bits */
73595   let lcode;                  /* local strm.lencode */
73596   let dcode;                  /* local strm.distcode */
73597   let lmask;                  /* mask for first level of length codes */
73598   let dmask;                  /* mask for first level of distance codes */
73599   let here;                   /* retrieved table entry */
73600   let op;                     /* code bits, operation, extra bits, or */
73601                               /*  window position, window bytes to copy */
73602   let len;                    /* match length, unused bytes */
73603   let dist;                   /* match distance */
73604   let from;                   /* where to copy match from */
73605   let from_source;
73606
73607
73608   let input, output; // JS specific, because we have no pointers
73609
73610   /* copy state to local variables */
73611   const state = strm.state;
73612   //here = state.here;
73613   _in = strm.next_in;
73614   input = strm.input;
73615   last = _in + (strm.avail_in - 5);
73616   _out = strm.next_out;
73617   output = strm.output;
73618   beg = _out - (start - strm.avail_out);
73619   end = _out + (strm.avail_out - 257);
73620 //#ifdef INFLATE_STRICT
73621   dmax = state.dmax;
73622 //#endif
73623   wsize = state.wsize;
73624   whave = state.whave;
73625   wnext = state.wnext;
73626   s_window = state.window;
73627   hold = state.hold;
73628   bits = state.bits;
73629   lcode = state.lencode;
73630   dcode = state.distcode;
73631   lmask = (1 << state.lenbits) - 1;
73632   dmask = (1 << state.distbits) - 1;
73633
73634
73635   /* decode literals and length/distances until end-of-block or not enough
73636      input data or output space */
73637
73638   top:
73639   do {
73640     if (bits < 15) {
73641       hold += input[_in++] << bits;
73642       bits += 8;
73643       hold += input[_in++] << bits;
73644       bits += 8;
73645     }
73646
73647     here = lcode[hold & lmask];
73648
73649     dolen:
73650     for (;;) { // Goto emulation
73651       op = here >>> 24/*here.bits*/;
73652       hold >>>= op;
73653       bits -= op;
73654       op = (here >>> 16) & 0xff/*here.op*/;
73655       if (op === 0) {                          /* literal */
73656         //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
73657         //        "inflate:         literal '%c'\n" :
73658         //        "inflate:         literal 0x%02x\n", here.val));
73659         output[_out++] = here & 0xffff/*here.val*/;
73660       }
73661       else if (op & 16) {                     /* length base */
73662         len = here & 0xffff/*here.val*/;
73663         op &= 15;                           /* number of extra bits */
73664         if (op) {
73665           if (bits < op) {
73666             hold += input[_in++] << bits;
73667             bits += 8;
73668           }
73669           len += hold & ((1 << op) - 1);
73670           hold >>>= op;
73671           bits -= op;
73672         }
73673         //Tracevv((stderr, "inflate:         length %u\n", len));
73674         if (bits < 15) {
73675           hold += input[_in++] << bits;
73676           bits += 8;
73677           hold += input[_in++] << bits;
73678           bits += 8;
73679         }
73680         here = dcode[hold & dmask];
73681
73682         dodist:
73683         for (;;) { // goto emulation
73684           op = here >>> 24/*here.bits*/;
73685           hold >>>= op;
73686           bits -= op;
73687           op = (here >>> 16) & 0xff/*here.op*/;
73688
73689           if (op & 16) {                      /* distance base */
73690             dist = here & 0xffff/*here.val*/;
73691             op &= 15;                       /* number of extra bits */
73692             if (bits < op) {
73693               hold += input[_in++] << bits;
73694               bits += 8;
73695               if (bits < op) {
73696                 hold += input[_in++] << bits;
73697                 bits += 8;
73698               }
73699             }
73700             dist += hold & ((1 << op) - 1);
73701 //#ifdef INFLATE_STRICT
73702             if (dist > dmax) {
73703               strm.msg = 'invalid distance too far back';
73704               state.mode = BAD$1;
73705               break top;
73706             }
73707 //#endif
73708             hold >>>= op;
73709             bits -= op;
73710             //Tracevv((stderr, "inflate:         distance %u\n", dist));
73711             op = _out - beg;                /* max distance in output */
73712             if (dist > op) {                /* see if copy from window */
73713               op = dist - op;               /* distance back in window */
73714               if (op > whave) {
73715                 if (state.sane) {
73716                   strm.msg = 'invalid distance too far back';
73717                   state.mode = BAD$1;
73718                   break top;
73719                 }
73720
73721 // (!) This block is disabled in zlib defaults,
73722 // don't enable it for binary compatibility
73723 //#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
73724 //                if (len <= op - whave) {
73725 //                  do {
73726 //                    output[_out++] = 0;
73727 //                  } while (--len);
73728 //                  continue top;
73729 //                }
73730 //                len -= op - whave;
73731 //                do {
73732 //                  output[_out++] = 0;
73733 //                } while (--op > whave);
73734 //                if (op === 0) {
73735 //                  from = _out - dist;
73736 //                  do {
73737 //                    output[_out++] = output[from++];
73738 //                  } while (--len);
73739 //                  continue top;
73740 //                }
73741 //#endif
73742               }
73743               from = 0; // window index
73744               from_source = s_window;
73745               if (wnext === 0) {           /* very common case */
73746                 from += wsize - op;
73747                 if (op < len) {         /* some from window */
73748                   len -= op;
73749                   do {
73750                     output[_out++] = s_window[from++];
73751                   } while (--op);
73752                   from = _out - dist;  /* rest from output */
73753                   from_source = output;
73754                 }
73755               }
73756               else if (wnext < op) {      /* wrap around window */
73757                 from += wsize + wnext - op;
73758                 op -= wnext;
73759                 if (op < len) {         /* some from end of window */
73760                   len -= op;
73761                   do {
73762                     output[_out++] = s_window[from++];
73763                   } while (--op);
73764                   from = 0;
73765                   if (wnext < len) {  /* some from start of window */
73766                     op = wnext;
73767                     len -= op;
73768                     do {
73769                       output[_out++] = s_window[from++];
73770                     } while (--op);
73771                     from = _out - dist;      /* rest from output */
73772                     from_source = output;
73773                   }
73774                 }
73775               }
73776               else {                      /* contiguous in window */
73777                 from += wnext - op;
73778                 if (op < len) {         /* some from window */
73779                   len -= op;
73780                   do {
73781                     output[_out++] = s_window[from++];
73782                   } while (--op);
73783                   from = _out - dist;  /* rest from output */
73784                   from_source = output;
73785                 }
73786               }
73787               while (len > 2) {
73788                 output[_out++] = from_source[from++];
73789                 output[_out++] = from_source[from++];
73790                 output[_out++] = from_source[from++];
73791                 len -= 3;
73792               }
73793               if (len) {
73794                 output[_out++] = from_source[from++];
73795                 if (len > 1) {
73796                   output[_out++] = from_source[from++];
73797                 }
73798               }
73799             }
73800             else {
73801               from = _out - dist;          /* copy direct from output */
73802               do {                        /* minimum length is three */
73803                 output[_out++] = output[from++];
73804                 output[_out++] = output[from++];
73805                 output[_out++] = output[from++];
73806                 len -= 3;
73807               } while (len > 2);
73808               if (len) {
73809                 output[_out++] = output[from++];
73810                 if (len > 1) {
73811                   output[_out++] = output[from++];
73812                 }
73813               }
73814             }
73815           }
73816           else if ((op & 64) === 0) {          /* 2nd level distance code */
73817             here = dcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];
73818             continue dodist;
73819           }
73820           else {
73821             strm.msg = 'invalid distance code';
73822             state.mode = BAD$1;
73823             break top;
73824           }
73825
73826           break; // need to emulate goto via "continue"
73827         }
73828       }
73829       else if ((op & 64) === 0) {              /* 2nd level length code */
73830         here = lcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];
73831         continue dolen;
73832       }
73833       else if (op & 32) {                     /* end-of-block */
73834         //Tracevv((stderr, "inflate:         end of block\n"));
73835         state.mode = TYPE$1;
73836         break top;
73837       }
73838       else {
73839         strm.msg = 'invalid literal/length code';
73840         state.mode = BAD$1;
73841         break top;
73842       }
73843
73844       break; // need to emulate goto via "continue"
73845     }
73846   } while (_in < last && _out < end);
73847
73848   /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
73849   len = bits >> 3;
73850   _in -= len;
73851   bits -= len << 3;
73852   hold &= (1 << bits) - 1;
73853
73854   /* update state and return */
73855   strm.next_in = _in;
73856   strm.next_out = _out;
73857   strm.avail_in = (_in < last ? 5 + (last - _in) : 5 - (_in - last));
73858   strm.avail_out = (_out < end ? 257 + (end - _out) : 257 - (_out - end));
73859   state.hold = hold;
73860   state.bits = bits;
73861   return;
73862 };
73863
73864 // (C) 1995-2013 Jean-loup Gailly and Mark Adler
73865 // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
73866 //
73867 // This software is provided 'as-is', without any express or implied
73868 // warranty. In no event will the authors be held liable for any damages
73869 // arising from the use of this software.
73870 //
73871 // Permission is granted to anyone to use this software for any purpose,
73872 // including commercial applications, and to alter it and redistribute it
73873 // freely, subject to the following restrictions:
73874 //
73875 // 1. The origin of this software must not be misrepresented; you must not
73876 //   claim that you wrote the original software. If you use this software
73877 //   in a product, an acknowledgment in the product documentation would be
73878 //   appreciated but is not required.
73879 // 2. Altered source versions must be plainly marked as such, and must not be
73880 //   misrepresented as being the original software.
73881 // 3. This notice may not be removed or altered from any source distribution.
73882
73883 const MAXBITS = 15;
73884 const ENOUGH_LENS$1 = 852;
73885 const ENOUGH_DISTS$1 = 592;
73886 //const ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS);
73887
73888 const CODES$1 = 0;
73889 const LENS$1 = 1;
73890 const DISTS$1 = 2;
73891
73892 const lbase = new Uint16Array([ /* Length codes 257..285 base */
73893   3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
73894   35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
73895 ]);
73896
73897 const lext = new Uint8Array([ /* Length codes 257..285 extra */
73898   16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
73899   19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78
73900 ]);
73901
73902 const dbase = new Uint16Array([ /* Distance codes 0..29 base */
73903   1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
73904   257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
73905   8193, 12289, 16385, 24577, 0, 0
73906 ]);
73907
73908 const dext = new Uint8Array([ /* Distance codes 0..29 extra */
73909   16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
73910   23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
73911   28, 28, 29, 29, 64, 64
73912 ]);
73913
73914 const inflate_table = (type, lens, lens_index, codes, table, table_index, work, opts) =>
73915 {
73916   const bits = opts.bits;
73917       //here = opts.here; /* table entry for duplication */
73918
73919   let len = 0;               /* a code's length in bits */
73920   let sym = 0;               /* index of code symbols */
73921   let min = 0, max = 0;          /* minimum and maximum code lengths */
73922   let root = 0;              /* number of index bits for root table */
73923   let curr = 0;              /* number of index bits for current table */
73924   let drop = 0;              /* code bits to drop for sub-table */
73925   let left = 0;                   /* number of prefix codes available */
73926   let used = 0;              /* code entries in table used */
73927   let huff = 0;              /* Huffman code */
73928   let incr;              /* for incrementing code, index */
73929   let fill;              /* index for replicating entries */
73930   let low;               /* low bits for current root entry */
73931   let mask;              /* mask for low root bits */
73932   let next;             /* next available space in table */
73933   let base = null;     /* base value table to use */
73934   let base_index = 0;
73935 //  let shoextra;    /* extra bits table to use */
73936   let end;                    /* use base and extra for symbol > end */
73937   const count = new Uint16Array(MAXBITS + 1); //[MAXBITS+1];    /* number of codes of each length */
73938   const offs = new Uint16Array(MAXBITS + 1); //[MAXBITS+1];     /* offsets in table for each length */
73939   let extra = null;
73940   let extra_index = 0;
73941
73942   let here_bits, here_op, here_val;
73943
73944   /*
73945    Process a set of code lengths to create a canonical Huffman code.  The
73946    code lengths are lens[0..codes-1].  Each length corresponds to the
73947    symbols 0..codes-1.  The Huffman code is generated by first sorting the
73948    symbols by length from short to long, and retaining the symbol order
73949    for codes with equal lengths.  Then the code starts with all zero bits
73950    for the first code of the shortest length, and the codes are integer
73951    increments for the same length, and zeros are appended as the length
73952    increases.  For the deflate format, these bits are stored backwards
73953    from their more natural integer increment ordering, and so when the
73954    decoding tables are built in the large loop below, the integer codes
73955    are incremented backwards.
73956
73957    This routine assumes, but does not check, that all of the entries in
73958    lens[] are in the range 0..MAXBITS.  The caller must assure this.
73959    1..MAXBITS is interpreted as that code length.  zero means that that
73960    symbol does not occur in this code.
73961
73962    The codes are sorted by computing a count of codes for each length,
73963    creating from that a table of starting indices for each length in the
73964    sorted table, and then entering the symbols in order in the sorted
73965    table.  The sorted table is work[], with that space being provided by
73966    the caller.
73967
73968    The length counts are used for other purposes as well, i.e. finding
73969    the minimum and maximum length codes, determining if there are any
73970    codes at all, checking for a valid set of lengths, and looking ahead
73971    at length counts to determine sub-table sizes when building the
73972    decoding tables.
73973    */
73974
73975   /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
73976   for (len = 0; len <= MAXBITS; len++) {
73977     count[len] = 0;
73978   }
73979   for (sym = 0; sym < codes; sym++) {
73980     count[lens[lens_index + sym]]++;
73981   }
73982
73983   /* bound code lengths, force root to be within code lengths */
73984   root = bits;
73985   for (max = MAXBITS; max >= 1; max--) {
73986     if (count[max] !== 0) { break; }
73987   }
73988   if (root > max) {
73989     root = max;
73990   }
73991   if (max === 0) {                     /* no symbols to code at all */
73992     //table.op[opts.table_index] = 64;  //here.op = (var char)64;    /* invalid code marker */
73993     //table.bits[opts.table_index] = 1;   //here.bits = (var char)1;
73994     //table.val[opts.table_index++] = 0;   //here.val = (var short)0;
73995     table[table_index++] = (1 << 24) | (64 << 16) | 0;
73996
73997
73998     //table.op[opts.table_index] = 64;
73999     //table.bits[opts.table_index] = 1;
74000     //table.val[opts.table_index++] = 0;
74001     table[table_index++] = (1 << 24) | (64 << 16) | 0;
74002
74003     opts.bits = 1;
74004     return 0;     /* no symbols, but wait for decoding to report error */
74005   }
74006   for (min = 1; min < max; min++) {
74007     if (count[min] !== 0) { break; }
74008   }
74009   if (root < min) {
74010     root = min;
74011   }
74012
74013   /* check for an over-subscribed or incomplete set of lengths */
74014   left = 1;
74015   for (len = 1; len <= MAXBITS; len++) {
74016     left <<= 1;
74017     left -= count[len];
74018     if (left < 0) {
74019       return -1;
74020     }        /* over-subscribed */
74021   }
74022   if (left > 0 && (type === CODES$1 || max !== 1)) {
74023     return -1;                      /* incomplete set */
74024   }
74025
74026   /* generate offsets into symbol table for each length for sorting */
74027   offs[1] = 0;
74028   for (len = 1; len < MAXBITS; len++) {
74029     offs[len + 1] = offs[len] + count[len];
74030   }
74031
74032   /* sort symbols by length, by symbol order within each length */
74033   for (sym = 0; sym < codes; sym++) {
74034     if (lens[lens_index + sym] !== 0) {
74035       work[offs[lens[lens_index + sym]]++] = sym;
74036     }
74037   }
74038
74039   /*
74040    Create and fill in decoding tables.  In this loop, the table being
74041    filled is at next and has curr index bits.  The code being used is huff
74042    with length len.  That code is converted to an index by dropping drop
74043    bits off of the bottom.  For codes where len is less than drop + curr,
74044    those top drop + curr - len bits are incremented through all values to
74045    fill the table with replicated entries.
74046
74047    root is the number of index bits for the root table.  When len exceeds
74048    root, sub-tables are created pointed to by the root entry with an index
74049    of the low root bits of huff.  This is saved in low to check for when a
74050    new sub-table should be started.  drop is zero when the root table is
74051    being filled, and drop is root when sub-tables are being filled.
74052
74053    When a new sub-table is needed, it is necessary to look ahead in the
74054    code lengths to determine what size sub-table is needed.  The length
74055    counts are used for this, and so count[] is decremented as codes are
74056    entered in the tables.
74057
74058    used keeps track of how many table entries have been allocated from the
74059    provided *table space.  It is checked for LENS and DIST tables against
74060    the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
74061    the initial root table size constants.  See the comments in inftrees.h
74062    for more information.
74063
74064    sym increments through all symbols, and the loop terminates when
74065    all codes of length max, i.e. all codes, have been processed.  This
74066    routine permits incomplete codes, so another loop after this one fills
74067    in the rest of the decoding tables with invalid code markers.
74068    */
74069
74070   /* set up for code type */
74071   // poor man optimization - use if-else instead of switch,
74072   // to avoid deopts in old v8
74073   if (type === CODES$1) {
74074     base = extra = work;    /* dummy value--not used */
74075     end = 19;
74076
74077   } else if (type === LENS$1) {
74078     base = lbase;
74079     base_index -= 257;
74080     extra = lext;
74081     extra_index -= 257;
74082     end = 256;
74083
74084   } else {                    /* DISTS */
74085     base = dbase;
74086     extra = dext;
74087     end = -1;
74088   }
74089
74090   /* initialize opts for loop */
74091   huff = 0;                   /* starting code */
74092   sym = 0;                    /* starting code symbol */
74093   len = min;                  /* starting code length */
74094   next = table_index;              /* current table to fill in */
74095   curr = root;                /* current table index bits */
74096   drop = 0;                   /* current bits to drop from code for index */
74097   low = -1;                   /* trigger new sub-table when len > root */
74098   used = 1 << root;          /* use root table entries */
74099   mask = used - 1;            /* mask for comparing low */
74100
74101   /* check available table space */
74102   if ((type === LENS$1 && used > ENOUGH_LENS$1) ||
74103     (type === DISTS$1 && used > ENOUGH_DISTS$1)) {
74104     return 1;
74105   }
74106
74107   /* process all codes and make table entries */
74108   for (;;) {
74109     /* create table entry */
74110     here_bits = len - drop;
74111     if (work[sym] < end) {
74112       here_op = 0;
74113       here_val = work[sym];
74114     }
74115     else if (work[sym] > end) {
74116       here_op = extra[extra_index + work[sym]];
74117       here_val = base[base_index + work[sym]];
74118     }
74119     else {
74120       here_op = 32 + 64;         /* end of block */
74121       here_val = 0;
74122     }
74123
74124     /* replicate for those indices with low len bits equal to huff */
74125     incr = 1 << (len - drop);
74126     fill = 1 << curr;
74127     min = fill;                 /* save offset to next table */
74128     do {
74129       fill -= incr;
74130       table[next + (huff >> drop) + fill] = (here_bits << 24) | (here_op << 16) | here_val |0;
74131     } while (fill !== 0);
74132
74133     /* backwards increment the len-bit code huff */
74134     incr = 1 << (len - 1);
74135     while (huff & incr) {
74136       incr >>= 1;
74137     }
74138     if (incr !== 0) {
74139       huff &= incr - 1;
74140       huff += incr;
74141     } else {
74142       huff = 0;
74143     }
74144
74145     /* go to next symbol, update count, len */
74146     sym++;
74147     if (--count[len] === 0) {
74148       if (len === max) { break; }
74149       len = lens[lens_index + work[sym]];
74150     }
74151
74152     /* create new sub-table if needed */
74153     if (len > root && (huff & mask) !== low) {
74154       /* if first time, transition to sub-tables */
74155       if (drop === 0) {
74156         drop = root;
74157       }
74158
74159       /* increment past last table */
74160       next += min;            /* here min is 1 << curr */
74161
74162       /* determine length of next table */
74163       curr = len - drop;
74164       left = 1 << curr;
74165       while (curr + drop < max) {
74166         left -= count[curr + drop];
74167         if (left <= 0) { break; }
74168         curr++;
74169         left <<= 1;
74170       }
74171
74172       /* check for enough space */
74173       used += 1 << curr;
74174       if ((type === LENS$1 && used > ENOUGH_LENS$1) ||
74175         (type === DISTS$1 && used > ENOUGH_DISTS$1)) {
74176         return 1;
74177       }
74178
74179       /* point entry in root table to sub-table */
74180       low = huff & mask;
74181       /*table.op[low] = curr;
74182       table.bits[low] = root;
74183       table.val[low] = next - opts.table_index;*/
74184       table[low] = (root << 24) | (curr << 16) | (next - table_index) |0;
74185     }
74186   }
74187
74188   /* fill in remaining table entry if code is incomplete (guaranteed to have
74189    at most one remaining entry, since if the code is incomplete, the
74190    maximum code length that was allowed to get this far is one bit) */
74191   if (huff !== 0) {
74192     //table.op[next + huff] = 64;            /* invalid code marker */
74193     //table.bits[next + huff] = len - drop;
74194     //table.val[next + huff] = 0;
74195     table[next + huff] = ((len - drop) << 24) | (64 << 16) |0;
74196   }
74197
74198   /* set return parameters */
74199   //opts.table_index += used;
74200   opts.bits = root;
74201   return 0;
74202 };
74203
74204
74205 var inftrees = inflate_table;
74206
74207 // (C) 1995-2013 Jean-loup Gailly and Mark Adler
74208 // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
74209 //
74210 // This software is provided 'as-is', without any express or implied
74211 // warranty. In no event will the authors be held liable for any damages
74212 // arising from the use of this software.
74213 //
74214 // Permission is granted to anyone to use this software for any purpose,
74215 // including commercial applications, and to alter it and redistribute it
74216 // freely, subject to the following restrictions:
74217 //
74218 // 1. The origin of this software must not be misrepresented; you must not
74219 //   claim that you wrote the original software. If you use this software
74220 //   in a product, an acknowledgment in the product documentation would be
74221 //   appreciated but is not required.
74222 // 2. Altered source versions must be plainly marked as such, and must not be
74223 //   misrepresented as being the original software.
74224 // 3. This notice may not be removed or altered from any source distribution.
74225
74226
74227
74228
74229
74230
74231 const CODES = 0;
74232 const LENS = 1;
74233 const DISTS = 2;
74234
74235 /* Public constants ==========================================================*/
74236 /* ===========================================================================*/
74237
74238 const {
74239   Z_FINISH: Z_FINISH$1, Z_BLOCK, Z_TREES,
74240   Z_OK: Z_OK$1, Z_STREAM_END: Z_STREAM_END$1, Z_NEED_DICT: Z_NEED_DICT$1, Z_STREAM_ERROR: Z_STREAM_ERROR$1, Z_DATA_ERROR: Z_DATA_ERROR$1, Z_MEM_ERROR: Z_MEM_ERROR$1, Z_BUF_ERROR,
74241   Z_DEFLATED
74242 } = constants$2;
74243
74244
74245 /* STATES ====================================================================*/
74246 /* ===========================================================================*/
74247
74248
74249 const    HEAD = 1;       /* i: waiting for magic header */
74250 const    FLAGS = 2;      /* i: waiting for method and flags (gzip) */
74251 const    TIME = 3;       /* i: waiting for modification time (gzip) */
74252 const    OS = 4;         /* i: waiting for extra flags and operating system (gzip) */
74253 const    EXLEN = 5;      /* i: waiting for extra length (gzip) */
74254 const    EXTRA = 6;      /* i: waiting for extra bytes (gzip) */
74255 const    NAME = 7;       /* i: waiting for end of file name (gzip) */
74256 const    COMMENT = 8;    /* i: waiting for end of comment (gzip) */
74257 const    HCRC = 9;       /* i: waiting for header crc (gzip) */
74258 const    DICTID = 10;    /* i: waiting for dictionary check value */
74259 const    DICT = 11;      /* waiting for inflateSetDictionary() call */
74260 const        TYPE = 12;      /* i: waiting for type bits, including last-flag bit */
74261 const        TYPEDO = 13;    /* i: same, but skip check to exit inflate on new block */
74262 const        STORED = 14;    /* i: waiting for stored size (length and complement) */
74263 const        COPY_ = 15;     /* i/o: same as COPY below, but only first time in */
74264 const        COPY = 16;      /* i/o: waiting for input or output to copy stored block */
74265 const        TABLE = 17;     /* i: waiting for dynamic block table lengths */
74266 const        LENLENS = 18;   /* i: waiting for code length code lengths */
74267 const        CODELENS = 19;  /* i: waiting for length/lit and distance code lengths */
74268 const            LEN_ = 20;      /* i: same as LEN below, but only first time in */
74269 const            LEN = 21;       /* i: waiting for length/lit/eob code */
74270 const            LENEXT = 22;    /* i: waiting for length extra bits */
74271 const            DIST = 23;      /* i: waiting for distance code */
74272 const            DISTEXT = 24;   /* i: waiting for distance extra bits */
74273 const            MATCH = 25;     /* o: waiting for output space to copy string */
74274 const            LIT = 26;       /* o: waiting for output space to write literal */
74275 const    CHECK = 27;     /* i: waiting for 32-bit check value */
74276 const    LENGTH = 28;    /* i: waiting for 32-bit length (gzip) */
74277 const    DONE = 29;      /* finished check, done -- remain here until reset */
74278 const    BAD = 30;       /* got a data error -- remain here until reset */
74279 const    MEM = 31;       /* got an inflate() memory error -- remain here until reset */
74280 const    SYNC = 32;      /* looking for synchronization bytes to restart inflate() */
74281
74282 /* ===========================================================================*/
74283
74284
74285
74286 const ENOUGH_LENS = 852;
74287 const ENOUGH_DISTS = 592;
74288 //const ENOUGH =  (ENOUGH_LENS+ENOUGH_DISTS);
74289
74290 const MAX_WBITS = 15;
74291 /* 32K LZ77 window */
74292 const DEF_WBITS = MAX_WBITS;
74293
74294
74295 const zswap32 = (q) => {
74296
74297   return  (((q >>> 24) & 0xff) +
74298           ((q >>> 8) & 0xff00) +
74299           ((q & 0xff00) << 8) +
74300           ((q & 0xff) << 24));
74301 };
74302
74303
74304 function InflateState() {
74305   this.mode = 0;             /* current inflate mode */
74306   this.last = false;          /* true if processing last block */
74307   this.wrap = 0;              /* bit 0 true for zlib, bit 1 true for gzip */
74308   this.havedict = false;      /* true if dictionary provided */
74309   this.flags = 0;             /* gzip header method and flags (0 if zlib) */
74310   this.dmax = 0;              /* zlib header max distance (INFLATE_STRICT) */
74311   this.check = 0;             /* protected copy of check value */
74312   this.total = 0;             /* protected copy of output count */
74313   // TODO: may be {}
74314   this.head = null;           /* where to save gzip header information */
74315
74316   /* sliding window */
74317   this.wbits = 0;             /* log base 2 of requested window size */
74318   this.wsize = 0;             /* window size or zero if not using window */
74319   this.whave = 0;             /* valid bytes in the window */
74320   this.wnext = 0;             /* window write index */
74321   this.window = null;         /* allocated sliding window, if needed */
74322
74323   /* bit accumulator */
74324   this.hold = 0;              /* input bit accumulator */
74325   this.bits = 0;              /* number of bits in "in" */
74326
74327   /* for string and stored block copying */
74328   this.length = 0;            /* literal or length of data to copy */
74329   this.offset = 0;            /* distance back to copy string from */
74330
74331   /* for table and code decoding */
74332   this.extra = 0;             /* extra bits needed */
74333
74334   /* fixed and dynamic code tables */
74335   this.lencode = null;          /* starting table for length/literal codes */
74336   this.distcode = null;         /* starting table for distance codes */
74337   this.lenbits = 0;           /* index bits for lencode */
74338   this.distbits = 0;          /* index bits for distcode */
74339
74340   /* dynamic table building */
74341   this.ncode = 0;             /* number of code length code lengths */
74342   this.nlen = 0;              /* number of length code lengths */
74343   this.ndist = 0;             /* number of distance code lengths */
74344   this.have = 0;              /* number of code lengths in lens[] */
74345   this.next = null;              /* next available space in codes[] */
74346
74347   this.lens = new Uint16Array(320); /* temporary storage for code lengths */
74348   this.work = new Uint16Array(288); /* work area for code table building */
74349
74350   /*
74351    because we don't have pointers in js, we use lencode and distcode directly
74352    as buffers so we don't need codes
74353   */
74354   //this.codes = new Int32Array(ENOUGH);       /* space for code tables */
74355   this.lendyn = null;              /* dynamic table for length/literal codes (JS specific) */
74356   this.distdyn = null;             /* dynamic table for distance codes (JS specific) */
74357   this.sane = 0;                   /* if false, allow invalid distance too far */
74358   this.back = 0;                   /* bits back of last unprocessed length/lit */
74359   this.was = 0;                    /* initial length of match */
74360 }
74361
74362
74363 const inflateResetKeep = (strm) => {
74364
74365   if (!strm || !strm.state) { return Z_STREAM_ERROR$1; }
74366   const state = strm.state;
74367   strm.total_in = strm.total_out = state.total = 0;
74368   strm.msg = ''; /*Z_NULL*/
74369   if (state.wrap) {       /* to support ill-conceived Java test suite */
74370     strm.adler = state.wrap & 1;
74371   }
74372   state.mode = HEAD;
74373   state.last = 0;
74374   state.havedict = 0;
74375   state.dmax = 32768;
74376   state.head = null/*Z_NULL*/;
74377   state.hold = 0;
74378   state.bits = 0;
74379   //state.lencode = state.distcode = state.next = state.codes;
74380   state.lencode = state.lendyn = new Int32Array(ENOUGH_LENS);
74381   state.distcode = state.distdyn = new Int32Array(ENOUGH_DISTS);
74382
74383   state.sane = 1;
74384   state.back = -1;
74385   //Tracev((stderr, "inflate: reset\n"));
74386   return Z_OK$1;
74387 };
74388
74389
74390 const inflateReset = (strm) => {
74391
74392   if (!strm || !strm.state) { return Z_STREAM_ERROR$1; }
74393   const state = strm.state;
74394   state.wsize = 0;
74395   state.whave = 0;
74396   state.wnext = 0;
74397   return inflateResetKeep(strm);
74398
74399 };
74400
74401
74402 const inflateReset2 = (strm, windowBits) => {
74403   let wrap;
74404
74405   /* get the state */
74406   if (!strm || !strm.state) { return Z_STREAM_ERROR$1; }
74407   const state = strm.state;
74408
74409   /* extract wrap request from windowBits parameter */
74410   if (windowBits < 0) {
74411     wrap = 0;
74412     windowBits = -windowBits;
74413   }
74414   else {
74415     wrap = (windowBits >> 4) + 1;
74416     if (windowBits < 48) {
74417       windowBits &= 15;
74418     }
74419   }
74420
74421   /* set number of window bits, free window if different */
74422   if (windowBits && (windowBits < 8 || windowBits > 15)) {
74423     return Z_STREAM_ERROR$1;
74424   }
74425   if (state.window !== null && state.wbits !== windowBits) {
74426     state.window = null;
74427   }
74428
74429   /* update state and reset the rest of it */
74430   state.wrap = wrap;
74431   state.wbits = windowBits;
74432   return inflateReset(strm);
74433 };
74434
74435
74436 const inflateInit2 = (strm, windowBits) => {
74437
74438   if (!strm) { return Z_STREAM_ERROR$1; }
74439   //strm.msg = Z_NULL;                 /* in case we return an error */
74440
74441   const state = new InflateState();
74442
74443   //if (state === Z_NULL) return Z_MEM_ERROR;
74444   //Tracev((stderr, "inflate: allocated\n"));
74445   strm.state = state;
74446   state.window = null/*Z_NULL*/;
74447   const ret = inflateReset2(strm, windowBits);
74448   if (ret !== Z_OK$1) {
74449     strm.state = null/*Z_NULL*/;
74450   }
74451   return ret;
74452 };
74453
74454
74455 const inflateInit = (strm) => {
74456
74457   return inflateInit2(strm, DEF_WBITS);
74458 };
74459
74460
74461 /*
74462  Return state with length and distance decoding tables and index sizes set to
74463  fixed code decoding.  Normally this returns fixed tables from inffixed.h.
74464  If BUILDFIXED is defined, then instead this routine builds the tables the
74465  first time it's called, and returns those tables the first time and
74466  thereafter.  This reduces the size of the code by about 2K bytes, in
74467  exchange for a little execution time.  However, BUILDFIXED should not be
74468  used for threaded applications, since the rewriting of the tables and virgin
74469  may not be thread-safe.
74470  */
74471 let virgin = true;
74472
74473 let lenfix, distfix; // We have no pointers in JS, so keep tables separate
74474
74475
74476 const fixedtables = (state) => {
74477
74478   /* build fixed huffman tables if first call (may not be thread safe) */
74479   if (virgin) {
74480     lenfix = new Int32Array(512);
74481     distfix = new Int32Array(32);
74482
74483     /* literal/length table */
74484     let sym = 0;
74485     while (sym < 144) { state.lens[sym++] = 8; }
74486     while (sym < 256) { state.lens[sym++] = 9; }
74487     while (sym < 280) { state.lens[sym++] = 7; }
74488     while (sym < 288) { state.lens[sym++] = 8; }
74489
74490     inftrees(LENS,  state.lens, 0, 288, lenfix,   0, state.work, { bits: 9 });
74491
74492     /* distance table */
74493     sym = 0;
74494     while (sym < 32) { state.lens[sym++] = 5; }
74495
74496     inftrees(DISTS, state.lens, 0, 32,   distfix, 0, state.work, { bits: 5 });
74497
74498     /* do this just once */
74499     virgin = false;
74500   }
74501
74502   state.lencode = lenfix;
74503   state.lenbits = 9;
74504   state.distcode = distfix;
74505   state.distbits = 5;
74506 };
74507
74508
74509 /*
74510  Update the window with the last wsize (normally 32K) bytes written before
74511  returning.  If window does not exist yet, create it.  This is only called
74512  when a window is already in use, or when output has been written during this
74513  inflate call, but the end of the deflate stream has not been reached yet.
74514  It is also called to create a window for dictionary data when a dictionary
74515  is loaded.
74516
74517  Providing output buffers larger than 32K to inflate() should provide a speed
74518  advantage, since only the last 32K of output is copied to the sliding window
74519  upon return from inflate(), and since all distances after the first 32K of
74520  output will fall in the output data, making match copies simpler and faster.
74521  The advantage may be dependent on the size of the processor's data caches.
74522  */
74523 const updatewindow = (strm, src, end, copy) => {
74524
74525   let dist;
74526   const state = strm.state;
74527
74528   /* if it hasn't been done already, allocate space for the window */
74529   if (state.window === null) {
74530     state.wsize = 1 << state.wbits;
74531     state.wnext = 0;
74532     state.whave = 0;
74533
74534     state.window = new Uint8Array(state.wsize);
74535   }
74536
74537   /* copy state->wsize or less output bytes into the circular window */
74538   if (copy >= state.wsize) {
74539     state.window.set(src.subarray(end - state.wsize, end), 0);
74540     state.wnext = 0;
74541     state.whave = state.wsize;
74542   }
74543   else {
74544     dist = state.wsize - state.wnext;
74545     if (dist > copy) {
74546       dist = copy;
74547     }
74548     //zmemcpy(state->window + state->wnext, end - copy, dist);
74549     state.window.set(src.subarray(end - copy, end - copy + dist), state.wnext);
74550     copy -= dist;
74551     if (copy) {
74552       //zmemcpy(state->window, end - copy, copy);
74553       state.window.set(src.subarray(end - copy, end), 0);
74554       state.wnext = copy;
74555       state.whave = state.wsize;
74556     }
74557     else {
74558       state.wnext += dist;
74559       if (state.wnext === state.wsize) { state.wnext = 0; }
74560       if (state.whave < state.wsize) { state.whave += dist; }
74561     }
74562   }
74563   return 0;
74564 };
74565
74566
74567 const inflate$2 = (strm, flush) => {
74568
74569   let state;
74570   let input, output;          // input/output buffers
74571   let next;                   /* next input INDEX */
74572   let put;                    /* next output INDEX */
74573   let have, left;             /* available input and output */
74574   let hold;                   /* bit buffer */
74575   let bits;                   /* bits in bit buffer */
74576   let _in, _out;              /* save starting available input and output */
74577   let copy;                   /* number of stored or match bytes to copy */
74578   let from;                   /* where to copy match bytes from */
74579   let from_source;
74580   let here = 0;               /* current decoding table entry */
74581   let here_bits, here_op, here_val; // paked "here" denormalized (JS specific)
74582   //let last;                   /* parent table entry */
74583   let last_bits, last_op, last_val; // paked "last" denormalized (JS specific)
74584   let len;                    /* length to copy for repeats, bits to drop */
74585   let ret;                    /* return code */
74586   const hbuf = new Uint8Array(4);    /* buffer for gzip header crc calculation */
74587   let opts;
74588
74589   let n; // temporary variable for NEED_BITS
74590
74591   const order = /* permutation of code lengths */
74592     new Uint8Array([ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ]);
74593
74594
74595   if (!strm || !strm.state || !strm.output ||
74596       (!strm.input && strm.avail_in !== 0)) {
74597     return Z_STREAM_ERROR$1;
74598   }
74599
74600   state = strm.state;
74601   if (state.mode === TYPE) { state.mode = TYPEDO; }    /* skip check */
74602
74603
74604   //--- LOAD() ---
74605   put = strm.next_out;
74606   output = strm.output;
74607   left = strm.avail_out;
74608   next = strm.next_in;
74609   input = strm.input;
74610   have = strm.avail_in;
74611   hold = state.hold;
74612   bits = state.bits;
74613   //---
74614
74615   _in = have;
74616   _out = left;
74617   ret = Z_OK$1;
74618
74619   inf_leave: // goto emulation
74620   for (;;) {
74621     switch (state.mode) {
74622       case HEAD:
74623         if (state.wrap === 0) {
74624           state.mode = TYPEDO;
74625           break;
74626         }
74627         //=== NEEDBITS(16);
74628         while (bits < 16) {
74629           if (have === 0) { break inf_leave; }
74630           have--;
74631           hold += input[next++] << bits;
74632           bits += 8;
74633         }
74634         //===//
74635         if ((state.wrap & 2) && hold === 0x8b1f) {  /* gzip header */
74636           state.check = 0/*crc32(0L, Z_NULL, 0)*/;
74637           //=== CRC2(state.check, hold);
74638           hbuf[0] = hold & 0xff;
74639           hbuf[1] = (hold >>> 8) & 0xff;
74640           state.check = crc32_1(state.check, hbuf, 2, 0);
74641           //===//
74642
74643           //=== INITBITS();
74644           hold = 0;
74645           bits = 0;
74646           //===//
74647           state.mode = FLAGS;
74648           break;
74649         }
74650         state.flags = 0;           /* expect zlib header */
74651         if (state.head) {
74652           state.head.done = false;
74653         }
74654         if (!(state.wrap & 1) ||   /* check if zlib header allowed */
74655           (((hold & 0xff)/*BITS(8)*/ << 8) + (hold >> 8)) % 31) {
74656           strm.msg = 'incorrect header check';
74657           state.mode = BAD;
74658           break;
74659         }
74660         if ((hold & 0x0f)/*BITS(4)*/ !== Z_DEFLATED) {
74661           strm.msg = 'unknown compression method';
74662           state.mode = BAD;
74663           break;
74664         }
74665         //--- DROPBITS(4) ---//
74666         hold >>>= 4;
74667         bits -= 4;
74668         //---//
74669         len = (hold & 0x0f)/*BITS(4)*/ + 8;
74670         if (state.wbits === 0) {
74671           state.wbits = len;
74672         }
74673         else if (len > state.wbits) {
74674           strm.msg = 'invalid window size';
74675           state.mode = BAD;
74676           break;
74677         }
74678
74679         // !!! pako patch. Force use `options.windowBits` if passed.
74680         // Required to always use max window size by default.
74681         state.dmax = 1 << state.wbits;
74682         //state.dmax = 1 << len;
74683
74684         //Tracev((stderr, "inflate:   zlib header ok\n"));
74685         strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;
74686         state.mode = hold & 0x200 ? DICTID : TYPE;
74687         //=== INITBITS();
74688         hold = 0;
74689         bits = 0;
74690         //===//
74691         break;
74692       case FLAGS:
74693         //=== NEEDBITS(16); */
74694         while (bits < 16) {
74695           if (have === 0) { break inf_leave; }
74696           have--;
74697           hold += input[next++] << bits;
74698           bits += 8;
74699         }
74700         //===//
74701         state.flags = hold;
74702         if ((state.flags & 0xff) !== Z_DEFLATED) {
74703           strm.msg = 'unknown compression method';
74704           state.mode = BAD;
74705           break;
74706         }
74707         if (state.flags & 0xe000) {
74708           strm.msg = 'unknown header flags set';
74709           state.mode = BAD;
74710           break;
74711         }
74712         if (state.head) {
74713           state.head.text = ((hold >> 8) & 1);
74714         }
74715         if (state.flags & 0x0200) {
74716           //=== CRC2(state.check, hold);
74717           hbuf[0] = hold & 0xff;
74718           hbuf[1] = (hold >>> 8) & 0xff;
74719           state.check = crc32_1(state.check, hbuf, 2, 0);
74720           //===//
74721         }
74722         //=== INITBITS();
74723         hold = 0;
74724         bits = 0;
74725         //===//
74726         state.mode = TIME;
74727         /* falls through */
74728       case TIME:
74729         //=== NEEDBITS(32); */
74730         while (bits < 32) {
74731           if (have === 0) { break inf_leave; }
74732           have--;
74733           hold += input[next++] << bits;
74734           bits += 8;
74735         }
74736         //===//
74737         if (state.head) {
74738           state.head.time = hold;
74739         }
74740         if (state.flags & 0x0200) {
74741           //=== CRC4(state.check, hold)
74742           hbuf[0] = hold & 0xff;
74743           hbuf[1] = (hold >>> 8) & 0xff;
74744           hbuf[2] = (hold >>> 16) & 0xff;
74745           hbuf[3] = (hold >>> 24) & 0xff;
74746           state.check = crc32_1(state.check, hbuf, 4, 0);
74747           //===
74748         }
74749         //=== INITBITS();
74750         hold = 0;
74751         bits = 0;
74752         //===//
74753         state.mode = OS;
74754         /* falls through */
74755       case OS:
74756         //=== NEEDBITS(16); */
74757         while (bits < 16) {
74758           if (have === 0) { break inf_leave; }
74759           have--;
74760           hold += input[next++] << bits;
74761           bits += 8;
74762         }
74763         //===//
74764         if (state.head) {
74765           state.head.xflags = (hold & 0xff);
74766           state.head.os = (hold >> 8);
74767         }
74768         if (state.flags & 0x0200) {
74769           //=== CRC2(state.check, hold);
74770           hbuf[0] = hold & 0xff;
74771           hbuf[1] = (hold >>> 8) & 0xff;
74772           state.check = crc32_1(state.check, hbuf, 2, 0);
74773           //===//
74774         }
74775         //=== INITBITS();
74776         hold = 0;
74777         bits = 0;
74778         //===//
74779         state.mode = EXLEN;
74780         /* falls through */
74781       case EXLEN:
74782         if (state.flags & 0x0400) {
74783           //=== NEEDBITS(16); */
74784           while (bits < 16) {
74785             if (have === 0) { break inf_leave; }
74786             have--;
74787             hold += input[next++] << bits;
74788             bits += 8;
74789           }
74790           //===//
74791           state.length = hold;
74792           if (state.head) {
74793             state.head.extra_len = hold;
74794           }
74795           if (state.flags & 0x0200) {
74796             //=== CRC2(state.check, hold);
74797             hbuf[0] = hold & 0xff;
74798             hbuf[1] = (hold >>> 8) & 0xff;
74799             state.check = crc32_1(state.check, hbuf, 2, 0);
74800             //===//
74801           }
74802           //=== INITBITS();
74803           hold = 0;
74804           bits = 0;
74805           //===//
74806         }
74807         else if (state.head) {
74808           state.head.extra = null/*Z_NULL*/;
74809         }
74810         state.mode = EXTRA;
74811         /* falls through */
74812       case EXTRA:
74813         if (state.flags & 0x0400) {
74814           copy = state.length;
74815           if (copy > have) { copy = have; }
74816           if (copy) {
74817             if (state.head) {
74818               len = state.head.extra_len - state.length;
74819               if (!state.head.extra) {
74820                 // Use untyped array for more convenient processing later
74821                 state.head.extra = new Uint8Array(state.head.extra_len);
74822               }
74823               state.head.extra.set(
74824                 input.subarray(
74825                   next,
74826                   // extra field is limited to 65536 bytes
74827                   // - no need for additional size check
74828                   next + copy
74829                 ),
74830                 /*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/
74831                 len
74832               );
74833               //zmemcpy(state.head.extra + len, next,
74834               //        len + copy > state.head.extra_max ?
74835               //        state.head.extra_max - len : copy);
74836             }
74837             if (state.flags & 0x0200) {
74838               state.check = crc32_1(state.check, input, copy, next);
74839             }
74840             have -= copy;
74841             next += copy;
74842             state.length -= copy;
74843           }
74844           if (state.length) { break inf_leave; }
74845         }
74846         state.length = 0;
74847         state.mode = NAME;
74848         /* falls through */
74849       case NAME:
74850         if (state.flags & 0x0800) {
74851           if (have === 0) { break inf_leave; }
74852           copy = 0;
74853           do {
74854             // TODO: 2 or 1 bytes?
74855             len = input[next + copy++];
74856             /* use constant limit because in js we should not preallocate memory */
74857             if (state.head && len &&
74858                 (state.length < 65536 /*state.head.name_max*/)) {
74859               state.head.name += String.fromCharCode(len);
74860             }
74861           } while (len && copy < have);
74862
74863           if (state.flags & 0x0200) {
74864             state.check = crc32_1(state.check, input, copy, next);
74865           }
74866           have -= copy;
74867           next += copy;
74868           if (len) { break inf_leave; }
74869         }
74870         else if (state.head) {
74871           state.head.name = null;
74872         }
74873         state.length = 0;
74874         state.mode = COMMENT;
74875         /* falls through */
74876       case COMMENT:
74877         if (state.flags & 0x1000) {
74878           if (have === 0) { break inf_leave; }
74879           copy = 0;
74880           do {
74881             len = input[next + copy++];
74882             /* use constant limit because in js we should not preallocate memory */
74883             if (state.head && len &&
74884                 (state.length < 65536 /*state.head.comm_max*/)) {
74885               state.head.comment += String.fromCharCode(len);
74886             }
74887           } while (len && copy < have);
74888           if (state.flags & 0x0200) {
74889             state.check = crc32_1(state.check, input, copy, next);
74890           }
74891           have -= copy;
74892           next += copy;
74893           if (len) { break inf_leave; }
74894         }
74895         else if (state.head) {
74896           state.head.comment = null;
74897         }
74898         state.mode = HCRC;
74899         /* falls through */
74900       case HCRC:
74901         if (state.flags & 0x0200) {
74902           //=== NEEDBITS(16); */
74903           while (bits < 16) {
74904             if (have === 0) { break inf_leave; }
74905             have--;
74906             hold += input[next++] << bits;
74907             bits += 8;
74908           }
74909           //===//
74910           if (hold !== (state.check & 0xffff)) {
74911             strm.msg = 'header crc mismatch';
74912             state.mode = BAD;
74913             break;
74914           }
74915           //=== INITBITS();
74916           hold = 0;
74917           bits = 0;
74918           //===//
74919         }
74920         if (state.head) {
74921           state.head.hcrc = ((state.flags >> 9) & 1);
74922           state.head.done = true;
74923         }
74924         strm.adler = state.check = 0;
74925         state.mode = TYPE;
74926         break;
74927       case DICTID:
74928         //=== NEEDBITS(32); */
74929         while (bits < 32) {
74930           if (have === 0) { break inf_leave; }
74931           have--;
74932           hold += input[next++] << bits;
74933           bits += 8;
74934         }
74935         //===//
74936         strm.adler = state.check = zswap32(hold);
74937         //=== INITBITS();
74938         hold = 0;
74939         bits = 0;
74940         //===//
74941         state.mode = DICT;
74942         /* falls through */
74943       case DICT:
74944         if (state.havedict === 0) {
74945           //--- RESTORE() ---
74946           strm.next_out = put;
74947           strm.avail_out = left;
74948           strm.next_in = next;
74949           strm.avail_in = have;
74950           state.hold = hold;
74951           state.bits = bits;
74952           //---
74953           return Z_NEED_DICT$1;
74954         }
74955         strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;
74956         state.mode = TYPE;
74957         /* falls through */
74958       case TYPE:
74959         if (flush === Z_BLOCK || flush === Z_TREES) { break inf_leave; }
74960         /* falls through */
74961       case TYPEDO:
74962         if (state.last) {
74963           //--- BYTEBITS() ---//
74964           hold >>>= bits & 7;
74965           bits -= bits & 7;
74966           //---//
74967           state.mode = CHECK;
74968           break;
74969         }
74970         //=== NEEDBITS(3); */
74971         while (bits < 3) {
74972           if (have === 0) { break inf_leave; }
74973           have--;
74974           hold += input[next++] << bits;
74975           bits += 8;
74976         }
74977         //===//
74978         state.last = (hold & 0x01)/*BITS(1)*/;
74979         //--- DROPBITS(1) ---//
74980         hold >>>= 1;
74981         bits -= 1;
74982         //---//
74983
74984         switch ((hold & 0x03)/*BITS(2)*/) {
74985           case 0:                             /* stored block */
74986             //Tracev((stderr, "inflate:     stored block%s\n",
74987             //        state.last ? " (last)" : ""));
74988             state.mode = STORED;
74989             break;
74990           case 1:                             /* fixed block */
74991             fixedtables(state);
74992             //Tracev((stderr, "inflate:     fixed codes block%s\n",
74993             //        state.last ? " (last)" : ""));
74994             state.mode = LEN_;             /* decode codes */
74995             if (flush === Z_TREES) {
74996               //--- DROPBITS(2) ---//
74997               hold >>>= 2;
74998               bits -= 2;
74999               //---//
75000               break inf_leave;
75001             }
75002             break;
75003           case 2:                             /* dynamic block */
75004             //Tracev((stderr, "inflate:     dynamic codes block%s\n",
75005             //        state.last ? " (last)" : ""));
75006             state.mode = TABLE;
75007             break;
75008           case 3:
75009             strm.msg = 'invalid block type';
75010             state.mode = BAD;
75011         }
75012         //--- DROPBITS(2) ---//
75013         hold >>>= 2;
75014         bits -= 2;
75015         //---//
75016         break;
75017       case STORED:
75018         //--- BYTEBITS() ---// /* go to byte boundary */
75019         hold >>>= bits & 7;
75020         bits -= bits & 7;
75021         //---//
75022         //=== NEEDBITS(32); */
75023         while (bits < 32) {
75024           if (have === 0) { break inf_leave; }
75025           have--;
75026           hold += input[next++] << bits;
75027           bits += 8;
75028         }
75029         //===//
75030         if ((hold & 0xffff) !== ((hold >>> 16) ^ 0xffff)) {
75031           strm.msg = 'invalid stored block lengths';
75032           state.mode = BAD;
75033           break;
75034         }
75035         state.length = hold & 0xffff;
75036         //Tracev((stderr, "inflate:       stored length %u\n",
75037         //        state.length));
75038         //=== INITBITS();
75039         hold = 0;
75040         bits = 0;
75041         //===//
75042         state.mode = COPY_;
75043         if (flush === Z_TREES) { break inf_leave; }
75044         /* falls through */
75045       case COPY_:
75046         state.mode = COPY;
75047         /* falls through */
75048       case COPY:
75049         copy = state.length;
75050         if (copy) {
75051           if (copy > have) { copy = have; }
75052           if (copy > left) { copy = left; }
75053           if (copy === 0) { break inf_leave; }
75054           //--- zmemcpy(put, next, copy); ---
75055           output.set(input.subarray(next, next + copy), put);
75056           //---//
75057           have -= copy;
75058           next += copy;
75059           left -= copy;
75060           put += copy;
75061           state.length -= copy;
75062           break;
75063         }
75064         //Tracev((stderr, "inflate:       stored end\n"));
75065         state.mode = TYPE;
75066         break;
75067       case TABLE:
75068         //=== NEEDBITS(14); */
75069         while (bits < 14) {
75070           if (have === 0) { break inf_leave; }
75071           have--;
75072           hold += input[next++] << bits;
75073           bits += 8;
75074         }
75075         //===//
75076         state.nlen = (hold & 0x1f)/*BITS(5)*/ + 257;
75077         //--- DROPBITS(5) ---//
75078         hold >>>= 5;
75079         bits -= 5;
75080         //---//
75081         state.ndist = (hold & 0x1f)/*BITS(5)*/ + 1;
75082         //--- DROPBITS(5) ---//
75083         hold >>>= 5;
75084         bits -= 5;
75085         //---//
75086         state.ncode = (hold & 0x0f)/*BITS(4)*/ + 4;
75087         //--- DROPBITS(4) ---//
75088         hold >>>= 4;
75089         bits -= 4;
75090         //---//
75091 //#ifndef PKZIP_BUG_WORKAROUND
75092         if (state.nlen > 286 || state.ndist > 30) {
75093           strm.msg = 'too many length or distance symbols';
75094           state.mode = BAD;
75095           break;
75096         }
75097 //#endif
75098         //Tracev((stderr, "inflate:       table sizes ok\n"));
75099         state.have = 0;
75100         state.mode = LENLENS;
75101         /* falls through */
75102       case LENLENS:
75103         while (state.have < state.ncode) {
75104           //=== NEEDBITS(3);
75105           while (bits < 3) {
75106             if (have === 0) { break inf_leave; }
75107             have--;
75108             hold += input[next++] << bits;
75109             bits += 8;
75110           }
75111           //===//
75112           state.lens[order[state.have++]] = (hold & 0x07);//BITS(3);
75113           //--- DROPBITS(3) ---//
75114           hold >>>= 3;
75115           bits -= 3;
75116           //---//
75117         }
75118         while (state.have < 19) {
75119           state.lens[order[state.have++]] = 0;
75120         }
75121         // We have separate tables & no pointers. 2 commented lines below not needed.
75122         //state.next = state.codes;
75123         //state.lencode = state.next;
75124         // Switch to use dynamic table
75125         state.lencode = state.lendyn;
75126         state.lenbits = 7;
75127
75128         opts = { bits: state.lenbits };
75129         ret = inftrees(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts);
75130         state.lenbits = opts.bits;
75131
75132         if (ret) {
75133           strm.msg = 'invalid code lengths set';
75134           state.mode = BAD;
75135           break;
75136         }
75137         //Tracev((stderr, "inflate:       code lengths ok\n"));
75138         state.have = 0;
75139         state.mode = CODELENS;
75140         /* falls through */
75141       case CODELENS:
75142         while (state.have < state.nlen + state.ndist) {
75143           for (;;) {
75144             here = state.lencode[hold & ((1 << state.lenbits) - 1)];/*BITS(state.lenbits)*/
75145             here_bits = here >>> 24;
75146             here_op = (here >>> 16) & 0xff;
75147             here_val = here & 0xffff;
75148
75149             if ((here_bits) <= bits) { break; }
75150             //--- PULLBYTE() ---//
75151             if (have === 0) { break inf_leave; }
75152             have--;
75153             hold += input[next++] << bits;
75154             bits += 8;
75155             //---//
75156           }
75157           if (here_val < 16) {
75158             //--- DROPBITS(here.bits) ---//
75159             hold >>>= here_bits;
75160             bits -= here_bits;
75161             //---//
75162             state.lens[state.have++] = here_val;
75163           }
75164           else {
75165             if (here_val === 16) {
75166               //=== NEEDBITS(here.bits + 2);
75167               n = here_bits + 2;
75168               while (bits < n) {
75169                 if (have === 0) { break inf_leave; }
75170                 have--;
75171                 hold += input[next++] << bits;
75172                 bits += 8;
75173               }
75174               //===//
75175               //--- DROPBITS(here.bits) ---//
75176               hold >>>= here_bits;
75177               bits -= here_bits;
75178               //---//
75179               if (state.have === 0) {
75180                 strm.msg = 'invalid bit length repeat';
75181                 state.mode = BAD;
75182                 break;
75183               }
75184               len = state.lens[state.have - 1];
75185               copy = 3 + (hold & 0x03);//BITS(2);
75186               //--- DROPBITS(2) ---//
75187               hold >>>= 2;
75188               bits -= 2;
75189               //---//
75190             }
75191             else if (here_val === 17) {
75192               //=== NEEDBITS(here.bits + 3);
75193               n = here_bits + 3;
75194               while (bits < n) {
75195                 if (have === 0) { break inf_leave; }
75196                 have--;
75197                 hold += input[next++] << bits;
75198                 bits += 8;
75199               }
75200               //===//
75201               //--- DROPBITS(here.bits) ---//
75202               hold >>>= here_bits;
75203               bits -= here_bits;
75204               //---//
75205               len = 0;
75206               copy = 3 + (hold & 0x07);//BITS(3);
75207               //--- DROPBITS(3) ---//
75208               hold >>>= 3;
75209               bits -= 3;
75210               //---//
75211             }
75212             else {
75213               //=== NEEDBITS(here.bits + 7);
75214               n = here_bits + 7;
75215               while (bits < n) {
75216                 if (have === 0) { break inf_leave; }
75217                 have--;
75218                 hold += input[next++] << bits;
75219                 bits += 8;
75220               }
75221               //===//
75222               //--- DROPBITS(here.bits) ---//
75223               hold >>>= here_bits;
75224               bits -= here_bits;
75225               //---//
75226               len = 0;
75227               copy = 11 + (hold & 0x7f);//BITS(7);
75228               //--- DROPBITS(7) ---//
75229               hold >>>= 7;
75230               bits -= 7;
75231               //---//
75232             }
75233             if (state.have + copy > state.nlen + state.ndist) {
75234               strm.msg = 'invalid bit length repeat';
75235               state.mode = BAD;
75236               break;
75237             }
75238             while (copy--) {
75239               state.lens[state.have++] = len;
75240             }
75241           }
75242         }
75243
75244         /* handle error breaks in while */
75245         if (state.mode === BAD) { break; }
75246
75247         /* check for end-of-block code (better have one) */
75248         if (state.lens[256] === 0) {
75249           strm.msg = 'invalid code -- missing end-of-block';
75250           state.mode = BAD;
75251           break;
75252         }
75253
75254         /* build code tables -- note: do not change the lenbits or distbits
75255            values here (9 and 6) without reading the comments in inftrees.h
75256            concerning the ENOUGH constants, which depend on those values */
75257         state.lenbits = 9;
75258
75259         opts = { bits: state.lenbits };
75260         ret = inftrees(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts);
75261         // We have separate tables & no pointers. 2 commented lines below not needed.
75262         // state.next_index = opts.table_index;
75263         state.lenbits = opts.bits;
75264         // state.lencode = state.next;
75265
75266         if (ret) {
75267           strm.msg = 'invalid literal/lengths set';
75268           state.mode = BAD;
75269           break;
75270         }
75271
75272         state.distbits = 6;
75273         //state.distcode.copy(state.codes);
75274         // Switch to use dynamic table
75275         state.distcode = state.distdyn;
75276         opts = { bits: state.distbits };
75277         ret = inftrees(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts);
75278         // We have separate tables & no pointers. 2 commented lines below not needed.
75279         // state.next_index = opts.table_index;
75280         state.distbits = opts.bits;
75281         // state.distcode = state.next;
75282
75283         if (ret) {
75284           strm.msg = 'invalid distances set';
75285           state.mode = BAD;
75286           break;
75287         }
75288         //Tracev((stderr, 'inflate:       codes ok\n'));
75289         state.mode = LEN_;
75290         if (flush === Z_TREES) { break inf_leave; }
75291         /* falls through */
75292       case LEN_:
75293         state.mode = LEN;
75294         /* falls through */
75295       case LEN:
75296         if (have >= 6 && left >= 258) {
75297           //--- RESTORE() ---
75298           strm.next_out = put;
75299           strm.avail_out = left;
75300           strm.next_in = next;
75301           strm.avail_in = have;
75302           state.hold = hold;
75303           state.bits = bits;
75304           //---
75305           inffast(strm, _out);
75306           //--- LOAD() ---
75307           put = strm.next_out;
75308           output = strm.output;
75309           left = strm.avail_out;
75310           next = strm.next_in;
75311           input = strm.input;
75312           have = strm.avail_in;
75313           hold = state.hold;
75314           bits = state.bits;
75315           //---
75316
75317           if (state.mode === TYPE) {
75318             state.back = -1;
75319           }
75320           break;
75321         }
75322         state.back = 0;
75323         for (;;) {
75324           here = state.lencode[hold & ((1 << state.lenbits) - 1)];  /*BITS(state.lenbits)*/
75325           here_bits = here >>> 24;
75326           here_op = (here >>> 16) & 0xff;
75327           here_val = here & 0xffff;
75328
75329           if (here_bits <= bits) { break; }
75330           //--- PULLBYTE() ---//
75331           if (have === 0) { break inf_leave; }
75332           have--;
75333           hold += input[next++] << bits;
75334           bits += 8;
75335           //---//
75336         }
75337         if (here_op && (here_op & 0xf0) === 0) {
75338           last_bits = here_bits;
75339           last_op = here_op;
75340           last_val = here_val;
75341           for (;;) {
75342             here = state.lencode[last_val +
75343                     ((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)];
75344             here_bits = here >>> 24;
75345             here_op = (here >>> 16) & 0xff;
75346             here_val = here & 0xffff;
75347
75348             if ((last_bits + here_bits) <= bits) { break; }
75349             //--- PULLBYTE() ---//
75350             if (have === 0) { break inf_leave; }
75351             have--;
75352             hold += input[next++] << bits;
75353             bits += 8;
75354             //---//
75355           }
75356           //--- DROPBITS(last.bits) ---//
75357           hold >>>= last_bits;
75358           bits -= last_bits;
75359           //---//
75360           state.back += last_bits;
75361         }
75362         //--- DROPBITS(here.bits) ---//
75363         hold >>>= here_bits;
75364         bits -= here_bits;
75365         //---//
75366         state.back += here_bits;
75367         state.length = here_val;
75368         if (here_op === 0) {
75369           //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
75370           //        "inflate:         literal '%c'\n" :
75371           //        "inflate:         literal 0x%02x\n", here.val));
75372           state.mode = LIT;
75373           break;
75374         }
75375         if (here_op & 32) {
75376           //Tracevv((stderr, "inflate:         end of block\n"));
75377           state.back = -1;
75378           state.mode = TYPE;
75379           break;
75380         }
75381         if (here_op & 64) {
75382           strm.msg = 'invalid literal/length code';
75383           state.mode = BAD;
75384           break;
75385         }
75386         state.extra = here_op & 15;
75387         state.mode = LENEXT;
75388         /* falls through */
75389       case LENEXT:
75390         if (state.extra) {
75391           //=== NEEDBITS(state.extra);
75392           n = state.extra;
75393           while (bits < n) {
75394             if (have === 0) { break inf_leave; }
75395             have--;
75396             hold += input[next++] << bits;
75397             bits += 8;
75398           }
75399           //===//
75400           state.length += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/;
75401           //--- DROPBITS(state.extra) ---//
75402           hold >>>= state.extra;
75403           bits -= state.extra;
75404           //---//
75405           state.back += state.extra;
75406         }
75407         //Tracevv((stderr, "inflate:         length %u\n", state.length));
75408         state.was = state.length;
75409         state.mode = DIST;
75410         /* falls through */
75411       case DIST:
75412         for (;;) {
75413           here = state.distcode[hold & ((1 << state.distbits) - 1)];/*BITS(state.distbits)*/
75414           here_bits = here >>> 24;
75415           here_op = (here >>> 16) & 0xff;
75416           here_val = here & 0xffff;
75417
75418           if ((here_bits) <= bits) { break; }
75419           //--- PULLBYTE() ---//
75420           if (have === 0) { break inf_leave; }
75421           have--;
75422           hold += input[next++] << bits;
75423           bits += 8;
75424           //---//
75425         }
75426         if ((here_op & 0xf0) === 0) {
75427           last_bits = here_bits;
75428           last_op = here_op;
75429           last_val = here_val;
75430           for (;;) {
75431             here = state.distcode[last_val +
75432                     ((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)];
75433             here_bits = here >>> 24;
75434             here_op = (here >>> 16) & 0xff;
75435             here_val = here & 0xffff;
75436
75437             if ((last_bits + here_bits) <= bits) { break; }
75438             //--- PULLBYTE() ---//
75439             if (have === 0) { break inf_leave; }
75440             have--;
75441             hold += input[next++] << bits;
75442             bits += 8;
75443             //---//
75444           }
75445           //--- DROPBITS(last.bits) ---//
75446           hold >>>= last_bits;
75447           bits -= last_bits;
75448           //---//
75449           state.back += last_bits;
75450         }
75451         //--- DROPBITS(here.bits) ---//
75452         hold >>>= here_bits;
75453         bits -= here_bits;
75454         //---//
75455         state.back += here_bits;
75456         if (here_op & 64) {
75457           strm.msg = 'invalid distance code';
75458           state.mode = BAD;
75459           break;
75460         }
75461         state.offset = here_val;
75462         state.extra = (here_op) & 15;
75463         state.mode = DISTEXT;
75464         /* falls through */
75465       case DISTEXT:
75466         if (state.extra) {
75467           //=== NEEDBITS(state.extra);
75468           n = state.extra;
75469           while (bits < n) {
75470             if (have === 0) { break inf_leave; }
75471             have--;
75472             hold += input[next++] << bits;
75473             bits += 8;
75474           }
75475           //===//
75476           state.offset += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/;
75477           //--- DROPBITS(state.extra) ---//
75478           hold >>>= state.extra;
75479           bits -= state.extra;
75480           //---//
75481           state.back += state.extra;
75482         }
75483 //#ifdef INFLATE_STRICT
75484         if (state.offset > state.dmax) {
75485           strm.msg = 'invalid distance too far back';
75486           state.mode = BAD;
75487           break;
75488         }
75489 //#endif
75490         //Tracevv((stderr, "inflate:         distance %u\n", state.offset));
75491         state.mode = MATCH;
75492         /* falls through */
75493       case MATCH:
75494         if (left === 0) { break inf_leave; }
75495         copy = _out - left;
75496         if (state.offset > copy) {         /* copy from window */
75497           copy = state.offset - copy;
75498           if (copy > state.whave) {
75499             if (state.sane) {
75500               strm.msg = 'invalid distance too far back';
75501               state.mode = BAD;
75502               break;
75503             }
75504 // (!) This block is disabled in zlib defaults,
75505 // don't enable it for binary compatibility
75506 //#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
75507 //          Trace((stderr, "inflate.c too far\n"));
75508 //          copy -= state.whave;
75509 //          if (copy > state.length) { copy = state.length; }
75510 //          if (copy > left) { copy = left; }
75511 //          left -= copy;
75512 //          state.length -= copy;
75513 //          do {
75514 //            output[put++] = 0;
75515 //          } while (--copy);
75516 //          if (state.length === 0) { state.mode = LEN; }
75517 //          break;
75518 //#endif
75519           }
75520           if (copy > state.wnext) {
75521             copy -= state.wnext;
75522             from = state.wsize - copy;
75523           }
75524           else {
75525             from = state.wnext - copy;
75526           }
75527           if (copy > state.length) { copy = state.length; }
75528           from_source = state.window;
75529         }
75530         else {                              /* copy from output */
75531           from_source = output;
75532           from = put - state.offset;
75533           copy = state.length;
75534         }
75535         if (copy > left) { copy = left; }
75536         left -= copy;
75537         state.length -= copy;
75538         do {
75539           output[put++] = from_source[from++];
75540         } while (--copy);
75541         if (state.length === 0) { state.mode = LEN; }
75542         break;
75543       case LIT:
75544         if (left === 0) { break inf_leave; }
75545         output[put++] = state.length;
75546         left--;
75547         state.mode = LEN;
75548         break;
75549       case CHECK:
75550         if (state.wrap) {
75551           //=== NEEDBITS(32);
75552           while (bits < 32) {
75553             if (have === 0) { break inf_leave; }
75554             have--;
75555             // Use '|' instead of '+' to make sure that result is signed
75556             hold |= input[next++] << bits;
75557             bits += 8;
75558           }
75559           //===//
75560           _out -= left;
75561           strm.total_out += _out;
75562           state.total += _out;
75563           if (_out) {
75564             strm.adler = state.check =
75565                 /*UPDATE(state.check, put - _out, _out);*/
75566                 (state.flags ? crc32_1(state.check, output, _out, put - _out) : adler32_1(state.check, output, _out, put - _out));
75567
75568           }
75569           _out = left;
75570           // NB: crc32 stored as signed 32-bit int, zswap32 returns signed too
75571           if ((state.flags ? hold : zswap32(hold)) !== state.check) {
75572             strm.msg = 'incorrect data check';
75573             state.mode = BAD;
75574             break;
75575           }
75576           //=== INITBITS();
75577           hold = 0;
75578           bits = 0;
75579           //===//
75580           //Tracev((stderr, "inflate:   check matches trailer\n"));
75581         }
75582         state.mode = LENGTH;
75583         /* falls through */
75584       case LENGTH:
75585         if (state.wrap && state.flags) {
75586           //=== NEEDBITS(32);
75587           while (bits < 32) {
75588             if (have === 0) { break inf_leave; }
75589             have--;
75590             hold += input[next++] << bits;
75591             bits += 8;
75592           }
75593           //===//
75594           if (hold !== (state.total & 0xffffffff)) {
75595             strm.msg = 'incorrect length check';
75596             state.mode = BAD;
75597             break;
75598           }
75599           //=== INITBITS();
75600           hold = 0;
75601           bits = 0;
75602           //===//
75603           //Tracev((stderr, "inflate:   length matches trailer\n"));
75604         }
75605         state.mode = DONE;
75606         /* falls through */
75607       case DONE:
75608         ret = Z_STREAM_END$1;
75609         break inf_leave;
75610       case BAD:
75611         ret = Z_DATA_ERROR$1;
75612         break inf_leave;
75613       case MEM:
75614         return Z_MEM_ERROR$1;
75615       case SYNC:
75616         /* falls through */
75617       default:
75618         return Z_STREAM_ERROR$1;
75619     }
75620   }
75621
75622   // inf_leave <- here is real place for "goto inf_leave", emulated via "break inf_leave"
75623
75624   /*
75625      Return from inflate(), updating the total counts and the check value.
75626      If there was no progress during the inflate() call, return a buffer
75627      error.  Call updatewindow() to create and/or update the window state.
75628      Note: a memory error from inflate() is non-recoverable.
75629    */
75630
75631   //--- RESTORE() ---
75632   strm.next_out = put;
75633   strm.avail_out = left;
75634   strm.next_in = next;
75635   strm.avail_in = have;
75636   state.hold = hold;
75637   state.bits = bits;
75638   //---
75639
75640   if (state.wsize || (_out !== strm.avail_out && state.mode < BAD &&
75641                       (state.mode < CHECK || flush !== Z_FINISH$1))) {
75642     if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) ;
75643   }
75644   _in -= strm.avail_in;
75645   _out -= strm.avail_out;
75646   strm.total_in += _in;
75647   strm.total_out += _out;
75648   state.total += _out;
75649   if (state.wrap && _out) {
75650     strm.adler = state.check = /*UPDATE(state.check, strm.next_out - _out, _out);*/
75651       (state.flags ? crc32_1(state.check, output, _out, strm.next_out - _out) : adler32_1(state.check, output, _out, strm.next_out - _out));
75652   }
75653   strm.data_type = state.bits + (state.last ? 64 : 0) +
75654                     (state.mode === TYPE ? 128 : 0) +
75655                     (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0);
75656   if (((_in === 0 && _out === 0) || flush === Z_FINISH$1) && ret === Z_OK$1) {
75657     ret = Z_BUF_ERROR;
75658   }
75659   return ret;
75660 };
75661
75662
75663 const inflateEnd = (strm) => {
75664
75665   if (!strm || !strm.state /*|| strm->zfree == (free_func)0*/) {
75666     return Z_STREAM_ERROR$1;
75667   }
75668
75669   let state = strm.state;
75670   if (state.window) {
75671     state.window = null;
75672   }
75673   strm.state = null;
75674   return Z_OK$1;
75675 };
75676
75677
75678 const inflateGetHeader = (strm, head) => {
75679
75680   /* check state */
75681   if (!strm || !strm.state) { return Z_STREAM_ERROR$1; }
75682   const state = strm.state;
75683   if ((state.wrap & 2) === 0) { return Z_STREAM_ERROR$1; }
75684
75685   /* save header structure */
75686   state.head = head;
75687   head.done = false;
75688   return Z_OK$1;
75689 };
75690
75691
75692 const inflateSetDictionary = (strm, dictionary) => {
75693   const dictLength = dictionary.length;
75694
75695   let state;
75696   let dictid;
75697   let ret;
75698
75699   /* check state */
75700   if (!strm /* == Z_NULL */ || !strm.state /* == Z_NULL */) { return Z_STREAM_ERROR$1; }
75701   state = strm.state;
75702
75703   if (state.wrap !== 0 && state.mode !== DICT) {
75704     return Z_STREAM_ERROR$1;
75705   }
75706
75707   /* check for correct dictionary identifier */
75708   if (state.mode === DICT) {
75709     dictid = 1; /* adler32(0, null, 0)*/
75710     /* dictid = adler32(dictid, dictionary, dictLength); */
75711     dictid = adler32_1(dictid, dictionary, dictLength, 0);
75712     if (dictid !== state.check) {
75713       return Z_DATA_ERROR$1;
75714     }
75715   }
75716   /* copy dictionary to window using updatewindow(), which will amend the
75717    existing dictionary if appropriate */
75718   ret = updatewindow(strm, dictionary, dictLength, dictLength);
75719   if (ret) {
75720     state.mode = MEM;
75721     return Z_MEM_ERROR$1;
75722   }
75723   state.havedict = 1;
75724   // Tracev((stderr, "inflate:   dictionary set\n"));
75725   return Z_OK$1;
75726 };
75727
75728
75729 var inflateReset_1 = inflateReset;
75730 var inflateReset2_1 = inflateReset2;
75731 var inflateResetKeep_1 = inflateResetKeep;
75732 var inflateInit_1 = inflateInit;
75733 var inflateInit2_1 = inflateInit2;
75734 var inflate_2$1 = inflate$2;
75735 var inflateEnd_1 = inflateEnd;
75736 var inflateGetHeader_1 = inflateGetHeader;
75737 var inflateSetDictionary_1 = inflateSetDictionary;
75738 var inflateInfo = 'pako inflate (from Nodeca project)';
75739
75740 /* Not implemented
75741 module.exports.inflateCopy = inflateCopy;
75742 module.exports.inflateGetDictionary = inflateGetDictionary;
75743 module.exports.inflateMark = inflateMark;
75744 module.exports.inflatePrime = inflatePrime;
75745 module.exports.inflateSync = inflateSync;
75746 module.exports.inflateSyncPoint = inflateSyncPoint;
75747 module.exports.inflateUndermine = inflateUndermine;
75748 */
75749
75750 var inflate_1$2 = {
75751         inflateReset: inflateReset_1,
75752         inflateReset2: inflateReset2_1,
75753         inflateResetKeep: inflateResetKeep_1,
75754         inflateInit: inflateInit_1,
75755         inflateInit2: inflateInit2_1,
75756         inflate: inflate_2$1,
75757         inflateEnd: inflateEnd_1,
75758         inflateGetHeader: inflateGetHeader_1,
75759         inflateSetDictionary: inflateSetDictionary_1,
75760         inflateInfo: inflateInfo
75761 };
75762
75763 // (C) 1995-2013 Jean-loup Gailly and Mark Adler
75764 // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
75765 //
75766 // This software is provided 'as-is', without any express or implied
75767 // warranty. In no event will the authors be held liable for any damages
75768 // arising from the use of this software.
75769 //
75770 // Permission is granted to anyone to use this software for any purpose,
75771 // including commercial applications, and to alter it and redistribute it
75772 // freely, subject to the following restrictions:
75773 //
75774 // 1. The origin of this software must not be misrepresented; you must not
75775 //   claim that you wrote the original software. If you use this software
75776 //   in a product, an acknowledgment in the product documentation would be
75777 //   appreciated but is not required.
75778 // 2. Altered source versions must be plainly marked as such, and must not be
75779 //   misrepresented as being the original software.
75780 // 3. This notice may not be removed or altered from any source distribution.
75781
75782 function GZheader() {
75783   /* true if compressed data believed to be text */
75784   this.text       = 0;
75785   /* modification time */
75786   this.time       = 0;
75787   /* extra flags (not used when writing a gzip file) */
75788   this.xflags     = 0;
75789   /* operating system */
75790   this.os         = 0;
75791   /* pointer to extra field or Z_NULL if none */
75792   this.extra      = null;
75793   /* extra field length (valid if extra != Z_NULL) */
75794   this.extra_len  = 0; // Actually, we don't need it in JS,
75795                        // but leave for few code modifications
75796
75797   //
75798   // Setup limits is not necessary because in js we should not preallocate memory
75799   // for inflate use constant limit in 65536 bytes
75800   //
75801
75802   /* space at extra (only when reading header) */
75803   // this.extra_max  = 0;
75804   /* pointer to zero-terminated file name or Z_NULL */
75805   this.name       = '';
75806   /* space at name (only when reading header) */
75807   // this.name_max   = 0;
75808   /* pointer to zero-terminated comment or Z_NULL */
75809   this.comment    = '';
75810   /* space at comment (only when reading header) */
75811   // this.comm_max   = 0;
75812   /* true if there was or will be a header crc */
75813   this.hcrc       = 0;
75814   /* true when done reading gzip header (not used when writing a gzip file) */
75815   this.done       = false;
75816 }
75817
75818 var gzheader = GZheader;
75819
75820 const toString = Object.prototype.toString;
75821
75822 /* Public constants ==========================================================*/
75823 /* ===========================================================================*/
75824
75825 const {
75826   Z_NO_FLUSH, Z_FINISH,
75827   Z_OK, Z_STREAM_END, Z_NEED_DICT, Z_STREAM_ERROR, Z_DATA_ERROR, Z_MEM_ERROR
75828 } = constants$2;
75829
75830 /* ===========================================================================*/
75831
75832
75833 /**
75834  * class Inflate
75835  *
75836  * Generic JS-style wrapper for zlib calls. If you don't need
75837  * streaming behaviour - use more simple functions: [[inflate]]
75838  * and [[inflateRaw]].
75839  **/
75840
75841 /* internal
75842  * inflate.chunks -> Array
75843  *
75844  * Chunks of output data, if [[Inflate#onData]] not overridden.
75845  **/
75846
75847 /**
75848  * Inflate.result -> Uint8Array|String
75849  *
75850  * Uncompressed result, generated by default [[Inflate#onData]]
75851  * and [[Inflate#onEnd]] handlers. Filled after you push last chunk
75852  * (call [[Inflate#push]] with `Z_FINISH` / `true` param).
75853  **/
75854
75855 /**
75856  * Inflate.err -> Number
75857  *
75858  * Error code after inflate finished. 0 (Z_OK) on success.
75859  * Should be checked if broken data possible.
75860  **/
75861
75862 /**
75863  * Inflate.msg -> String
75864  *
75865  * Error message, if [[Inflate.err]] != 0
75866  **/
75867
75868
75869 /**
75870  * new Inflate(options)
75871  * - options (Object): zlib inflate options.
75872  *
75873  * Creates new inflator instance with specified params. Throws exception
75874  * on bad params. Supported options:
75875  *
75876  * - `windowBits`
75877  * - `dictionary`
75878  *
75879  * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
75880  * for more information on these.
75881  *
75882  * Additional options, for internal needs:
75883  *
75884  * - `chunkSize` - size of generated data chunks (16K by default)
75885  * - `raw` (Boolean) - do raw inflate
75886  * - `to` (String) - if equal to 'string', then result will be converted
75887  *   from utf8 to utf16 (javascript) string. When string output requested,
75888  *   chunk length can differ from `chunkSize`, depending on content.
75889  *
75890  * By default, when no options set, autodetect deflate/gzip data format via
75891  * wrapper header.
75892  *
75893  * ##### Example:
75894  *
75895  * ```javascript
75896  * const pako = require('pako')
75897  * const chunk1 = new Uint8Array([1,2,3,4,5,6,7,8,9])
75898  * const chunk2 = new Uint8Array([10,11,12,13,14,15,16,17,18,19]);
75899  *
75900  * const inflate = new pako.Inflate({ level: 3});
75901  *
75902  * inflate.push(chunk1, false);
75903  * inflate.push(chunk2, true);  // true -> last chunk
75904  *
75905  * if (inflate.err) { throw new Error(inflate.err); }
75906  *
75907  * console.log(inflate.result);
75908  * ```
75909  **/
75910 function Inflate$1(options) {
75911   this.options = common.assign({
75912     chunkSize: 1024 * 64,
75913     windowBits: 15,
75914     to: ''
75915   }, options || {});
75916
75917   const opt = this.options;
75918
75919   // Force window size for `raw` data, if not set directly,
75920   // because we have no header for autodetect.
75921   if (opt.raw && (opt.windowBits >= 0) && (opt.windowBits < 16)) {
75922     opt.windowBits = -opt.windowBits;
75923     if (opt.windowBits === 0) { opt.windowBits = -15; }
75924   }
75925
75926   // If `windowBits` not defined (and mode not raw) - set autodetect flag for gzip/deflate
75927   if ((opt.windowBits >= 0) && (opt.windowBits < 16) &&
75928       !(options && options.windowBits)) {
75929     opt.windowBits += 32;
75930   }
75931
75932   // Gzip header has no info about windows size, we can do autodetect only
75933   // for deflate. So, if window size not set, force it to max when gzip possible
75934   if ((opt.windowBits > 15) && (opt.windowBits < 48)) {
75935     // bit 3 (16) -> gzipped data
75936     // bit 4 (32) -> autodetect gzip/deflate
75937     if ((opt.windowBits & 15) === 0) {
75938       opt.windowBits |= 15;
75939     }
75940   }
75941
75942   this.err    = 0;      // error code, if happens (0 = Z_OK)
75943   this.msg    = '';     // error message
75944   this.ended  = false;  // used to avoid multiple onEnd() calls
75945   this.chunks = [];     // chunks of compressed data
75946
75947   this.strm   = new zstream();
75948   this.strm.avail_out = 0;
75949
75950   let status  = inflate_1$2.inflateInit2(
75951     this.strm,
75952     opt.windowBits
75953   );
75954
75955   if (status !== Z_OK) {
75956     throw new Error(messages[status]);
75957   }
75958
75959   this.header = new gzheader();
75960
75961   inflate_1$2.inflateGetHeader(this.strm, this.header);
75962
75963   // Setup dictionary
75964   if (opt.dictionary) {
75965     // Convert data if needed
75966     if (typeof opt.dictionary === 'string') {
75967       opt.dictionary = strings.string2buf(opt.dictionary);
75968     } else if (toString.call(opt.dictionary) === '[object ArrayBuffer]') {
75969       opt.dictionary = new Uint8Array(opt.dictionary);
75970     }
75971     if (opt.raw) { //In raw mode we need to set the dictionary early
75972       status = inflate_1$2.inflateSetDictionary(this.strm, opt.dictionary);
75973       if (status !== Z_OK) {
75974         throw new Error(messages[status]);
75975       }
75976     }
75977   }
75978 }
75979
75980 /**
75981  * Inflate#push(data[, flush_mode]) -> Boolean
75982  * - data (Uint8Array|ArrayBuffer): input data
75983  * - flush_mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE
75984  *   flush modes. See constants. Skipped or `false` means Z_NO_FLUSH,
75985  *   `true` means Z_FINISH.
75986  *
75987  * Sends input data to inflate pipe, generating [[Inflate#onData]] calls with
75988  * new output chunks. Returns `true` on success. If end of stream detected,
75989  * [[Inflate#onEnd]] will be called.
75990  *
75991  * `flush_mode` is not needed for normal operation, because end of stream
75992  * detected automatically. You may try to use it for advanced things, but
75993  * this functionality was not tested.
75994  *
75995  * On fail call [[Inflate#onEnd]] with error code and return false.
75996  *
75997  * ##### Example
75998  *
75999  * ```javascript
76000  * push(chunk, false); // push one of data chunks
76001  * ...
76002  * push(chunk, true);  // push last chunk
76003  * ```
76004  **/
76005 Inflate$1.prototype.push = function (data, flush_mode) {
76006   const strm = this.strm;
76007   const chunkSize = this.options.chunkSize;
76008   const dictionary = this.options.dictionary;
76009   let status, _flush_mode, last_avail_out;
76010
76011   if (this.ended) return false;
76012
76013   if (flush_mode === ~~flush_mode) _flush_mode = flush_mode;
76014   else _flush_mode = flush_mode === true ? Z_FINISH : Z_NO_FLUSH;
76015
76016   // Convert data if needed
76017   if (toString.call(data) === '[object ArrayBuffer]') {
76018     strm.input = new Uint8Array(data);
76019   } else {
76020     strm.input = data;
76021   }
76022
76023   strm.next_in = 0;
76024   strm.avail_in = strm.input.length;
76025
76026   for (;;) {
76027     if (strm.avail_out === 0) {
76028       strm.output = new Uint8Array(chunkSize);
76029       strm.next_out = 0;
76030       strm.avail_out = chunkSize;
76031     }
76032
76033     status = inflate_1$2.inflate(strm, _flush_mode);
76034
76035     if (status === Z_NEED_DICT && dictionary) {
76036       status = inflate_1$2.inflateSetDictionary(strm, dictionary);
76037
76038       if (status === Z_OK) {
76039         status = inflate_1$2.inflate(strm, _flush_mode);
76040       } else if (status === Z_DATA_ERROR) {
76041         // Replace code with more verbose
76042         status = Z_NEED_DICT;
76043       }
76044     }
76045
76046     // Skip snyc markers if more data follows and not raw mode
76047     while (strm.avail_in > 0 &&
76048            status === Z_STREAM_END &&
76049            strm.state.wrap > 0 &&
76050            data[strm.next_in] !== 0)
76051     {
76052       inflate_1$2.inflateReset(strm);
76053       status = inflate_1$2.inflate(strm, _flush_mode);
76054     }
76055
76056     switch (status) {
76057       case Z_STREAM_ERROR:
76058       case Z_DATA_ERROR:
76059       case Z_NEED_DICT:
76060       case Z_MEM_ERROR:
76061         this.onEnd(status);
76062         this.ended = true;
76063         return false;
76064     }
76065
76066     // Remember real `avail_out` value, because we may patch out buffer content
76067     // to align utf8 strings boundaries.
76068     last_avail_out = strm.avail_out;
76069
76070     if (strm.next_out) {
76071       if (strm.avail_out === 0 || status === Z_STREAM_END) {
76072
76073         if (this.options.to === 'string') {
76074
76075           let next_out_utf8 = strings.utf8border(strm.output, strm.next_out);
76076
76077           let tail = strm.next_out - next_out_utf8;
76078           let utf8str = strings.buf2string(strm.output, next_out_utf8);
76079
76080           // move tail & realign counters
76081           strm.next_out = tail;
76082           strm.avail_out = chunkSize - tail;
76083           if (tail) strm.output.set(strm.output.subarray(next_out_utf8, next_out_utf8 + tail), 0);
76084
76085           this.onData(utf8str);
76086
76087         } else {
76088           this.onData(strm.output.length === strm.next_out ? strm.output : strm.output.subarray(0, strm.next_out));
76089         }
76090       }
76091     }
76092
76093     // Must repeat iteration if out buffer is full
76094     if (status === Z_OK && last_avail_out === 0) continue;
76095
76096     // Finalize if end of stream reached.
76097     if (status === Z_STREAM_END) {
76098       status = inflate_1$2.inflateEnd(this.strm);
76099       this.onEnd(status);
76100       this.ended = true;
76101       return true;
76102     }
76103
76104     if (strm.avail_in === 0) break;
76105   }
76106
76107   return true;
76108 };
76109
76110
76111 /**
76112  * Inflate#onData(chunk) -> Void
76113  * - chunk (Uint8Array|String): output data. When string output requested,
76114  *   each chunk will be string.
76115  *
76116  * By default, stores data blocks in `chunks[]` property and glue
76117  * those in `onEnd`. Override this handler, if you need another behaviour.
76118  **/
76119 Inflate$1.prototype.onData = function (chunk) {
76120   this.chunks.push(chunk);
76121 };
76122
76123
76124 /**
76125  * Inflate#onEnd(status) -> Void
76126  * - status (Number): inflate status. 0 (Z_OK) on success,
76127  *   other if not.
76128  *
76129  * Called either after you tell inflate that the input stream is
76130  * complete (Z_FINISH). By default - join collected chunks,
76131  * free memory and fill `results` / `err` properties.
76132  **/
76133 Inflate$1.prototype.onEnd = function (status) {
76134   // On success - join
76135   if (status === Z_OK) {
76136     if (this.options.to === 'string') {
76137       this.result = this.chunks.join('');
76138     } else {
76139       this.result = common.flattenChunks(this.chunks);
76140     }
76141   }
76142   this.chunks = [];
76143   this.err = status;
76144   this.msg = this.strm.msg;
76145 };
76146
76147
76148 /**
76149  * inflate(data[, options]) -> Uint8Array|String
76150  * - data (Uint8Array): input data to decompress.
76151  * - options (Object): zlib inflate options.
76152  *
76153  * Decompress `data` with inflate/ungzip and `options`. Autodetect
76154  * format via wrapper header by default. That's why we don't provide
76155  * separate `ungzip` method.
76156  *
76157  * Supported options are:
76158  *
76159  * - windowBits
76160  *
76161  * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
76162  * for more information.
76163  *
76164  * Sugar (options):
76165  *
76166  * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify
76167  *   negative windowBits implicitly.
76168  * - `to` (String) - if equal to 'string', then result will be converted
76169  *   from utf8 to utf16 (javascript) string. When string output requested,
76170  *   chunk length can differ from `chunkSize`, depending on content.
76171  *
76172  *
76173  * ##### Example:
76174  *
76175  * ```javascript
76176  * const pako = require('pako');
76177  * const input = pako.deflate(new Uint8Array([1,2,3,4,5,6,7,8,9]));
76178  * let output;
76179  *
76180  * try {
76181  *   output = pako.inflate(input);
76182  * } catch (err) {
76183  *   console.log(err);
76184  * }
76185  * ```
76186  **/
76187 function inflate$1(input, options) {
76188   const inflator = new Inflate$1(options);
76189
76190   inflator.push(input);
76191
76192   // That will never happens, if you don't cheat with options :)
76193   if (inflator.err) throw inflator.msg || messages[inflator.err];
76194
76195   return inflator.result;
76196 }
76197
76198
76199 /**
76200  * inflateRaw(data[, options]) -> Uint8Array|String
76201  * - data (Uint8Array): input data to decompress.
76202  * - options (Object): zlib inflate options.
76203  *
76204  * The same as [[inflate]], but creates raw data, without wrapper
76205  * (header and adler32 crc).
76206  **/
76207 function inflateRaw$1(input, options) {
76208   options = options || {};
76209   options.raw = true;
76210   return inflate$1(input, options);
76211 }
76212
76213
76214 /**
76215  * ungzip(data[, options]) -> Uint8Array|String
76216  * - data (Uint8Array): input data to decompress.
76217  * - options (Object): zlib inflate options.
76218  *
76219  * Just shortcut to [[inflate]], because it autodetects format
76220  * by header.content. Done for convenience.
76221  **/
76222
76223
76224 var Inflate_1$1 = Inflate$1;
76225 var inflate_2 = inflate$1;
76226 var inflateRaw_1$1 = inflateRaw$1;
76227 var ungzip$1 = inflate$1;
76228 var constants = constants$2;
76229
76230 var inflate_1$1 = {
76231         Inflate: Inflate_1$1,
76232         inflate: inflate_2,
76233         inflateRaw: inflateRaw_1$1,
76234         ungzip: ungzip$1,
76235         constants: constants
76236 };
76237
76238 const { Inflate, inflate, inflateRaw, ungzip } = inflate_1$1;
76239 var inflate_1 = inflate;
76240
76241 var ieee754$1 = {};
76242
76243 /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
76244
76245 ieee754$1.read = function (buffer, offset, isLE, mLen, nBytes) {
76246   var e, m;
76247   var eLen = (nBytes * 8) - mLen - 1;
76248   var eMax = (1 << eLen) - 1;
76249   var eBias = eMax >> 1;
76250   var nBits = -7;
76251   var i = isLE ? (nBytes - 1) : 0;
76252   var d = isLE ? -1 : 1;
76253   var s = buffer[offset + i];
76254
76255   i += d;
76256
76257   e = s & ((1 << (-nBits)) - 1);
76258   s >>= (-nBits);
76259   nBits += eLen;
76260   for (; nBits > 0; e = (e * 256) + buffer[offset + i], i += d, nBits -= 8) {}
76261
76262   m = e & ((1 << (-nBits)) - 1);
76263   e >>= (-nBits);
76264   nBits += mLen;
76265   for (; nBits > 0; m = (m * 256) + buffer[offset + i], i += d, nBits -= 8) {}
76266
76267   if (e === 0) {
76268     e = 1 - eBias;
76269   } else if (e === eMax) {
76270     return m ? NaN : ((s ? -1 : 1) * Infinity)
76271   } else {
76272     m = m + Math.pow(2, mLen);
76273     e = e - eBias;
76274   }
76275   return (s ? -1 : 1) * m * Math.pow(2, e - mLen)
76276 };
76277
76278 ieee754$1.write = function (buffer, value, offset, isLE, mLen, nBytes) {
76279   var e, m, c;
76280   var eLen = (nBytes * 8) - mLen - 1;
76281   var eMax = (1 << eLen) - 1;
76282   var eBias = eMax >> 1;
76283   var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0);
76284   var i = isLE ? 0 : (nBytes - 1);
76285   var d = isLE ? 1 : -1;
76286   var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0;
76287
76288   value = Math.abs(value);
76289
76290   if (isNaN(value) || value === Infinity) {
76291     m = isNaN(value) ? 1 : 0;
76292     e = eMax;
76293   } else {
76294     e = Math.floor(Math.log(value) / Math.LN2);
76295     if (value * (c = Math.pow(2, -e)) < 1) {
76296       e--;
76297       c *= 2;
76298     }
76299     if (e + eBias >= 1) {
76300       value += rt / c;
76301     } else {
76302       value += rt * Math.pow(2, 1 - eBias);
76303     }
76304     if (value * c >= 2) {
76305       e++;
76306       c /= 2;
76307     }
76308
76309     if (e + eBias >= eMax) {
76310       m = 0;
76311       e = eMax;
76312     } else if (e + eBias >= 1) {
76313       m = ((value * c) - 1) * Math.pow(2, mLen);
76314       e = e + eBias;
76315     } else {
76316       m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
76317       e = 0;
76318     }
76319   }
76320
76321   for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}
76322
76323   e = (e << mLen) | m;
76324   eLen += mLen;
76325   for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}
76326
76327   buffer[offset + i - d] |= s * 128;
76328 };
76329
76330 var pbf = Pbf;
76331
76332 var ieee754 = ieee754$1;
76333
76334 function Pbf(buf) {
76335     this.buf = ArrayBuffer.isView && ArrayBuffer.isView(buf) ? buf : new Uint8Array(buf || 0);
76336     this.pos = 0;
76337     this.type = 0;
76338     this.length = this.buf.length;
76339 }
76340
76341 Pbf.Varint  = 0; // varint: int32, int64, uint32, uint64, sint32, sint64, bool, enum
76342 Pbf.Fixed64 = 1; // 64-bit: double, fixed64, sfixed64
76343 Pbf.Bytes   = 2; // length-delimited: string, bytes, embedded messages, packed repeated fields
76344 Pbf.Fixed32 = 5; // 32-bit: float, fixed32, sfixed32
76345
76346 var SHIFT_LEFT_32 = (1 << 16) * (1 << 16),
76347     SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32;
76348
76349 // Threshold chosen based on both benchmarking and knowledge about browser string
76350 // data structures (which currently switch structure types at 12 bytes or more)
76351 var TEXT_DECODER_MIN_LENGTH = 12;
76352 var utf8TextDecoder = typeof TextDecoder === 'undefined' ? null : new TextDecoder('utf8');
76353
76354 Pbf.prototype = {
76355
76356     destroy: function() {
76357         this.buf = null;
76358     },
76359
76360     // === READING =================================================================
76361
76362     readFields: function(readField, result, end) {
76363         end = end || this.length;
76364
76365         while (this.pos < end) {
76366             var val = this.readVarint(),
76367                 tag = val >> 3,
76368                 startPos = this.pos;
76369
76370             this.type = val & 0x7;
76371             readField(tag, result, this);
76372
76373             if (this.pos === startPos) this.skip(val);
76374         }
76375         return result;
76376     },
76377
76378     readMessage: function(readField, result) {
76379         return this.readFields(readField, result, this.readVarint() + this.pos);
76380     },
76381
76382     readFixed32: function() {
76383         var val = readUInt32(this.buf, this.pos);
76384         this.pos += 4;
76385         return val;
76386     },
76387
76388     readSFixed32: function() {
76389         var val = readInt32(this.buf, this.pos);
76390         this.pos += 4;
76391         return val;
76392     },
76393
76394     // 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed)
76395
76396     readFixed64: function() {
76397         var val = readUInt32(this.buf, this.pos) + readUInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
76398         this.pos += 8;
76399         return val;
76400     },
76401
76402     readSFixed64: function() {
76403         var val = readUInt32(this.buf, this.pos) + readInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
76404         this.pos += 8;
76405         return val;
76406     },
76407
76408     readFloat: function() {
76409         var val = ieee754.read(this.buf, this.pos, true, 23, 4);
76410         this.pos += 4;
76411         return val;
76412     },
76413
76414     readDouble: function() {
76415         var val = ieee754.read(this.buf, this.pos, true, 52, 8);
76416         this.pos += 8;
76417         return val;
76418     },
76419
76420     readVarint: function(isSigned) {
76421         var buf = this.buf,
76422             val, b;
76423
76424         b = buf[this.pos++]; val  =  b & 0x7f;        if (b < 0x80) return val;
76425         b = buf[this.pos++]; val |= (b & 0x7f) << 7;  if (b < 0x80) return val;
76426         b = buf[this.pos++]; val |= (b & 0x7f) << 14; if (b < 0x80) return val;
76427         b = buf[this.pos++]; val |= (b & 0x7f) << 21; if (b < 0x80) return val;
76428         b = buf[this.pos];   val |= (b & 0x0f) << 28;
76429
76430         return readVarintRemainder(val, isSigned, this);
76431     },
76432
76433     readVarint64: function() { // for compatibility with v2.0.1
76434         return this.readVarint(true);
76435     },
76436
76437     readSVarint: function() {
76438         var num = this.readVarint();
76439         return num % 2 === 1 ? (num + 1) / -2 : num / 2; // zigzag encoding
76440     },
76441
76442     readBoolean: function() {
76443         return Boolean(this.readVarint());
76444     },
76445
76446     readString: function() {
76447         var end = this.readVarint() + this.pos;
76448         var pos = this.pos;
76449         this.pos = end;
76450
76451         if (end - pos >= TEXT_DECODER_MIN_LENGTH && utf8TextDecoder) {
76452             // longer strings are fast with the built-in browser TextDecoder API
76453             return readUtf8TextDecoder(this.buf, pos, end);
76454         }
76455         // short strings are fast with our custom implementation
76456         return readUtf8(this.buf, pos, end);
76457     },
76458
76459     readBytes: function() {
76460         var end = this.readVarint() + this.pos,
76461             buffer = this.buf.subarray(this.pos, end);
76462         this.pos = end;
76463         return buffer;
76464     },
76465
76466     // verbose for performance reasons; doesn't affect gzipped size
76467
76468     readPackedVarint: function(arr, isSigned) {
76469         if (this.type !== Pbf.Bytes) return arr.push(this.readVarint(isSigned));
76470         var end = readPackedEnd(this);
76471         arr = arr || [];
76472         while (this.pos < end) arr.push(this.readVarint(isSigned));
76473         return arr;
76474     },
76475     readPackedSVarint: function(arr) {
76476         if (this.type !== Pbf.Bytes) return arr.push(this.readSVarint());
76477         var end = readPackedEnd(this);
76478         arr = arr || [];
76479         while (this.pos < end) arr.push(this.readSVarint());
76480         return arr;
76481     },
76482     readPackedBoolean: function(arr) {
76483         if (this.type !== Pbf.Bytes) return arr.push(this.readBoolean());
76484         var end = readPackedEnd(this);
76485         arr = arr || [];
76486         while (this.pos < end) arr.push(this.readBoolean());
76487         return arr;
76488     },
76489     readPackedFloat: function(arr) {
76490         if (this.type !== Pbf.Bytes) return arr.push(this.readFloat());
76491         var end = readPackedEnd(this);
76492         arr = arr || [];
76493         while (this.pos < end) arr.push(this.readFloat());
76494         return arr;
76495     },
76496     readPackedDouble: function(arr) {
76497         if (this.type !== Pbf.Bytes) return arr.push(this.readDouble());
76498         var end = readPackedEnd(this);
76499         arr = arr || [];
76500         while (this.pos < end) arr.push(this.readDouble());
76501         return arr;
76502     },
76503     readPackedFixed32: function(arr) {
76504         if (this.type !== Pbf.Bytes) return arr.push(this.readFixed32());
76505         var end = readPackedEnd(this);
76506         arr = arr || [];
76507         while (this.pos < end) arr.push(this.readFixed32());
76508         return arr;
76509     },
76510     readPackedSFixed32: function(arr) {
76511         if (this.type !== Pbf.Bytes) return arr.push(this.readSFixed32());
76512         var end = readPackedEnd(this);
76513         arr = arr || [];
76514         while (this.pos < end) arr.push(this.readSFixed32());
76515         return arr;
76516     },
76517     readPackedFixed64: function(arr) {
76518         if (this.type !== Pbf.Bytes) return arr.push(this.readFixed64());
76519         var end = readPackedEnd(this);
76520         arr = arr || [];
76521         while (this.pos < end) arr.push(this.readFixed64());
76522         return arr;
76523     },
76524     readPackedSFixed64: function(arr) {
76525         if (this.type !== Pbf.Bytes) return arr.push(this.readSFixed64());
76526         var end = readPackedEnd(this);
76527         arr = arr || [];
76528         while (this.pos < end) arr.push(this.readSFixed64());
76529         return arr;
76530     },
76531
76532     skip: function(val) {
76533         var type = val & 0x7;
76534         if (type === Pbf.Varint) while (this.buf[this.pos++] > 0x7f) {}
76535         else if (type === Pbf.Bytes) this.pos = this.readVarint() + this.pos;
76536         else if (type === Pbf.Fixed32) this.pos += 4;
76537         else if (type === Pbf.Fixed64) this.pos += 8;
76538         else throw new Error('Unimplemented type: ' + type);
76539     },
76540
76541     // === WRITING =================================================================
76542
76543     writeTag: function(tag, type) {
76544         this.writeVarint((tag << 3) | type);
76545     },
76546
76547     realloc: function(min) {
76548         var length = this.length || 16;
76549
76550         while (length < this.pos + min) length *= 2;
76551
76552         if (length !== this.length) {
76553             var buf = new Uint8Array(length);
76554             buf.set(this.buf);
76555             this.buf = buf;
76556             this.length = length;
76557         }
76558     },
76559
76560     finish: function() {
76561         this.length = this.pos;
76562         this.pos = 0;
76563         return this.buf.subarray(0, this.length);
76564     },
76565
76566     writeFixed32: function(val) {
76567         this.realloc(4);
76568         writeInt32(this.buf, val, this.pos);
76569         this.pos += 4;
76570     },
76571
76572     writeSFixed32: function(val) {
76573         this.realloc(4);
76574         writeInt32(this.buf, val, this.pos);
76575         this.pos += 4;
76576     },
76577
76578     writeFixed64: function(val) {
76579         this.realloc(8);
76580         writeInt32(this.buf, val & -1, this.pos);
76581         writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
76582         this.pos += 8;
76583     },
76584
76585     writeSFixed64: function(val) {
76586         this.realloc(8);
76587         writeInt32(this.buf, val & -1, this.pos);
76588         writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
76589         this.pos += 8;
76590     },
76591
76592     writeVarint: function(val) {
76593         val = +val || 0;
76594
76595         if (val > 0xfffffff || val < 0) {
76596             writeBigVarint(val, this);
76597             return;
76598         }
76599
76600         this.realloc(4);
76601
76602         this.buf[this.pos++] =           val & 0x7f  | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return;
76603         this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return;
76604         this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return;
76605         this.buf[this.pos++] =   (val >>> 7) & 0x7f;
76606     },
76607
76608     writeSVarint: function(val) {
76609         this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2);
76610     },
76611
76612     writeBoolean: function(val) {
76613         this.writeVarint(Boolean(val));
76614     },
76615
76616     writeString: function(str) {
76617         str = String(str);
76618         this.realloc(str.length * 4);
76619
76620         this.pos++; // reserve 1 byte for short string length
76621
76622         var startPos = this.pos;
76623         // write the string directly to the buffer and see how much was written
76624         this.pos = writeUtf8(this.buf, str, this.pos);
76625         var len = this.pos - startPos;
76626
76627         if (len >= 0x80) makeRoomForExtraLength(startPos, len, this);
76628
76629         // finally, write the message length in the reserved place and restore the position
76630         this.pos = startPos - 1;
76631         this.writeVarint(len);
76632         this.pos += len;
76633     },
76634
76635     writeFloat: function(val) {
76636         this.realloc(4);
76637         ieee754.write(this.buf, val, this.pos, true, 23, 4);
76638         this.pos += 4;
76639     },
76640
76641     writeDouble: function(val) {
76642         this.realloc(8);
76643         ieee754.write(this.buf, val, this.pos, true, 52, 8);
76644         this.pos += 8;
76645     },
76646
76647     writeBytes: function(buffer) {
76648         var len = buffer.length;
76649         this.writeVarint(len);
76650         this.realloc(len);
76651         for (var i = 0; i < len; i++) this.buf[this.pos++] = buffer[i];
76652     },
76653
76654     writeRawMessage: function(fn, obj) {
76655         this.pos++; // reserve 1 byte for short message length
76656
76657         // write the message directly to the buffer and see how much was written
76658         var startPos = this.pos;
76659         fn(obj, this);
76660         var len = this.pos - startPos;
76661
76662         if (len >= 0x80) makeRoomForExtraLength(startPos, len, this);
76663
76664         // finally, write the message length in the reserved place and restore the position
76665         this.pos = startPos - 1;
76666         this.writeVarint(len);
76667         this.pos += len;
76668     },
76669
76670     writeMessage: function(tag, fn, obj) {
76671         this.writeTag(tag, Pbf.Bytes);
76672         this.writeRawMessage(fn, obj);
76673     },
76674
76675     writePackedVarint:   function(tag, arr) { if (arr.length) this.writeMessage(tag, writePackedVarint, arr);   },
76676     writePackedSVarint:  function(tag, arr) { if (arr.length) this.writeMessage(tag, writePackedSVarint, arr);  },
76677     writePackedBoolean:  function(tag, arr) { if (arr.length) this.writeMessage(tag, writePackedBoolean, arr);  },
76678     writePackedFloat:    function(tag, arr) { if (arr.length) this.writeMessage(tag, writePackedFloat, arr);    },
76679     writePackedDouble:   function(tag, arr) { if (arr.length) this.writeMessage(tag, writePackedDouble, arr);   },
76680     writePackedFixed32:  function(tag, arr) { if (arr.length) this.writeMessage(tag, writePackedFixed32, arr);  },
76681     writePackedSFixed32: function(tag, arr) { if (arr.length) this.writeMessage(tag, writePackedSFixed32, arr); },
76682     writePackedFixed64:  function(tag, arr) { if (arr.length) this.writeMessage(tag, writePackedFixed64, arr);  },
76683     writePackedSFixed64: function(tag, arr) { if (arr.length) this.writeMessage(tag, writePackedSFixed64, arr); },
76684
76685     writeBytesField: function(tag, buffer) {
76686         this.writeTag(tag, Pbf.Bytes);
76687         this.writeBytes(buffer);
76688     },
76689     writeFixed32Field: function(tag, val) {
76690         this.writeTag(tag, Pbf.Fixed32);
76691         this.writeFixed32(val);
76692     },
76693     writeSFixed32Field: function(tag, val) {
76694         this.writeTag(tag, Pbf.Fixed32);
76695         this.writeSFixed32(val);
76696     },
76697     writeFixed64Field: function(tag, val) {
76698         this.writeTag(tag, Pbf.Fixed64);
76699         this.writeFixed64(val);
76700     },
76701     writeSFixed64Field: function(tag, val) {
76702         this.writeTag(tag, Pbf.Fixed64);
76703         this.writeSFixed64(val);
76704     },
76705     writeVarintField: function(tag, val) {
76706         this.writeTag(tag, Pbf.Varint);
76707         this.writeVarint(val);
76708     },
76709     writeSVarintField: function(tag, val) {
76710         this.writeTag(tag, Pbf.Varint);
76711         this.writeSVarint(val);
76712     },
76713     writeStringField: function(tag, str) {
76714         this.writeTag(tag, Pbf.Bytes);
76715         this.writeString(str);
76716     },
76717     writeFloatField: function(tag, val) {
76718         this.writeTag(tag, Pbf.Fixed32);
76719         this.writeFloat(val);
76720     },
76721     writeDoubleField: function(tag, val) {
76722         this.writeTag(tag, Pbf.Fixed64);
76723         this.writeDouble(val);
76724     },
76725     writeBooleanField: function(tag, val) {
76726         this.writeVarintField(tag, Boolean(val));
76727     }
76728 };
76729
76730 function readVarintRemainder(l, s, p) {
76731     var buf = p.buf,
76732         h, b;
76733
76734     b = buf[p.pos++]; h  = (b & 0x70) >> 4;  if (b < 0x80) return toNum(l, h, s);
76735     b = buf[p.pos++]; h |= (b & 0x7f) << 3;  if (b < 0x80) return toNum(l, h, s);
76736     b = buf[p.pos++]; h |= (b & 0x7f) << 10; if (b < 0x80) return toNum(l, h, s);
76737     b = buf[p.pos++]; h |= (b & 0x7f) << 17; if (b < 0x80) return toNum(l, h, s);
76738     b = buf[p.pos++]; h |= (b & 0x7f) << 24; if (b < 0x80) return toNum(l, h, s);
76739     b = buf[p.pos++]; h |= (b & 0x01) << 31; if (b < 0x80) return toNum(l, h, s);
76740
76741     throw new Error('Expected varint not more than 10 bytes');
76742 }
76743
76744 function readPackedEnd(pbf) {
76745     return pbf.type === Pbf.Bytes ?
76746         pbf.readVarint() + pbf.pos : pbf.pos + 1;
76747 }
76748
76749 function toNum(low, high, isSigned) {
76750     if (isSigned) {
76751         return high * 0x100000000 + (low >>> 0);
76752     }
76753
76754     return ((high >>> 0) * 0x100000000) + (low >>> 0);
76755 }
76756
76757 function writeBigVarint(val, pbf) {
76758     var low, high;
76759
76760     if (val >= 0) {
76761         low  = (val % 0x100000000) | 0;
76762         high = (val / 0x100000000) | 0;
76763     } else {
76764         low  = ~(-val % 0x100000000);
76765         high = ~(-val / 0x100000000);
76766
76767         if (low ^ 0xffffffff) {
76768             low = (low + 1) | 0;
76769         } else {
76770             low = 0;
76771             high = (high + 1) | 0;
76772         }
76773     }
76774
76775     if (val >= 0x10000000000000000 || val < -0x10000000000000000) {
76776         throw new Error('Given varint doesn\'t fit into 10 bytes');
76777     }
76778
76779     pbf.realloc(10);
76780
76781     writeBigVarintLow(low, high, pbf);
76782     writeBigVarintHigh(high, pbf);
76783 }
76784
76785 function writeBigVarintLow(low, high, pbf) {
76786     pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7;
76787     pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7;
76788     pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7;
76789     pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7;
76790     pbf.buf[pbf.pos]   = low & 0x7f;
76791 }
76792
76793 function writeBigVarintHigh(high, pbf) {
76794     var lsb = (high & 0x07) << 4;
76795
76796     pbf.buf[pbf.pos++] |= lsb         | ((high >>>= 3) ? 0x80 : 0); if (!high) return;
76797     pbf.buf[pbf.pos++]  = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return;
76798     pbf.buf[pbf.pos++]  = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return;
76799     pbf.buf[pbf.pos++]  = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return;
76800     pbf.buf[pbf.pos++]  = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return;
76801     pbf.buf[pbf.pos++]  = high & 0x7f;
76802 }
76803
76804 function makeRoomForExtraLength(startPos, len, pbf) {
76805     var extraLen =
76806         len <= 0x3fff ? 1 :
76807         len <= 0x1fffff ? 2 :
76808         len <= 0xfffffff ? 3 : Math.floor(Math.log(len) / (Math.LN2 * 7));
76809
76810     // if 1 byte isn't enough for encoding message length, shift the data to the right
76811     pbf.realloc(extraLen);
76812     for (var i = pbf.pos - 1; i >= startPos; i--) pbf.buf[i + extraLen] = pbf.buf[i];
76813 }
76814
76815 function writePackedVarint(arr, pbf)   { for (var i = 0; i < arr.length; i++) pbf.writeVarint(arr[i]);   }
76816 function writePackedSVarint(arr, pbf)  { for (var i = 0; i < arr.length; i++) pbf.writeSVarint(arr[i]);  }
76817 function writePackedFloat(arr, pbf)    { for (var i = 0; i < arr.length; i++) pbf.writeFloat(arr[i]);    }
76818 function writePackedDouble(arr, pbf)   { for (var i = 0; i < arr.length; i++) pbf.writeDouble(arr[i]);   }
76819 function writePackedBoolean(arr, pbf)  { for (var i = 0; i < arr.length; i++) pbf.writeBoolean(arr[i]);  }
76820 function writePackedFixed32(arr, pbf)  { for (var i = 0; i < arr.length; i++) pbf.writeFixed32(arr[i]);  }
76821 function writePackedSFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed32(arr[i]); }
76822 function writePackedFixed64(arr, pbf)  { for (var i = 0; i < arr.length; i++) pbf.writeFixed64(arr[i]);  }
76823 function writePackedSFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed64(arr[i]); }
76824
76825 // Buffer code below from https://github.com/feross/buffer, MIT-licensed
76826
76827 function readUInt32(buf, pos) {
76828     return ((buf[pos]) |
76829         (buf[pos + 1] << 8) |
76830         (buf[pos + 2] << 16)) +
76831         (buf[pos + 3] * 0x1000000);
76832 }
76833
76834 function writeInt32(buf, val, pos) {
76835     buf[pos] = val;
76836     buf[pos + 1] = (val >>> 8);
76837     buf[pos + 2] = (val >>> 16);
76838     buf[pos + 3] = (val >>> 24);
76839 }
76840
76841 function readInt32(buf, pos) {
76842     return ((buf[pos]) |
76843         (buf[pos + 1] << 8) |
76844         (buf[pos + 2] << 16)) +
76845         (buf[pos + 3] << 24);
76846 }
76847
76848 function readUtf8(buf, pos, end) {
76849     var str = '';
76850     var i = pos;
76851
76852     while (i < end) {
76853         var b0 = buf[i];
76854         var c = null; // codepoint
76855         var bytesPerSequence =
76856             b0 > 0xEF ? 4 :
76857             b0 > 0xDF ? 3 :
76858             b0 > 0xBF ? 2 : 1;
76859
76860         if (i + bytesPerSequence > end) break;
76861
76862         var b1, b2, b3;
76863
76864         if (bytesPerSequence === 1) {
76865             if (b0 < 0x80) {
76866                 c = b0;
76867             }
76868         } else if (bytesPerSequence === 2) {
76869             b1 = buf[i + 1];
76870             if ((b1 & 0xC0) === 0x80) {
76871                 c = (b0 & 0x1F) << 0x6 | (b1 & 0x3F);
76872                 if (c <= 0x7F) {
76873                     c = null;
76874                 }
76875             }
76876         } else if (bytesPerSequence === 3) {
76877             b1 = buf[i + 1];
76878             b2 = buf[i + 2];
76879             if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80) {
76880                 c = (b0 & 0xF) << 0xC | (b1 & 0x3F) << 0x6 | (b2 & 0x3F);
76881                 if (c <= 0x7FF || (c >= 0xD800 && c <= 0xDFFF)) {
76882                     c = null;
76883                 }
76884             }
76885         } else if (bytesPerSequence === 4) {
76886             b1 = buf[i + 1];
76887             b2 = buf[i + 2];
76888             b3 = buf[i + 3];
76889             if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80) {
76890                 c = (b0 & 0xF) << 0x12 | (b1 & 0x3F) << 0xC | (b2 & 0x3F) << 0x6 | (b3 & 0x3F);
76891                 if (c <= 0xFFFF || c >= 0x110000) {
76892                     c = null;
76893                 }
76894             }
76895         }
76896
76897         if (c === null) {
76898             c = 0xFFFD;
76899             bytesPerSequence = 1;
76900
76901         } else if (c > 0xFFFF) {
76902             c -= 0x10000;
76903             str += String.fromCharCode(c >>> 10 & 0x3FF | 0xD800);
76904             c = 0xDC00 | c & 0x3FF;
76905         }
76906
76907         str += String.fromCharCode(c);
76908         i += bytesPerSequence;
76909     }
76910
76911     return str;
76912 }
76913
76914 function readUtf8TextDecoder(buf, pos, end) {
76915     return utf8TextDecoder.decode(buf.subarray(pos, end));
76916 }
76917
76918 function writeUtf8(buf, str, pos) {
76919     for (var i = 0, c, lead; i < str.length; i++) {
76920         c = str.charCodeAt(i); // code point
76921
76922         if (c > 0xD7FF && c < 0xE000) {
76923             if (lead) {
76924                 if (c < 0xDC00) {
76925                     buf[pos++] = 0xEF;
76926                     buf[pos++] = 0xBF;
76927                     buf[pos++] = 0xBD;
76928                     lead = c;
76929                     continue;
76930                 } else {
76931                     c = lead - 0xD800 << 10 | c - 0xDC00 | 0x10000;
76932                     lead = null;
76933                 }
76934             } else {
76935                 if (c > 0xDBFF || (i + 1 === str.length)) {
76936                     buf[pos++] = 0xEF;
76937                     buf[pos++] = 0xBF;
76938                     buf[pos++] = 0xBD;
76939                 } else {
76940                     lead = c;
76941                 }
76942                 continue;
76943             }
76944         } else if (lead) {
76945             buf[pos++] = 0xEF;
76946             buf[pos++] = 0xBF;
76947             buf[pos++] = 0xBD;
76948             lead = null;
76949         }
76950
76951         if (c < 0x80) {
76952             buf[pos++] = c;
76953         } else {
76954             if (c < 0x800) {
76955                 buf[pos++] = c >> 0x6 | 0xC0;
76956             } else {
76957                 if (c < 0x10000) {
76958                     buf[pos++] = c >> 0xC | 0xE0;
76959                 } else {
76960                     buf[pos++] = c >> 0x12 | 0xF0;
76961                     buf[pos++] = c >> 0xC & 0x3F | 0x80;
76962                 }
76963                 buf[pos++] = c >> 0x6 & 0x3F | 0x80;
76964             }
76965             buf[pos++] = c & 0x3F | 0x80;
76966         }
76967     }
76968     return pos;
76969 }
76970
76971 /**
76972  * Decompress and parse an array buffer containing zipped
76973  * json data and return as a json object.
76974  *
76975  * @description Handles array buffers continaing zipped json
76976  * data.
76977  *
76978  * @param {ArrayBuffer} buffer - Array buffer to decompress.
76979  * @returns {Object} Parsed object.
76980  */
76981 function decompress(buffer) {
76982     const inflated = inflate_1(buffer, { to: "string" });
76983     return JSON.parse(inflated);
76984 }
76985 /**
76986  * Retrieves a resource as an array buffer and returns a promise
76987  * to the buffer.
76988  *
76989  * @description Rejects the promise on request failure.
76990  *
76991  * @param {string} url - URL for resource to retrieve.
76992  * @param {Promise} [abort] - Optional promise for aborting
76993  * the request through rejection.
76994  * @returns {Promise<ArrayBuffer>} Promise to the array buffer
76995  * resource.
76996  */
76997 function fetchArrayBuffer(url, abort) {
76998     const method = "GET";
76999     const responseType = "arraybuffer";
77000     return xhrFetch(url, method, responseType, [], null, abort);
77001 }
77002 function xhrFetch(url, method, responseType, headers, body, abort) {
77003     const xhr = new XMLHttpRequest();
77004     const promise = new Promise((resolve, reject) => {
77005         xhr.open(method, url, true);
77006         for (const header of headers) {
77007             xhr.setRequestHeader(header.name, header.value);
77008         }
77009         xhr.responseType = responseType;
77010         xhr.timeout = 15000;
77011         xhr.onload = () => {
77012             var _a;
77013             if (xhr.status !== 200) {
77014                 const error = (_a = xhr.response) !== null && _a !== void 0 ? _a : new MapillaryError(`Response status error: ${url}`);
77015                 reject(error);
77016             }
77017             if (!xhr.response) {
77018                 reject(new MapillaryError(`Response empty: ${url}`));
77019             }
77020             resolve(xhr.response);
77021         };
77022         xhr.onerror = () => {
77023             reject(new MapillaryError(`Request error: ${url}`));
77024         };
77025         xhr.ontimeout = () => {
77026             reject(new MapillaryError(`Request timeout: ${url}`));
77027         };
77028         xhr.onabort = () => {
77029             reject(new MapillaryError(`Request aborted: ${url}`));
77030         };
77031         xhr.send(method === "POST" ? body : null);
77032     });
77033     if (!!abort) {
77034         abort.catch(() => { xhr.abort(); });
77035     }
77036     return promise;
77037 }
77038 /**
77039  * Read the fields of a protobuf array buffer into a mesh
77040  * object.
77041  *
77042  * @param {ArrayBuffer} buffer - Protobuf array buffer
77043  * to read from.
77044  * @returns {MeshContract} Mesh object.
77045  */
77046 function readMeshPbf(buffer) {
77047     const pbf$1 = new pbf(buffer);
77048     const mesh = { faces: [], vertices: [] };
77049     return pbf$1.readFields(readMeshPbfField, mesh);
77050 }
77051 function readMeshPbfField(tag, mesh, pbf) {
77052     if (tag === 1) {
77053         mesh.vertices.push(pbf.readFloat());
77054     }
77055     else if (tag === 2) {
77056         mesh.faces.push(pbf.readVarint());
77057     }
77058     else {
77059         console.warn(`Unsupported pbf tag (${tag})`);
77060     }
77061 }
77062
77063 /**
77064  * @class DataProviderBase
77065  *
77066  * @classdesc Base class to extend if implementing a data provider
77067  * class.
77068  *
77069  * @fires datacreate
77070  *
77071  * @example
77072  * ```js
77073  * class MyDataProvider extends DataProviderBase {
77074  *   constructor() {
77075  *     super(new S2GeometryProvider());
77076  *   }
77077  *   ...
77078  * }
77079  * ```
77080  */
77081 class DataProviderBase extends EventEmitter {
77082     /**
77083      * Create a new data provider base instance.
77084      *
77085      * @param {IGeometryProvider} geometry - Geometry
77086      * provider instance.
77087      */
77088     constructor(_geometry) {
77089         super();
77090         this._geometry = _geometry;
77091     }
77092     /**
77093      * Get geometry property.
77094      *
77095      * @returns {IGeometryProvider} Geometry provider instance.
77096      */
77097     get geometry() {
77098         return this._geometry;
77099     }
77100     fire(type, event) {
77101         super.fire(type, event);
77102     }
77103     /**
77104      * Get core images in a geometry cell.
77105      *
77106      * @param {string} cellId - The id of the geometry cell.
77107      * @returns {Promise<CoreImagesContract>} Promise to
77108      * the core images of the requested geometry cell id.
77109      * @throws Rejects the promise on errors.
77110      */
77111     getCoreImages(cellId) {
77112         return Promise.reject(new MapillaryError("Not implemented"));
77113     }
77114     /**
77115      * Get a cluster reconstruction.
77116      *
77117      * @param {string} url - URL for the cluster reconstruction
77118      * to retrieve.
77119      * @param {Promise} [abort] - Optional promise for aborting
77120      * the request through rejection.
77121      * @returns {Promise<ClusterContract>} Promise to the
77122      * cluster reconstruction.
77123      * @throws Rejects the promise on errors.
77124      */
77125     getCluster(url, abort) {
77126         return Promise.reject(new MapillaryError("Not implemented"));
77127     }
77128     /**
77129      * Get spatial images.
77130      *
77131      * @param {Array<string>} imageIds - The ids for the
77132      * images to retrieve.
77133      * @returns {Promise<SpatialImagesContract>} Promise to
77134      * the spatial images of the requested image ids.
77135      * @throws Rejects the promise on errors.
77136      */
77137     getSpatialImages(imageIds) {
77138         return Promise.reject(new MapillaryError("Not implemented"));
77139     }
77140     /**
77141      * Get complete images.
77142      *
77143      * @param {Array<string>} imageIds - The ids for the
77144      * images to retrieve.
77145      * @returns {Promise<ImagesContract>} Promise to the images of the
77146      * requested image ids.
77147      * @throws Rejects the promise on errors.
77148      */
77149     getImages(imageIds) {
77150         return Promise.reject(new MapillaryError("Not implemented"));
77151     }
77152     /**
77153      * Get an image as an array buffer.
77154      *
77155      * @param {string} url - URL for image to retrieve.
77156      * @param {Promise<void>} [abort] - Optional promise for aborting
77157      * the request through rejection.
77158      * @returns {Promise<ArrayBuffer>} Promise to the array
77159      * buffer containing the image.
77160      * @throws Rejects the promise on errors.
77161      */
77162     getImageBuffer(url, abort) {
77163         return Promise.reject(new MapillaryError("Not implemented"));
77164     }
77165     /**
77166      * Get image tiles urls for a tile level.
77167      *
77168      * @param {ImageTilesRequestContract} tiles - Tiles to request
77169      * @returns {Promise<ImageTilesContract>} Promise to the
77170      * image tiles response contract
77171      *
77172      * @throws Rejects the promise on errors.
77173      *
77174      * @example
77175      * ```js
77176      * var tileRequest = { imageId: 'image-id', z: 12 };
77177      * provider.getImageTiles(tileRequest)
77178      *   .then((response) => console.log(response));
77179      * ```
77180      */
77181     getImageTiles(tiles) {
77182         return Promise.reject(new MapillaryError("Not implemented"));
77183     }
77184     /**
77185      * Get a mesh.
77186      *
77187      * @param {string} url - URL for mesh to retrieve.
77188      * @param {Promise<void>} [abort] - Optional promise for aborting
77189      * the request through rejection.
77190      * @returns {Promise<MeshContract>} Promise to the mesh.
77191      * @throws Rejects the promise on errors.
77192      */
77193     getMesh(url, abort) {
77194         return Promise.reject(new MapillaryError("Not implemented"));
77195     }
77196     /**
77197      * Get sequence.
77198      *
77199      * @param {Array<string>} sequenceId - The id for the
77200      * sequence to retrieve.
77201      * @returns {Promise} Promise to the sequences of the
77202      * requested image ids.
77203      * @throws Rejects the promise on errors.
77204      */
77205     getSequence(sequenceId) {
77206         return Promise.reject(new MapillaryError("Not implemented"));
77207     }
77208     off(type, handler) {
77209         super.off(type, handler);
77210     }
77211     on(type, handler) {
77212         super.on(type, handler);
77213     }
77214     /**
77215      * Set an access token for authenticated API requests of
77216      * protected resources.
77217      *
77218      * @param {string} [accessToken] accessToken - User access
77219      * token or client access token.
77220      */
77221     setAccessToken(accessToken) {
77222         throw new MapillaryError("Not implemented");
77223     }
77224 }
77225
77226 /**
77227  * @class GeometryProviderBase
77228  *
77229  * @classdesc Base class to extend if implementing a geometry
77230  * provider class.
77231  *
77232  * @example
77233  * ```js
77234  * class MyGeometryProvider extends GeometryProviderBase {
77235  *      ...
77236  * }
77237  * ```
77238  */
77239 class GeometryProviderBase {
77240     /**
77241      * Create a new geometry provider base instance.
77242      */
77243     constructor() { }
77244     /**
77245      * Convert a geodetic bounding box to the the minimum set
77246      * of cell ids containing the bounding box.
77247      *
77248      * @description The bounding box needs
77249      * to be sufficiently small to be contained in an area with the size
77250      * of maximally four tiles. Up to nine adjacent tiles may be returned.
77251      *
77252      * @param {LngLat} sw - South west corner of bounding box.
77253      * @param {LngLat} ne - North east corner of bounding box.
77254      *
77255      * @returns {Array<string>} Array of cell ids.
77256      */
77257     bboxToCellIds(sw, ne) {
77258         throw new MapillaryError("Not implemented");
77259     }
77260     /**
77261      * Get the cell ids of all adjacent cells.
77262      *
77263      * @description In the case of approximately rectangular cells
77264      * this is typically the eight orthogonally and diagonally adjacent
77265      * cells.
77266      *
77267      * @param {string} cellId - Id of cell.
77268      * @returns {Array<string>} Array of cell ids. No specific
77269      * order is guaranteed.
77270      */
77271     getAdjacent(cellId) {
77272         throw new MapillaryError("Not implemented");
77273     }
77274     /**
77275      * Get the vertices of a cell.
77276      *
77277      * @description The vertices form an unclosed
77278      * clockwise polygon in the 2D longitude, latitude
77279      * space. No assumption on the position of the first
77280      * vertex relative to the others can be made.
77281      *
77282      * @param {string} cellId - Id of cell.
77283      * @returns {Array<LngLat>} Unclosed clockwise polygon.
77284      */
77285     getVertices(cellId) {
77286         throw new MapillaryError("Not implemented");
77287     }
77288     /**
77289      * Convert geodetic coordinates to a cell id.
77290      *
77291      * @param {LngLat} lngLat - Longitude, latitude to convert.
77292      * @returns {string} Cell id for the longitude, latitude.
77293      */
77294     lngLatToCellId(lngLat) {
77295         throw new MapillaryError("Not implemented");
77296     }
77297     /** @ignore */
77298     _approxBboxToCellIds(sw, ne) {
77299         if (ne.lat <= sw.lat || ne.lng <= sw.lng) {
77300             throw new MapillaryError("North east needs to be top right of south west");
77301         }
77302         const centerLat = (sw.lat + ne.lat) / 2;
77303         const centerLng = (sw.lng + ne.lng) / 2;
77304         const enu = geodeticToEnu(ne.lng, ne.lat, 0, centerLng, centerLat, 0);
77305         const threshold = Math.max(enu[0], enu[1]);
77306         return this._lngLatToCellIds({ lat: centerLat, lng: centerLng }, threshold);
77307     }
77308     /** @ignore */
77309     _enuToGeodetic(point, reference) {
77310         const [lng, lat] = enuToGeodetic(point[0], point[1], point[2], reference.lng, reference.lat, 0);
77311         return { lat, lng };
77312     }
77313     /** @ignore */
77314     _getLngLatBoundingBoxCorners(lngLat, threshold) {
77315         return [
77316             [-threshold, threshold, 0],
77317             [threshold, threshold, 0],
77318             [threshold, -threshold, 0],
77319             [-threshold, -threshold, 0],
77320         ].map((point) => {
77321             return this._enuToGeodetic(point, lngLat);
77322         });
77323     }
77324     /**
77325      * Convert a geodetic square to cell ids.
77326      *
77327      * The square is specified as a longitude, latitude
77328      * and a threshold from the position using Manhattan distance.
77329      *
77330      * @param {LngLat} lngLat - Longitude, latitude.
77331      * @param {number} threshold - Threshold of the conversion in meters.
77332      *
77333      * @returns {Array<string>} Array of cell ids reachable within
77334      * the threshold.
77335      *
77336      * @ignore
77337      */
77338     _lngLatToCellIds(lngLat, threshold) {
77339         const cellId = this.lngLatToCellId(lngLat);
77340         const bboxCorners = this._getLngLatBoundingBoxCorners(lngLat, threshold);
77341         for (const corner of bboxCorners) {
77342             const cid = this.lngLatToCellId(corner);
77343             if (cid !== cellId) {
77344                 return [cellId, ...this.getAdjacent(cellId)];
77345             }
77346         }
77347         return [cellId];
77348     }
77349 }
77350
77351 var s2geometry = {exports: {}};
77352
77353 var long = {exports: {}};
77354
77355 /*
77356  Copyright 2013 Daniel Wirtz <dcode@dcode.io>
77357  Copyright 2009 The Closure Library Authors. All Rights Reserved.
77358
77359  Licensed under the Apache License, Version 2.0 (the "License");
77360  you may not use this file except in compliance with the License.
77361  You may obtain a copy of the License at
77362
77363  http://www.apache.org/licenses/LICENSE-2.0
77364
77365  Unless required by applicable law or agreed to in writing, software
77366  distributed under the License is distributed on an "AS-IS" BASIS,
77367  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
77368  See the License for the specific language governing permissions and
77369  limitations under the License.
77370  */
77371
77372 (function (module) {
77373 /**
77374  * @license long.js (c) 2013 Daniel Wirtz <dcode@dcode.io>
77375  * Released under the Apache License, Version 2.0
77376  * see: https://github.com/dcodeIO/long.js for details
77377  */
77378 (function(global, factory) {
77379
77380     /* AMD */ if (typeof commonjsRequire === 'function' && 'object' === "object" && module && module["exports"])
77381         module["exports"] = factory();
77382     /* Global */ else
77383         (global["dcodeIO"] = global["dcodeIO"] || {})["Long"] = factory();
77384
77385 })(commonjsGlobal, function() {
77386
77387     /**
77388      * Constructs a 64 bit two's-complement integer, given its low and high 32 bit values as *signed* integers.
77389      *  See the from* functions below for more convenient ways of constructing Longs.
77390      * @exports Long
77391      * @class A Long class for representing a 64 bit two's-complement integer value.
77392      * @param {number} low The low (signed) 32 bits of the long
77393      * @param {number} high The high (signed) 32 bits of the long
77394      * @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed
77395      * @constructor
77396      */
77397     function Long(low, high, unsigned) {
77398
77399         /**
77400          * The low 32 bits as a signed value.
77401          * @type {number}
77402          */
77403         this.low = low | 0;
77404
77405         /**
77406          * The high 32 bits as a signed value.
77407          * @type {number}
77408          */
77409         this.high = high | 0;
77410
77411         /**
77412          * Whether unsigned or not.
77413          * @type {boolean}
77414          */
77415         this.unsigned = !!unsigned;
77416     }
77417
77418     // The internal representation of a long is the two given signed, 32-bit values.
77419     // We use 32-bit pieces because these are the size of integers on which
77420     // Javascript performs bit-operations.  For operations like addition and
77421     // multiplication, we split each number into 16 bit pieces, which can easily be
77422     // multiplied within Javascript's floating-point representation without overflow
77423     // or change in sign.
77424     //
77425     // In the algorithms below, we frequently reduce the negative case to the
77426     // positive case by negating the input(s) and then post-processing the result.
77427     // Note that we must ALWAYS check specially whether those values are MIN_VALUE
77428     // (-2^63) because -MIN_VALUE == MIN_VALUE (since 2^63 cannot be represented as
77429     // a positive number, it overflows back into a negative).  Not handling this
77430     // case would often result in infinite recursion.
77431     //
77432     // Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the from*
77433     // methods on which they depend.
77434
77435     /**
77436      * An indicator used to reliably determine if an object is a Long or not.
77437      * @type {boolean}
77438      * @const
77439      * @private
77440      */
77441     Long.prototype.__isLong__;
77442
77443     Object.defineProperty(Long.prototype, "__isLong__", {
77444         value: true,
77445         enumerable: false,
77446         configurable: false
77447     });
77448
77449     /**
77450      * @function
77451      * @param {*} obj Object
77452      * @returns {boolean}
77453      * @inner
77454      */
77455     function isLong(obj) {
77456         return (obj && obj["__isLong__"]) === true;
77457     }
77458
77459     /**
77460      * Tests if the specified object is a Long.
77461      * @function
77462      * @param {*} obj Object
77463      * @returns {boolean}
77464      */
77465     Long.isLong = isLong;
77466
77467     /**
77468      * A cache of the Long representations of small integer values.
77469      * @type {!Object}
77470      * @inner
77471      */
77472     var INT_CACHE = {};
77473
77474     /**
77475      * A cache of the Long representations of small unsigned integer values.
77476      * @type {!Object}
77477      * @inner
77478      */
77479     var UINT_CACHE = {};
77480
77481     /**
77482      * @param {number} value
77483      * @param {boolean=} unsigned
77484      * @returns {!Long}
77485      * @inner
77486      */
77487     function fromInt(value, unsigned) {
77488         var obj, cachedObj, cache;
77489         if (unsigned) {
77490             value >>>= 0;
77491             if (cache = (0 <= value && value < 256)) {
77492                 cachedObj = UINT_CACHE[value];
77493                 if (cachedObj)
77494                     return cachedObj;
77495             }
77496             obj = fromBits(value, (value | 0) < 0 ? -1 : 0, true);
77497             if (cache)
77498                 UINT_CACHE[value] = obj;
77499             return obj;
77500         } else {
77501             value |= 0;
77502             if (cache = (-128 <= value && value < 128)) {
77503                 cachedObj = INT_CACHE[value];
77504                 if (cachedObj)
77505                     return cachedObj;
77506             }
77507             obj = fromBits(value, value < 0 ? -1 : 0, false);
77508             if (cache)
77509                 INT_CACHE[value] = obj;
77510             return obj;
77511         }
77512     }
77513
77514     /**
77515      * Returns a Long representing the given 32 bit integer value.
77516      * @function
77517      * @param {number} value The 32 bit integer in question
77518      * @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed
77519      * @returns {!Long} The corresponding Long value
77520      */
77521     Long.fromInt = fromInt;
77522
77523     /**
77524      * @param {number} value
77525      * @param {boolean=} unsigned
77526      * @returns {!Long}
77527      * @inner
77528      */
77529     function fromNumber(value, unsigned) {
77530         if (isNaN(value) || !isFinite(value))
77531             return unsigned ? UZERO : ZERO;
77532         if (unsigned) {
77533             if (value < 0)
77534                 return UZERO;
77535             if (value >= TWO_PWR_64_DBL)
77536                 return MAX_UNSIGNED_VALUE;
77537         } else {
77538             if (value <= -TWO_PWR_63_DBL)
77539                 return MIN_VALUE;
77540             if (value + 1 >= TWO_PWR_63_DBL)
77541                 return MAX_VALUE;
77542         }
77543         if (value < 0)
77544             return fromNumber(-value, unsigned).neg();
77545         return fromBits((value % TWO_PWR_32_DBL) | 0, (value / TWO_PWR_32_DBL) | 0, unsigned);
77546     }
77547
77548     /**
77549      * Returns a Long representing the given value, provided that it is a finite number. Otherwise, zero is returned.
77550      * @function
77551      * @param {number} value The number in question
77552      * @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed
77553      * @returns {!Long} The corresponding Long value
77554      */
77555     Long.fromNumber = fromNumber;
77556
77557     /**
77558      * @param {number} lowBits
77559      * @param {number} highBits
77560      * @param {boolean=} unsigned
77561      * @returns {!Long}
77562      * @inner
77563      */
77564     function fromBits(lowBits, highBits, unsigned) {
77565         return new Long(lowBits, highBits, unsigned);
77566     }
77567
77568     /**
77569      * Returns a Long representing the 64 bit integer that comes by concatenating the given low and high bits. Each is
77570      *  assumed to use 32 bits.
77571      * @function
77572      * @param {number} lowBits The low 32 bits
77573      * @param {number} highBits The high 32 bits
77574      * @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed
77575      * @returns {!Long} The corresponding Long value
77576      */
77577     Long.fromBits = fromBits;
77578
77579     /**
77580      * @function
77581      * @param {number} base
77582      * @param {number} exponent
77583      * @returns {number}
77584      * @inner
77585      */
77586     var pow_dbl = Math.pow; // Used 4 times (4*8 to 15+4)
77587
77588     /**
77589      * @param {string} str
77590      * @param {(boolean|number)=} unsigned
77591      * @param {number=} radix
77592      * @returns {!Long}
77593      * @inner
77594      */
77595     function fromString(str, unsigned, radix) {
77596         if (str.length === 0)
77597             throw Error('empty string');
77598         if (str === "NaN" || str === "Infinity" || str === "+Infinity" || str === "-Infinity")
77599             return ZERO;
77600         if (typeof unsigned === 'number') {
77601             // For goog.math.long compatibility
77602             radix = unsigned,
77603             unsigned = false;
77604         } else {
77605             unsigned = !! unsigned;
77606         }
77607         radix = radix || 10;
77608         if (radix < 2 || 36 < radix)
77609             throw RangeError('radix');
77610
77611         var p;
77612         if ((p = str.indexOf('-')) > 0)
77613             throw Error('interior hyphen');
77614         else if (p === 0) {
77615             return fromString(str.substring(1), unsigned, radix).neg();
77616         }
77617
77618         // Do several (8) digits each time through the loop, so as to
77619         // minimize the calls to the very expensive emulated div.
77620         var radixToPower = fromNumber(pow_dbl(radix, 8));
77621
77622         var result = ZERO;
77623         for (var i = 0; i < str.length; i += 8) {
77624             var size = Math.min(8, str.length - i),
77625                 value = parseInt(str.substring(i, i + size), radix);
77626             if (size < 8) {
77627                 var power = fromNumber(pow_dbl(radix, size));
77628                 result = result.mul(power).add(fromNumber(value));
77629             } else {
77630                 result = result.mul(radixToPower);
77631                 result = result.add(fromNumber(value));
77632             }
77633         }
77634         result.unsigned = unsigned;
77635         return result;
77636     }
77637
77638     /**
77639      * Returns a Long representation of the given string, written using the specified radix.
77640      * @function
77641      * @param {string} str The textual representation of the Long
77642      * @param {(boolean|number)=} unsigned Whether unsigned or not, defaults to `false` for signed
77643      * @param {number=} radix The radix in which the text is written (2-36), defaults to 10
77644      * @returns {!Long} The corresponding Long value
77645      */
77646     Long.fromString = fromString;
77647
77648     /**
77649      * @function
77650      * @param {!Long|number|string|!{low: number, high: number, unsigned: boolean}} val
77651      * @returns {!Long}
77652      * @inner
77653      */
77654     function fromValue(val) {
77655         if (val /* is compatible */ instanceof Long)
77656             return val;
77657         if (typeof val === 'number')
77658             return fromNumber(val);
77659         if (typeof val === 'string')
77660             return fromString(val);
77661         // Throws for non-objects, converts non-instanceof Long:
77662         return fromBits(val.low, val.high, val.unsigned);
77663     }
77664
77665     /**
77666      * Converts the specified value to a Long.
77667      * @function
77668      * @param {!Long|number|string|!{low: number, high: number, unsigned: boolean}} val Value
77669      * @returns {!Long}
77670      */
77671     Long.fromValue = fromValue;
77672
77673     // NOTE: the compiler should inline these constant values below and then remove these variables, so there should be
77674     // no runtime penalty for these.
77675
77676     /**
77677      * @type {number}
77678      * @const
77679      * @inner
77680      */
77681     var TWO_PWR_16_DBL = 1 << 16;
77682
77683     /**
77684      * @type {number}
77685      * @const
77686      * @inner
77687      */
77688     var TWO_PWR_24_DBL = 1 << 24;
77689
77690     /**
77691      * @type {number}
77692      * @const
77693      * @inner
77694      */
77695     var TWO_PWR_32_DBL = TWO_PWR_16_DBL * TWO_PWR_16_DBL;
77696
77697     /**
77698      * @type {number}
77699      * @const
77700      * @inner
77701      */
77702     var TWO_PWR_64_DBL = TWO_PWR_32_DBL * TWO_PWR_32_DBL;
77703
77704     /**
77705      * @type {number}
77706      * @const
77707      * @inner
77708      */
77709     var TWO_PWR_63_DBL = TWO_PWR_64_DBL / 2;
77710
77711     /**
77712      * @type {!Long}
77713      * @const
77714      * @inner
77715      */
77716     var TWO_PWR_24 = fromInt(TWO_PWR_24_DBL);
77717
77718     /**
77719      * @type {!Long}
77720      * @inner
77721      */
77722     var ZERO = fromInt(0);
77723
77724     /**
77725      * Signed zero.
77726      * @type {!Long}
77727      */
77728     Long.ZERO = ZERO;
77729
77730     /**
77731      * @type {!Long}
77732      * @inner
77733      */
77734     var UZERO = fromInt(0, true);
77735
77736     /**
77737      * Unsigned zero.
77738      * @type {!Long}
77739      */
77740     Long.UZERO = UZERO;
77741
77742     /**
77743      * @type {!Long}
77744      * @inner
77745      */
77746     var ONE = fromInt(1);
77747
77748     /**
77749      * Signed one.
77750      * @type {!Long}
77751      */
77752     Long.ONE = ONE;
77753
77754     /**
77755      * @type {!Long}
77756      * @inner
77757      */
77758     var UONE = fromInt(1, true);
77759
77760     /**
77761      * Unsigned one.
77762      * @type {!Long}
77763      */
77764     Long.UONE = UONE;
77765
77766     /**
77767      * @type {!Long}
77768      * @inner
77769      */
77770     var NEG_ONE = fromInt(-1);
77771
77772     /**
77773      * Signed negative one.
77774      * @type {!Long}
77775      */
77776     Long.NEG_ONE = NEG_ONE;
77777
77778     /**
77779      * @type {!Long}
77780      * @inner
77781      */
77782     var MAX_VALUE = fromBits(0xFFFFFFFF|0, 0x7FFFFFFF|0, false);
77783
77784     /**
77785      * Maximum signed value.
77786      * @type {!Long}
77787      */
77788     Long.MAX_VALUE = MAX_VALUE;
77789
77790     /**
77791      * @type {!Long}
77792      * @inner
77793      */
77794     var MAX_UNSIGNED_VALUE = fromBits(0xFFFFFFFF|0, 0xFFFFFFFF|0, true);
77795
77796     /**
77797      * Maximum unsigned value.
77798      * @type {!Long}
77799      */
77800     Long.MAX_UNSIGNED_VALUE = MAX_UNSIGNED_VALUE;
77801
77802     /**
77803      * @type {!Long}
77804      * @inner
77805      */
77806     var MIN_VALUE = fromBits(0, 0x80000000|0, false);
77807
77808     /**
77809      * Minimum signed value.
77810      * @type {!Long}
77811      */
77812     Long.MIN_VALUE = MIN_VALUE;
77813
77814     /**
77815      * @alias Long.prototype
77816      * @inner
77817      */
77818     var LongPrototype = Long.prototype;
77819
77820     /**
77821      * Converts the Long to a 32 bit integer, assuming it is a 32 bit integer.
77822      * @returns {number}
77823      */
77824     LongPrototype.toInt = function toInt() {
77825         return this.unsigned ? this.low >>> 0 : this.low;
77826     };
77827
77828     /**
77829      * Converts the Long to a the nearest floating-point representation of this value (double, 53 bit mantissa).
77830      * @returns {number}
77831      */
77832     LongPrototype.toNumber = function toNumber() {
77833         if (this.unsigned)
77834             return ((this.high >>> 0) * TWO_PWR_32_DBL) + (this.low >>> 0);
77835         return this.high * TWO_PWR_32_DBL + (this.low >>> 0);
77836     };
77837
77838     /**
77839      * Converts the Long to a string written in the specified radix.
77840      * @param {number=} radix Radix (2-36), defaults to 10
77841      * @returns {string}
77842      * @override
77843      * @throws {RangeError} If `radix` is out of range
77844      */
77845     LongPrototype.toString = function toString(radix) {
77846         radix = radix || 10;
77847         if (radix < 2 || 36 < radix)
77848             throw RangeError('radix');
77849         if (this.isZero())
77850             return '0';
77851         if (this.isNegative()) { // Unsigned Longs are never negative
77852             if (this.eq(MIN_VALUE)) {
77853                 // We need to change the Long value before it can be negated, so we remove
77854                 // the bottom-most digit in this base and then recurse to do the rest.
77855                 var radixLong = fromNumber(radix),
77856                     div = this.div(radixLong),
77857                     rem1 = div.mul(radixLong).sub(this);
77858                 return div.toString(radix) + rem1.toInt().toString(radix);
77859             } else
77860                 return '-' + this.neg().toString(radix);
77861         }
77862
77863         // Do several (6) digits each time through the loop, so as to
77864         // minimize the calls to the very expensive emulated div.
77865         var radixToPower = fromNumber(pow_dbl(radix, 6), this.unsigned),
77866             rem = this;
77867         var result = '';
77868         while (true) {
77869             var remDiv = rem.div(radixToPower),
77870                 intval = rem.sub(remDiv.mul(radixToPower)).toInt() >>> 0,
77871                 digits = intval.toString(radix);
77872             rem = remDiv;
77873             if (rem.isZero())
77874                 return digits + result;
77875             else {
77876                 while (digits.length < 6)
77877                     digits = '0' + digits;
77878                 result = '' + digits + result;
77879             }
77880         }
77881     };
77882
77883     /**
77884      * Gets the high 32 bits as a signed integer.
77885      * @returns {number} Signed high bits
77886      */
77887     LongPrototype.getHighBits = function getHighBits() {
77888         return this.high;
77889     };
77890
77891     /**
77892      * Gets the high 32 bits as an unsigned integer.
77893      * @returns {number} Unsigned high bits
77894      */
77895     LongPrototype.getHighBitsUnsigned = function getHighBitsUnsigned() {
77896         return this.high >>> 0;
77897     };
77898
77899     /**
77900      * Gets the low 32 bits as a signed integer.
77901      * @returns {number} Signed low bits
77902      */
77903     LongPrototype.getLowBits = function getLowBits() {
77904         return this.low;
77905     };
77906
77907     /**
77908      * Gets the low 32 bits as an unsigned integer.
77909      * @returns {number} Unsigned low bits
77910      */
77911     LongPrototype.getLowBitsUnsigned = function getLowBitsUnsigned() {
77912         return this.low >>> 0;
77913     };
77914
77915     /**
77916      * Gets the number of bits needed to represent the absolute value of this Long.
77917      * @returns {number}
77918      */
77919     LongPrototype.getNumBitsAbs = function getNumBitsAbs() {
77920         if (this.isNegative()) // Unsigned Longs are never negative
77921             return this.eq(MIN_VALUE) ? 64 : this.neg().getNumBitsAbs();
77922         var val = this.high != 0 ? this.high : this.low;
77923         for (var bit = 31; bit > 0; bit--)
77924             if ((val & (1 << bit)) != 0)
77925                 break;
77926         return this.high != 0 ? bit + 33 : bit + 1;
77927     };
77928
77929     /**
77930      * Tests if this Long's value equals zero.
77931      * @returns {boolean}
77932      */
77933     LongPrototype.isZero = function isZero() {
77934         return this.high === 0 && this.low === 0;
77935     };
77936
77937     /**
77938      * Tests if this Long's value is negative.
77939      * @returns {boolean}
77940      */
77941     LongPrototype.isNegative = function isNegative() {
77942         return !this.unsigned && this.high < 0;
77943     };
77944
77945     /**
77946      * Tests if this Long's value is positive.
77947      * @returns {boolean}
77948      */
77949     LongPrototype.isPositive = function isPositive() {
77950         return this.unsigned || this.high >= 0;
77951     };
77952
77953     /**
77954      * Tests if this Long's value is odd.
77955      * @returns {boolean}
77956      */
77957     LongPrototype.isOdd = function isOdd() {
77958         return (this.low & 1) === 1;
77959     };
77960
77961     /**
77962      * Tests if this Long's value is even.
77963      * @returns {boolean}
77964      */
77965     LongPrototype.isEven = function isEven() {
77966         return (this.low & 1) === 0;
77967     };
77968
77969     /**
77970      * Tests if this Long's value equals the specified's.
77971      * @param {!Long|number|string} other Other value
77972      * @returns {boolean}
77973      */
77974     LongPrototype.equals = function equals(other) {
77975         if (!isLong(other))
77976             other = fromValue(other);
77977         if (this.unsigned !== other.unsigned && (this.high >>> 31) === 1 && (other.high >>> 31) === 1)
77978             return false;
77979         return this.high === other.high && this.low === other.low;
77980     };
77981
77982     /**
77983      * Tests if this Long's value equals the specified's. This is an alias of {@link Long#equals}.
77984      * @function
77985      * @param {!Long|number|string} other Other value
77986      * @returns {boolean}
77987      */
77988     LongPrototype.eq = LongPrototype.equals;
77989
77990     /**
77991      * Tests if this Long's value differs from the specified's.
77992      * @param {!Long|number|string} other Other value
77993      * @returns {boolean}
77994      */
77995     LongPrototype.notEquals = function notEquals(other) {
77996         return !this.eq(/* validates */ other);
77997     };
77998
77999     /**
78000      * Tests if this Long's value differs from the specified's. This is an alias of {@link Long#notEquals}.
78001      * @function
78002      * @param {!Long|number|string} other Other value
78003      * @returns {boolean}
78004      */
78005     LongPrototype.neq = LongPrototype.notEquals;
78006
78007     /**
78008      * Tests if this Long's value is less than the specified's.
78009      * @param {!Long|number|string} other Other value
78010      * @returns {boolean}
78011      */
78012     LongPrototype.lessThan = function lessThan(other) {
78013         return this.comp(/* validates */ other) < 0;
78014     };
78015
78016     /**
78017      * Tests if this Long's value is less than the specified's. This is an alias of {@link Long#lessThan}.
78018      * @function
78019      * @param {!Long|number|string} other Other value
78020      * @returns {boolean}
78021      */
78022     LongPrototype.lt = LongPrototype.lessThan;
78023
78024     /**
78025      * Tests if this Long's value is less than or equal the specified's.
78026      * @param {!Long|number|string} other Other value
78027      * @returns {boolean}
78028      */
78029     LongPrototype.lessThanOrEqual = function lessThanOrEqual(other) {
78030         return this.comp(/* validates */ other) <= 0;
78031     };
78032
78033     /**
78034      * Tests if this Long's value is less than or equal the specified's. This is an alias of {@link Long#lessThanOrEqual}.
78035      * @function
78036      * @param {!Long|number|string} other Other value
78037      * @returns {boolean}
78038      */
78039     LongPrototype.lte = LongPrototype.lessThanOrEqual;
78040
78041     /**
78042      * Tests if this Long's value is greater than the specified's.
78043      * @param {!Long|number|string} other Other value
78044      * @returns {boolean}
78045      */
78046     LongPrototype.greaterThan = function greaterThan(other) {
78047         return this.comp(/* validates */ other) > 0;
78048     };
78049
78050     /**
78051      * Tests if this Long's value is greater than the specified's. This is an alias of {@link Long#greaterThan}.
78052      * @function
78053      * @param {!Long|number|string} other Other value
78054      * @returns {boolean}
78055      */
78056     LongPrototype.gt = LongPrototype.greaterThan;
78057
78058     /**
78059      * Tests if this Long's value is greater than or equal the specified's.
78060      * @param {!Long|number|string} other Other value
78061      * @returns {boolean}
78062      */
78063     LongPrototype.greaterThanOrEqual = function greaterThanOrEqual(other) {
78064         return this.comp(/* validates */ other) >= 0;
78065     };
78066
78067     /**
78068      * Tests if this Long's value is greater than or equal the specified's. This is an alias of {@link Long#greaterThanOrEqual}.
78069      * @function
78070      * @param {!Long|number|string} other Other value
78071      * @returns {boolean}
78072      */
78073     LongPrototype.gte = LongPrototype.greaterThanOrEqual;
78074
78075     /**
78076      * Compares this Long's value with the specified's.
78077      * @param {!Long|number|string} other Other value
78078      * @returns {number} 0 if they are the same, 1 if the this is greater and -1
78079      *  if the given one is greater
78080      */
78081     LongPrototype.compare = function compare(other) {
78082         if (!isLong(other))
78083             other = fromValue(other);
78084         if (this.eq(other))
78085             return 0;
78086         var thisNeg = this.isNegative(),
78087             otherNeg = other.isNegative();
78088         if (thisNeg && !otherNeg)
78089             return -1;
78090         if (!thisNeg && otherNeg)
78091             return 1;
78092         // At this point the sign bits are the same
78093         if (!this.unsigned)
78094             return this.sub(other).isNegative() ? -1 : 1;
78095         // Both are positive if at least one is unsigned
78096         return (other.high >>> 0) > (this.high >>> 0) || (other.high === this.high && (other.low >>> 0) > (this.low >>> 0)) ? -1 : 1;
78097     };
78098
78099     /**
78100      * Compares this Long's value with the specified's. This is an alias of {@link Long#compare}.
78101      * @function
78102      * @param {!Long|number|string} other Other value
78103      * @returns {number} 0 if they are the same, 1 if the this is greater and -1
78104      *  if the given one is greater
78105      */
78106     LongPrototype.comp = LongPrototype.compare;
78107
78108     /**
78109      * Negates this Long's value.
78110      * @returns {!Long} Negated Long
78111      */
78112     LongPrototype.negate = function negate() {
78113         if (!this.unsigned && this.eq(MIN_VALUE))
78114             return MIN_VALUE;
78115         return this.not().add(ONE);
78116     };
78117
78118     /**
78119      * Negates this Long's value. This is an alias of {@link Long#negate}.
78120      * @function
78121      * @returns {!Long} Negated Long
78122      */
78123     LongPrototype.neg = LongPrototype.negate;
78124
78125     /**
78126      * Returns the sum of this and the specified Long.
78127      * @param {!Long|number|string} addend Addend
78128      * @returns {!Long} Sum
78129      */
78130     LongPrototype.add = function add(addend) {
78131         if (!isLong(addend))
78132             addend = fromValue(addend);
78133
78134         // Divide each number into 4 chunks of 16 bits, and then sum the chunks.
78135
78136         var a48 = this.high >>> 16;
78137         var a32 = this.high & 0xFFFF;
78138         var a16 = this.low >>> 16;
78139         var a00 = this.low & 0xFFFF;
78140
78141         var b48 = addend.high >>> 16;
78142         var b32 = addend.high & 0xFFFF;
78143         var b16 = addend.low >>> 16;
78144         var b00 = addend.low & 0xFFFF;
78145
78146         var c48 = 0, c32 = 0, c16 = 0, c00 = 0;
78147         c00 += a00 + b00;
78148         c16 += c00 >>> 16;
78149         c00 &= 0xFFFF;
78150         c16 += a16 + b16;
78151         c32 += c16 >>> 16;
78152         c16 &= 0xFFFF;
78153         c32 += a32 + b32;
78154         c48 += c32 >>> 16;
78155         c32 &= 0xFFFF;
78156         c48 += a48 + b48;
78157         c48 &= 0xFFFF;
78158         return fromBits((c16 << 16) | c00, (c48 << 16) | c32, this.unsigned);
78159     };
78160
78161     /**
78162      * Returns the difference of this and the specified Long.
78163      * @param {!Long|number|string} subtrahend Subtrahend
78164      * @returns {!Long} Difference
78165      */
78166     LongPrototype.subtract = function subtract(subtrahend) {
78167         if (!isLong(subtrahend))
78168             subtrahend = fromValue(subtrahend);
78169         return this.add(subtrahend.neg());
78170     };
78171
78172     /**
78173      * Returns the difference of this and the specified Long. This is an alias of {@link Long#subtract}.
78174      * @function
78175      * @param {!Long|number|string} subtrahend Subtrahend
78176      * @returns {!Long} Difference
78177      */
78178     LongPrototype.sub = LongPrototype.subtract;
78179
78180     /**
78181      * Returns the product of this and the specified Long.
78182      * @param {!Long|number|string} multiplier Multiplier
78183      * @returns {!Long} Product
78184      */
78185     LongPrototype.multiply = function multiply(multiplier) {
78186         if (this.isZero())
78187             return ZERO;
78188         if (!isLong(multiplier))
78189             multiplier = fromValue(multiplier);
78190         if (multiplier.isZero())
78191             return ZERO;
78192         if (this.eq(MIN_VALUE))
78193             return multiplier.isOdd() ? MIN_VALUE : ZERO;
78194         if (multiplier.eq(MIN_VALUE))
78195             return this.isOdd() ? MIN_VALUE : ZERO;
78196
78197         if (this.isNegative()) {
78198             if (multiplier.isNegative())
78199                 return this.neg().mul(multiplier.neg());
78200             else
78201                 return this.neg().mul(multiplier).neg();
78202         } else if (multiplier.isNegative())
78203             return this.mul(multiplier.neg()).neg();
78204
78205         // If both longs are small, use float multiplication
78206         if (this.lt(TWO_PWR_24) && multiplier.lt(TWO_PWR_24))
78207             return fromNumber(this.toNumber() * multiplier.toNumber(), this.unsigned);
78208
78209         // Divide each long into 4 chunks of 16 bits, and then add up 4x4 products.
78210         // We can skip products that would overflow.
78211
78212         var a48 = this.high >>> 16;
78213         var a32 = this.high & 0xFFFF;
78214         var a16 = this.low >>> 16;
78215         var a00 = this.low & 0xFFFF;
78216
78217         var b48 = multiplier.high >>> 16;
78218         var b32 = multiplier.high & 0xFFFF;
78219         var b16 = multiplier.low >>> 16;
78220         var b00 = multiplier.low & 0xFFFF;
78221
78222         var c48 = 0, c32 = 0, c16 = 0, c00 = 0;
78223         c00 += a00 * b00;
78224         c16 += c00 >>> 16;
78225         c00 &= 0xFFFF;
78226         c16 += a16 * b00;
78227         c32 += c16 >>> 16;
78228         c16 &= 0xFFFF;
78229         c16 += a00 * b16;
78230         c32 += c16 >>> 16;
78231         c16 &= 0xFFFF;
78232         c32 += a32 * b00;
78233         c48 += c32 >>> 16;
78234         c32 &= 0xFFFF;
78235         c32 += a16 * b16;
78236         c48 += c32 >>> 16;
78237         c32 &= 0xFFFF;
78238         c32 += a00 * b32;
78239         c48 += c32 >>> 16;
78240         c32 &= 0xFFFF;
78241         c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48;
78242         c48 &= 0xFFFF;
78243         return fromBits((c16 << 16) | c00, (c48 << 16) | c32, this.unsigned);
78244     };
78245
78246     /**
78247      * Returns the product of this and the specified Long. This is an alias of {@link Long#multiply}.
78248      * @function
78249      * @param {!Long|number|string} multiplier Multiplier
78250      * @returns {!Long} Product
78251      */
78252     LongPrototype.mul = LongPrototype.multiply;
78253
78254     /**
78255      * Returns this Long divided by the specified. The result is signed if this Long is signed or
78256      *  unsigned if this Long is unsigned.
78257      * @param {!Long|number|string} divisor Divisor
78258      * @returns {!Long} Quotient
78259      */
78260     LongPrototype.divide = function divide(divisor) {
78261         if (!isLong(divisor))
78262             divisor = fromValue(divisor);
78263         if (divisor.isZero())
78264             throw Error('division by zero');
78265         if (this.isZero())
78266             return this.unsigned ? UZERO : ZERO;
78267         var approx, rem, res;
78268         if (!this.unsigned) {
78269             // This section is only relevant for signed longs and is derived from the
78270             // closure library as a whole.
78271             if (this.eq(MIN_VALUE)) {
78272                 if (divisor.eq(ONE) || divisor.eq(NEG_ONE))
78273                     return MIN_VALUE;  // recall that -MIN_VALUE == MIN_VALUE
78274                 else if (divisor.eq(MIN_VALUE))
78275                     return ONE;
78276                 else {
78277                     // At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|.
78278                     var halfThis = this.shr(1);
78279                     approx = halfThis.div(divisor).shl(1);
78280                     if (approx.eq(ZERO)) {
78281                         return divisor.isNegative() ? ONE : NEG_ONE;
78282                     } else {
78283                         rem = this.sub(divisor.mul(approx));
78284                         res = approx.add(rem.div(divisor));
78285                         return res;
78286                     }
78287                 }
78288             } else if (divisor.eq(MIN_VALUE))
78289                 return this.unsigned ? UZERO : ZERO;
78290             if (this.isNegative()) {
78291                 if (divisor.isNegative())
78292                     return this.neg().div(divisor.neg());
78293                 return this.neg().div(divisor).neg();
78294             } else if (divisor.isNegative())
78295                 return this.div(divisor.neg()).neg();
78296             res = ZERO;
78297         } else {
78298             // The algorithm below has not been made for unsigned longs. It's therefore
78299             // required to take special care of the MSB prior to running it.
78300             if (!divisor.unsigned)
78301                 divisor = divisor.toUnsigned();
78302             if (divisor.gt(this))
78303                 return UZERO;
78304             if (divisor.gt(this.shru(1))) // 15 >>> 1 = 7 ; with divisor = 8 ; true
78305                 return UONE;
78306             res = UZERO;
78307         }
78308
78309         // Repeat the following until the remainder is less than other:  find a
78310         // floating-point that approximates remainder / other *from below*, add this
78311         // into the result, and subtract it from the remainder.  It is critical that
78312         // the approximate value is less than or equal to the real value so that the
78313         // remainder never becomes negative.
78314         rem = this;
78315         while (rem.gte(divisor)) {
78316             // Approximate the result of division. This may be a little greater or
78317             // smaller than the actual value.
78318             approx = Math.max(1, Math.floor(rem.toNumber() / divisor.toNumber()));
78319
78320             // We will tweak the approximate result by changing it in the 48-th digit or
78321             // the smallest non-fractional digit, whichever is larger.
78322             var log2 = Math.ceil(Math.log(approx) / Math.LN2),
78323                 delta = (log2 <= 48) ? 1 : pow_dbl(2, log2 - 48),
78324
78325             // Decrease the approximation until it is smaller than the remainder.  Note
78326             // that if it is too large, the product overflows and is negative.
78327                 approxRes = fromNumber(approx),
78328                 approxRem = approxRes.mul(divisor);
78329             while (approxRem.isNegative() || approxRem.gt(rem)) {
78330                 approx -= delta;
78331                 approxRes = fromNumber(approx, this.unsigned);
78332                 approxRem = approxRes.mul(divisor);
78333             }
78334
78335             // We know the answer can't be zero... and actually, zero would cause
78336             // infinite recursion since we would make no progress.
78337             if (approxRes.isZero())
78338                 approxRes = ONE;
78339
78340             res = res.add(approxRes);
78341             rem = rem.sub(approxRem);
78342         }
78343         return res;
78344     };
78345
78346     /**
78347      * Returns this Long divided by the specified. This is an alias of {@link Long#divide}.
78348      * @function
78349      * @param {!Long|number|string} divisor Divisor
78350      * @returns {!Long} Quotient
78351      */
78352     LongPrototype.div = LongPrototype.divide;
78353
78354     /**
78355      * Returns this Long modulo the specified.
78356      * @param {!Long|number|string} divisor Divisor
78357      * @returns {!Long} Remainder
78358      */
78359     LongPrototype.modulo = function modulo(divisor) {
78360         if (!isLong(divisor))
78361             divisor = fromValue(divisor);
78362         return this.sub(this.div(divisor).mul(divisor));
78363     };
78364
78365     /**
78366      * Returns this Long modulo the specified. This is an alias of {@link Long#modulo}.
78367      * @function
78368      * @param {!Long|number|string} divisor Divisor
78369      * @returns {!Long} Remainder
78370      */
78371     LongPrototype.mod = LongPrototype.modulo;
78372
78373     /**
78374      * Returns the bitwise NOT of this Long.
78375      * @returns {!Long}
78376      */
78377     LongPrototype.not = function not() {
78378         return fromBits(~this.low, ~this.high, this.unsigned);
78379     };
78380
78381     /**
78382      * Returns the bitwise AND of this Long and the specified.
78383      * @param {!Long|number|string} other Other Long
78384      * @returns {!Long}
78385      */
78386     LongPrototype.and = function and(other) {
78387         if (!isLong(other))
78388             other = fromValue(other);
78389         return fromBits(this.low & other.low, this.high & other.high, this.unsigned);
78390     };
78391
78392     /**
78393      * Returns the bitwise OR of this Long and the specified.
78394      * @param {!Long|number|string} other Other Long
78395      * @returns {!Long}
78396      */
78397     LongPrototype.or = function or(other) {
78398         if (!isLong(other))
78399             other = fromValue(other);
78400         return fromBits(this.low | other.low, this.high | other.high, this.unsigned);
78401     };
78402
78403     /**
78404      * Returns the bitwise XOR of this Long and the given one.
78405      * @param {!Long|number|string} other Other Long
78406      * @returns {!Long}
78407      */
78408     LongPrototype.xor = function xor(other) {
78409         if (!isLong(other))
78410             other = fromValue(other);
78411         return fromBits(this.low ^ other.low, this.high ^ other.high, this.unsigned);
78412     };
78413
78414     /**
78415      * Returns this Long with bits shifted to the left by the given amount.
78416      * @param {number|!Long} numBits Number of bits
78417      * @returns {!Long} Shifted Long
78418      */
78419     LongPrototype.shiftLeft = function shiftLeft(numBits) {
78420         if (isLong(numBits))
78421             numBits = numBits.toInt();
78422         if ((numBits &= 63) === 0)
78423             return this;
78424         else if (numBits < 32)
78425             return fromBits(this.low << numBits, (this.high << numBits) | (this.low >>> (32 - numBits)), this.unsigned);
78426         else
78427             return fromBits(0, this.low << (numBits - 32), this.unsigned);
78428     };
78429
78430     /**
78431      * Returns this Long with bits shifted to the left by the given amount. This is an alias of {@link Long#shiftLeft}.
78432      * @function
78433      * @param {number|!Long} numBits Number of bits
78434      * @returns {!Long} Shifted Long
78435      */
78436     LongPrototype.shl = LongPrototype.shiftLeft;
78437
78438     /**
78439      * Returns this Long with bits arithmetically shifted to the right by the given amount.
78440      * @param {number|!Long} numBits Number of bits
78441      * @returns {!Long} Shifted Long
78442      */
78443     LongPrototype.shiftRight = function shiftRight(numBits) {
78444         if (isLong(numBits))
78445             numBits = numBits.toInt();
78446         if ((numBits &= 63) === 0)
78447             return this;
78448         else if (numBits < 32)
78449             return fromBits((this.low >>> numBits) | (this.high << (32 - numBits)), this.high >> numBits, this.unsigned);
78450         else
78451             return fromBits(this.high >> (numBits - 32), this.high >= 0 ? 0 : -1, this.unsigned);
78452     };
78453
78454     /**
78455      * Returns this Long with bits arithmetically shifted to the right by the given amount. This is an alias of {@link Long#shiftRight}.
78456      * @function
78457      * @param {number|!Long} numBits Number of bits
78458      * @returns {!Long} Shifted Long
78459      */
78460     LongPrototype.shr = LongPrototype.shiftRight;
78461
78462     /**
78463      * Returns this Long with bits logically shifted to the right by the given amount.
78464      * @param {number|!Long} numBits Number of bits
78465      * @returns {!Long} Shifted Long
78466      */
78467     LongPrototype.shiftRightUnsigned = function shiftRightUnsigned(numBits) {
78468         if (isLong(numBits))
78469             numBits = numBits.toInt();
78470         numBits &= 63;
78471         if (numBits === 0)
78472             return this;
78473         else {
78474             var high = this.high;
78475             if (numBits < 32) {
78476                 var low = this.low;
78477                 return fromBits((low >>> numBits) | (high << (32 - numBits)), high >>> numBits, this.unsigned);
78478             } else if (numBits === 32)
78479                 return fromBits(high, 0, this.unsigned);
78480             else
78481                 return fromBits(high >>> (numBits - 32), 0, this.unsigned);
78482         }
78483     };
78484
78485     /**
78486      * Returns this Long with bits logically shifted to the right by the given amount. This is an alias of {@link Long#shiftRightUnsigned}.
78487      * @function
78488      * @param {number|!Long} numBits Number of bits
78489      * @returns {!Long} Shifted Long
78490      */
78491     LongPrototype.shru = LongPrototype.shiftRightUnsigned;
78492
78493     /**
78494      * Converts this Long to signed.
78495      * @returns {!Long} Signed long
78496      */
78497     LongPrototype.toSigned = function toSigned() {
78498         if (!this.unsigned)
78499             return this;
78500         return fromBits(this.low, this.high, false);
78501     };
78502
78503     /**
78504      * Converts this Long to unsigned.
78505      * @returns {!Long} Unsigned long
78506      */
78507     LongPrototype.toUnsigned = function toUnsigned() {
78508         if (this.unsigned)
78509             return this;
78510         return fromBits(this.low, this.high, true);
78511     };
78512
78513     /**
78514      * Converts this Long to its byte representation.
78515      * @param {boolean=} le Whether little or big endian, defaults to big endian
78516      * @returns {!Array.<number>} Byte representation
78517      */
78518     LongPrototype.toBytes = function(le) {
78519         return le ? this.toBytesLE() : this.toBytesBE();
78520     };
78521
78522     /**
78523      * Converts this Long to its little endian byte representation.
78524      * @returns {!Array.<number>} Little endian byte representation
78525      */
78526     LongPrototype.toBytesLE = function() {
78527         var hi = this.high,
78528             lo = this.low;
78529         return [
78530              lo         & 0xff,
78531             (lo >>>  8) & 0xff,
78532             (lo >>> 16) & 0xff,
78533             (lo >>> 24) & 0xff,
78534              hi         & 0xff,
78535             (hi >>>  8) & 0xff,
78536             (hi >>> 16) & 0xff,
78537             (hi >>> 24) & 0xff
78538         ];
78539     };
78540
78541     /**
78542      * Converts this Long to its big endian byte representation.
78543      * @returns {!Array.<number>} Big endian byte representation
78544      */
78545     LongPrototype.toBytesBE = function() {
78546         var hi = this.high,
78547             lo = this.low;
78548         return [
78549             (hi >>> 24) & 0xff,
78550             (hi >>> 16) & 0xff,
78551             (hi >>>  8) & 0xff,
78552              hi         & 0xff,
78553             (lo >>> 24) & 0xff,
78554             (lo >>> 16) & 0xff,
78555             (lo >>>  8) & 0xff,
78556              lo         & 0xff
78557         ];
78558     };
78559
78560     return Long;
78561 });
78562 }(long));
78563
78564 (function (module) {
78565 /// S2 Geometry functions
78566 // the regional scoreboard is based on a level 6 S2 Cell
78567 // - https://docs.google.com/presentation/d/1Hl4KapfAENAOf4gv-pSngKwvS_jwNVHRPZTTDzXXn6Q/view?pli=1#slide=id.i22
78568 // at the time of writing there's no actual API for the intel map to retrieve scoreboard data,
78569 // but it's still useful to plot the score cells on the intel map
78570
78571
78572 // the S2 geometry is based on projecting the earth sphere onto a cube, with some scaling of face coordinates to
78573 // keep things close to approximate equal area for adjacent cells
78574 // to convert a lat,lng into a cell id:
78575 // - convert lat,lng to x,y,z
78576 // - convert x,y,z into face,u,v
78577 // - u,v scaled to s,t with quadratic formula
78578 // - s,t converted to integer i,j offsets
78579 // - i,j converted to a position along a Hubbert space-filling curve
78580 // - combine face,position to get the cell id
78581
78582 //NOTE: compared to the google S2 geometry library, we vary from their code in the following ways
78583 // - cell IDs: they combine face and the hilbert curve position into a single 64 bit number. this gives efficient space
78584 //             and speed. javascript doesn't have appropriate data types, and speed is not cricical, so we use
78585 //             as [face,[bitpair,bitpair,...]] instead
78586 // - i,j: they always use 30 bits, adjusting as needed. we use 0 to (1<<level)-1 instead
78587 //        (so GetSizeIJ for a cell is always 1)
78588
78589 (function (exports) {
78590
78591 var S2 = exports.S2 = { L: {} };
78592
78593 S2.L.LatLng = function (/*Number*/ rawLat, /*Number*/ rawLng, /*Boolean*/ noWrap) {
78594   var lat = parseFloat(rawLat, 10);
78595   var lng = parseFloat(rawLng, 10);
78596
78597   if (isNaN(lat) || isNaN(lng)) {
78598     throw new Error('Invalid LatLng object: (' + rawLat + ', ' + rawLng + ')');
78599   }
78600
78601   if (noWrap !== true) {
78602     lat = Math.max(Math.min(lat, 90), -90);                 // clamp latitude into -90..90
78603     lng = (lng + 180) % 360 + ((lng < -180 || lng === 180) ? 180 : -180);   // wrap longtitude into -180..180
78604   }
78605
78606   return { lat: lat, lng: lng };
78607 };
78608
78609 S2.L.LatLng.DEG_TO_RAD = Math.PI / 180;
78610 S2.L.LatLng.RAD_TO_DEG = 180 / Math.PI;
78611
78612 /*
78613 S2.LatLngToXYZ = function(latLng) {
78614   // http://stackoverflow.com/questions/8981943/lat-long-to-x-y-z-position-in-js-not-working
78615   var lat = latLng.lat;
78616   var lon = latLng.lng;
78617   var DEG_TO_RAD = Math.PI / 180.0;
78618
78619   var phi = lat * DEG_TO_RAD;
78620   var theta = lon * DEG_TO_RAD;
78621
78622   var cosLat = Math.cos(phi);
78623   var sinLat = Math.sin(phi);
78624   var cosLon = Math.cos(theta);
78625   var sinLon = Math.sin(theta);
78626   var rad = 500.0;
78627
78628   return [
78629     rad * cosLat * cosLon
78630   , rad * cosLat * sinLon
78631   , rad * sinLat
78632   ];
78633 };
78634 */
78635 S2.LatLngToXYZ = function(latLng) {
78636   var d2r = S2.L.LatLng.DEG_TO_RAD;
78637
78638   var phi = latLng.lat*d2r;
78639   var theta = latLng.lng*d2r;
78640
78641   var cosphi = Math.cos(phi);
78642
78643   return [Math.cos(theta)*cosphi, Math.sin(theta)*cosphi, Math.sin(phi)];
78644 };
78645
78646 S2.XYZToLatLng = function(xyz) {
78647   var r2d = S2.L.LatLng.RAD_TO_DEG;
78648
78649   var lat = Math.atan2(xyz[2], Math.sqrt(xyz[0]*xyz[0]+xyz[1]*xyz[1]));
78650   var lng = Math.atan2(xyz[1], xyz[0]);
78651
78652   return S2.L.LatLng(lat*r2d, lng*r2d);
78653 };
78654
78655 var largestAbsComponent = function(xyz) {
78656   var temp = [Math.abs(xyz[0]), Math.abs(xyz[1]), Math.abs(xyz[2])];
78657
78658   if (temp[0] > temp[1]) {
78659     if (temp[0] > temp[2]) {
78660       return 0;
78661     } else {
78662       return 2;
78663     }
78664   } else {
78665     if (temp[1] > temp[2]) {
78666       return 1;
78667     } else {
78668       return 2;
78669     }
78670   }
78671
78672 };
78673
78674 var faceXYZToUV = function(face,xyz) {
78675   var u,v;
78676
78677   switch (face) {
78678     case 0: u =  xyz[1]/xyz[0]; v =  xyz[2]/xyz[0]; break;
78679     case 1: u = -xyz[0]/xyz[1]; v =  xyz[2]/xyz[1]; break;
78680     case 2: u = -xyz[0]/xyz[2]; v = -xyz[1]/xyz[2]; break;
78681     case 3: u =  xyz[2]/xyz[0]; v =  xyz[1]/xyz[0]; break;
78682     case 4: u =  xyz[2]/xyz[1]; v = -xyz[0]/xyz[1]; break;
78683     case 5: u = -xyz[1]/xyz[2]; v = -xyz[0]/xyz[2]; break;
78684     default: throw {error: 'Invalid face'};
78685   }
78686
78687   return [u,v];
78688 };
78689
78690
78691
78692
78693 S2.XYZToFaceUV = function(xyz) {
78694   var face = largestAbsComponent(xyz);
78695
78696   if (xyz[face] < 0) {
78697     face += 3;
78698   }
78699
78700   var uv = faceXYZToUV (face,xyz);
78701
78702   return [face, uv];
78703 };
78704
78705 S2.FaceUVToXYZ = function(face,uv) {
78706   var u = uv[0];
78707   var v = uv[1];
78708
78709   switch (face) {
78710     case 0: return [ 1, u, v];
78711     case 1: return [-u, 1, v];
78712     case 2: return [-u,-v, 1];
78713     case 3: return [-1,-v,-u];
78714     case 4: return [ v,-1,-u];
78715     case 5: return [ v, u,-1];
78716     default: throw {error: 'Invalid face'};
78717   }
78718 };
78719
78720 var singleSTtoUV = function(st) {
78721   if (st >= 0.5) {
78722     return (1/3.0) * (4*st*st - 1);
78723   } else {
78724     return (1/3.0) * (1 - (4*(1-st)*(1-st)));
78725   }
78726 };
78727
78728 S2.STToUV = function(st) {
78729   return [singleSTtoUV(st[0]), singleSTtoUV(st[1])];
78730 };
78731
78732
78733 var singleUVtoST = function(uv) {
78734   if (uv >= 0) {
78735     return 0.5 * Math.sqrt (1 + 3*uv);
78736   } else {
78737     return 1 - 0.5 * Math.sqrt (1 - 3*uv);
78738   }
78739 };
78740 S2.UVToST = function(uv) {
78741   return [singleUVtoST(uv[0]), singleUVtoST(uv[1])];
78742 };
78743
78744
78745 S2.STToIJ = function(st,order) {
78746   var maxSize = (1<<order);
78747
78748   var singleSTtoIJ = function(st) {
78749     var ij = Math.floor(st * maxSize);
78750     return Math.max(0, Math.min(maxSize-1, ij));
78751   };
78752
78753   return [singleSTtoIJ(st[0]), singleSTtoIJ(st[1])];
78754 };
78755
78756
78757 S2.IJToST = function(ij,order,offsets) {
78758   var maxSize = (1<<order);
78759
78760   return [
78761     (ij[0]+offsets[0])/maxSize,
78762     (ij[1]+offsets[1])/maxSize
78763   ];
78764 };
78765
78766
78767
78768 var rotateAndFlipQuadrant = function(n, point, rx, ry)
78769 {
78770         if(ry == 0)
78771         {
78772                 if(rx == 1){
78773                         point.x = n - 1 - point.x;
78774                         point.y = n - 1 - point.y;
78775
78776                 }
78777
78778     var x = point.x;
78779                 point.x = point.y;
78780                 point.y = x;
78781         }
78782
78783 };
78784
78785
78786
78787
78788
78789 // hilbert space-filling curve
78790 // based on http://blog.notdot.net/2009/11/Damn-Cool-Algorithms-Spatial-indexing-with-Quadtrees-and-Hilbert-Curves
78791 // note: rather then calculating the final integer hilbert position, we just return the list of quads
78792 // this ensures no precision issues whth large orders (S3 cell IDs use up to 30), and is more
78793 // convenient for pulling out the individual bits as needed later
78794 var pointToHilbertQuadList = function(x,y,order,face) {
78795   var hilbertMap = {
78796     'a': [ [0,'d'], [1,'a'], [3,'b'], [2,'a'] ],
78797     'b': [ [2,'b'], [1,'b'], [3,'a'], [0,'c'] ],
78798     'c': [ [2,'c'], [3,'d'], [1,'c'], [0,'b'] ],
78799     'd': [ [0,'a'], [3,'c'], [1,'d'], [2,'d'] ]
78800   };
78801
78802   if ('number' !== typeof face) {
78803     console.warn(new Error("called pointToHilbertQuadList without face value, defaulting to '0'").stack);
78804   }
78805   var currentSquare = (face % 2) ? 'd' : 'a';
78806   var positions = [];
78807
78808   for (var i=order-1; i>=0; i--) {
78809
78810     var mask = 1<<i;
78811
78812     var quad_x = x&mask ? 1 : 0;
78813     var quad_y = y&mask ? 1 : 0;
78814
78815     var t = hilbertMap[currentSquare][quad_x*2+quad_y];
78816
78817     positions.push(t[0]);
78818
78819     currentSquare = t[1];
78820   }
78821
78822   return positions;
78823 };
78824
78825 // S2Cell class
78826
78827 S2.S2Cell = function(){};
78828
78829 S2.S2Cell.FromHilbertQuadKey = function(hilbertQuadkey) {
78830   var parts = hilbertQuadkey.split('/');
78831   var face = parseInt(parts[0]);
78832   var position = parts[1];
78833   var maxLevel = position.length;
78834   var point = {
78835     x : 0,
78836     y: 0
78837   };
78838   var i;
78839   var level;
78840   var bit;
78841   var rx, ry;
78842   var val;
78843
78844         for(i = maxLevel - 1; i >= 0; i--) {
78845
78846                 level = maxLevel - i;
78847                 bit = position[i];
78848                 rx = 0;
78849     ry = 0;
78850                 if (bit === '1') {
78851                         ry = 1;
78852                 }
78853                 else if (bit === '2') {
78854                         rx = 1;
78855                         ry = 1;
78856                 }
78857                 else if (bit === '3') {
78858                         rx = 1;
78859                 }
78860
78861                 val = Math.pow(2, level - 1);
78862                 rotateAndFlipQuadrant(val, point, rx, ry);
78863
78864                 point.x += val * rx;
78865                 point.y += val * ry;
78866
78867         }
78868
78869   if (face % 2 === 1) {
78870     var t = point.x;
78871     point.x = point.y;
78872     point.y = t;
78873   }
78874
78875
78876   return S2.S2Cell.FromFaceIJ(parseInt(face), [point.x, point.y], level);
78877 };
78878
78879 //static method to construct
78880 S2.S2Cell.FromLatLng = function(latLng, level) {
78881   if ((!latLng.lat && latLng.lat !== 0) || (!latLng.lng && latLng.lng !== 0)) {
78882     throw new Error("Pass { lat: lat, lng: lng } to S2.S2Cell.FromLatLng");
78883   }
78884   var xyz = S2.LatLngToXYZ(latLng);
78885
78886   var faceuv = S2.XYZToFaceUV(xyz);
78887   var st = S2.UVToST(faceuv[1]);
78888
78889   var ij = S2.STToIJ(st,level);
78890
78891   return S2.S2Cell.FromFaceIJ (faceuv[0], ij, level);
78892 };
78893
78894 /*
78895 S2.faceIjLevelToXyz = function (face, ij, level) {
78896   var st = S2.IJToST(ij, level, [0.5, 0.5]);
78897   var uv = S2.STToUV(st);
78898   var xyz = S2.FaceUVToXYZ(face, uv);
78899
78900   return S2.XYZToLatLng(xyz);
78901   return xyz;
78902 };
78903 */
78904
78905 S2.S2Cell.FromFaceIJ = function(face,ij,level) {
78906   var cell = new S2.S2Cell();
78907   cell.face = face;
78908   cell.ij = ij;
78909   cell.level = level;
78910
78911   return cell;
78912 };
78913
78914
78915 S2.S2Cell.prototype.toString = function() {
78916   return 'F'+this.face+'ij['+this.ij[0]+','+this.ij[1]+']@'+this.level;
78917 };
78918
78919 S2.S2Cell.prototype.getLatLng = function() {
78920   var st = S2.IJToST(this.ij,this.level, [0.5,0.5]);
78921   var uv = S2.STToUV(st);
78922   var xyz = S2.FaceUVToXYZ(this.face, uv);
78923
78924   return S2.XYZToLatLng(xyz);
78925 };
78926
78927 S2.S2Cell.prototype.getCornerLatLngs = function() {
78928   var result = [];
78929   var offsets = [
78930     [ 0.0, 0.0 ],
78931     [ 0.0, 1.0 ],
78932     [ 1.0, 1.0 ],
78933     [ 1.0, 0.0 ]
78934   ];
78935
78936   for (var i=0; i<4; i++) {
78937     var st = S2.IJToST(this.ij, this.level, offsets[i]);
78938     var uv = S2.STToUV(st);
78939     var xyz = S2.FaceUVToXYZ(this.face, uv);
78940
78941     result.push ( S2.XYZToLatLng(xyz) );
78942   }
78943   return result;
78944 };
78945
78946
78947 S2.S2Cell.prototype.getFaceAndQuads = function () {
78948   var quads = pointToHilbertQuadList(this.ij[0], this.ij[1], this.level, this.face);
78949
78950   return [this.face,quads];
78951 };
78952 S2.S2Cell.prototype.toHilbertQuadkey = function () {
78953   var quads = pointToHilbertQuadList(this.ij[0], this.ij[1], this.level, this.face);
78954
78955   return this.face.toString(10) + '/' + quads.join('');
78956 };
78957
78958 S2.latLngToNeighborKeys = S2.S2Cell.latLngToNeighborKeys = function (lat, lng, level) {
78959   return S2.S2Cell.FromLatLng({ lat: lat, lng: lng }, level).getNeighbors().map(function (cell) {
78960     return cell.toHilbertQuadkey();
78961   });
78962 };
78963 S2.S2Cell.prototype.getNeighbors = function() {
78964
78965   var fromFaceIJWrap = function(face,ij,level) {
78966     var maxSize = (1<<level);
78967     if (ij[0]>=0 && ij[1]>=0 && ij[0]<maxSize && ij[1]<maxSize) {
78968       // no wrapping out of bounds
78969       return S2.S2Cell.FromFaceIJ(face,ij,level);
78970     } else {
78971       // the new i,j are out of range.
78972       // with the assumption that they're only a little past the borders we can just take the points as
78973       // just beyond the cube face, project to XYZ, then re-create FaceUV from the XYZ vector
78974
78975       var st = S2.IJToST(ij,level,[0.5,0.5]);
78976       var uv = S2.STToUV(st);
78977       var xyz = S2.FaceUVToXYZ(face,uv);
78978       var faceuv = S2.XYZToFaceUV(xyz);
78979       face = faceuv[0];
78980       uv = faceuv[1];
78981       st = S2.UVToST(uv);
78982       ij = S2.STToIJ(st,level);
78983       return S2.S2Cell.FromFaceIJ (face, ij, level);
78984     }
78985   };
78986
78987   var face = this.face;
78988   var i = this.ij[0];
78989   var j = this.ij[1];
78990   var level = this.level;
78991
78992
78993   return [
78994     fromFaceIJWrap(face, [i-1,j], level),
78995     fromFaceIJWrap(face, [i,j-1], level),
78996     fromFaceIJWrap(face, [i+1,j], level),
78997     fromFaceIJWrap(face, [i,j+1], level)
78998   ];
78999
79000 };
79001
79002 //
79003 // Functional Style
79004 //
79005 S2.FACE_BITS = 3;
79006 S2.MAX_LEVEL = 30;
79007 S2.POS_BITS = (2 * S2.MAX_LEVEL) + 1; // 61 (60 bits of data, 1 bit lsb marker)
79008
79009 S2.facePosLevelToId = S2.S2Cell.facePosLevelToId = S2.fromFacePosLevel = function (faceN, posS, levelN) {
79010   var Long = exports.dcodeIO && exports.dcodeIO.Long || long.exports;
79011   var faceB;
79012   var posB;
79013   var bin;
79014
79015   if (!levelN) {
79016     levelN = posS.length;
79017   }
79018   if (posS.length > levelN) {
79019     posS = posS.substr(0, levelN);
79020   }
79021
79022   // 3-bit face value
79023   faceB = Long.fromString(faceN.toString(10), true, 10).toString(2);
79024   while (faceB.length < S2.FACE_BITS) {
79025     faceB = '0' + faceB;
79026   }
79027
79028   // 60-bit position value
79029   posB = Long.fromString(posS, true, 4).toString(2);
79030   while (posB.length < (2 * levelN)) {
79031     posB = '0' + posB;
79032   }
79033
79034   bin = faceB + posB;
79035   // 1-bit lsb marker
79036   bin += '1';
79037   // n-bit padding to 64-bits
79038   while (bin.length < (S2.FACE_BITS + S2.POS_BITS)) {
79039     bin += '0';
79040   }
79041
79042   return Long.fromString(bin, true, 2).toString(10);
79043 };
79044
79045 S2.keyToId = S2.S2Cell.keyToId
79046 = S2.toId = S2.toCellId = S2.fromKey
79047 = function (key) {
79048   var parts = key.split('/');
79049
79050   return S2.fromFacePosLevel(parts[0], parts[1], parts[1].length);
79051 };
79052
79053 S2.idToKey = S2.S2Cell.idToKey
79054 = S2.S2Cell.toKey = S2.toKey
79055 = S2.fromId = S2.fromCellId
79056 = S2.S2Cell.toHilbertQuadkey  = S2.toHilbertQuadkey
79057 = function (idS) {
79058   var Long = exports.dcodeIO && exports.dcodeIO.Long || long.exports;
79059   var bin = Long.fromString(idS, true, 10).toString(2);
79060
79061   while (bin.length < (S2.FACE_BITS + S2.POS_BITS)) {
79062     bin = '0' + bin;
79063   }
79064
79065   // MUST come AFTER binstr has been left-padded with '0's
79066   var lsbIndex = bin.lastIndexOf('1');
79067   // substr(start, len)
79068   // substring(start, end) // includes start, does not include end
79069   var faceB = bin.substring(0, 3);
79070   // posB will always be a multiple of 2 (or it's invalid)
79071   var posB = bin.substring(3, lsbIndex);
79072   var levelN = posB.length / 2;
79073
79074   var faceS = Long.fromString(faceB, true, 2).toString(10);
79075   var posS = Long.fromString(posB, true, 2).toString(4);
79076
79077   while (posS.length < levelN) {
79078     posS = '0' + posS;
79079   }
79080
79081   return faceS + '/' + posS;
79082 };
79083
79084 S2.keyToLatLng = S2.S2Cell.keyToLatLng = function (key) {
79085   var cell2 = S2.S2Cell.FromHilbertQuadKey(key);
79086   return cell2.getLatLng();
79087 };
79088
79089 S2.idToLatLng = S2.S2Cell.idToLatLng = function (id) {
79090   var key = S2.idToKey(id);
79091   return S2.keyToLatLng(key);
79092 };
79093
79094 S2.S2Cell.latLngToKey = S2.latLngToKey
79095 = S2.latLngToQuadkey = function (lat, lng, level) {
79096   if (isNaN(level) || level < 1 || level > 30) {
79097     throw new Error("'level' is not a number between 1 and 30 (but it should be)");
79098   }
79099   // TODO
79100   //
79101   // S2.idToLatLng(id)
79102   // S2.keyToLatLng(key)
79103   // S2.nextFace(key)     // prevent wrapping on nextKey
79104   // S2.prevFace(key)     // prevent wrapping on prevKey
79105   //
79106   // .toKeyArray(id)  // face,quadtree
79107   // .toKey(id)       // hilbert
79108   // .toPoint(id)     // ij
79109   // .toId(key)       // uint64 (as string)
79110   // .toLong(key)     // long.js
79111   // .toLatLng(id)    // object? or array?, or string (with comma)?
79112   //
79113   // maybe S2.HQ.x, S2.GPS.x, S2.CI.x?
79114   return S2.S2Cell.FromLatLng({ lat: lat, lng: lng }, level).toHilbertQuadkey();
79115 };
79116
79117 S2.stepKey = function (key, num) {
79118   var Long = exports.dcodeIO && exports.dcodeIO.Long || long.exports;
79119   var parts = key.split('/');
79120
79121   var faceS = parts[0];
79122   var posS = parts[1];
79123   var level = parts[1].length;
79124
79125   var posL = Long.fromString(posS, true, 4);
79126   // TODO handle wrapping (0 === pos + 1)
79127   // (only on the 12 edges of the globe)
79128   var otherL;
79129   if (num > 0) {
79130     otherL = posL.add(Math.abs(num));
79131   }
79132   else if (num < 0) {
79133     otherL = posL.subtract(Math.abs(num));
79134   }
79135   var otherS = otherL.toString(4);
79136
79137   if ('0' === otherS) {
79138     console.warning(new Error("face/position wrapping is not yet supported"));
79139   }
79140
79141   while (otherS.length < level) {
79142     otherS = '0' + otherS;
79143   }
79144
79145   return faceS + '/' + otherS;
79146 };
79147
79148 S2.S2Cell.prevKey = S2.prevKey = function (key) {
79149   return S2.stepKey(key, -1);
79150 };
79151
79152 S2.S2Cell.nextKey = S2.nextKey = function (key) {
79153   return S2.stepKey(key, 1);
79154 };
79155
79156 })(module.exports );
79157 }(s2geometry));
79158
79159 /**
79160  * @class S2GeometryProvider
79161  *
79162  * @classdesc Geometry provider based on S2 cells.
79163  *
79164  * @example
79165  * ```js
79166  * class MyDataProvider extends DataProviderBase {
79167  *      ...
79168  * }
79169  *
79170  * const geometryProvider = new S2GeometryProvider();
79171  * const dataProvider = new MyDataProvider(geometryProvider);
79172  * ```
79173  */
79174 class S2GeometryProvider extends GeometryProviderBase {
79175     /**
79176      * Create a new S2 geometry provider instance.
79177      */
79178     constructor(_level = 17) {
79179         super();
79180         this._level = _level;
79181     }
79182     /** @inheritdoc */
79183     bboxToCellIds(sw, ne) {
79184         return this._approxBboxToCellIds(sw, ne);
79185     }
79186     /** @inheritdoc */
79187     getAdjacent(cellId) {
79188         const k = s2geometry.exports.S2.idToKey(cellId);
79189         const position = k.split('/')[1];
79190         const level = position.length;
79191         const [a0, a1, a2, a3] = this._getNeighbors(k, level);
79192         const existing = [k, a0, a1, a2, a3];
79193         const others = Array
79194             .from(new Set([
79195             ...this._getNeighbors(a0, level),
79196             ...this._getNeighbors(a1, level),
79197             ...this._getNeighbors(a2, level),
79198             ...this._getNeighbors(a3, level),
79199         ].filter((o) => {
79200             return !existing.includes(o);
79201         })));
79202         const adjacent = [a0, a1, a2, a3];
79203         for (const other of others) {
79204             let count = 0;
79205             for (const n of this._getNeighbors(other, level)) {
79206                 if (existing.includes(n)) {
79207                     count++;
79208                 }
79209             }
79210             if (count === 2) {
79211                 adjacent.push(other);
79212             }
79213         }
79214         return adjacent.map((a) => s2geometry.exports.S2.keyToId(a));
79215     }
79216     /** @inheritdoc */
79217     getVertices(cellId) {
79218         const key = s2geometry.exports.S2.idToKey(cellId);
79219         const cell = s2geometry.exports.S2.S2Cell.FromHilbertQuadKey(key);
79220         return cell
79221             .getCornerLatLngs()
79222             .map((c) => {
79223             return { lat: c.lat, lng: c.lng };
79224         });
79225     }
79226     /** @inheritdoc */
79227     lngLatToCellId(lngLat) {
79228         return this._lngLatToId(lngLat, this._level);
79229     }
79230     _getNeighbors(s2key, level) {
79231         const latlng = s2geometry.exports.S2.keyToLatLng(s2key);
79232         const neighbors = s2geometry.exports.S2.latLngToNeighborKeys(latlng.lat, latlng.lng, level);
79233         return neighbors;
79234     }
79235     _lngLatToId(lngLat, level) {
79236         const s2key = s2geometry.exports.S2.latLngToKey(lngLat.lat, lngLat.lng, level);
79237         return s2geometry.exports.S2.keyToId(s2key);
79238     }
79239 }
79240
79241 function convertCameraType(graphCameraType) {
79242     switch (graphCameraType) {
79243         case "equirectangular":
79244         case "spherical":
79245             return "spherical";
79246         case "fisheye":
79247             return "fisheye";
79248         default:
79249             return "perspective";
79250     }
79251 }
79252 class GraphConverter {
79253     clusterReconstruction(source) {
79254         const id = null;
79255         const points = source.points;
79256         const normalize = 1 / 255;
79257         for (const pointId in points) {
79258             if (!points.hasOwnProperty(pointId)) {
79259                 continue;
79260             }
79261             const color = points[pointId].color;
79262             color[0] *= normalize;
79263             color[1] *= normalize;
79264             color[2] *= normalize;
79265         }
79266         const lla = source.reference_lla;
79267         const reference = {
79268             alt: lla.altitude,
79269             lat: lla.latitude,
79270             lng: lla.longitude,
79271         };
79272         return {
79273             id,
79274             points,
79275             reference,
79276         };
79277     }
79278     coreImage(source) {
79279         const geometry = this._geometry(source.geometry);
79280         const computedGeometry = this._geometry(source.computed_geometry);
79281         const sequence = { id: source.sequence };
79282         const id = source.id;
79283         return {
79284             computed_geometry: computedGeometry,
79285             geometry,
79286             id,
79287             sequence,
79288         };
79289     }
79290     spatialImage(source) {
79291         var _a, _b, _c, _d;
79292         source.camera_type = convertCameraType(source.camera_type);
79293         source.merge_id = source.merge_cc ? source.merge_cc.toString() : null;
79294         source.private = null;
79295         const thumbUrl = source.camera_type === 'spherical' ?
79296             source.thumb_2048_url : source.thumb_1024_url;
79297         source.thumb = (_a = source.thumb) !== null && _a !== void 0 ? _a : { id: null, url: thumbUrl };
79298         source.cluster = (_b = source.sfm_cluster) !== null && _b !== void 0 ? _b : { id: null, url: null };
79299         source.creator = { id: null, username: null };
79300         source.owner = (_c = source.organization) !== null && _c !== void 0 ? _c : { id: null };
79301         source.mesh = (_d = source.mesh) !== null && _d !== void 0 ? _d : { id: null, url: null };
79302         return source;
79303     }
79304     _geometry(geometry) {
79305         const coords = geometry === null || geometry === void 0 ? void 0 : geometry.coordinates;
79306         const lngLat = coords ?
79307             {
79308                 lat: coords[1],
79309                 lng: coords[0],
79310             } : null;
79311         return lngLat;
79312     }
79313 }
79314
79315 class GraphQueryCreator {
79316     constructor() {
79317         this.imagesPath = 'images';
79318         this.sequencePath = 'image_ids';
79319         this._imageTilesPath = 'tiles';
79320         this.coreFields = ['computed_geometry', 'geometry', 'sequence'];
79321         this.idFields = ['id'];
79322         this.spatialFields = [
79323             'altitude',
79324             'atomic_scale',
79325             'camera_parameters',
79326             'camera_type',
79327             'captured_at',
79328             'compass_angle',
79329             'computed_altitude',
79330             'computed_compass_angle',
79331             'computed_rotation',
79332             'exif_orientation',
79333             'height',
79334             'merge_cc',
79335             'mesh',
79336             'organization',
79337             'quality_score',
79338             'sfm_cluster',
79339             'thumb_1024_url',
79340             'thumb_2048_url',
79341             'width',
79342         ];
79343         this.imageTileFields = ['url', 'z', 'x', 'y'];
79344     }
79345     images(imageIds, fields) {
79346         return `image_ids=${imageIds.join(',')}&fields=${fields.join(',')}`;
79347     }
79348     imagesS2(cellId, fields) {
79349         return `s2=${cellId}&fields=${fields.join(',')}`;
79350     }
79351     imageTiles(z, fields) {
79352         return `z=${z}&fields=${fields.join(',')}`;
79353     }
79354     imageTilesPath(imageId) {
79355         return `${imageId}/${this._imageTilesPath}`;
79356     }
79357     sequence(sequenceId) {
79358         return `sequence_id=${sequenceId}`;
79359     }
79360 }
79361
79362 class GraphDataProvider extends DataProviderBase {
79363     constructor(options, geometry, converter, queryCreator) {
79364         var _a;
79365         super(geometry !== null && geometry !== void 0 ? geometry : new S2GeometryProvider());
79366         this._convert = converter !== null && converter !== void 0 ? converter : new GraphConverter();
79367         this._query = queryCreator !== null && queryCreator !== void 0 ? queryCreator : new GraphQueryCreator();
79368         this._method = 'GET';
79369         const opts = options !== null && options !== void 0 ? options : {};
79370         this._endpoint = (_a = opts.endpoint) !== null && _a !== void 0 ? _a : "https://graph.mapillary.com";
79371         this._accessToken = opts.accessToken;
79372     }
79373     getCluster(url, abort) {
79374         return fetchArrayBuffer(url, abort)
79375             .then((buffer) => {
79376             const reconstructions = decompress(buffer);
79377             if (reconstructions.length < 1) {
79378                 throw new Error('Cluster reconstruction empty');
79379             }
79380             return this._convert
79381                 .clusterReconstruction(reconstructions[0]);
79382         });
79383     }
79384     getCoreImages(cellId) {
79385         const fields = [
79386             ...this._query.idFields,
79387             ...this._query.coreFields,
79388         ];
79389         const query = this._query.imagesS2(cellId, fields);
79390         const url = new URL(this._query.imagesPath, this._endpoint).href;
79391         return this
79392             ._fetchGraphContract(query, url)
79393             .then(r => {
79394             const result = {
79395                 cell_id: cellId,
79396                 images: [],
79397             };
79398             const items = r.data;
79399             for (const item of items) {
79400                 const coreImage = this._convert.coreImage(item);
79401                 result.images.push(coreImage);
79402             }
79403             return result;
79404         });
79405     }
79406     getImageBuffer(url, abort) {
79407         return fetchArrayBuffer(url, abort);
79408     }
79409     getImages(imageIds) {
79410         const fields = [
79411             ...this._query.idFields,
79412             ...this._query.coreFields,
79413             ...this._query.spatialFields,
79414         ];
79415         const query = this._query.images(imageIds, fields);
79416         const url = new URL(this._query.imagesPath, this._endpoint).href;
79417         return this
79418             ._fetchGraphContract(query, url)
79419             .then(r => {
79420             const result = [];
79421             const items = r.data;
79422             for (const item of items) {
79423                 const coreImage = this._convert.coreImage(item);
79424                 const spatialImage = this._convert.spatialImage(item);
79425                 const image = Object.assign({}, spatialImage, coreImage);
79426                 const contract = {
79427                     node: image,
79428                     node_id: item.id,
79429                 };
79430                 result.push(contract);
79431             }
79432             return result;
79433         });
79434     }
79435     getImageTiles(request) {
79436         const fields = [
79437             ...this._query.imageTileFields,
79438         ];
79439         const query = this._query.imageTiles(request.z, fields);
79440         const url = new URL(this._query.imageTilesPath(request.imageId), this._endpoint).href;
79441         return this
79442             ._fetchGraphContract(query, url)
79443             .then(r => {
79444             const result = {
79445                 node: r.data,
79446                 node_id: request.imageId,
79447             };
79448             return result;
79449         });
79450     }
79451     getMesh(url, abort) {
79452         return fetchArrayBuffer(url, abort)
79453             .then((buffer) => {
79454             return readMeshPbf(buffer);
79455         });
79456     }
79457     getSequence(sequenceId) {
79458         const query = this._query.sequence(sequenceId);
79459         const url = new URL(this._query.sequencePath, this._endpoint).href;
79460         return this
79461             ._fetchGraphContract(query, url)
79462             .then(r => {
79463             const result = {
79464                 id: sequenceId,
79465                 image_ids: r.data.map(item => item.id),
79466             };
79467             return result;
79468         });
79469     }
79470     getSpatialImages(imageIds) {
79471         const fields = [
79472             ...this._query.idFields,
79473             ...this._query.coreFields,
79474             ...this._query.spatialFields,
79475         ];
79476         const query = this._query.images(imageIds, fields);
79477         const url = new URL(this._query.imagesPath, this._endpoint).href;
79478         return this
79479             ._fetchGraphContract(query, url)
79480             .then(r => {
79481             const result = [];
79482             const items = r.data;
79483             for (const item of items) {
79484                 const spatialImage = this._convert.spatialImage(item);
79485                 const contract = {
79486                     node: spatialImage,
79487                     node_id: item.id,
79488                 };
79489                 result.push(contract);
79490             }
79491             return result;
79492         });
79493     }
79494     setAccessToken(accessToken) {
79495         this._accessToken = accessToken;
79496     }
79497     _createHeaders() {
79498         const headers = [
79499             { name: 'Accept', value: 'application/json' },
79500             {
79501                 name: 'Content-Type',
79502                 value: 'application/x-www-form-urlencoded',
79503             },
79504         ];
79505         if (this._accessToken) {
79506             headers.push({
79507                 name: 'Authorization',
79508                 value: `OAuth ${this._accessToken}`,
79509             });
79510         }
79511         return headers;
79512     }
79513     _fetchGraphContract(body, url) {
79514         const method = this._method;
79515         const headers = this._createHeaders();
79516         const query = `${url}?${body}`;
79517         return xhrFetch(query, method, "json", headers, null, null)
79518             .catch((error) => {
79519             const message = this._makeErrorMessage(error);
79520             throw new MapillaryError(message);
79521         });
79522     }
79523     _makeErrorMessage(graphError) {
79524         const error = graphError.error;
79525         const message = error ?
79526             `${error.code} (${error.type}, ${error.fbtrace_id}): ${error.message}` :
79527             "Failed to fetch data";
79528         return message;
79529     }
79530 }
79531
79532 /**
79533  * @class Marker
79534  *
79535  * @classdesc Represents an abstract marker class that should be extended
79536  * by marker implementations used in the marker component.
79537  */
79538 class Marker {
79539     constructor(id, lngLat) {
79540         this._id = id;
79541         this._lngLat = lngLat;
79542     }
79543     /**
79544      * Get id.
79545      * @returns {string} The id of the marker.
79546      */
79547     get id() {
79548         return this._id;
79549     }
79550     /**
79551      * Get geometry.
79552      *
79553      * @ignore
79554      */
79555     get geometry() {
79556         return this._geometry;
79557     }
79558     /**
79559      * Get lngLat.
79560      * @returns {LngLat} The geographic coordinates of the marker.
79561      */
79562     get lngLat() {
79563         return this._lngLat;
79564     }
79565     /** @ignore */
79566     createGeometry(position) {
79567         if (!!this._geometry) {
79568             return;
79569         }
79570         this._createGeometry(position);
79571         // update matrix world if raycasting occurs before first render
79572         this._geometry.updateMatrixWorld(true);
79573     }
79574     /** @ignore */
79575     disposeGeometry() {
79576         if (!this._geometry) {
79577             return;
79578         }
79579         this._disposeGeometry();
79580         this._geometry = undefined;
79581     }
79582     /** @ignore */
79583     getInteractiveObjects() {
79584         if (!this._geometry) {
79585             return [];
79586         }
79587         return this._getInteractiveObjects();
79588     }
79589     /** @ignore */
79590     lerpAltitude(alt, alpha) {
79591         if (!this._geometry) {
79592             return;
79593         }
79594         this._geometry.position.z =
79595             (1 - alpha) * this._geometry.position.z + alpha * alt;
79596     }
79597     /** @ignore */
79598     updatePosition(position, lngLat) {
79599         if (!!lngLat) {
79600             this._lngLat.lat = lngLat.lat;
79601             this._lngLat.lng = lngLat.lng;
79602         }
79603         if (!this._geometry) {
79604             return;
79605         }
79606         this._geometry.position.fromArray(position);
79607         this._geometry.updateMatrixWorld(true);
79608     }
79609 }
79610
79611 /**
79612  * @class CircleMarker
79613  *
79614  * @classdesc Non-interactive marker with a flat circle shape. The circle
79615  * marker can not be configured to be interactive.
79616  *
79617  * Circle marker properties can not be updated after creation.
79618  *
79619  * To create and add one `CircleMarker` with default configuration
79620  * and one with configuration use
79621  *
79622  * @example
79623  * ```js
79624  * var defaultMarker = new CircleMarker(
79625  *     "id-1",
79626  *     { lat: 0, lng: 0, });
79627  *
79628  * var configuredMarker = new CircleMarker(
79629  *     "id-2",
79630  *     { lat: 0, lng: 0, },
79631  *     {
79632  *         color: "#0ff",
79633  *         opacity: 0.3,
79634  *         radius: 0.7,
79635  *     });
79636  *
79637  * markerComponent.add([defaultMarker, configuredMarker]);
79638  * ```
79639  */
79640 class CircleMarker extends Marker {
79641     constructor(id, lngLat, options) {
79642         super(id, lngLat);
79643         options = !!options ? options : {};
79644         this._color = options.color != null ? options.color : 0xffffff;
79645         this._opacity = options.opacity != null ? options.opacity : 0.4;
79646         this._radius = options.radius != null ? options.radius : 1;
79647     }
79648     _createGeometry(position) {
79649         const circle = new Mesh(new CircleGeometry(this._radius, 16), new MeshBasicMaterial({
79650             color: this._color,
79651             opacity: this._opacity,
79652             transparent: true,
79653         }));
79654         circle.up.fromArray([0, 0, 1]);
79655         circle.renderOrder = -1;
79656         const group = new Object3D();
79657         group.add(circle);
79658         group.position.fromArray(position);
79659         this._geometry = group;
79660     }
79661     _disposeGeometry() {
79662         for (let mesh of this._geometry.children) {
79663             mesh.geometry.dispose();
79664             mesh.material.dispose();
79665         }
79666     }
79667     _getInteractiveObjects() {
79668         return [];
79669     }
79670 }
79671
79672 /**
79673  * @class SimpleMarker
79674  *
79675  * @classdesc Interactive marker with ice cream shape. The sphere
79676  * inside the ice cream can be configured to be interactive.
79677  *
79678  * Simple marker properties can not be updated after creation.
79679  *
79680  * To create and add one `SimpleMarker` with default configuration
79681  * (non-interactive) and one interactive with configuration use
79682  *
79683  * @example
79684  * ```js
79685  * var defaultMarker = new SimpleMarker(
79686  *     "id-1",
79687  *     { lat: 0, lng: 0, });
79688  *
79689  * var interactiveMarker = new SimpleMarker(
79690  *     "id-2",
79691  *     { lat: 0, lng: 0, },
79692  *     {
79693  *         ballColor: "#00f",
79694  *         ballOpacity: 0.5,
79695  *         color: "#00f",
79696  *         interactive: true,
79697  *         opacity: 0.3,
79698  *         radius: 0.7,
79699  *     });
79700  *
79701  * markerComponent.add([defaultMarker, interactiveMarker]);
79702  * ```
79703  */
79704 class SimpleMarker extends Marker {
79705     constructor(id, lngLat, options) {
79706         super(id, lngLat);
79707         options = !!options ? options : {};
79708         this._ballColor = options.ballColor != null ? options.ballColor : 0xff0000;
79709         this._ballOpacity = options.ballOpacity != null ? options.ballOpacity : 0.8;
79710         this._circleToRayAngle = 2;
79711         this._color = options.color != null ? options.color : 0xff0000;
79712         this._interactive = !!options.interactive;
79713         this._opacity = options.opacity != null ? options.opacity : 0.4;
79714         this._radius = options.radius != null ? options.radius : 1;
79715     }
79716     _createGeometry(position) {
79717         const radius = this._radius;
79718         const height = this._markerHeight(radius);
79719         const markerMaterial = new MeshBasicMaterial({
79720             color: this._color,
79721             opacity: this._opacity,
79722             transparent: true,
79723             depthWrite: false,
79724         });
79725         const marker = new Mesh(this._createMarkerGeometry(radius, 8, 8), markerMaterial);
79726         const interactive = new Mesh(new SphereGeometry(radius / 2, 8, 8), new MeshBasicMaterial({
79727             color: this._ballColor,
79728             opacity: this._ballOpacity,
79729             transparent: true,
79730         }));
79731         interactive.position.z = height;
79732         interactive.renderOrder = 1;
79733         const group = new Object3D();
79734         group.add(interactive);
79735         group.add(marker);
79736         group.position.fromArray(position);
79737         this._geometry = group;
79738     }
79739     _disposeGeometry() {
79740         for (const mesh of this._geometry.children) {
79741             mesh.geometry.dispose();
79742             mesh.material.dispose();
79743         }
79744     }
79745     _getInteractiveObjects() {
79746         return this._interactive ? [this._geometry.children[0]] : [];
79747     }
79748     _markerHeight(radius) {
79749         const t = Math.tan(Math.PI - this._circleToRayAngle);
79750         return radius * Math.sqrt(1 + t * t);
79751     }
79752     _createMarkerGeometry(radius, widthSegments, heightSegments) {
79753         const height = this._markerHeight(radius);
79754         const circleToRayAngle = this._circleToRayAngle;
79755         const indexRows = [];
79756         const positions = new Float32Array(3 * (widthSegments + 1) * (heightSegments + 1));
79757         let positionIndex = 0;
79758         for (let y = 0; y <= heightSegments; ++y) {
79759             const indexRow = [];
79760             for (let x = 0; x <= widthSegments; ++x) {
79761                 const u = x / widthSegments * Math.PI * 2;
79762                 const v = y / heightSegments * Math.PI;
79763                 let r = radius;
79764                 if (v > circleToRayAngle) {
79765                     const t = Math.tan(v - circleToRayAngle);
79766                     r = radius * Math.sqrt(1 + t * t);
79767                 }
79768                 const arrayIndex = 3 * positionIndex;
79769                 const sinv = Math.sin(v);
79770                 positions[arrayIndex + 0] = r * Math.cos(u) * sinv;
79771                 positions[arrayIndex + 1] = r * Math.sin(u) * sinv;
79772                 positions[arrayIndex + 2] = r * Math.cos(v) + height;
79773                 indexRow.push(positionIndex++);
79774             }
79775             indexRows.push(indexRow);
79776         }
79777         const indices = new Uint16Array(6 * widthSegments * heightSegments);
79778         let index = 0;
79779         for (let y = 0; y < heightSegments; ++y) {
79780             for (let x = 0; x < widthSegments; ++x) {
79781                 const pi1 = indexRows[y][x + 1];
79782                 const pi2 = indexRows[y][x];
79783                 const pi3 = indexRows[y + 1][x];
79784                 const pi4 = indexRows[y + 1][x + 1];
79785                 indices[index++] = pi1;
79786                 indices[index++] = pi2;
79787                 indices[index++] = pi4;
79788                 indices[index++] = pi2;
79789                 indices[index++] = pi3;
79790                 indices[index++] = pi4;
79791             }
79792         }
79793         const geometry = new BufferGeometry();
79794         const positionAttribute = new BufferAttribute(positions, 3);
79795         geometry.setAttribute("position", positionAttribute);
79796         geometry.setIndex(new BufferAttribute(indices, 1));
79797         return geometry;
79798     }
79799 }
79800
79801 /**
79802  * @class Popup
79803  *
79804  * @classdesc Popup instance for rendering custom HTML content
79805  * on top of images. Popups are based on 2D basic image coordinates
79806  * (see the {@link Viewer} class documentation for more information about coordinate
79807  * systems) and a certain popup is therefore only relevant to a single image.
79808  * Popups related to a certain image should be removed when moving
79809  * to another image.
79810  *
79811  * A popup must have both its content and its point or rect set to be
79812  * rendered. Popup options can not be updated after creation but the
79813  * basic point or rect as well as its content can be changed by calling
79814  * the appropriate methods.
79815  *
79816  * To create and add one `Popup` with default configuration
79817  * (tooltip visuals and automatic float) and one with specific options
79818  * use
79819  *
79820  * @example
79821  * ```js
79822  * var defaultSpan = document.createElement('span');
79823  * defaultSpan.innerHTML = 'hello default';
79824  *
79825  * var defaultPopup = new Popup();
79826  * defaultPopup.setDOMContent(defaultSpan);
79827  * defaultPopup.setBasicPoint([0.3, 0.3]);
79828  *
79829  * var cleanSpan = document.createElement('span');
79830  * cleanSpan.innerHTML = 'hello clean';
79831  *
79832  * var cleanPopup = new Popup({
79833  *     clean: true,
79834  *     float: Alignment.Top,
79835  *     offset: 10,
79836  *     opacity: 0.7,
79837  * });
79838  *
79839  * cleanPopup.setDOMContent(cleanSpan);
79840  * cleanPopup.setBasicPoint([0.6, 0.6]);
79841  *
79842  * popupComponent.add([defaultPopup, cleanPopup]);
79843  * ```
79844  *
79845  * @description Implementation of API methods and API documentation inspired
79846  * by/used from https://github.com/mapbox/mapbox-gl-js/blob/v0.38.0/src/ui/popup.js
79847  */
79848 class Popup {
79849     constructor(options, viewportCoords, dom) {
79850         this._options = {};
79851         options = !!options ? options : {};
79852         this._options.capturePointer = options.capturePointer === false ?
79853             options.capturePointer : true;
79854         this._options.clean = options.clean;
79855         this._options.float = options.float;
79856         this._options.offset = options.offset;
79857         this._options.opacity = options.opacity;
79858         this._options.position = options.position;
79859         this._dom = !!dom ? dom : new DOM();
79860         this._viewportCoords = !!viewportCoords ? viewportCoords : new ViewportCoords();
79861         this._notifyChanged$ = new Subject();
79862     }
79863     /**
79864      * @description Internal observable used by the component to
79865      * render the popup when its position or content has changed.
79866      * @ignore
79867      */
79868     get changed$() {
79869         return this._notifyChanged$;
79870     }
79871     /**
79872      * @description Internal method used by the component to
79873      * remove all references to the popup.
79874      * @ignore
79875      */
79876     remove() {
79877         if (this._content && this._content.parentNode) {
79878             this._content.parentNode.removeChild(this._content);
79879         }
79880         if (this._container) {
79881             this._container.parentNode.removeChild(this._container);
79882             delete this._container;
79883         }
79884         if (this._parentContainer) {
79885             delete this._parentContainer;
79886         }
79887     }
79888     /**
79889      * Sets a 2D basic image coordinates point to the popup's anchor, and
79890      * moves the popup to it.
79891      *
79892      * @description Overwrites any previously set point or rect.
79893      *
79894      * @param {Array<number>} basicPoint - Point in 2D basic image coordinates.
79895      *
79896      * @example
79897      * ```js
79898      * var popup = new Popup();
79899      * popup.setText('hello image');
79900      * popup.setBasicPoint([0.3, 0.3]);
79901      *
79902      * popupComponent.add([popup]);
79903      * ```
79904      */
79905     setBasicPoint(basicPoint) {
79906         this._point = basicPoint.slice();
79907         this._rect = null;
79908         this._notifyChanged$.next(this);
79909     }
79910     /**
79911      * Sets a 2D basic image coordinates rect to the popup's anchor, and
79912      * moves the popup to it.
79913      *
79914      * @description Overwrites any previously set point or rect.
79915      *
79916      * @param {Array<number>} basicRect - Rect in 2D basic image
79917      * coordinates ([topLeftX, topLeftY, bottomRightX, bottomRightY]) .
79918      *
79919      * @example
79920      * ```js
79921      * var popup = new Popup();
79922      * popup.setText('hello image');
79923      * popup.setBasicRect([0.3, 0.3, 0.5, 0.6]);
79924      *
79925      * popupComponent.add([popup]);
79926      * ```
79927      */
79928     setBasicRect(basicRect) {
79929         this._rect = basicRect.slice();
79930         this._point = null;
79931         this._notifyChanged$.next(this);
79932     }
79933     /**
79934      * Sets the popup's content to the element provided as a DOM node.
79935      *
79936      * @param {Node} htmlNode - A DOM node to be used as content for the popup.
79937      *
79938      * @example
79939      * ```js
79940      * var div = document.createElement('div');
79941      * div.innerHTML = 'hello image';
79942      *
79943      * var popup = new Popup();
79944      * popup.setDOMContent(div);
79945      * popup.setBasicPoint([0.3, 0.3]);
79946      *
79947      * popupComponent.add([popup]);
79948      * ```
79949      */
79950     setDOMContent(htmlNode) {
79951         if (this._content && this._content.parentNode) {
79952             this._content.parentNode.removeChild(this._content);
79953         }
79954         const className = "mapillary-popup-content" +
79955             (this._options.clean === true ? "-clean" : "") +
79956             (this._options.capturePointer === true ? " mapillary-popup-capture-pointer" : "");
79957         this._content = this._dom.createElement("div", className, this._container);
79958         this._content.appendChild(htmlNode);
79959         this._notifyChanged$.next(this);
79960     }
79961     /**
79962      * Sets the popup's content to the HTML provided as a string.
79963      *
79964      * @description This method does not perform HTML filtering or sanitization,
79965      * and must be used only with trusted content. Consider
79966      * {@link Popup.setText} if the
79967      * content is an untrusted text string.
79968      *
79969      * @param {string} html - A string representing HTML content for the popup.
79970      *
79971      * @example
79972      * ```js
79973      * var popup = new Popup();
79974      * popup.setHTML('<div>hello image</div>');
79975      * popup.setBasicPoint([0.3, 0.3]);
79976      *
79977      * popupComponent.add([popup]);
79978      * ```
79979      */
79980     setHTML(html) {
79981         const frag = this._dom.document.createDocumentFragment();
79982         const temp = this._dom.createElement("body");
79983         let child;
79984         temp.innerHTML = html;
79985         while (true) {
79986             child = temp.firstChild;
79987             if (!child) {
79988                 break;
79989             }
79990             frag.appendChild(child);
79991         }
79992         this.setDOMContent(frag);
79993     }
79994     /**
79995      * Sets the popup's content to a string of text.
79996      *
79997      * @description This function creates a Text node in the DOM, so it cannot insert raw HTML.
79998      * Use this method for security against XSS if the popup content is user-provided.
79999      *
80000      * @param {string} text - Textual content for the popup.
80001      *
80002      * @example
80003      * ```js
80004      * var popup = new Popup();
80005      * popup.setText('hello image');
80006      * popup.setBasicPoint([0.3, 0.3]);
80007      *
80008      * popupComponent.add([popup]);
80009      * ```
80010      */
80011     setText(text) {
80012         this.setDOMContent(this._dom.document.createTextNode(text));
80013     }
80014     /**
80015      * @description Internal method for attaching the popup to
80016      * its parent container so that it is rendered in the DOM tree.
80017      * @ignore
80018      */
80019     setParentContainer(parentContainer) {
80020         this._parentContainer = parentContainer;
80021     }
80022     /**
80023      * @description Internal method for updating the rendered
80024      * position of the popup called by the popup component.
80025      * @ignore
80026      */
80027     update(renderCamera, size, transform) {
80028         if (!this._parentContainer || !this._content) {
80029             return;
80030         }
80031         if (!this._point && !this._rect) {
80032             return;
80033         }
80034         if (!this._container) {
80035             this._container = this._dom.createElement("div", "mapillary-popup", this._parentContainer);
80036             const showTip = this._options.clean !== true &&
80037                 this._options.float !== Alignment.Center;
80038             if (showTip) {
80039                 const tipClassName = "mapillary-popup-tip" +
80040                     (this._options.capturePointer === true ? " mapillary-popup-capture-pointer" : "");
80041                 this._tip = this._dom.createElement("div", tipClassName, this._container);
80042                 this._dom.createElement("div", "mapillary-popup-tip-inner", this._tip);
80043             }
80044             this._container.appendChild(this._content);
80045             this._parentContainer.appendChild(this._container);
80046             if (this._options.opacity != null) {
80047                 this._container.style.opacity = this._options.opacity.toString();
80048             }
80049         }
80050         let pointPixel = null;
80051         let position = this._alignmentToPopupAligment(this._options.position);
80052         let float = this._alignmentToPopupAligment(this._options.float);
80053         const classList = this._container.classList;
80054         if (this._point != null) {
80055             pointPixel =
80056                 this._viewportCoords.basicToCanvasSafe(this._point[0], this._point[1], { offsetHeight: size.height, offsetWidth: size.width }, transform, renderCamera.perspective);
80057         }
80058         else {
80059             const alignments = ["center", "top", "bottom", "left", "right", "top-left", "top-right", "bottom-left", "bottom-right"];
80060             let appliedPosition = null;
80061             for (const alignment of alignments) {
80062                 if (classList.contains(`mapillary-popup-float-${alignment}`)) {
80063                     appliedPosition = alignment;
80064                     break;
80065                 }
80066             }
80067             [pointPixel, position] = this._rectToPixel(this._rect, position, appliedPosition, renderCamera, size, transform);
80068             if (!float) {
80069                 float = position;
80070             }
80071         }
80072         if (pointPixel == null) {
80073             this._container.style.display = "none";
80074             return;
80075         }
80076         this._container.style.display = "";
80077         if (!float) {
80078             const width = this._container.offsetWidth;
80079             const height = this._container.offsetHeight;
80080             const floats = this._pixelToFloats(pointPixel, size, width, height);
80081             float = floats.length === 0 ? "top" : floats.join("-");
80082         }
80083         const offset = this._normalizeOffset(this._options.offset);
80084         pointPixel = [pointPixel[0] + offset[float][0], pointPixel[1] + offset[float][1]];
80085         pointPixel = [Math.round(pointPixel[0]), Math.round(pointPixel[1])];
80086         const floatTranslate = {
80087             "bottom": "translate(-50%,0)",
80088             "bottom-left": "translate(-100%,0)",
80089             "bottom-right": "translate(0,0)",
80090             "center": "translate(-50%,-50%)",
80091             "left": "translate(-100%,-50%)",
80092             "right": "translate(0,-50%)",
80093             "top": "translate(-50%,-100%)",
80094             "top-left": "translate(-100%,-100%)",
80095             "top-right": "translate(0,-100%)",
80096         };
80097         for (const key in floatTranslate) {
80098             if (!floatTranslate.hasOwnProperty(key)) {
80099                 continue;
80100             }
80101             classList.remove(`mapillary-popup-float-${key}`);
80102         }
80103         classList.add(`mapillary-popup-float-${float}`);
80104         this._container.style.transform = `${floatTranslate[float]} translate(${pointPixel[0]}px,${pointPixel[1]}px)`;
80105     }
80106     _rectToPixel(rect, position, appliedPosition, renderCamera, size, transform) {
80107         if (!position) {
80108             const width = this._container.offsetWidth;
80109             const height = this._container.offsetHeight;
80110             const floatOffsets = {
80111                 "bottom": [0, height / 2],
80112                 "bottom-left": [-width / 2, height / 2],
80113                 "bottom-right": [width / 2, height / 2],
80114                 "left": [-width / 2, 0],
80115                 "right": [width / 2, 0],
80116                 "top": [0, -height / 2],
80117                 "top-left": [-width / 2, -height / 2],
80118                 "top-right": [width / 2, -height / 2],
80119             };
80120             const automaticPositions = ["top", "bottom", "left", "right"];
80121             let largestVisibleArea = [0, null, null];
80122             for (const automaticPosition of automaticPositions) {
80123                 const autoPointBasic = this._pointFromRectPosition(rect, automaticPosition);
80124                 const autoPointPixel = this._viewportCoords.basicToCanvasSafe(autoPointBasic[0], autoPointBasic[1], { offsetHeight: size.height, offsetWidth: size.width }, transform, renderCamera.perspective);
80125                 if (autoPointPixel == null) {
80126                     continue;
80127                 }
80128                 const floatOffset = floatOffsets[automaticPosition];
80129                 const offsetedPosition = [autoPointPixel[0] + floatOffset[0], autoPointPixel[1] + floatOffset[1]];
80130                 const staticCoeff = appliedPosition != null && appliedPosition === automaticPosition ? 1 : 0.7;
80131                 const floats = this._pixelToFloats(offsetedPosition, size, width / staticCoeff, height / (2 * staticCoeff));
80132                 if (floats.length === 0 &&
80133                     autoPointPixel[0] > 0 &&
80134                     autoPointPixel[0] < size.width &&
80135                     autoPointPixel[1] > 0 &&
80136                     autoPointPixel[1] < size.height) {
80137                     return [autoPointPixel, automaticPosition];
80138                 }
80139                 const minX = Math.max(offsetedPosition[0] - width / 2, 0);
80140                 const maxX = Math.min(offsetedPosition[0] + width / 2, size.width);
80141                 const minY = Math.max(offsetedPosition[1] - height / 2, 0);
80142                 const maxY = Math.min(offsetedPosition[1] + height / 2, size.height);
80143                 const visibleX = Math.max(0, maxX - minX);
80144                 const visibleY = Math.max(0, maxY - minY);
80145                 const visibleArea = staticCoeff * visibleX * visibleY;
80146                 if (visibleArea > largestVisibleArea[0]) {
80147                     largestVisibleArea[0] = visibleArea;
80148                     largestVisibleArea[1] = autoPointPixel;
80149                     largestVisibleArea[2] = automaticPosition;
80150                 }
80151             }
80152             if (largestVisibleArea[0] > 0) {
80153                 return [largestVisibleArea[1], largestVisibleArea[2]];
80154             }
80155         }
80156         const pointBasic = this._pointFromRectPosition(rect, position);
80157         const pointPixel = this._viewportCoords.basicToCanvasSafe(pointBasic[0], pointBasic[1], { offsetHeight: size.height, offsetWidth: size.width }, transform, renderCamera.perspective);
80158         return [pointPixel, position != null ? position : "top"];
80159     }
80160     _alignmentToPopupAligment(float) {
80161         switch (float) {
80162             case Alignment.Bottom:
80163                 return "bottom";
80164             case Alignment.BottomLeft:
80165                 return "bottom-left";
80166             case Alignment.BottomRight:
80167                 return "bottom-right";
80168             case Alignment.Center:
80169                 return "center";
80170             case Alignment.Left:
80171                 return "left";
80172             case Alignment.Right:
80173                 return "right";
80174             case Alignment.Top:
80175                 return "top";
80176             case Alignment.TopLeft:
80177                 return "top-left";
80178             case Alignment.TopRight:
80179                 return "top-right";
80180             default:
80181                 return null;
80182         }
80183     }
80184     _normalizeOffset(offset) {
80185         if (offset == null) {
80186             return this._normalizeOffset(0);
80187         }
80188         if (typeof offset === "number") {
80189             // input specifies a radius
80190             const sideOffset = offset;
80191             const sign = sideOffset >= 0 ? 1 : -1;
80192             const cornerOffset = sign * Math.round(Math.sqrt(0.5 * Math.pow(sideOffset, 2)));
80193             return {
80194                 "bottom": [0, sideOffset],
80195                 "bottom-left": [-cornerOffset, cornerOffset],
80196                 "bottom-right": [cornerOffset, cornerOffset],
80197                 "center": [0, 0],
80198                 "left": [-sideOffset, 0],
80199                 "right": [sideOffset, 0],
80200                 "top": [0, -sideOffset],
80201                 "top-left": [-cornerOffset, -cornerOffset],
80202                 "top-right": [cornerOffset, -cornerOffset],
80203             };
80204         }
80205         else {
80206             // input specifes a value for each position
80207             return {
80208                 "bottom": offset.bottom || [0, 0],
80209                 "bottom-left": offset.bottomLeft || [0, 0],
80210                 "bottom-right": offset.bottomRight || [0, 0],
80211                 "center": offset.center || [0, 0],
80212                 "left": offset.left || [0, 0],
80213                 "right": offset.right || [0, 0],
80214                 "top": offset.top || [0, 0],
80215                 "top-left": offset.topLeft || [0, 0],
80216                 "top-right": offset.topRight || [0, 0],
80217             };
80218         }
80219     }
80220     _pixelToFloats(pointPixel, size, width, height) {
80221         const floats = [];
80222         if (pointPixel[1] < height) {
80223             floats.push("bottom");
80224         }
80225         else if (pointPixel[1] > size.height - height) {
80226             floats.push("top");
80227         }
80228         if (pointPixel[0] < width / 2) {
80229             floats.push("right");
80230         }
80231         else if (pointPixel[0] > size.width - width / 2) {
80232             floats.push("left");
80233         }
80234         return floats;
80235     }
80236     _pointFromRectPosition(rect, position) {
80237         const x0 = rect[0];
80238         const x1 = rect[0] < rect[2] ? rect[2] : rect[2] + 1;
80239         const y0 = rect[1];
80240         const y1 = rect[3];
80241         switch (position) {
80242             case "bottom":
80243                 return [(x0 + x1) / 2, y1];
80244             case "bottom-left":
80245                 return [x0, y1];
80246             case "bottom-right":
80247                 return [x1, y1];
80248             case "center":
80249                 return [(x0 + x1) / 2, (y0 + y1) / 2];
80250             case "left":
80251                 return [x0, (y0 + y1) / 2];
80252             case "right":
80253                 return [x1, (y0 + y1) / 2];
80254             case "top":
80255                 return [(x0 + x1) / 2, y0];
80256             case "top-left":
80257                 return [x0, y0];
80258             case "top-right":
80259                 return [x1, y0];
80260             default:
80261                 return [(x0 + x1) / 2, y1];
80262         }
80263     }
80264 }
80265
80266 function isBrowser() {
80267     return (typeof window !== "undefined" &&
80268         typeof document !== "undefined");
80269 }
80270 function isArraySupported() {
80271     return !!(Array.prototype &&
80272         Array.prototype.concat &&
80273         Array.prototype.filter &&
80274         Array.prototype.includes &&
80275         Array.prototype.indexOf &&
80276         Array.prototype.join &&
80277         Array.prototype.map &&
80278         Array.prototype.push &&
80279         Array.prototype.pop &&
80280         Array.prototype.reverse &&
80281         Array.prototype.shift &&
80282         Array.prototype.slice &&
80283         Array.prototype.splice &&
80284         Array.prototype.sort &&
80285         Array.prototype.unshift);
80286 }
80287 function isBlobSupported() {
80288     return ("Blob" in window &&
80289         "URL" in window);
80290 }
80291 function isFunctionSupported() {
80292     return !!(Function.prototype &&
80293         Function.prototype.apply &&
80294         Function.prototype.bind);
80295 }
80296 function isJSONSupported() {
80297     return ("JSON" in window &&
80298         "parse" in JSON &&
80299         "stringify" in JSON);
80300 }
80301 function isMapSupported() {
80302     return "Map" in window;
80303 }
80304 function isObjectSupported() {
80305     return !!(Object.assign &&
80306         Object.keys &&
80307         Object.values);
80308 }
80309 function isPromiseSupported() {
80310     return !!("Promise" in window &&
80311         Promise.resolve &&
80312         Promise.reject &&
80313         Promise.prototype &&
80314         Promise.prototype.catch &&
80315         Promise.prototype.then);
80316 }
80317 function isSetSupported() {
80318     return "Set" in window;
80319 }
80320 let isWebGLSupportedCache = undefined;
80321 function isWebGLSupportedCached() {
80322     if (isWebGLSupportedCache === undefined) {
80323         isWebGLSupportedCache = isWebGLSupported();
80324     }
80325     return isWebGLSupportedCache;
80326 }
80327 function isWebGLSupported() {
80328     const attributes = {
80329         alpha: false,
80330         antialias: false,
80331         depth: true,
80332         failIfMajorPerformanceCaveat: false,
80333         premultipliedAlpha: true,
80334         preserveDrawingBuffer: false,
80335         stencil: true,
80336     };
80337     const canvas = document.createElement("canvas");
80338     const webGL2Context = canvas.getContext("webgl2", attributes);
80339     if (!!webGL2Context) {
80340         return true;
80341     }
80342     const context = canvas.getContext("webgl", attributes) ||
80343         canvas
80344             .getContext("experimental-webgl", attributes);
80345     if (!context) {
80346         return false;
80347     }
80348     const requiredExtensions = ["OES_standard_derivatives"];
80349     const supportedExtensions = context.getSupportedExtensions();
80350     for (const requiredExtension of requiredExtensions) {
80351         if (supportedExtensions.indexOf(requiredExtension) === -1) {
80352             return false;
80353         }
80354     }
80355     return true;
80356 }
80357 /**
80358  * Test whether the current browser supports the full
80359  * functionality of MapillaryJS.
80360  *
80361  * @description The full functionality includes WebGL rendering.
80362  *
80363  * @return {boolean}
80364  *
80365  * @example `var supported = isSupported();`
80366  */
80367 function isSupported() {
80368     return isFallbackSupported() &&
80369         isWebGLSupportedCached();
80370 }
80371 /**
80372  * Test whether the current browser supports the fallback
80373  * functionality of MapillaryJS.
80374  *
80375  * @description The fallback functionality does not include WebGL
80376  * rendering, only 2D canvas rendering.
80377  *
80378  * @return {boolean}
80379  *
80380  * @example `var fallbackSupported = isFallbackSupported();`
80381  */
80382 function isFallbackSupported() {
80383     return isBrowser() &&
80384         isArraySupported() &&
80385         isBlobSupported() &&
80386         isFunctionSupported() &&
80387         isJSONSupported() &&
80388         isMapSupported() &&
80389         isObjectSupported() &&
80390         isPromiseSupported() &&
80391         isSetSupported();
80392 }
80393
80394 /**
80395  * Enumeration for camera controls.
80396  *
80397  * @description Specifies different modes for how the
80398  * camera is controlled through pointer, keyboard or
80399  * other modes of input.
80400  *
80401  * @enum {number}
80402  * @readonly
80403  */
80404 var CameraControls;
80405 (function (CameraControls) {
80406     /**
80407      * Control the camera with custom logic by
80408      * attaching a custom camera controls
80409      * instance to the {@link Viewer}.
80410      */
80411     CameraControls[CameraControls["Custom"] = 0] = "Custom";
80412     /**
80413      * Control the camera from a birds perspective
80414      * to get an overview.
80415      */
80416     CameraControls[CameraControls["Earth"] = 1] = "Earth";
80417     /**
80418      * Control the camera in a first person view
80419      * from the street level perspective.
80420      */
80421     CameraControls[CameraControls["Street"] = 2] = "Street";
80422 })(CameraControls || (CameraControls = {}));
80423
80424 /**
80425  * Enumeration for render mode
80426  * @enum {number}
80427  * @readonly
80428  * @description Modes for specifying how rendering is done
80429  * in the viewer. All modes preserves the original aspect
80430  * ratio of the images.
80431  */
80432 var RenderMode;
80433 (function (RenderMode) {
80434     /**
80435      * Displays all content within the viewer.
80436      *
80437      * @description Black bars shown on both
80438      * sides of the content. Bars are shown
80439      * either below and above or to the left
80440      * and right of the content depending on
80441      * the aspect ratio relation between the
80442      * image and the viewer.
80443      */
80444     RenderMode[RenderMode["Letterbox"] = 0] = "Letterbox";
80445     /**
80446      * Fills the viewer by cropping content.
80447      *
80448      * @description Cropping is done either
80449      * in horizontal or vertical direction
80450      * depending on the aspect ratio relation
80451      * between the image and the viewer.
80452      */
80453     RenderMode[RenderMode["Fill"] = 1] = "Fill";
80454 })(RenderMode || (RenderMode = {}));
80455
80456 var RenderPass;
80457 (function (RenderPass) {
80458     /**
80459      * Occurs after the background render pass.
80460      */
80461     RenderPass[RenderPass["Opaque"] = 0] = "Opaque";
80462 })(RenderPass || (RenderPass = {}));
80463
80464 /**
80465  * Enumeration for transition mode
80466  * @enum {number}
80467  * @readonly
80468  * @description Modes for specifying how transitions
80469  * between images are performed.
80470  */
80471 var TransitionMode;
80472 (function (TransitionMode) {
80473     /**
80474      * Default transitions.
80475      *
80476      * @description The viewer dynamically determines
80477      * whether transitions should be performed with or
80478      * without motion and blending for each transition
80479      * based on the underlying data.
80480      */
80481     TransitionMode[TransitionMode["Default"] = 0] = "Default";
80482     /**
80483      * Instantaneous transitions.
80484      *
80485      * @description All transitions are performed
80486      * without motion or blending.
80487      */
80488     TransitionMode[TransitionMode["Instantaneous"] = 1] = "Instantaneous";
80489 })(TransitionMode || (TransitionMode = {}));
80490
80491 class ComponentController {
80492     constructor(container, navigator, observer, key, options, componentService) {
80493         this._container = container;
80494         this._observer = observer;
80495         this._navigator = navigator;
80496         this._options = options != null ? options : {};
80497         this._key = key;
80498         this._navigable = key == null;
80499         this._componentService = !!componentService ?
80500             componentService :
80501             new ComponentService(this._container, this._navigator);
80502         this._coverComponent = this._componentService.getCover();
80503         this._initializeComponents();
80504         if (key) {
80505             this._initilizeCoverComponent();
80506             this._subscribeCoverComponent();
80507         }
80508         else {
80509             this._navigator.movedToId$.pipe(first((k) => {
80510                 return k != null;
80511             }))
80512                 .subscribe((k) => {
80513                 this._key = k;
80514                 this._componentService.deactivateCover();
80515                 this._coverComponent.configure({
80516                     id: this._key,
80517                     state: CoverState.Hidden,
80518                 });
80519                 this._subscribeCoverComponent();
80520                 this._navigator.stateService.start();
80521                 this._navigator.cacheService.start();
80522                 this._navigator.panService.start();
80523                 this._observer.startEmit();
80524             });
80525         }
80526     }
80527     get navigable() {
80528         return this._navigable;
80529     }
80530     get(name) {
80531         return this._componentService.get(name);
80532     }
80533     activate(name) {
80534         this._componentService.activate(name);
80535     }
80536     activateCover() {
80537         this._coverComponent.configure({ state: CoverState.Visible });
80538     }
80539     deactivate(name) {
80540         this._componentService.deactivate(name);
80541     }
80542     deactivateCover() {
80543         this._coverComponent.configure({ state: CoverState.Loading });
80544     }
80545     remove() {
80546         this._componentService.remove();
80547         if (this._configurationSubscription != null) {
80548             this._configurationSubscription.unsubscribe();
80549         }
80550     }
80551     _initializeComponents() {
80552         var _a, _b;
80553         const options = this._options;
80554         this._uFalse((_a = options.fallback) === null || _a === void 0 ? void 0 : _a.image, "imagefallback");
80555         this._uFalse((_b = options.fallback) === null || _b === void 0 ? void 0 : _b.navigation, "navigationfallback");
80556         this._uFalse(options.marker, "marker");
80557         this._uFalse(options.popup, "popup");
80558         this._uFalse(options.slider, "slider");
80559         this._uFalse(options.spatial, "spatial");
80560         this._uFalse(options.tag, "tag");
80561         this._uTrue(options.attribution, "attribution");
80562         this._uTrue(options.bearing, "bearing");
80563         this._uTrue(options.cache, "cache");
80564         this._uTrue(options.direction, "direction");
80565         this._uTrue(options.image, "image");
80566         this._uTrue(options.keyboard, "keyboard");
80567         this._uTrue(options.pointer, "pointer");
80568         this._uTrue(options.sequence, "sequence");
80569         this._uTrue(options.zoom, "zoom");
80570     }
80571     _initilizeCoverComponent() {
80572         let options = this._options;
80573         this._coverComponent.configure({ id: this._key });
80574         if (options.cover === undefined || options.cover) {
80575             this.activateCover();
80576         }
80577         else {
80578             this.deactivateCover();
80579         }
80580     }
80581     _setNavigable(navigable) {
80582         if (this._navigable === navigable) {
80583             return;
80584         }
80585         this._navigable = navigable;
80586         this._observer.navigable$.next(navigable);
80587     }
80588     _subscribeCoverComponent() {
80589         this._configurationSubscription =
80590             this._coverComponent.configuration$.pipe(distinctUntilChanged(undefined, (c) => {
80591                 return c.state;
80592             }))
80593                 .subscribe((conf) => {
80594                 if (conf.state === CoverState.Loading) {
80595                     this._navigator.stateService.currentId$.pipe(first(), switchMap((key) => {
80596                         const keyChanged = key == null || key !== conf.id;
80597                         if (keyChanged) {
80598                             this._setNavigable(false);
80599                         }
80600                         return keyChanged ?
80601                             this._navigator.moveTo$(conf.id) :
80602                             this._navigator.stateService.currentImage$.pipe(first());
80603                     }))
80604                         .subscribe(() => {
80605                         this._navigator.stateService.start();
80606                         this._navigator.cacheService.start();
80607                         this._navigator.panService.start();
80608                         this._observer.startEmit();
80609                         this._coverComponent.configure({ state: CoverState.Hidden });
80610                         this._componentService.deactivateCover();
80611                         this._setNavigable(true);
80612                     }, (error) => {
80613                         console.error("Failed to deactivate cover.", error);
80614                         this._coverComponent.configure({ state: CoverState.Visible });
80615                     });
80616                 }
80617                 else if (conf.state === CoverState.Visible) {
80618                     this._observer.stopEmit();
80619                     this._navigator.stateService.stop();
80620                     this._navigator.cacheService.stop();
80621                     this._navigator.playService.stop();
80622                     this._navigator.panService.stop();
80623                     this._componentService.activateCover();
80624                     this._setNavigable(conf.id == null);
80625                 }
80626             });
80627     }
80628     _uFalse(option, name) {
80629         if (option === undefined) {
80630             this._componentService.deactivate(name);
80631             return;
80632         }
80633         if (typeof option === "boolean") {
80634             if (option) {
80635                 this._componentService.activate(name);
80636             }
80637             else {
80638                 this._componentService.deactivate(name);
80639             }
80640             return;
80641         }
80642         this._componentService.configure(name, option);
80643         this._componentService.activate(name);
80644     }
80645     _uTrue(option, name) {
80646         if (option === undefined) {
80647             this._componentService.activate(name);
80648             return;
80649         }
80650         if (typeof option === "boolean") {
80651             if (option) {
80652                 this._componentService.activate(name);
80653             }
80654             else {
80655                 this._componentService.deactivate(name);
80656             }
80657             return;
80658         }
80659         this._componentService.configure(name, option);
80660         this._componentService.activate(name);
80661     }
80662 }
80663
80664 class DOMRenderer {
80665     constructor(element, renderService, currentFrame$) {
80666         this._adaptiveOperation$ = new Subject();
80667         this._render$ = new Subject();
80668         this._renderAdaptive$ = new Subject();
80669         this._subscriptions = new SubscriptionHolder();
80670         this._renderService = renderService;
80671         this._currentFrame$ = currentFrame$;
80672         const subs = this._subscriptions;
80673         const rootNode = virtualDom.create(virtualDom.h("div.mapillary-dom-renderer", []));
80674         element.appendChild(rootNode);
80675         this._offset$ = this._adaptiveOperation$.pipe(scan((adaptive, operation) => {
80676             return operation(adaptive);
80677         }, {
80678             elementHeight: element.offsetHeight,
80679             elementWidth: element.offsetWidth,
80680             imageAspect: 0,
80681             renderMode: RenderMode.Fill,
80682         }), filter((adaptive) => {
80683             return adaptive.imageAspect > 0 && adaptive.elementWidth > 0 && adaptive.elementHeight > 0;
80684         }), map((adaptive) => {
80685             const elementAspect = adaptive.elementWidth / adaptive.elementHeight;
80686             const ratio = adaptive.imageAspect / elementAspect;
80687             let verticalOffset = 0;
80688             let horizontalOffset = 0;
80689             if (adaptive.renderMode === RenderMode.Letterbox) {
80690                 if (adaptive.imageAspect > elementAspect) {
80691                     verticalOffset = adaptive.elementHeight * (1 - 1 / ratio) / 2;
80692                 }
80693                 else {
80694                     horizontalOffset = adaptive.elementWidth * (1 - ratio) / 2;
80695                 }
80696             }
80697             else {
80698                 if (adaptive.imageAspect > elementAspect) {
80699                     horizontalOffset = -adaptive.elementWidth * (ratio - 1) / 2;
80700                 }
80701                 else {
80702                     verticalOffset = -adaptive.elementHeight * (1 / ratio - 1) / 2;
80703                 }
80704             }
80705             return {
80706                 bottom: verticalOffset,
80707                 left: horizontalOffset,
80708                 right: horizontalOffset,
80709                 top: verticalOffset,
80710             };
80711         }));
80712         const imageAspectSubscription = this._currentFrame$.pipe(filter((frame) => {
80713             return frame.state.currentImage != null;
80714         }), distinctUntilChanged((k1, k2) => {
80715             return k1 === k2;
80716         }, (frame) => {
80717             return frame.state.currentImage.id;
80718         }), map((frame) => {
80719             return frame.state.currentTransform.basicAspect;
80720         }), map((aspect) => {
80721             return (adaptive) => {
80722                 adaptive.imageAspect = aspect;
80723                 return adaptive;
80724             };
80725         }))
80726             .subscribe(this._adaptiveOperation$);
80727         const renderAdaptiveSubscription = combineLatest(this._renderAdaptive$.pipe(scan((vNodeHashes, vNodeHash) => {
80728             if (vNodeHash.vNode == null) {
80729                 delete vNodeHashes[vNodeHash.name];
80730             }
80731             else {
80732                 vNodeHashes[vNodeHash.name] = vNodeHash.vNode;
80733             }
80734             return vNodeHashes;
80735         }, {})), this._offset$).pipe(map((vo) => {
80736             const vNodes = [];
80737             const hashes = vo[0];
80738             for (const name in hashes) {
80739                 if (!hashes.hasOwnProperty(name)) {
80740                     continue;
80741                 }
80742                 vNodes.push(hashes[name]);
80743             }
80744             const offset = vo[1];
80745             const properties = {
80746                 style: {
80747                     bottom: offset.bottom + "px",
80748                     left: offset.left + "px",
80749                     "pointer-events": "none",
80750                     position: "absolute",
80751                     right: offset.right + "px",
80752                     top: offset.top + "px",
80753                 },
80754             };
80755             return {
80756                 name: "mapillary-dom-adaptive-renderer",
80757                 vNode: virtualDom.h("div.mapillary-dom-adaptive-renderer", properties, vNodes),
80758             };
80759         }))
80760             .subscribe(this._render$);
80761         this._vNode$ = this._render$.pipe(scan((vNodeHashes, vNodeHash) => {
80762             if (vNodeHash.vNode == null) {
80763                 delete vNodeHashes[vNodeHash.name];
80764             }
80765             else {
80766                 vNodeHashes[vNodeHash.name] = vNodeHash.vNode;
80767             }
80768             return vNodeHashes;
80769         }, {}), map((hashes) => {
80770             const vNodes = [];
80771             for (const name in hashes) {
80772                 if (!hashes.hasOwnProperty(name)) {
80773                     continue;
80774                 }
80775                 vNodes.push(hashes[name]);
80776             }
80777             return virtualDom.h("div.mapillary-dom-renderer", vNodes);
80778         }));
80779         this._vPatch$ = this._vNode$.pipe(scan((nodePatch, vNode) => {
80780             nodePatch.vpatch = virtualDom.diff(nodePatch.vNode, vNode);
80781             nodePatch.vNode = vNode;
80782             return nodePatch;
80783         }, { vNode: virtualDom.h("div.mapillary-dom-renderer", []), vpatch: null }), pluck("vpatch"));
80784         this._element$ = this._vPatch$.pipe(scan((oldElement, vPatch) => {
80785             return virtualDom.patch(oldElement, vPatch);
80786         }, rootNode), publishReplay(1), refCount());
80787         subs.push(imageAspectSubscription);
80788         subs.push(renderAdaptiveSubscription);
80789         subs.push(this._element$.subscribe(() => { }));
80790         subs.push(this._renderService.size$.pipe(map((size) => {
80791             return (adaptive) => {
80792                 adaptive.elementWidth = size.width;
80793                 adaptive.elementHeight = size.height;
80794                 return adaptive;
80795             };
80796         }))
80797             .subscribe(this._adaptiveOperation$));
80798         subs.push(this._renderService.renderMode$.pipe(map((renderMode) => {
80799             return (adaptive) => {
80800                 adaptive.renderMode = renderMode;
80801                 return adaptive;
80802             };
80803         }))
80804             .subscribe(this._adaptiveOperation$));
80805     }
80806     get element$() {
80807         return this._element$;
80808     }
80809     get render$() {
80810         return this._render$;
80811     }
80812     get renderAdaptive$() {
80813         return this._renderAdaptive$;
80814     }
80815     clear(name) {
80816         this._renderAdaptive$.next({ name: name, vNode: null });
80817         this._render$.next({ name: name, vNode: null });
80818     }
80819     remove() {
80820         this._subscriptions.unsubscribe();
80821     }
80822 }
80823
80824 class GLRenderer {
80825     constructor(canvas, canvasContainer, renderService) {
80826         this._renderFrame$ = new Subject();
80827         this._renderCameraOperation$ = new Subject();
80828         this._render$ = new Subject();
80829         this._clear$ = new Subject();
80830         this._renderOperation$ = new Subject();
80831         this._rendererOperation$ = new Subject();
80832         this._eraserOperation$ = new Subject();
80833         this._triggerOperation$ = new Subject();
80834         this._subscriptions = new SubscriptionHolder();
80835         this._opaqueRender$ = new Subject();
80836         this._renderService = renderService;
80837         const subs = this._subscriptions;
80838         this._renderer$ = this._rendererOperation$.pipe(scan((renderer, operation) => {
80839             return operation(renderer);
80840         }, { needsRender: false, renderer: null }), filter((renderer) => {
80841             return !!renderer.renderer;
80842         }));
80843         this._renderCollection$ = this._renderOperation$.pipe(scan((hashes, operation) => {
80844             return operation(hashes);
80845         }, {}), share());
80846         this._renderCamera$ = this._renderCameraOperation$.pipe(scan((rc, operation) => {
80847             return operation(rc);
80848         }, { frameId: -1, needsRender: false, perspective: null }));
80849         this._eraser$ = this._eraserOperation$.pipe(startWith((eraser) => {
80850             return eraser;
80851         }), scan((eraser, operation) => {
80852             return operation(eraser);
80853         }, { needsRender: false }));
80854         const trigger$ = this._triggerOperation$.pipe(startWith((trigger) => {
80855             return trigger;
80856         }), scan((trigger, operation) => {
80857             return operation(trigger);
80858         }, { needsRender: false }));
80859         const clearColor = new Color(0x0F0F0F);
80860         const renderSubscription = combineLatest(this._renderer$, this._renderCollection$, this._renderCamera$, this._eraser$, trigger$).pipe(map(([renderer, hashes, rc, eraser, trigger]) => {
80861             const renders = Object.keys(hashes)
80862                 .map((key) => {
80863                 return hashes[key];
80864             });
80865             return { camera: rc, eraser: eraser, trigger: trigger, renderer: renderer, renders: renders };
80866         }), filter((co) => {
80867             let needsRender = co.renderer.needsRender ||
80868                 co.camera.needsRender ||
80869                 co.eraser.needsRender ||
80870                 co.trigger.needsRender;
80871             const frameId = co.camera.frameId;
80872             for (const render of co.renders) {
80873                 if (render.frameId !== frameId) {
80874                     return false;
80875                 }
80876                 needsRender = needsRender || render.needsRender;
80877             }
80878             return needsRender;
80879         }), distinctUntilChanged((n1, n2) => {
80880             return n1 === n2;
80881         }, (co) => {
80882             return co.eraser.needsRender ||
80883                 co.trigger.needsRender ? -co.camera.frameId : co.camera.frameId;
80884         }))
80885             .subscribe((co) => {
80886             co.renderer.needsRender = false;
80887             co.camera.needsRender = false;
80888             co.eraser.needsRender = false;
80889             co.trigger.needsRender = false;
80890             const perspectiveCamera = co.camera.perspective;
80891             const backgroundRenders = [];
80892             const opaqueRenders = [];
80893             for (const render of co.renders) {
80894                 if (render.pass === RenderPass$1.Background) {
80895                     backgroundRenders.push(render.render);
80896                 }
80897                 else if (render.pass === RenderPass$1.Opaque) {
80898                     opaqueRenders.push(render.render);
80899                 }
80900             }
80901             const renderer = co.renderer.renderer;
80902             renderer.resetState();
80903             renderer.setClearColor(clearColor, 1.0);
80904             renderer.clear();
80905             for (const renderBackground of backgroundRenders) {
80906                 renderBackground(perspectiveCamera, renderer);
80907             }
80908             renderer.clearDepth();
80909             for (const renderOpaque of opaqueRenders) {
80910                 renderOpaque(perspectiveCamera, renderer);
80911             }
80912             renderer.resetState();
80913             this._opaqueRender$.next();
80914         });
80915         subs.push(renderSubscription);
80916         subs.push(this._renderFrame$.pipe(map((rc) => {
80917             return (irc) => {
80918                 irc.frameId = rc.frameId;
80919                 irc.perspective = rc.perspective;
80920                 if (rc.changed === true) {
80921                     irc.needsRender = true;
80922                 }
80923                 return irc;
80924             };
80925         }))
80926             .subscribe(this._renderCameraOperation$));
80927         this._renderFrameSubscribe();
80928         const renderHash$ = this._render$.pipe(map((hash) => {
80929             return (hashes) => {
80930                 hashes[hash.name] = hash.renderer;
80931                 return hashes;
80932             };
80933         }));
80934         const clearHash$ = this._clear$.pipe(map((name) => {
80935             return (hashes) => {
80936                 delete hashes[name];
80937                 return hashes;
80938             };
80939         }));
80940         subs.push(merge(renderHash$, clearHash$)
80941             .subscribe(this._renderOperation$));
80942         this._webGLRenderer$ = this._render$.pipe(first(), map(() => {
80943             canvasContainer.appendChild(canvas);
80944             const element = renderService.element;
80945             const webGLRenderer = new WebGLRenderer({ canvas: canvas });
80946             webGLRenderer.setPixelRatio(window.devicePixelRatio);
80947             webGLRenderer.setSize(element.offsetWidth, element.offsetHeight);
80948             webGLRenderer.autoClear = false;
80949             return webGLRenderer;
80950         }), publishReplay(1), refCount());
80951         subs.push(this._webGLRenderer$
80952             .subscribe(() => { }));
80953         const createRenderer$ = this._webGLRenderer$.pipe(first(), map((webGLRenderer) => {
80954             return (renderer) => {
80955                 renderer.needsRender = true;
80956                 renderer.renderer = webGLRenderer;
80957                 return renderer;
80958             };
80959         }));
80960         const resizeRenderer$ = this._renderService.size$.pipe(map((size) => {
80961             return (renderer) => {
80962                 if (renderer.renderer == null) {
80963                     return renderer;
80964                 }
80965                 renderer.renderer.setSize(size.width, size.height);
80966                 renderer.needsRender = true;
80967                 return renderer;
80968             };
80969         }));
80970         const clearRenderer$ = this._clear$.pipe(map(() => {
80971             return (renderer) => {
80972                 if (renderer.renderer == null) {
80973                     return renderer;
80974                 }
80975                 renderer.needsRender = true;
80976                 return renderer;
80977             };
80978         }));
80979         subs.push(merge(createRenderer$, resizeRenderer$, clearRenderer$)
80980             .subscribe(this._rendererOperation$));
80981         const renderCollectionEmpty$ = this._renderCollection$.pipe(filter((hashes) => {
80982             return Object.keys(hashes).length === 0;
80983         }), share());
80984         subs.push(renderCollectionEmpty$
80985             .subscribe(() => {
80986             if (this._renderFrameSubscription == null) {
80987                 return;
80988             }
80989             this._renderFrameSubscription.unsubscribe();
80990             this._renderFrameSubscription = null;
80991             this._renderFrameSubscribe();
80992         }));
80993         subs.push(renderCollectionEmpty$.pipe(map(() => {
80994             return (eraser) => {
80995                 eraser.needsRender = true;
80996                 return eraser;
80997             };
80998         }))
80999             .subscribe(this._eraserOperation$));
81000     }
81001     get render$() {
81002         return this._render$;
81003     }
81004     get opaqueRender$() {
81005         return this._opaqueRender$;
81006     }
81007     get webGLRenderer$() {
81008         return this._webGLRenderer$;
81009     }
81010     clear(name) {
81011         this._clear$.next(name);
81012     }
81013     remove() {
81014         this._rendererOperation$.next((renderer) => {
81015             if (renderer.renderer != null) {
81016                 const extension = renderer.renderer
81017                     .getContext()
81018                     .getExtension('WEBGL_lose_context');
81019                 if (!!extension) {
81020                     extension.loseContext();
81021                 }
81022                 renderer.renderer = null;
81023             }
81024             return renderer;
81025         });
81026         if (this._renderFrameSubscription != null) {
81027             this._renderFrameSubscription.unsubscribe();
81028         }
81029         this._subscriptions.unsubscribe();
81030     }
81031     triggerRerender() {
81032         this._renderService.renderCameraFrame$
81033             .pipe(skip(1), first())
81034             .subscribe(() => {
81035             this._triggerOperation$.next((trigger) => {
81036                 trigger.needsRender = true;
81037                 return trigger;
81038             });
81039         });
81040     }
81041     _renderFrameSubscribe() {
81042         this._render$.pipe(first(), map(() => {
81043             return (irc) => {
81044                 irc.needsRender = true;
81045                 return irc;
81046             };
81047         }))
81048             .subscribe((operation) => {
81049             this._renderCameraOperation$.next(operation);
81050         });
81051         this._renderFrameSubscription = this._render$.pipe(first(), mergeMap(() => {
81052             return this._renderService.renderCameraFrame$;
81053         }))
81054             .subscribe(this._renderFrame$);
81055     }
81056 }
81057
81058 /**
81059  * @class Camera
81060  *
81061  * @classdesc Holds information about a camera.
81062  */
81063 class Camera {
81064     /**
81065      * Create a new camera instance.
81066      * @param {Transform} [transform] - Optional transform instance.
81067      */
81068     constructor(transform) {
81069         if (transform != null) {
81070             this._position = new Vector3().fromArray(transform.unprojectSfM([0, 0], 0));
81071             this._lookat = new Vector3().fromArray(transform.unprojectSfM([0, 0], 10));
81072             this._up = transform.upVector();
81073             this._focal = this._getFocal(transform);
81074         }
81075         else {
81076             this._position = new Vector3(0, 0, 0);
81077             this._lookat = new Vector3(1, 0, 0);
81078             this._up = new Vector3(0, 0, 1);
81079             this._focal = 1;
81080         }
81081     }
81082     /**
81083      * Get position.
81084      * @returns {THREE.Vector3} The position vector.
81085      */
81086     get position() {
81087         return this._position;
81088     }
81089     /**
81090      * Get lookat.
81091      * @returns {THREE.Vector3} The lookat vector.
81092      */
81093     get lookat() {
81094         return this._lookat;
81095     }
81096     /**
81097      * Get up.
81098      * @returns {THREE.Vector3} The up vector.
81099      */
81100     get up() {
81101         return this._up;
81102     }
81103     /**
81104      * Get focal.
81105      * @returns {number} The focal length.
81106      */
81107     get focal() {
81108         return this._focal;
81109     }
81110     /**
81111      * Set focal.
81112      */
81113     set focal(value) {
81114         this._focal = value;
81115     }
81116     /**
81117      * Update this camera to the linearly interpolated value of two other cameras.
81118      *
81119      * @param {Camera} a - First camera.
81120      * @param {Camera} b - Second camera.
81121      * @param {number} alpha - Interpolation value on the interval [0, 1].
81122      */
81123     lerpCameras(a, b, alpha) {
81124         this._position.subVectors(b.position, a.position).multiplyScalar(alpha).add(a.position);
81125         this._lookat.subVectors(b.lookat, a.lookat).multiplyScalar(alpha).add(a.lookat);
81126         this._up.subVectors(b.up, a.up).multiplyScalar(alpha).add(a.up);
81127         this._focal = (1 - alpha) * a.focal + alpha * b.focal;
81128     }
81129     /**
81130      * Copy the properties of another camera to this camera.
81131      *
81132      * @param {Camera} other - Another camera.
81133      */
81134     copy(other) {
81135         this._position.copy(other.position);
81136         this._lookat.copy(other.lookat);
81137         this._up.copy(other.up);
81138         this._focal = other.focal;
81139     }
81140     /**
81141      * Clone this camera.
81142      *
81143      * @returns {Camera} A camera with cloned properties equal to this camera.
81144      */
81145     clone() {
81146         let camera = new Camera();
81147         camera.position.copy(this._position);
81148         camera.lookat.copy(this._lookat);
81149         camera.up.copy(this._up);
81150         camera.focal = this._focal;
81151         return camera;
81152     }
81153     /**
81154      * Determine the distance between this camera and another camera.
81155      *
81156      * @param {Camera} other - Another camera.
81157      * @returns {number} The distance between the cameras.
81158      */
81159     diff(other) {
81160         let pd = this._position.distanceToSquared(other.position);
81161         let ld = this._lookat.distanceToSquared(other.lookat);
81162         let ud = this._up.distanceToSquared(other.up);
81163         let fd = 100 * Math.abs(this._focal - other.focal);
81164         return Math.max(pd, ld, ud, fd);
81165     }
81166     /**
81167      * Get the focal length based on the transform.
81168      *
81169      * @description Returns the focal length corresponding
81170      * to a 90 degree field of view for spherical
81171      * transforms.
81172      *
81173      * Returns the transform focal length for other
81174      * projection types.
81175      *
81176      * @returns {number} Focal length.
81177      */
81178     _getFocal(transform) {
81179         if (!isSpherical(transform.cameraType)) {
81180             return transform.focal;
81181         }
81182         return 0.5 / Math.tan(Math.PI / 2);
81183     }
81184 }
81185
81186 class RenderCamera {
81187     constructor(elementWidth, elementHeight, renderMode) {
81188         this._spatial = new Spatial();
81189         this._viewportCoords = new ViewportCoords();
81190         this._size = { width: elementWidth, height: elementHeight };
81191         this._initialFov = 60;
81192         this._alpha = -1;
81193         this._stateTransitionAlpha = -1;
81194         this._stateTransitionFov = -1;
81195         this._renderMode = renderMode;
81196         this._zoom = 0;
81197         this._frameId = -1;
81198         this._changed = false;
81199         this._changedForFrame = -1;
81200         this._currentImageId = null;
81201         this._previousImageId = null;
81202         this._currentSpherical = false;
81203         this._previousSpherical = false;
81204         this._state = null;
81205         this._currentProjectedPoints = [];
81206         this._previousProjectedPoints = [];
81207         this._currentFov = this._initialFov;
81208         this._previousFov = this._initialFov;
81209         this._camera = new Camera();
81210         this._perspective = new PerspectiveCamera(this._initialFov, this._computeAspect(elementWidth, elementHeight), 0.1, 10000);
81211         this._perspective.position.copy(this._camera.position);
81212         this._perspective.up.copy(this._camera.up);
81213         this._perspective.lookAt(this._camera.lookat);
81214         this._perspective.updateMatrixWorld(true);
81215         this._perspective.matrixAutoUpdate = false;
81216         this._rotation = { phi: 0, theta: 0 };
81217     }
81218     get alpha() {
81219         return this._alpha;
81220     }
81221     get camera() {
81222         return this._camera;
81223     }
81224     get changed() {
81225         return this._frameId === this._changedForFrame;
81226     }
81227     get frameId() {
81228         return this._frameId;
81229     }
81230     get perspective() {
81231         return this._perspective;
81232     }
81233     get renderMode() {
81234         return this._renderMode;
81235     }
81236     get rotation() {
81237         return this._rotation;
81238     }
81239     get zoom() {
81240         return this._zoom;
81241     }
81242     get size() {
81243         return this._size;
81244     }
81245     getTilt() {
81246         return 90 - this._spatial.radToDeg(this._rotation.theta);
81247     }
81248     fovToZoom(fov) {
81249         fov = Math.min(90, Math.max(0, fov));
81250         const currentFov = this._computeCurrentFov(0);
81251         const actualFov = this._alpha === 1 ?
81252             currentFov :
81253             this._interpolateFov(currentFov, this._computePreviousFov(0), this._alpha);
81254         const y0 = Math.tan(actualFov / 2 * Math.PI / 180);
81255         const y1 = Math.tan(fov / 2 * Math.PI / 180);
81256         const zoom = Math.log(y0 / y1) / Math.log(2);
81257         return zoom;
81258     }
81259     setFrame(frame) {
81260         const state = frame.state;
81261         if (state.state !== this._state) {
81262             this._state = state.state;
81263             if (this._state !== State.Custom) {
81264                 this.setRenderMode(this._renderMode);
81265                 this.setSize(this._size);
81266             }
81267             if (this._state === State.Earth) {
81268                 const y = this._fovToY(this._perspective.fov, this._zoom);
81269                 this._stateTransitionFov = this._yToFov(y, 0);
81270             }
81271             this._changed = true;
81272         }
81273         const currentImageId = state.currentImage.id;
81274         const previousImageId = !!state.previousImage ? state.previousImage.id : null;
81275         if (currentImageId !== this._currentImageId) {
81276             this._currentImageId = currentImageId;
81277             this._currentSpherical = isSpherical(state.currentTransform.cameraType);
81278             this._currentProjectedPoints = this._computeProjectedPoints(state.currentTransform);
81279             this._changed = true;
81280         }
81281         if (previousImageId !== this._previousImageId) {
81282             this._previousImageId = previousImageId;
81283             this._previousSpherical =
81284                 isSpherical(state.previousTransform.cameraType);
81285             this._previousProjectedPoints = this._computeProjectedPoints(state.previousTransform);
81286             this._changed = true;
81287         }
81288         const zoom = state.zoom;
81289         if (zoom !== this._zoom) {
81290             this._changed = true;
81291         }
81292         if (this._changed) {
81293             this._currentFov = this._computeCurrentFov(zoom);
81294             this._previousFov = this._computePreviousFov(zoom);
81295         }
81296         const alpha = state.alpha;
81297         const sta = state.stateTransitionAlpha;
81298         if (this._changed ||
81299             alpha !== this._alpha ||
81300             sta !== this._stateTransitionAlpha) {
81301             this._alpha = alpha;
81302             this._stateTransitionAlpha = sta;
81303             switch (this._state) {
81304                 case State.Earth: {
81305                     const startFov = this._stateTransitionFov;
81306                     const endFov = this._focalToFov(state.camera.focal);
81307                     const fov = MathUtils.lerp(startFov, endFov, sta);
81308                     const y = this._fovToY(fov, 0);
81309                     this._perspective.fov = this._yToFov(y, zoom);
81310                     break;
81311                 }
81312                 case State.Custom:
81313                     break;
81314                 default:
81315                     this._perspective.fov =
81316                         this._interpolateFov(this._currentFov, this._previousFov, this._alpha);
81317                     this._changed = true;
81318                     break;
81319             }
81320             this._zoom = zoom;
81321             if (this._state !== State.Custom) {
81322                 this._perspective.updateProjectionMatrix();
81323             }
81324         }
81325         const camera = state.camera;
81326         if (this._camera.diff(camera) > 1e-9) {
81327             this._camera.copy(camera);
81328             this._rotation = this._computeRotation(camera);
81329             this._perspective.up.copy(camera.up);
81330             this._perspective.position.copy(camera.position);
81331             // Workaround for shaking camera
81332             this._perspective.matrixAutoUpdate = true;
81333             this._perspective.lookAt(camera.lookat);
81334             this._perspective.matrixAutoUpdate = false;
81335             this._perspective.updateMatrix();
81336             this._perspective.updateMatrixWorld(false);
81337             this._changed = true;
81338         }
81339         this._setFrameId(frame.id);
81340     }
81341     setProjectionMatrix(matrix) {
81342         this._perspective.fov = this._focalToFov(matrix[5] / 2);
81343         this._perspective.projectionMatrix.fromArray(matrix);
81344         this._perspective.projectionMatrixInverse
81345             .copy(this._perspective.projectionMatrix)
81346             .invert();
81347         this._changed = true;
81348     }
81349     setRenderMode(renderMode) {
81350         this._renderMode = renderMode;
81351         if (this._state === State.Custom) {
81352             return;
81353         }
81354         this._perspective.fov = this._computeFov();
81355         this._perspective.updateProjectionMatrix();
81356         this._changed = true;
81357     }
81358     setSize(size) {
81359         this._size = size;
81360         if (this._state === State.Custom) {
81361             return;
81362         }
81363         this._perspective.aspect = this._computeAspect(size.width, size.height);
81364         this._perspective.fov = this._computeFov();
81365         this._perspective.updateProjectionMatrix();
81366         this._changed = true;
81367     }
81368     _computeAspect(elementWidth, elementHeight) {
81369         return elementWidth === 0 ? 0 : elementWidth / elementHeight;
81370     }
81371     _computeCurrentFov(zoom) {
81372         if (this._perspective.aspect === 0) {
81373             return 0;
81374         }
81375         if (!this._currentImageId) {
81376             return this._initialFov;
81377         }
81378         return this._currentSpherical ?
81379             this._yToFov(1, zoom) :
81380             this._computeVerticalFov(this._currentProjectedPoints, this._renderMode, zoom, this.perspective.aspect);
81381     }
81382     _computeFov() {
81383         this._currentFov = this._computeCurrentFov(this._zoom);
81384         this._previousFov = this._computePreviousFov(this._zoom);
81385         return this._interpolateFov(this._currentFov, this._previousFov, this._alpha);
81386     }
81387     _computePreviousFov(zoom) {
81388         if (this._perspective.aspect === 0) {
81389             return 0;
81390         }
81391         if (!this._currentImageId) {
81392             return this._initialFov;
81393         }
81394         return !this._previousImageId ?
81395             this._currentFov :
81396             this._previousSpherical ?
81397                 this._yToFov(1, zoom) :
81398                 this._computeVerticalFov(this._previousProjectedPoints, this._renderMode, zoom, this.perspective.aspect);
81399     }
81400     _computeProjectedPoints(transform) {
81401         const vertices = [[0.5, 0], [1, 0]];
81402         const directions = [[0.5, 0], [0, 0.5]];
81403         const pointsPerLine = 100;
81404         return computeProjectedPoints(transform, vertices, directions, pointsPerLine, this._viewportCoords);
81405     }
81406     _computeRequiredVerticalFov(projectedPoint, zoom, aspect) {
81407         const maxY = Math.max(projectedPoint[0] / aspect, projectedPoint[1]);
81408         return this._yToFov(maxY, zoom);
81409     }
81410     _computeRotation(camera) {
81411         let direction = camera.lookat.clone().sub(camera.position);
81412         let up = camera.up.clone();
81413         let phi = this._spatial.azimuthal(direction.toArray(), up.toArray());
81414         let theta = Math.PI / 2 - this._spatial.angleToPlane(direction.toArray(), [0, 0, 1]);
81415         return { phi: phi, theta: theta };
81416     }
81417     _computeVerticalFov(projectedPoints, renderMode, zoom, aspect) {
81418         const fovs = projectedPoints
81419             .map((projectedPoint) => {
81420             return this._computeRequiredVerticalFov(projectedPoint, zoom, aspect);
81421         });
81422         const fov = renderMode === RenderMode.Fill ?
81423             Math.min(...fovs) * 0.995 :
81424             Math.max(...fovs);
81425         return fov;
81426     }
81427     _yToFov(y, zoom) {
81428         return 2 * Math.atan(y / Math.pow(2, zoom)) * 180 / Math.PI;
81429     }
81430     _focalToFov(focal) {
81431         return 2 * Math.atan2(1, 2 * focal) * 180 / Math.PI;
81432     }
81433     _fovToY(fov, zoom) {
81434         return Math.pow(2, zoom) * Math.tan(Math.PI * fov / 360);
81435     }
81436     _interpolateFov(v1, v2, alpha) {
81437         return alpha * v1 + (1 - alpha) * v2;
81438     }
81439     _setFrameId(frameId) {
81440         this._frameId = frameId;
81441         if (this._changed) {
81442             this._changed = false;
81443             this._changedForFrame = frameId;
81444         }
81445     }
81446 }
81447
81448 class RenderService {
81449     constructor(element, currentFrame$, renderMode, renderCamera) {
81450         this._subscriptions = new SubscriptionHolder();
81451         this._element = element;
81452         this._currentFrame$ = currentFrame$;
81453         this._spatial = new Spatial();
81454         renderMode = renderMode != null ? renderMode : RenderMode.Fill;
81455         this._resize$ = new Subject();
81456         this._projectionMatrix$ = new Subject();
81457         this._renderCameraOperation$ =
81458             new Subject();
81459         this._size$ =
81460             new BehaviorSubject({
81461                 height: this._element.offsetHeight,
81462                 width: this._element.offsetWidth,
81463             });
81464         const subs = this._subscriptions;
81465         subs.push(this._resize$.pipe(map(() => {
81466             return {
81467                 height: this._element.offsetHeight,
81468                 width: this._element.offsetWidth,
81469             };
81470         }))
81471             .subscribe(this._size$));
81472         this._renderMode$ = new BehaviorSubject(renderMode);
81473         this._renderCameraHolder$ = this._renderCameraOperation$.pipe(startWith((rc) => {
81474             return rc;
81475         }), scan((rc, operation) => {
81476             return operation(rc);
81477         }, renderCamera !== null && renderCamera !== void 0 ? renderCamera : new RenderCamera(this._element.offsetWidth, this._element.offsetHeight, renderMode)), publishReplay(1), refCount());
81478         this._renderCameraFrame$ = this._currentFrame$.pipe(withLatestFrom(this._renderCameraHolder$), tap(([frame, rc]) => {
81479             rc.setFrame(frame);
81480         }), map((args) => {
81481             return args[1];
81482         }), publishReplay(1), refCount());
81483         this._renderCamera$ = this._renderCameraFrame$.pipe(filter((rc) => {
81484             return rc.changed;
81485         }), publishReplay(1), refCount());
81486         this._bearing$ = this._renderCamera$.pipe(map((rc) => {
81487             let bearing = this._spatial.radToDeg(this._spatial.azimuthalToBearing(rc.rotation.phi));
81488             return this._spatial.wrap(bearing, 0, 360);
81489         }), publishReplay(1), refCount());
81490         subs.push(this._size$.pipe(skip(1), map((size) => {
81491             return (rc) => {
81492                 rc.setSize(size);
81493                 return rc;
81494             };
81495         }))
81496             .subscribe(this._renderCameraOperation$));
81497         subs.push(this._renderMode$.pipe(skip(1), map((rm) => {
81498             return (rc) => {
81499                 rc.setRenderMode(rm);
81500                 return rc;
81501             };
81502         }))
81503             .subscribe(this._renderCameraOperation$));
81504         subs.push(this._projectionMatrix$.pipe(map((projectionMatrix) => {
81505             return (rc) => {
81506                 rc.setProjectionMatrix(projectionMatrix);
81507                 return rc;
81508             };
81509         }))
81510             .subscribe(this._renderCameraOperation$));
81511         subs.push(this._bearing$.subscribe(() => { }));
81512         subs.push(this._renderCameraHolder$.subscribe(() => { }));
81513         subs.push(this._size$.subscribe(() => { }));
81514         subs.push(this._renderMode$.subscribe(() => { }));
81515         subs.push(this._renderCamera$.subscribe(() => { }));
81516         subs.push(this._renderCameraFrame$.subscribe(() => { }));
81517     }
81518     get bearing$() {
81519         return this._bearing$;
81520     }
81521     get element() {
81522         return this._element;
81523     }
81524     get projectionMatrix$() {
81525         return this._projectionMatrix$;
81526     }
81527     get renderCamera$() {
81528         return this._renderCamera$;
81529     }
81530     get renderCameraFrame$() {
81531         return this._renderCameraFrame$;
81532     }
81533     get renderMode$() {
81534         return this._renderMode$;
81535     }
81536     get resize$() {
81537         return this._resize$;
81538     }
81539     get size$() {
81540         return this._size$;
81541     }
81542     dispose() {
81543         this._subscriptions.unsubscribe();
81544     }
81545 }
81546
81547 class KeyboardService {
81548     constructor(canvasContainer) {
81549         this._keyDown$ = fromEvent(canvasContainer, "keydown");
81550         this._keyUp$ = fromEvent(canvasContainer, "keyup");
81551     }
81552     get keyDown$() {
81553         return this._keyDown$;
81554     }
81555     get keyUp$() {
81556         return this._keyUp$;
81557     }
81558 }
81559
81560 // MouseEvent.button
81561 const LEFT_BUTTON = 0;
81562 const RIGHT_BUTTON = 2;
81563 // MouseEvent.buttons
81564 const BUTTONS_MAP = {
81565     [LEFT_BUTTON]: 1,
81566     [RIGHT_BUTTON]: 2
81567 };
81568 class MouseService {
81569     constructor(container, canvasContainer, domContainer, doc) {
81570         this._subscriptions = new SubscriptionHolder();
81571         const subs = this._subscriptions;
81572         this._activeSubject$ = new BehaviorSubject(false);
81573         this._active$ = this._activeSubject$
81574             .pipe(distinctUntilChanged(), publishReplay(1), refCount());
81575         this._claimMouse$ = new Subject();
81576         this._claimWheel$ = new Subject();
81577         this._deferPixelClaims$ = new Subject();
81578         this._deferPixels$ = this._deferPixelClaims$
81579             .pipe(scan((claims, claim) => {
81580             if (claim.deferPixels == null) {
81581                 delete claims[claim.name];
81582             }
81583             else {
81584                 claims[claim.name] = claim.deferPixels;
81585             }
81586             return claims;
81587         }, {}), map((claims) => {
81588             let deferPixelMax = -1;
81589             for (const key in claims) {
81590                 if (!claims.hasOwnProperty(key)) {
81591                     continue;
81592                 }
81593                 const deferPixels = claims[key];
81594                 if (deferPixels > deferPixelMax) {
81595                     deferPixelMax = deferPixels;
81596                 }
81597             }
81598             return deferPixelMax;
81599         }), startWith(-1), publishReplay(1), refCount());
81600         subs.push(this._deferPixels$.subscribe(() => { }));
81601         this._documentMouseMove$ =
81602             fromEvent(doc, "pointermove")
81603                 .pipe(filter(this._isMousePen));
81604         this._documentMouseUp$ =
81605             fromEvent(doc, "pointerup")
81606                 .pipe(filter(this._isMousePen));
81607         this._mouseDown$ =
81608             fromEvent(canvasContainer, "pointerdown")
81609                 .pipe(filter(this._isMousePen));
81610         this._mouseEnter$ =
81611             fromEvent(canvasContainer, "pointerenter")
81612                 .pipe(filter(this._isMousePen));
81613         this._mouseLeave$ =
81614             fromEvent(canvasContainer, "pointerleave")
81615                 .pipe(filter(this._isMousePen));
81616         this._mouseMove$ =
81617             fromEvent(canvasContainer, "pointermove")
81618                 .pipe(filter(this._isMousePen));
81619         this._mouseUp$ =
81620             fromEvent(canvasContainer, "pointerup")
81621                 .pipe(filter(this._isMousePen));
81622         this._mouseOut$ =
81623             fromEvent(canvasContainer, "pointerout")
81624                 .pipe(filter(this._isMousePen));
81625         this._mouseOver$ =
81626             fromEvent(canvasContainer, "pointerover")
81627                 .pipe(filter(this._isMousePen));
81628         this._domMouseDown$ =
81629             fromEvent(domContainer, "pointerdown")
81630                 .pipe(filter(this._isMousePen));
81631         this._domMouseMove$ =
81632             fromEvent(domContainer, "pointermove")
81633                 .pipe(filter(this._isMousePen));
81634         this._click$ =
81635             fromEvent(canvasContainer, "click");
81636         this._contextMenu$ =
81637             fromEvent(canvasContainer, "contextmenu");
81638         this._windowBlur$ =
81639             fromEvent(window, "blur");
81640         this._dblClick$ = merge(fromEvent(container, "click"), fromEvent(canvasContainer, "dblclick"))
81641             .pipe(bufferCount(3, 1), filter((events) => {
81642             const event1 = events[0];
81643             const event2 = events[1];
81644             const event3 = events[2];
81645             return event1.type === "click" &&
81646                 event2.type === "click" &&
81647                 event3.type === "dblclick" &&
81648                 event1.target.parentNode === canvasContainer &&
81649                 event2.target.parentNode === canvasContainer;
81650         }), map((events) => {
81651             return events[2];
81652         }), share());
81653         subs.push(merge(this._domMouseDown$, this._domMouseMove$, this._dblClick$, this._contextMenu$)
81654             .subscribe((event) => {
81655             event.preventDefault();
81656         }));
81657         this._mouseWheel$ = merge(fromEvent(canvasContainer, "wheel"), fromEvent(domContainer, "wheel"))
81658             .pipe(share());
81659         this._consistentContextMenu$ =
81660             merge(this._mouseDown$, this._mouseMove$, this._mouseOut$, this._mouseUp$, this._contextMenu$)
81661                 .pipe(bufferCount(3, 1), filter((events) => {
81662                 // fire context menu on mouse up both on mac and windows
81663                 return events[0].type === "pointerdown" &&
81664                     events[1].type === "contextmenu" &&
81665                     events[2].type === "pointerup";
81666             }), map((events) => {
81667                 return events[1];
81668             }), share());
81669         const dragStop$ = merge(this._windowBlur$, this._documentMouseMove$
81670             .pipe(filter((e) => {
81671             return this._buttonReleased(e, LEFT_BUTTON);
81672         })), this._documentMouseUp$
81673             .pipe(filter((e) => {
81674             return this._mouseButton(e) === LEFT_BUTTON;
81675         })))
81676             .pipe(share());
81677         const mouseDragInitiate$ = this._createMouseDragInitiate$(LEFT_BUTTON, this._mouseDown$, dragStop$, true)
81678             .pipe(share());
81679         this._mouseDragStart$ =
81680             this._createMouseDragStart$(mouseDragInitiate$)
81681                 .pipe(share());
81682         this._mouseDrag$ =
81683             this._createMouseDrag$(mouseDragInitiate$, dragStop$)
81684                 .pipe(share());
81685         this._mouseDragEnd$ =
81686             this._createMouseDragEnd$(this._mouseDragStart$, dragStop$)
81687                 .pipe(share());
81688         const domMouseDragInitiate$ = this._createMouseDragInitiate$(LEFT_BUTTON, this._domMouseDown$, dragStop$, false)
81689             .pipe(share());
81690         this._domMouseDragStart$ =
81691             this._createMouseDragStart$(domMouseDragInitiate$)
81692                 .pipe(share());
81693         this._domMouseDrag$ =
81694             this._createMouseDrag$(domMouseDragInitiate$, dragStop$)
81695                 .pipe(share());
81696         this._domMouseDragEnd$ =
81697             this._createMouseDragEnd$(this._domMouseDragStart$, dragStop$)
81698                 .pipe(share());
81699         const rightDragStop$ = merge(this._windowBlur$, this._documentMouseMove$.pipe(filter((e) => {
81700             return this._buttonReleased(e, RIGHT_BUTTON);
81701         })), this._documentMouseUp$.pipe(filter((e) => {
81702             return this._mouseButton(e) === RIGHT_BUTTON;
81703         })))
81704             .pipe(share());
81705         const mouseRightDragInitiate$ = this._createMouseDragInitiate$(RIGHT_BUTTON, this._mouseDown$, rightDragStop$, true)
81706             .pipe(share());
81707         this._mouseRightDragStart$ =
81708             this._createMouseDragStart$(mouseRightDragInitiate$)
81709                 .pipe(share());
81710         this._mouseRightDrag$ =
81711             this._createMouseDrag$(mouseRightDragInitiate$, rightDragStop$)
81712                 .pipe(share());
81713         this._mouseRightDragEnd$ =
81714             this._createMouseDragEnd$(this._mouseRightDragStart$, rightDragStop$)
81715                 .pipe(share());
81716         this._proximateClick$ = this._mouseDown$
81717             .pipe(switchMap((mouseDown) => {
81718             return this._click$.pipe(takeUntil(this._createDeferredMouseMove$(mouseDown, this._documentMouseMove$)), take(1));
81719         }), share());
81720         this._staticClick$ = this._mouseDown$
81721             .pipe(switchMap(() => {
81722             return this._click$.pipe(takeUntil(this._documentMouseMove$), take(1));
81723         }), share());
81724         subs.push(this._mouseDragStart$.subscribe());
81725         subs.push(this._mouseDrag$.subscribe());
81726         subs.push(this._mouseDragEnd$.subscribe());
81727         subs.push(this._domMouseDragStart$.subscribe());
81728         subs.push(this._domMouseDrag$.subscribe());
81729         subs.push(this._domMouseDragEnd$.subscribe());
81730         subs.push(this._mouseRightDragStart$.subscribe());
81731         subs.push(this._mouseRightDrag$.subscribe());
81732         subs.push(this._mouseRightDragEnd$.subscribe());
81733         subs.push(this._staticClick$.subscribe());
81734         this._mouseOwner$ = this._createOwner$(this._claimMouse$)
81735             .pipe(publishReplay(1), refCount());
81736         this._wheelOwner$ = this._createOwner$(this._claimWheel$)
81737             .pipe(publishReplay(1), refCount());
81738         subs.push(this._mouseOwner$.subscribe(() => { }));
81739         subs.push(this._wheelOwner$.subscribe(() => { }));
81740     }
81741     get active$() {
81742         return this._active$;
81743     }
81744     get activate$() {
81745         return this._activeSubject$;
81746     }
81747     get documentMouseMove$() {
81748         return this._documentMouseMove$;
81749     }
81750     get documentMouseUp$() {
81751         return this._documentMouseUp$;
81752     }
81753     get domMouseDragStart$() {
81754         return this._domMouseDragStart$;
81755     }
81756     get domMouseDrag$() {
81757         return this._domMouseDrag$;
81758     }
81759     get domMouseDragEnd$() {
81760         return this._domMouseDragEnd$;
81761     }
81762     get domMouseDown$() {
81763         return this._domMouseDown$;
81764     }
81765     get domMouseMove$() {
81766         return this._domMouseMove$;
81767     }
81768     get mouseOwner$() {
81769         return this._mouseOwner$;
81770     }
81771     get mouseDown$() {
81772         return this._mouseDown$;
81773     }
81774     get mouseEnter$() {
81775         return this._mouseEnter$;
81776     }
81777     get mouseMove$() {
81778         return this._mouseMove$;
81779     }
81780     get mouseLeave$() {
81781         return this._mouseLeave$;
81782     }
81783     get mouseOut$() {
81784         return this._mouseOut$;
81785     }
81786     get mouseOver$() {
81787         return this._mouseOver$;
81788     }
81789     get mouseUp$() {
81790         return this._mouseUp$;
81791     }
81792     get click$() {
81793         return this._click$;
81794     }
81795     get dblClick$() {
81796         return this._dblClick$;
81797     }
81798     get contextMenu$() {
81799         return this._consistentContextMenu$;
81800     }
81801     get mouseWheel$() {
81802         return this._mouseWheel$;
81803     }
81804     get mouseDragStart$() {
81805         return this._mouseDragStart$;
81806     }
81807     get mouseDrag$() {
81808         return this._mouseDrag$;
81809     }
81810     get mouseDragEnd$() {
81811         return this._mouseDragEnd$;
81812     }
81813     get mouseRightDragStart$() {
81814         return this._mouseRightDragStart$;
81815     }
81816     get mouseRightDrag$() {
81817         return this._mouseRightDrag$;
81818     }
81819     get mouseRightDragEnd$() {
81820         return this._mouseRightDragEnd$;
81821     }
81822     get proximateClick$() {
81823         return this._proximateClick$;
81824     }
81825     get staticClick$() {
81826         return this._staticClick$;
81827     }
81828     get windowBlur$() {
81829         return this._windowBlur$;
81830     }
81831     dispose() {
81832         this._subscriptions.unsubscribe();
81833     }
81834     claimMouse(name, zindex) {
81835         this._claimMouse$.next({ name: name, zindex: zindex });
81836     }
81837     unclaimMouse(name) {
81838         this._claimMouse$.next({ name: name, zindex: null });
81839     }
81840     deferPixels(name, deferPixels) {
81841         this._deferPixelClaims$.next({ name: name, deferPixels: deferPixels });
81842     }
81843     undeferPixels(name) {
81844         this._deferPixelClaims$.next({ name: name, deferPixels: null });
81845     }
81846     claimWheel(name, zindex) {
81847         this._claimWheel$.next({ name: name, zindex: zindex });
81848     }
81849     unclaimWheel(name) {
81850         this._claimWheel$.next({ name: name, zindex: null });
81851     }
81852     filtered$(name, observable$) {
81853         return this._filtered(name, observable$, this._mouseOwner$);
81854     }
81855     filteredWheel$(name, observable$) {
81856         return this._filtered(name, observable$, this._wheelOwner$);
81857     }
81858     _createDeferredMouseMove$(origin, mouseMove$) {
81859         return mouseMove$.pipe(map((mouseMove) => {
81860             const deltaX = mouseMove.clientX - origin.clientX;
81861             const deltaY = mouseMove.clientY - origin.clientY;
81862             return [mouseMove, Math.sqrt(deltaX * deltaX + deltaY * deltaY)];
81863         }), withLatestFrom(this._deferPixels$), filter(([[, delta], deferPixels]) => {
81864             return delta > deferPixels;
81865         }), map(([[mouseMove]]) => {
81866             return mouseMove;
81867         }));
81868     }
81869     _createMouseDrag$(mouseDragStartInitiate$, stop$) {
81870         return mouseDragStartInitiate$.pipe(map(([, mouseMove]) => {
81871             return mouseMove;
81872         }), switchMap((mouseMove) => {
81873             return concat(of(mouseMove), this._documentMouseMove$).pipe(takeUntil(stop$));
81874         }));
81875     }
81876     _createMouseDragEnd$(mouseDragStart$, stop$) {
81877         return mouseDragStart$.pipe(switchMap(() => {
81878             return stop$.pipe(first());
81879         }));
81880     }
81881     _createMouseDragStart$(mouseDragStartInitiate$) {
81882         return mouseDragStartInitiate$.pipe(map(([mouseDown]) => {
81883             return mouseDown;
81884         }));
81885     }
81886     _createMouseDragInitiate$(button, mouseDown$, stop$, defer) {
81887         return mouseDown$.pipe(filter((mouseDown) => {
81888             return this._mouseButton(mouseDown) === button;
81889         }), switchMap((mouseDown) => {
81890             return combineLatest(of(mouseDown), defer ?
81891                 this._createDeferredMouseMove$(mouseDown, this._documentMouseMove$) :
81892                 this._documentMouseMove$).pipe(takeUntil(stop$), take(1));
81893         }));
81894     }
81895     _createOwner$(claim$) {
81896         return claim$.pipe(scan((claims, claim) => {
81897             if (claim.zindex == null) {
81898                 delete claims[claim.name];
81899             }
81900             else {
81901                 claims[claim.name] = claim.zindex;
81902             }
81903             return claims;
81904         }, {}), map((claims) => {
81905             let owner = null;
81906             let zIndexMax = -1;
81907             for (const name in claims) {
81908                 if (!claims.hasOwnProperty(name)) {
81909                     continue;
81910                 }
81911                 if (claims[name] > zIndexMax) {
81912                     zIndexMax = claims[name];
81913                     owner = name;
81914                 }
81915             }
81916             return owner;
81917         }), startWith(null));
81918     }
81919     _filtered(name, observable$, owner$) {
81920         return observable$.pipe(withLatestFrom(owner$), filter(([, owner]) => {
81921             return owner === name;
81922         }), map(([item]) => {
81923             return item;
81924         }));
81925     }
81926     _mouseButton(event) {
81927         const upOrDown = event.type === "pointerdown" || event.type === "pointerup";
81928         const InstallTrigger = window.InstallTrigger;
81929         if (upOrDown &&
81930             typeof InstallTrigger !== 'undefined' &&
81931             event.button === RIGHT_BUTTON && event.ctrlKey &&
81932             window.navigator.platform.toUpperCase().indexOf('MAC') >= 0) {
81933             // Fix for the fact that Firefox (detected by InstallTrigger)
81934             // on Mac determines e.button = 2 when using Control + left click.
81935             return LEFT_BUTTON;
81936         }
81937         return event.button;
81938     }
81939     _buttonReleased(event, button) {
81940         // Right button `mouseup` is not fired in
81941         // Chrome on Mac outside the window or iframe. If
81942         // the button is no longer pressed during move
81943         // it may have been released and drag stop
81944         // should be emitted.
81945         const flag = BUTTONS_MAP[button];
81946         return event.buttons === undefined || (event.buttons & flag) !== flag;
81947     }
81948     _isMousePen(event) {
81949         const type = event.pointerType;
81950         return type === "mouse" || type === "pen";
81951     }
81952 }
81953
81954 class SpriteAtlas {
81955     set json(value) {
81956         this._json = value;
81957     }
81958     set image(value) {
81959         this._image = value;
81960         this._texture = new Texture(this._image);
81961         this._texture.minFilter = NearestFilter;
81962     }
81963     get loaded() {
81964         return !!(this._image && this._json);
81965     }
81966     getGLSprite(name) {
81967         if (!this.loaded) {
81968             throw new Error("Sprites cannot be retrieved before the atlas is loaded.");
81969         }
81970         let definition = this._json[name];
81971         if (!definition) {
81972             console.warn("Sprite with key" + name + "does not exist in sprite definition.");
81973             return new Object3D();
81974         }
81975         let texture = this._texture.clone();
81976         texture.needsUpdate = true;
81977         let width = this._image.width;
81978         let height = this._image.height;
81979         texture.offset.x = definition.x / width;
81980         texture.offset.y = (height - definition.y - definition.height) / height;
81981         texture.repeat.x = definition.width / width;
81982         texture.repeat.y = definition.height / height;
81983         let material = new SpriteMaterial({ map: texture });
81984         return new Sprite(material);
81985     }
81986     getDOMSprite(name, float) {
81987         if (!this.loaded) {
81988             throw new Error("Sprites cannot be retrieved before the atlas is loaded.");
81989         }
81990         if (float == null) {
81991             float = Alignment.Center;
81992         }
81993         let definition = this._json[name];
81994         if (!definition) {
81995             console.warn("Sprite with key" + name + "does not exist in sprite definition.");
81996             return virtualDom.h("div", {}, []);
81997         }
81998         let clipTop = definition.y;
81999         let clipRigth = definition.x + definition.width;
82000         let clipBottom = definition.y + definition.height;
82001         let clipLeft = definition.x;
82002         let left = -definition.x;
82003         let top = -definition.y;
82004         let height = this._image.height;
82005         let width = this._image.width;
82006         switch (float) {
82007             case Alignment.Bottom:
82008             case Alignment.Center:
82009             case Alignment.Top:
82010                 left -= definition.width / 2;
82011                 break;
82012             case Alignment.BottomLeft:
82013             case Alignment.Left:
82014             case Alignment.TopLeft:
82015                 left -= definition.width;
82016                 break;
82017             case Alignment.BottomRight:
82018             case Alignment.Right:
82019             case Alignment.TopRight:
82020         }
82021         switch (float) {
82022             case Alignment.Center:
82023             case Alignment.Left:
82024             case Alignment.Right:
82025                 top -= definition.height / 2;
82026                 break;
82027             case Alignment.Top:
82028             case Alignment.TopLeft:
82029             case Alignment.TopRight:
82030                 top -= definition.height;
82031                 break;
82032             case Alignment.Bottom:
82033             case Alignment.BottomLeft:
82034             case Alignment.BottomRight:
82035         }
82036         let pixelRatioInverse = 1 / definition.pixelRatio;
82037         clipTop *= pixelRatioInverse;
82038         clipRigth *= pixelRatioInverse;
82039         clipBottom *= pixelRatioInverse;
82040         clipLeft *= pixelRatioInverse;
82041         left *= pixelRatioInverse;
82042         top *= pixelRatioInverse;
82043         height *= pixelRatioInverse;
82044         width *= pixelRatioInverse;
82045         let properties = {
82046             src: this._image.src,
82047             style: {
82048                 clip: `rect(${clipTop}px, ${clipRigth}px, ${clipBottom}px, ${clipLeft}px)`,
82049                 height: `${height}px`,
82050                 left: `${left}px`,
82051                 position: "absolute",
82052                 top: `${top}px`,
82053                 width: `${width}px`,
82054             },
82055         };
82056         return virtualDom.h("img", properties, []);
82057     }
82058 }
82059 class SpriteService {
82060     constructor(sprite) {
82061         this._retina = window.devicePixelRatio > 1;
82062         this._spriteAtlasOperation$ = new Subject();
82063         this._spriteAtlas$ = this._spriteAtlasOperation$.pipe(startWith((atlas) => {
82064             return atlas;
82065         }), scan((atlas, operation) => {
82066             return operation(atlas);
82067         }, new SpriteAtlas()), publishReplay(1), refCount());
82068         this._atlasSubscription = this._spriteAtlas$
82069             .subscribe(() => { });
82070         if (sprite == null) {
82071             return;
82072         }
82073         let format = this._retina ? "@2x" : "";
82074         let imageXmlHTTP = new XMLHttpRequest();
82075         imageXmlHTTP.open("GET", sprite + format + ".png", true);
82076         imageXmlHTTP.responseType = "arraybuffer";
82077         imageXmlHTTP.onload = () => {
82078             let image = new Image();
82079             image.onload = () => {
82080                 this._spriteAtlasOperation$.next((atlas) => {
82081                     atlas.image = image;
82082                     return atlas;
82083                 });
82084             };
82085             let blob = new Blob([imageXmlHTTP.response]);
82086             image.src = window.URL.createObjectURL(blob);
82087         };
82088         imageXmlHTTP.onerror = (error) => {
82089             console.error(new Error(`Failed to fetch sprite sheet (${sprite}${format}.png)`));
82090         };
82091         imageXmlHTTP.send();
82092         let jsonXmlHTTP = new XMLHttpRequest();
82093         jsonXmlHTTP.open("GET", sprite + format + ".json", true);
82094         jsonXmlHTTP.responseType = "text";
82095         jsonXmlHTTP.onload = () => {
82096             let json = JSON.parse(jsonXmlHTTP.response);
82097             this._spriteAtlasOperation$.next((atlas) => {
82098                 atlas.json = json;
82099                 return atlas;
82100             });
82101         };
82102         jsonXmlHTTP.onerror = (error) => {
82103             console.error(new Error(`Failed to fetch sheet (${sprite}${format}.json)`));
82104         };
82105         jsonXmlHTTP.send();
82106     }
82107     get spriteAtlas$() {
82108         return this._spriteAtlas$;
82109     }
82110     dispose() {
82111         this._atlasSubscription.unsubscribe();
82112     }
82113 }
82114
82115 class TouchService {
82116     constructor(canvasContainer, domContainer) {
82117         this._subscriptions = new SubscriptionHolder();
82118         const subs = this._subscriptions;
82119         this._activeSubject$ = new BehaviorSubject(false);
82120         this._active$ = this._activeSubject$.pipe(distinctUntilChanged(), publishReplay(1), refCount());
82121         subs.push(fromEvent(domContainer, "touchmove")
82122             .subscribe((event) => {
82123             event.preventDefault();
82124         }));
82125         this._touchStart$ = fromEvent(canvasContainer, "touchstart");
82126         this._touchMove$ = fromEvent(canvasContainer, "touchmove");
82127         this._touchEnd$ = fromEvent(canvasContainer, "touchend");
82128         this._touchCancel$ = fromEvent(canvasContainer, "touchcancel");
82129         const tapStart$ = this._touchStart$.pipe(filter((te) => {
82130             return te.touches.length === 1 && te.targetTouches.length === 1;
82131         }), share());
82132         this._doubleTap$ = tapStart$.pipe(bufferWhen(() => {
82133             return tapStart$.pipe(first(), switchMap(() => {
82134                 return merge(timer(300), tapStart$).pipe(take(1));
82135             }));
82136         }), filter((events) => {
82137             return events.length === 2;
82138         }), map((events) => {
82139             return events[events.length - 1];
82140         }), share());
82141         subs.push(this._doubleTap$
82142             .subscribe((event) => {
82143             event.preventDefault();
82144         }));
82145         this._singleTouchMove$ = this._touchMove$.pipe(filter((te) => {
82146             return te.touches.length === 1 && te.targetTouches.length === 1;
82147         }), share());
82148         let singleTouchStart$ = merge(this._touchStart$, this._touchEnd$, this._touchCancel$).pipe(filter((te) => {
82149             return te.touches.length === 1 && te.targetTouches.length === 1;
82150         }));
82151         let multipleTouchStart$ = merge(this._touchStart$, this._touchEnd$, this._touchCancel$).pipe(filter((te) => {
82152             return te.touches.length >= 1;
82153         }));
82154         let touchStop$ = merge(this._touchEnd$, this._touchCancel$).pipe(filter((te) => {
82155             return te.touches.length === 0;
82156         }));
82157         this._singleTouchDragStart$ = singleTouchStart$.pipe(mergeMap(() => {
82158             return this._singleTouchMove$.pipe(takeUntil(merge(touchStop$, multipleTouchStart$)), take(1));
82159         }));
82160         this._singleTouchDragEnd$ = singleTouchStart$.pipe(mergeMap(() => {
82161             return merge(touchStop$, multipleTouchStart$).pipe(first());
82162         }));
82163         this._singleTouchDrag$ = singleTouchStart$.pipe(switchMap(() => {
82164             return this._singleTouchMove$.pipe(skip(1), takeUntil(merge(multipleTouchStart$, touchStop$)));
82165         }));
82166         let touchesChanged$ = merge(this._touchStart$, this._touchEnd$, this._touchCancel$);
82167         this._pinchStart$ = touchesChanged$.pipe(filter((te) => {
82168             return te.touches.length === 2 && te.targetTouches.length === 2;
82169         }));
82170         this._pinchEnd$ = touchesChanged$.pipe(filter((te) => {
82171             return te.touches.length !== 2 || te.targetTouches.length !== 2;
82172         }));
82173         this._pinchOperation$ = new Subject();
82174         this._pinch$ = this._pinchOperation$.pipe(scan((pinch, operation) => {
82175             return operation(pinch);
82176         }, {
82177             changeX: 0,
82178             changeY: 0,
82179             clientX: 0,
82180             clientY: 0,
82181             distance: 0,
82182             distanceChange: 0,
82183             distanceX: 0,
82184             distanceY: 0,
82185             originalEvent: null,
82186             pageX: 0,
82187             pageY: 0,
82188             screenX: 0,
82189             screenY: 0,
82190             touch1: null,
82191             touch2: null,
82192         }));
82193         const pinchSubscription = this._touchMove$.pipe(filter((te) => {
82194             return te.touches.length === 2 && te.targetTouches.length === 2;
82195         }), map((te) => {
82196             return (previous) => {
82197                 let touch1 = te.touches[0];
82198                 let touch2 = te.touches[1];
82199                 let minX = Math.min(touch1.clientX, touch2.clientX);
82200                 let maxX = Math.max(touch1.clientX, touch2.clientX);
82201                 let minY = Math.min(touch1.clientY, touch2.clientY);
82202                 let maxY = Math.max(touch1.clientY, touch2.clientY);
82203                 let centerClientX = minX + (maxX - minX) / 2;
82204                 let centerClientY = minY + (maxY - minY) / 2;
82205                 let centerPageX = centerClientX + touch1.pageX - touch1.clientX;
82206                 let centerPageY = centerClientY + touch1.pageY - touch1.clientY;
82207                 let centerScreenX = centerClientX + touch1.screenX - touch1.clientX;
82208                 let centerScreenY = centerClientY + touch1.screenY - touch1.clientY;
82209                 let distanceX = Math.abs(touch1.clientX - touch2.clientX);
82210                 let distanceY = Math.abs(touch1.clientY - touch2.clientY);
82211                 let distance = Math.sqrt(distanceX * distanceX + distanceY * distanceY);
82212                 let distanceChange = distance - previous.distance;
82213                 let changeX = distanceX - previous.distanceX;
82214                 let changeY = distanceY - previous.distanceY;
82215                 let current = {
82216                     changeX: changeX,
82217                     changeY: changeY,
82218                     clientX: centerClientX,
82219                     clientY: centerClientY,
82220                     distance: distance,
82221                     distanceChange: distanceChange,
82222                     distanceX: distanceX,
82223                     distanceY: distanceY,
82224                     originalEvent: te,
82225                     pageX: centerPageX,
82226                     pageY: centerPageY,
82227                     screenX: centerScreenX,
82228                     screenY: centerScreenY,
82229                     touch1: touch1,
82230                     touch2: touch2,
82231                 };
82232                 return current;
82233             };
82234         }))
82235             .subscribe(this._pinchOperation$);
82236         subs.push(pinchSubscription);
82237         this._pinchChange$ = this._pinchStart$.pipe(switchMap(() => {
82238             return this._pinch$.pipe(skip(1), takeUntil(this._pinchEnd$));
82239         }));
82240     }
82241     get active$() {
82242         return this._active$;
82243     }
82244     get activate$() {
82245         return this._activeSubject$;
82246     }
82247     get doubleTap$() {
82248         return this._doubleTap$;
82249     }
82250     get touchStart$() {
82251         return this._touchStart$;
82252     }
82253     get touchMove$() {
82254         return this._touchMove$;
82255     }
82256     get touchEnd$() {
82257         return this._touchEnd$;
82258     }
82259     get touchCancel$() {
82260         return this._touchCancel$;
82261     }
82262     get singleTouchDragStart$() {
82263         return this._singleTouchDragStart$;
82264     }
82265     get singleTouchDrag$() {
82266         return this._singleTouchDrag$;
82267     }
82268     get singleTouchDragEnd$() {
82269         return this._singleTouchDragEnd$;
82270     }
82271     get pinch$() {
82272         return this._pinchChange$;
82273     }
82274     get pinchStart$() {
82275         return this._pinchStart$;
82276     }
82277     get pinchEnd$() {
82278         return this._pinchEnd$;
82279     }
82280     dispose() {
82281         this._subscriptions.unsubscribe();
82282     }
82283 }
82284
82285 class ConfigurationService {
82286     constructor(options) {
82287         var _a, _b, _c, _d;
82288         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";
82289         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";
82290         const exploreUrl = `${scheme}://${host}`;
82291         this._exploreUrl$ = of(exploreUrl);
82292         const imageTiling = (options === null || options === void 0 ? void 0 : options.imageTiling) === false ? false : true;
82293         this._imageTiling$ = of(imageTiling);
82294     }
82295     get exploreUrl$() {
82296         return this._exploreUrl$;
82297     }
82298     get imageTiling$() {
82299         return this._imageTiling$;
82300     }
82301 }
82302
82303 class Container {
82304     constructor(options, stateService, dom) {
82305         var _a;
82306         this._onWindowResize = () => {
82307             if (this._trackResize) {
82308                 this.renderService.resize$.next();
82309             }
82310         };
82311         this._dom = dom !== null && dom !== void 0 ? dom : new DOM();
82312         if (typeof options.container === "string") {
82313             this._container = this._dom.document
82314                 .getElementById(options.container);
82315             if (!this._container) {
82316                 throw new Error(`Container "${options.container}" not found.`);
82317             }
82318         }
82319         else if (options.container instanceof HTMLElement) {
82320             this._container = options.container;
82321         }
82322         else {
82323             throw new Error(`Invalid type: "container" must be ` +
82324                 `a String or HTMLElement.`);
82325         }
82326         this._trackResize =
82327             options.trackResize === false ?
82328                 false : true;
82329         this.id = (_a = this._container.id) !== null && _a !== void 0 ? _a : "mapillary-fallback-container-id";
82330         this._container.classList
82331             .add("mapillary-viewer");
82332         this._canvasContainer = this._dom
82333             .createElement("div", "mapillary-interactive", this._container);
82334         this._canvas = this._dom
82335             .createElement("canvas", "mapillary-canvas");
82336         this._canvas.style.position = "absolute";
82337         this._canvas.setAttribute("tabindex", "0");
82338         // Add DOM container after canvas container to
82339         // render DOM elements on top of the interactive
82340         // canvas.
82341         this._domContainer = this._dom
82342             .createElement("div", "mapillary-dom", this._container);
82343         this.configurationService = new ConfigurationService(options);
82344         this.renderService =
82345             new RenderService(this._container, stateService.currentState$, options.renderMode);
82346         this.glRenderer =
82347             new GLRenderer(this._canvas, this._canvasContainer, this.renderService);
82348         this.domRenderer =
82349             new DOMRenderer(this._domContainer, this.renderService, stateService.currentState$);
82350         this.keyboardService =
82351             new KeyboardService(this._canvasContainer);
82352         this.mouseService =
82353             new MouseService(this._container, this._canvasContainer, this._domContainer, document);
82354         this.touchService =
82355             new TouchService(this._canvasContainer, this._domContainer);
82356         this.spriteService =
82357             new SpriteService(options.sprite);
82358         window.addEventListener('resize', this._onWindowResize, false);
82359     }
82360     get canvas() {
82361         return !!this._canvas.parentNode ?
82362             this._canvas : null;
82363     }
82364     get canvasContainer() {
82365         return this._canvasContainer;
82366     }
82367     get container() {
82368         return this._container;
82369     }
82370     get domContainer() {
82371         return this._domContainer;
82372     }
82373     remove() {
82374         window.removeEventListener('resize', this._onWindowResize, false);
82375         this.spriteService.dispose();
82376         this.touchService.dispose();
82377         this.mouseService.dispose();
82378         this.glRenderer.remove();
82379         this.domRenderer.remove();
82380         this.renderService.dispose();
82381         this._removeNode(this._canvasContainer);
82382         this._removeNode(this._domContainer);
82383         this._container.classList
82384             .remove("mapillary-viewer");
82385     }
82386     _removeNode(node) {
82387         if (node.parentNode) {
82388             node.parentNode.removeChild(node);
82389         }
82390     }
82391 }
82392
82393 class CacheService {
82394     constructor(_graphService, _stateService, _api) {
82395         this._graphService = _graphService;
82396         this._stateService = _stateService;
82397         this._api = _api;
82398         this._subscriptions = new SubscriptionHolder();
82399         this._started = false;
82400         this._cellDepth = 1;
82401     }
82402     get started() {
82403         return this._started;
82404     }
82405     configure(configuration) {
82406         if (!configuration) {
82407             this._cellDepth = 1;
82408             return;
82409         }
82410         this._cellDepth = Math.max(1, Math.min(3, configuration.cellDepth));
82411     }
82412     start() {
82413         if (this._started) {
82414             return;
82415         }
82416         const subs = this._subscriptions;
82417         subs.push(this._stateService.currentState$
82418             .pipe(distinctUntilChanged(undefined, (frame) => {
82419             return frame.state.currentImage.id;
82420         }), map((frame) => {
82421             const state = frame.state;
82422             const trajectory = state.trajectory;
82423             const trajectoryKeys = trajectory
82424                 .map((n) => {
82425                 return n.id;
82426             });
82427             const sequenceKey = trajectory[trajectory.length - 1].sequenceId;
82428             return [
82429                 trajectoryKeys,
82430                 state.currentImage.originalLngLat,
82431                 sequenceKey,
82432             ];
82433         }), bufferCount(1, 5), withLatestFrom(this._graphService.graphMode$), switchMap(([keepBuffer, graphMode]) => {
82434             const keepKeys = keepBuffer[0][0];
82435             const lngLat = keepBuffer[0][1];
82436             const geometry = this._api.data.geometry;
82437             const cellId = geometry.lngLatToCellId(lngLat);
82438             const keepCellIds = connectedComponent(cellId, this._cellDepth, geometry);
82439             const keepSequenceKey = graphMode === GraphMode.Sequence ?
82440                 keepBuffer[0][2] :
82441                 undefined;
82442             return this._graphService
82443                 .uncache$(keepKeys, keepCellIds, keepSequenceKey);
82444         }))
82445             .subscribe(() => { }));
82446         subs.push(this._graphService.graphMode$
82447             .pipe(skip(1), withLatestFrom(this._stateService.currentState$), switchMap(([mode, frame]) => {
82448             return mode === GraphMode.Sequence ?
82449                 this._keyToEdges(frame.state.currentImage.id, (image) => {
82450                     return image.sequenceEdges$;
82451                 }) :
82452                 from(frame.state.trajectory
82453                     .map((image) => {
82454                     return image.id;
82455                 })
82456                     .slice(frame.state.currentIndex)).pipe(mergeMap((key) => {
82457                     return this._keyToEdges(key, (image) => {
82458                         return image.spatialEdges$;
82459                     });
82460                 }, 6));
82461         }))
82462             .subscribe(() => { }));
82463         subs.push(this._graphService.dataAdded$
82464             .pipe(withLatestFrom(this._stateService.currentId$), switchMap(([_, imageId]) => {
82465             return this._graphService.cacheImage$(imageId);
82466         }))
82467             .subscribe(() => { }));
82468         this._started = true;
82469     }
82470     stop() {
82471         if (!this._started) {
82472             return;
82473         }
82474         this._subscriptions.unsubscribe();
82475         this._started = false;
82476     }
82477     _keyToEdges(key, imageToEdgeMap) {
82478         return this._graphService.cacheImage$(key).pipe(switchMap(imageToEdgeMap), first((status) => {
82479             return status.cached;
82480         }), timeout(15000), catchError((error) => {
82481             console.error(`Failed to cache edges (${key}).`, error);
82482             return empty();
82483         }));
82484     }
82485 }
82486
82487 class LoadingService {
82488     constructor() {
82489         this._loadersSubject$ = new Subject();
82490         this._loaders$ = this._loadersSubject$.pipe(scan((loaders, loader) => {
82491             if (loader.task !== undefined) {
82492                 loaders[loader.task] = loader.loading;
82493             }
82494             return loaders;
82495         }, {}), startWith({}), publishReplay(1), refCount());
82496     }
82497     get loading$() {
82498         return this._loaders$.pipe(map((loaders) => {
82499             for (const key in loaders) {
82500                 if (!loaders.hasOwnProperty(key)) {
82501                     continue;
82502                 }
82503                 if (loaders[key]) {
82504                     return true;
82505                 }
82506             }
82507             return false;
82508         }), debounceTime(100), distinctUntilChanged());
82509     }
82510     taskLoading$(task) {
82511         return this._loaders$.pipe(map((loaders) => {
82512             return !!loaders[task];
82513         }), debounceTime(100), distinctUntilChanged());
82514     }
82515     startLoading(task) {
82516         this._loadersSubject$.next({ loading: true, task: task });
82517     }
82518     stopLoading(task) {
82519         this._loadersSubject$.next({ loading: false, task: task });
82520     }
82521 }
82522
82523 var PanMode;
82524 (function (PanMode) {
82525     PanMode[PanMode["Disabled"] = 0] = "Disabled";
82526     PanMode[PanMode["Enabled"] = 1] = "Enabled";
82527     PanMode[PanMode["Started"] = 2] = "Started";
82528 })(PanMode || (PanMode = {}));
82529 class PanService {
82530     constructor(graphService, stateService, enabled, graphCalculator, spatial, viewportCoords) {
82531         this._subscriptions = new SubscriptionHolder();
82532         this._graphService = graphService;
82533         this._stateService = stateService;
82534         this._graphCalculator = graphCalculator !== null && graphCalculator !== void 0 ? graphCalculator : new GraphCalculator();
82535         this._spatial = spatial !== null && spatial !== void 0 ? spatial : new Spatial();
82536         this._viewportCoords = viewportCoords !== null && viewportCoords !== void 0 ? viewportCoords : new ViewportCoords();
82537         this._mode = enabled !== false ?
82538             PanMode.Enabled : PanMode.Disabled;
82539         this._panImagesSubject$ = new Subject();
82540         this._panImages$ = this._panImagesSubject$.pipe(startWith([]), publishReplay(1), refCount());
82541         this._subscriptions.push(this._panImages$.subscribe());
82542     }
82543     get panImages$() {
82544         return this._panImages$;
82545     }
82546     dispose() {
82547         this.stop();
82548         if (this._panImagesSubscription != null) {
82549             this._panImagesSubscription.unsubscribe();
82550         }
82551         this._subscriptions.unsubscribe();
82552     }
82553     enable() {
82554         if (this._mode !== PanMode.Disabled) {
82555             return;
82556         }
82557         this._mode = PanMode.Enabled;
82558         this.start();
82559     }
82560     disable() {
82561         if (this._mode === PanMode.Disabled) {
82562             return;
82563         }
82564         this.stop();
82565         this._mode = PanMode.Disabled;
82566     }
82567     start() {
82568         if (this._mode !== PanMode.Enabled) {
82569             return;
82570         }
82571         const panImages$ = this._stateService.currentImage$.pipe(switchMap((current) => {
82572             if (!current.merged || isSpherical(current.cameraType)) {
82573                 return of([]);
82574             }
82575             const current$ = of(current);
82576             const bounds = this._graphCalculator.boundingBoxCorners(current.lngLat, 20);
82577             const adjacent$ = this._graphService
82578                 .cacheBoundingBox$(bounds[0], bounds[1]).pipe(catchError((error) => {
82579                 console.error(`Failed to cache periphery bounding box (${current.id})`, error);
82580                 return empty();
82581             }), map((images) => {
82582                 if (isSpherical(current.cameraType)) {
82583                     return [];
82584                 }
82585                 const potential = [];
82586                 for (const image of images) {
82587                     if (image.id === current.id) {
82588                         continue;
82589                     }
82590                     if (image.mergeId !== current.mergeId) {
82591                         continue;
82592                     }
82593                     if (isSpherical(image.cameraType)) {
82594                         continue;
82595                     }
82596                     if (this._distance(image, current) > 4) {
82597                         continue;
82598                     }
82599                     potential.push(image);
82600                 }
82601                 return potential;
82602             }));
82603             return combineLatest(current$, adjacent$).pipe(withLatestFrom(this._stateService.reference$), map(([[cn, adjacent], reference]) => {
82604                 const currentDirection = this._spatial.viewingDirection(cn.rotation);
82605                 const currentTranslation = computeTranslation({ lat: cn.lngLat.lat, lng: cn.lngLat.lng, alt: cn.computedAltitude }, cn.rotation, reference);
82606                 const currentTransform = this._createTransform(cn, currentTranslation);
82607                 const currentAzimuthal = this._spatial.wrap(this._spatial.azimuthal(currentDirection.toArray(), currentTransform.upVector().toArray()), 0, 2 * Math.PI);
82608                 const currentProjectedPoints = this._computeProjectedPoints(currentTransform);
82609                 const currentHFov = this._computeHorizontalFov(currentProjectedPoints) / 180 * Math.PI;
82610                 const preferredOverlap = Math.PI / 8;
82611                 let left = undefined;
82612                 let right = undefined;
82613                 for (const a of adjacent) {
82614                     const translation = computeTranslation({ lat: a.lngLat.lat, lng: a.lngLat.lng, alt: a.computedAltitude }, a.rotation, reference);
82615                     const transform = this._createTransform(a, translation);
82616                     const projectedPoints = this._computeProjectedPoints(transform);
82617                     const hFov = this._computeHorizontalFov(projectedPoints) / 180 * Math.PI;
82618                     const direction = this._spatial.viewingDirection(a.rotation);
82619                     const azimuthal = this._spatial.wrap(this._spatial.azimuthal(direction.toArray(), transform.upVector().toArray()), 0, 2 * Math.PI);
82620                     const directionChange = this._spatial.angleBetweenVector2(currentDirection.x, currentDirection.y, direction.x, direction.y);
82621                     let overlap = Number.NEGATIVE_INFINITY;
82622                     if (directionChange > 0) {
82623                         if (currentAzimuthal > azimuthal) {
82624                             overlap = currentAzimuthal - 2 * Math.PI + currentHFov / 2 - (azimuthal - hFov / 2);
82625                         }
82626                         else {
82627                             overlap = currentAzimuthal + currentHFov / 2 - (azimuthal - hFov / 2);
82628                         }
82629                     }
82630                     else {
82631                         if (currentAzimuthal < azimuthal) {
82632                             overlap = azimuthal + hFov / 2 - (currentAzimuthal + 2 * Math.PI - currentHFov / 2);
82633                         }
82634                         else {
82635                             overlap = azimuthal + hFov / 2 - (currentAzimuthal - currentHFov / 2);
82636                         }
82637                     }
82638                     const nonOverlap = Math.abs(hFov - overlap);
82639                     const distanceCost = this._distance(a, cn);
82640                     const timeCost = Math.min(this._timeDifference(a, cn), 4);
82641                     const overlapCost = 20 * Math.abs(overlap - preferredOverlap);
82642                     const fovCost = Math.min(5, 1 / Math.min(hFov / currentHFov, 1));
82643                     const nonOverlapCost = overlap > 0 ? -2 * nonOverlap : 0;
82644                     const cost = distanceCost + timeCost + overlapCost + fovCost + nonOverlapCost;
82645                     if (overlap > 0 &&
82646                         overlap < 0.5 * currentHFov &&
82647                         overlap < 0.5 * hFov &&
82648                         nonOverlap > 0.5 * currentHFov) {
82649                         if (directionChange > 0) {
82650                             if (!left) {
82651                                 left = [cost, a, transform, hFov];
82652                             }
82653                             else {
82654                                 if (cost < left[0]) {
82655                                     left = [cost, a, transform, hFov];
82656                                 }
82657                             }
82658                         }
82659                         else {
82660                             if (!right) {
82661                                 right = [cost, a, transform, hFov];
82662                             }
82663                             else {
82664                                 if (cost < right[0]) {
82665                                     right = [cost, a, transform, hFov];
82666                                 }
82667                             }
82668                         }
82669                     }
82670                 }
82671                 const panImagess = [];
82672                 if (!!left) {
82673                     panImagess.push([left[1], left[2], left[3]]);
82674                 }
82675                 if (!!right) {
82676                     panImagess.push([right[1], right[2], right[3]]);
82677                 }
82678                 return panImagess;
82679             }), startWith([]));
82680         }));
82681         this._panImagesSubscription = this._stateService.currentState$.pipe(map((frame) => {
82682             return frame.state.imagesAhead > 0;
82683         }), distinctUntilChanged(), switchMap((traversing) => {
82684             return traversing ? of([]) : panImages$;
82685         }))
82686             .subscribe((panImages) => {
82687             this._panImagesSubject$.next(panImages);
82688         });
82689         this._mode = PanMode.Started;
82690     }
82691     stop() {
82692         if (this._mode !== PanMode.Started) {
82693             return;
82694         }
82695         this._panImagesSubscription.unsubscribe();
82696         this._panImagesSubject$.next([]);
82697         this._mode = PanMode.Enabled;
82698     }
82699     _distance(image, reference) {
82700         const [x, y, z] = geodeticToEnu(image.lngLat.lng, image.lngLat.lat, image.computedAltitude, reference.lngLat.lng, reference.lngLat.lat, reference.computedAltitude);
82701         return Math.sqrt(x * x + y * y + z * z);
82702     }
82703     _timeDifference(image, reference) {
82704         const milliSecond = (1000 * 60 * 60 * 24 * 30);
82705         return Math.abs(image.capturedAt - reference.capturedAt) / milliSecond;
82706     }
82707     _createTransform(image, translation) {
82708         return new Transform(image.exifOrientation, image.width, image.height, image.scale, image.rotation, translation, image.assetsCached ? image.image : undefined, undefined, image.cameraParameters, image.cameraType);
82709     }
82710     _computeProjectedPoints(transform) {
82711         const vertices = [[1, 0]];
82712         const directions = [[0, 0.5]];
82713         const pointsPerLine = 20;
82714         return computeProjectedPoints(transform, vertices, directions, pointsPerLine, this._viewportCoords);
82715     }
82716     _computeHorizontalFov(projectedPoints) {
82717         const fovs = projectedPoints
82718             .map((projectedPoint) => {
82719             return this._coordToFov(projectedPoint[0]);
82720         });
82721         const fov = Math.min(...fovs);
82722         return fov;
82723     }
82724     _coordToFov(x) {
82725         return 2 * Math.atan(x) * 180 / Math.PI;
82726     }
82727 }
82728
82729 /**
82730  * @class API
82731  *
82732  * @classdesc Provides methods for access to the API.
82733  */
82734 class APIWrapper {
82735     constructor(_data) {
82736         this._data = _data;
82737     }
82738     get data() {
82739         return this._data;
82740     }
82741     getCoreImages$(cellId) {
82742         return this._wrap$(this._data.getCoreImages(cellId));
82743     }
82744     getImages$(imageIds) {
82745         return this._wrap$(this._data.getImages(imageIds));
82746     }
82747     getImageTiles$(tiles) {
82748         return this._wrap$(this._data.getImageTiles(tiles));
82749     }
82750     getSequence$(sequenceId) {
82751         return this._wrap$(this._data.getSequence(sequenceId));
82752     }
82753     getSpatialImages$(imageIds) {
82754         return this._wrap$(this._data.getSpatialImages(imageIds));
82755     }
82756     setAccessToken(accessToken) {
82757         this._data.setAccessToken(accessToken);
82758     }
82759     _wrap$(promise) {
82760         return Observable.create((subscriber) => {
82761             promise.then((value) => {
82762                 subscriber.next(value);
82763                 subscriber.complete();
82764             }, (error) => {
82765                 subscriber.error(error);
82766             });
82767         });
82768     }
82769 }
82770
82771 /**
82772  * @class GraphService
82773  *
82774  * @classdesc Represents a service for graph operations.
82775  */
82776 class GraphService {
82777     /**
82778      * Create a new graph service instance.
82779      *
82780      * @param {Graph} graph - Graph instance to be operated on.
82781      */
82782     constructor(graph) {
82783         this._dataAdded$ = new Subject();
82784         this._subscriptions = new SubscriptionHolder();
82785         this._onDataAdded = (event) => {
82786             this._graph$
82787                 .pipe(first(), mergeMap(graph => {
82788                 return graph.updateCells$(event.cellIds).pipe(tap(() => { graph.resetSpatialEdges(); }));
82789             }))
82790                 .subscribe(cellId => { this._dataAdded$.next(cellId); });
82791         };
82792         const subs = this._subscriptions;
82793         this._graph$ = concat(of(graph), graph.changed$).pipe(publishReplay(1), refCount());
82794         subs.push(this._graph$.subscribe(() => { }));
82795         this._graphMode = GraphMode.Spatial;
82796         this._graphModeSubject$ = new Subject();
82797         this._graphMode$ = this._graphModeSubject$.pipe(startWith(this._graphMode), publishReplay(1), refCount());
82798         subs.push(this._graphMode$.subscribe(() => { }));
82799         this._firstGraphSubjects$ = [];
82800         this._initializeCacheSubscriptions = [];
82801         this._sequenceSubscriptions = [];
82802         this._spatialSubscriptions = [];
82803         graph.api.data.on("datacreate", this._onDataAdded);
82804     }
82805     /**
82806      * Get dataAdded$.
82807      *
82808      * @returns {Observable<string>} Observable emitting
82809      * a cell id every time data has been added to a cell.
82810      */
82811     get dataAdded$() {
82812         return this._dataAdded$;
82813     }
82814     /**
82815      * Get filter observable.
82816      *
82817      * @desciption Emits the filter every time it has changed.
82818      *
82819      * @returns {Observable<FilterFunction>} Observable
82820      * emitting the filter function every time it is set.
82821      */
82822     get filter$() {
82823         return this._graph$.pipe(first(), mergeMap((graph) => {
82824             return graph.filter$;
82825         }));
82826     }
82827     /**
82828      * Get graph mode observable.
82829      *
82830      * @description Emits the current graph mode.
82831      *
82832      * @returns {Observable<GraphMode>} Observable
82833      * emitting the current graph mode when it changes.
82834      */
82835     get graphMode$() {
82836         return this._graphMode$;
82837     }
82838     /**
82839      * Cache full images in a bounding box.
82840      *
82841      * @description When called, the full properties of
82842      * the image are retrieved. The image cache is not initialized
82843      * for any new images retrieved and the image assets are not
82844      * retrieved, {@link cacheImage$} needs to be called for caching
82845      * assets.
82846      *
82847      * @param {LngLat} sw - South west corner of bounding box.
82848      * @param {LngLat} ne - North east corner of bounding box.
82849      * @return {Observable<Array<Image>>} Observable emitting a single item,
82850      * the images of the bounding box, when they have all been retrieved.
82851      * @throws {Error} Propagates any IO image caching errors to the caller.
82852      */
82853     cacheBoundingBox$(sw, ne) {
82854         return this._graph$.pipe(first(), mergeMap((graph) => {
82855             return graph.cacheBoundingBox$(sw, ne);
82856         }));
82857     }
82858     /**
82859      * Cache full images in a cell.
82860      *
82861      * @description When called, the full properties of
82862      * the image are retrieved. The image cache is not initialized
82863      * for any new images retrieved and the image assets are not
82864      * retrieved, {@link cacheImage$} needs to be called for caching
82865      * assets.
82866      *
82867      * @param {string} cellId - Id of the cell.
82868      * @return {Observable<Array<Image>>} Observable emitting a single item,
82869      * the images of the cell, when they have all been retrieved.
82870      * @throws {Error} Propagates any IO image caching errors to the caller.
82871      */
82872     cacheCell$(cellId) {
82873         return this._graph$.pipe(first(), mergeMap((graph) => {
82874             return graph.cacheCell$(cellId);
82875         }));
82876     }
82877     /**
82878      * Cache a image in the graph and retrieve it.
82879      *
82880      * @description When called, the full properties of
82881      * the image are retrieved and the image cache is initialized.
82882      * After that the image assets are cached and the image
82883      * is emitted to the observable when.
82884      * In parallel to caching the image assets, the sequence and
82885      * spatial edges of the image are cached. For this, the sequence
82886      * of the image and the required tiles and spatial images are
82887      * retrieved. The sequence and spatial edges may be set before
82888      * or after the image is returned.
82889      *
82890      * @param {string} id - Id of the image to cache.
82891      * @return {Observable<Image>} Observable emitting a single item,
82892      * the image, when it has been retrieved and its assets are cached.
82893      * @throws {Error} Propagates any IO image caching errors to the caller.
82894      */
82895     cacheImage$(id) {
82896         const firstGraphSubject$ = new Subject();
82897         this._firstGraphSubjects$.push(firstGraphSubject$);
82898         const firstGraph$ = firstGraphSubject$.pipe(publishReplay(1), refCount());
82899         const image$ = firstGraph$.pipe(map((graph) => {
82900             return graph.getNode(id);
82901         }), mergeMap((image) => {
82902             return image.assetsCached ?
82903                 of(image) :
82904                 image.cacheAssets$();
82905         }), publishReplay(1), refCount());
82906         image$.subscribe(undefined, (error) => {
82907             console.error(`Failed to cache image (${id}).`, error);
82908         });
82909         let initializeCacheSubscription;
82910         initializeCacheSubscription = this._graph$.pipe(first(), mergeMap((graph) => {
82911             if (graph.isCachingFull(id) || !graph.hasNode(id)) {
82912                 return graph.cacheFull$(id);
82913             }
82914             if (graph.isCachingFill(id) || !graph.getNode(id).complete) {
82915                 return graph.cacheFill$(id);
82916             }
82917             return of(graph);
82918         }), tap((graph) => {
82919             if (!graph.hasNode(id)) {
82920                 throw new GraphMapillaryError(`Failed to cache image (${id})`);
82921             }
82922             if (!graph.hasInitializedCache(id)) {
82923                 graph.initializeCache(id);
82924             }
82925         }), finalize(() => {
82926             if (initializeCacheSubscription == null) {
82927                 return;
82928             }
82929             this._removeFromArray(initializeCacheSubscription, this._initializeCacheSubscriptions);
82930             this._removeFromArray(firstGraphSubject$, this._firstGraphSubjects$);
82931         }))
82932             .subscribe((graph) => {
82933             firstGraphSubject$.next(graph);
82934             firstGraphSubject$.complete();
82935         }, (error) => {
82936             firstGraphSubject$.error(error);
82937         });
82938         if (!initializeCacheSubscription.closed) {
82939             this._initializeCacheSubscriptions.push(initializeCacheSubscription);
82940         }
82941         const graphSequence$ = firstGraph$.pipe(catchError(() => {
82942             return empty();
82943         }), mergeMap((graph) => {
82944             if (graph.isCachingNodeSequence(id) || !graph.hasNodeSequence(id)) {
82945                 return graph.cacheNodeSequence$(id);
82946             }
82947             return of(graph);
82948         }), publishReplay(1), refCount());
82949         let sequenceSubscription;
82950         sequenceSubscription = graphSequence$.pipe(tap((graph) => {
82951             if (!graph.getNode(id).sequenceEdges.cached) {
82952                 graph.cacheSequenceEdges(id);
82953             }
82954         }), finalize(() => {
82955             if (sequenceSubscription == null) {
82956                 return;
82957             }
82958             this._removeFromArray(sequenceSubscription, this._sequenceSubscriptions);
82959         }))
82960             .subscribe(() => { return; }, (error) => {
82961             console.error(`Failed to cache sequence edges (${id}).`, error);
82962         });
82963         if (!sequenceSubscription.closed) {
82964             this._sequenceSubscriptions.push(sequenceSubscription);
82965         }
82966         if (this._graphMode === GraphMode.Spatial) {
82967             let spatialSubscription;
82968             spatialSubscription = firstGraph$.pipe(catchError(() => {
82969                 return empty();
82970             }), expand((graph) => {
82971                 if (graph.hasTiles(id)) {
82972                     return empty();
82973                 }
82974                 return from(graph.cacheTiles$(id)).pipe(mergeMap((graph$) => {
82975                     return graph$.pipe(mergeMap((g) => {
82976                         if (g.isCachingTiles(id)) {
82977                             return empty();
82978                         }
82979                         return of(g);
82980                     }), catchError((error) => {
82981                         console.error(`Failed to cache tile data (${id}).`, error);
82982                         return empty();
82983                     }));
82984                 }));
82985             }), takeLast(1), mergeMap((graph) => {
82986                 if (graph.hasSpatialArea(id)) {
82987                     return of(graph);
82988                 }
82989                 return from(graph.cacheSpatialArea$(id)).pipe(mergeMap((graph$) => {
82990                     return graph$.pipe(catchError((error) => {
82991                         console.error(`Failed to cache spatial images (${id}).`, error);
82992                         return empty();
82993                     }));
82994                 }));
82995             }), takeLast(1), mergeMap((graph) => {
82996                 return graph.hasNodeSequence(id) ?
82997                     of(graph) :
82998                     graph.cacheNodeSequence$(id);
82999             }), tap((graph) => {
83000                 if (!graph.getNode(id).spatialEdges.cached) {
83001                     graph.cacheSpatialEdges(id);
83002                 }
83003             }), finalize(() => {
83004                 if (spatialSubscription == null) {
83005                     return;
83006                 }
83007                 this._removeFromArray(spatialSubscription, this._spatialSubscriptions);
83008             }))
83009                 .subscribe(() => { return; }, (error) => {
83010                 const message = `Failed to cache spatial edges (${id}).`;
83011                 console.error(message, error);
83012             });
83013             if (!spatialSubscription.closed) {
83014                 this._spatialSubscriptions.push(spatialSubscription);
83015             }
83016         }
83017         return image$.pipe(first((image) => {
83018             return image.assetsCached;
83019         }));
83020     }
83021     /**
83022      * Cache a sequence in the graph and retrieve it.
83023      *
83024      * @param {string} sequenceId - Sequence id.
83025      * @returns {Observable<Sequence>} Observable emitting a single item,
83026      * the sequence, when it has been retrieved and its assets are cached.
83027      * @throws {Error} Propagates any IO image caching errors to the caller.
83028      */
83029     cacheSequence$(sequenceId) {
83030         return this._graph$.pipe(first(), mergeMap((graph) => {
83031             if (graph.isCachingSequence(sequenceId) || !graph.hasSequence(sequenceId)) {
83032                 return graph.cacheSequence$(sequenceId);
83033             }
83034             return of(graph);
83035         }), map((graph) => {
83036             return graph.getSequence(sequenceId);
83037         }));
83038     }
83039     /**
83040      * Cache a sequence and its images in the graph and retrieve the sequence.
83041      *
83042      * @description Caches a sequence and its assets are cached and
83043      * retrieves all images belonging to the sequence. The image assets
83044      * or edges will not be cached.
83045      *
83046      * @param {string} sequenceId - Sequence id.
83047      * @param {string} referenceImageId - Id of image to use as reference
83048      * for optimized caching.
83049      * @returns {Observable<Sequence>} Observable emitting a single item,
83050      * the sequence, when it has been retrieved, its assets are cached and
83051      * all images belonging to the sequence has been retrieved.
83052      * @throws {Error} Propagates any IO image caching errors to the caller.
83053      */
83054     cacheSequenceImages$(sequenceId, referenceImageId) {
83055         return this._graph$.pipe(first(), mergeMap((graph) => {
83056             if (graph.isCachingSequence(sequenceId) || !graph.hasSequence(sequenceId)) {
83057                 return graph.cacheSequence$(sequenceId);
83058             }
83059             return of(graph);
83060         }), mergeMap((graph) => {
83061             if (graph.isCachingSequenceNodes(sequenceId) || !graph.hasSequenceNodes(sequenceId)) {
83062                 return graph.cacheSequenceNodes$(sequenceId, referenceImageId);
83063             }
83064             return of(graph);
83065         }), map((graph) => {
83066             return graph.getSequence(sequenceId);
83067         }));
83068     }
83069     /**
83070      * Dispose the graph service and its children.
83071      */
83072     dispose() {
83073         this._graph$
83074             .pipe(first())
83075             .subscribe((graph) => { graph.unsubscribe(); });
83076         this._subscriptions.unsubscribe();
83077     }
83078     /**
83079      * Set a spatial edge filter on the graph.
83080      *
83081      * @description Resets the spatial edges of all cached images.
83082      *
83083      * @param {FilterExpression} filter - Filter expression to be applied.
83084      * @return {Observable<Graph>} Observable emitting a single item,
83085      * the graph, when the spatial edges have been reset.
83086      */
83087     setFilter$(filter) {
83088         this._resetSubscriptions(this._spatialSubscriptions);
83089         return this._graph$.pipe(first(), tap((graph) => {
83090             graph.resetSpatialEdges();
83091             graph.setFilter(filter);
83092         }), map(() => {
83093             return undefined;
83094         }));
83095     }
83096     /**
83097      * Set the graph mode.
83098      *
83099      * @description If graph mode is set to spatial, caching
83100      * is performed with emphasis on spatial edges. If graph
83101      * mode is set to sequence no tile data is requested and
83102      * no spatial edges are computed.
83103      *
83104      * When setting graph mode to sequence all spatial
83105      * subscriptions are aborted.
83106      *
83107      * @param {GraphMode} mode - Graph mode to set.
83108      */
83109     setGraphMode(mode) {
83110         if (this._graphMode === mode) {
83111             return;
83112         }
83113         if (mode === GraphMode.Sequence) {
83114             this._resetSubscriptions(this._spatialSubscriptions);
83115         }
83116         this._graphMode = mode;
83117         this._graphModeSubject$.next(this._graphMode);
83118     }
83119     /**
83120      * Reset the graph.
83121      *
83122      * @description Resets the graph but keeps the images of the
83123      * supplied ids.
83124      *
83125      * @param {Array<string>} keepIds - Ids of images to keep in graph.
83126      * @return {Observable<Image>} Observable emitting a single item,
83127      * the graph, when it has been reset.
83128      */
83129     reset$(keepIds) {
83130         this._abortSubjects(this._firstGraphSubjects$);
83131         this._resetSubscriptions(this._initializeCacheSubscriptions);
83132         this._resetSubscriptions(this._sequenceSubscriptions);
83133         this._resetSubscriptions(this._spatialSubscriptions);
83134         return this._graph$.pipe(first(), tap((graph) => {
83135             graph.reset(keepIds);
83136         }), map(() => {
83137             return undefined;
83138         }));
83139     }
83140     /**
83141      * Uncache the graph.
83142      *
83143      * @description Uncaches the graph by removing tiles, images and
83144      * sequences. Keeps the images of the supplied ids and the tiles
83145      * related to those images.
83146      *
83147      * @param {Array<string>} keepIds - Ids of images to keep in graph.
83148      * @param {Array<string>} keepCellIds - Ids of cells to keep in graph.
83149      * @param {string} keepSequenceId - Optional id of sequence
83150      * for which the belonging images should not be disposed or
83151      * removed from the graph. These images may still be uncached if
83152      * not specified in keep ids param.
83153      * @return {Observable<Graph>} Observable emitting a single item,
83154      * the graph, when the graph has been uncached.
83155      */
83156     uncache$(keepIds, keepCellIds, keepSequenceId) {
83157         return this._graph$.pipe(first(), tap((graph) => {
83158             graph.uncache(keepIds, keepCellIds, keepSequenceId);
83159         }), map(() => {
83160             return undefined;
83161         }));
83162     }
83163     _abortSubjects(subjects) {
83164         for (const subject of subjects.slice()) {
83165             this._removeFromArray(subject, subjects);
83166             subject.error(new Error("Cache image request was aborted."));
83167         }
83168     }
83169     _removeFromArray(object, objects) {
83170         const index = objects.indexOf(object);
83171         if (index !== -1) {
83172             objects.splice(index, 1);
83173         }
83174     }
83175     _resetSubscriptions(subscriptions) {
83176         for (const subscription of subscriptions.slice()) {
83177             this._removeFromArray(subscription, subscriptions);
83178             if (!subscription.closed) {
83179                 subscription.unsubscribe();
83180             }
83181         }
83182     }
83183 }
83184
83185 class FrameGenerator {
83186     constructor(root) {
83187         if (root.requestAnimationFrame) {
83188             this._cancelAnimationFrame = root.cancelAnimationFrame.bind(root);
83189             this._requestAnimationFrame = root.requestAnimationFrame.bind(root);
83190         }
83191         else if (root.mozRequestAnimationFrame) {
83192             this._cancelAnimationFrame = root.mozCancelAnimationFrame.bind(root);
83193             this._requestAnimationFrame = root.mozRequestAnimationFrame.bind(root);
83194         }
83195         else if (root.webkitRequestAnimationFrame) {
83196             this._cancelAnimationFrame = root.webkitCancelAnimationFrame.bind(root);
83197             this._requestAnimationFrame = root.webkitRequestAnimationFrame.bind(root);
83198         }
83199         else if (root.msRequestAnimationFrame) {
83200             this._cancelAnimationFrame = root.msCancelAnimationFrame.bind(root);
83201             this._requestAnimationFrame = root.msRequestAnimationFrame.bind(root);
83202         }
83203         else if (root.oRequestAnimationFrame) {
83204             this._cancelAnimationFrame = root.oCancelAnimationFrame.bind(root);
83205             this._requestAnimationFrame = root.oRequestAnimationFrame.bind(root);
83206         }
83207         else {
83208             this._cancelAnimationFrame = root.clearTimeout.bind(root);
83209             this._requestAnimationFrame = (cb) => { return root.setTimeout(cb, 1000 / 60); };
83210         }
83211     }
83212     get cancelAnimationFrame() {
83213         return this._cancelAnimationFrame;
83214     }
83215     get requestAnimationFrame() {
83216         return this._requestAnimationFrame;
83217     }
83218 }
83219
83220 class StateBase {
83221     constructor(state) {
83222         this._spatial = new Spatial();
83223         this._referenceThreshold = 0.01;
83224         this._transitionMode = state.transitionMode;
83225         this._reference = state.reference;
83226         this._alpha = state.alpha;
83227         this._stateTransitionAlpha = 0;
83228         this._camera = state.camera.clone();
83229         this._zoom = state.zoom;
83230         this._currentIndex = state.currentIndex;
83231         this._trajectory = state.trajectory.slice();
83232         this._trajectoryTransforms = [];
83233         this._trajectoryCameras = [];
83234         for (let image of this._trajectory) {
83235             let translation = this._imageToTranslation(image, this._reference);
83236             let transform = new Transform(image.exifOrientation, image.width, image.height, image.scale, image.rotation, translation, image.image, undefined, image.cameraParameters, image.cameraType);
83237             this._trajectoryTransforms.push(transform);
83238             this._trajectoryCameras.push(new Camera(transform));
83239         }
83240         this._currentImage = this._trajectory.length > 0 ?
83241             this._trajectory[this._currentIndex] :
83242             null;
83243         this._previousImage = this._trajectory.length > 1 && this.currentIndex > 0 ?
83244             this._trajectory[this._currentIndex - 1] :
83245             null;
83246         this._currentCamera = this._trajectoryCameras.length > 0 ?
83247             this._trajectoryCameras[this._currentIndex].clone() :
83248             new Camera();
83249         this._previousCamera = this._trajectoryCameras.length > 1 && this.currentIndex > 0 ?
83250             this._trajectoryCameras[this._currentIndex - 1].clone() :
83251             this._currentCamera.clone();
83252     }
83253     get reference() {
83254         return this._reference;
83255     }
83256     get alpha() {
83257         return this._getAlpha();
83258     }
83259     get stateTransitionAlpha() {
83260         return this._getStateTransitionAlpha();
83261     }
83262     get camera() {
83263         return this._camera;
83264     }
83265     get zoom() {
83266         return this._zoom;
83267     }
83268     get trajectory() {
83269         return this._trajectory;
83270     }
83271     get currentIndex() {
83272         return this._currentIndex;
83273     }
83274     get currentImage() {
83275         return this._currentImage;
83276     }
83277     get previousImage() {
83278         return this._previousImage;
83279     }
83280     get currentCamera() {
83281         return this._currentCamera;
83282     }
83283     get currentTransform() {
83284         return this._trajectoryTransforms.length > 0 ?
83285             this._trajectoryTransforms[this.currentIndex] : null;
83286     }
83287     get previousTransform() {
83288         return this._trajectoryTransforms.length > 1 && this.currentIndex > 0 ?
83289             this._trajectoryTransforms[this.currentIndex - 1] : null;
83290     }
83291     get motionless() {
83292         return this._motionless;
83293     }
83294     get transitionMode() {
83295         return this._transitionMode;
83296     }
83297     move(delta) { }
83298     moveTo(position) { }
83299     rotate(delta) { }
83300     rotateUnbounded(delta) { }
83301     rotateWithoutInertia(delta) { }
83302     rotateBasic(basicRotation) { }
83303     rotateBasicUnbounded(basicRotation) { }
83304     rotateBasicWithoutInertia(basicRotation) { }
83305     rotateToBasic(basic) { }
83306     setSpeed(speed) { }
83307     zoomIn(delta, reference) { }
83308     update(delta) { }
83309     setCenter(center) { }
83310     setZoom(zoom) { }
83311     dolly(delta) { }
83312     orbit(rotation) { }
83313     setViewMatrix(matrix) { }
83314     truck(direction) { }
83315     append(images) {
83316         if (images.length < 1) {
83317             throw Error("Trajectory can not be empty");
83318         }
83319         if (this._currentIndex < 0) {
83320             this.set(images);
83321         }
83322         else {
83323             this._trajectory = this._trajectory.concat(images);
83324             this._appendToTrajectories(images);
83325         }
83326     }
83327     prepend(images) {
83328         if (images.length < 1) {
83329             throw Error("Trajectory can not be empty");
83330         }
83331         this._trajectory = images.slice().concat(this._trajectory);
83332         this._currentIndex += images.length;
83333         this._setCurrentImage();
83334         let referenceReset = this._setReference(this._currentImage);
83335         if (referenceReset) {
83336             this._setTrajectories();
83337         }
83338         else {
83339             this._prependToTrajectories(images);
83340         }
83341         this._setCurrentCamera();
83342     }
83343     remove(n) {
83344         if (n < 0) {
83345             throw Error("n must be a positive integer");
83346         }
83347         if (this._currentIndex - 1 < n) {
83348             throw Error("Current and previous images can not be removed");
83349         }
83350         for (let i = 0; i < n; i++) {
83351             this._trajectory.shift();
83352             this._trajectoryTransforms.shift();
83353             this._trajectoryCameras.shift();
83354             this._currentIndex--;
83355         }
83356         this._setCurrentImage();
83357     }
83358     clearPrior() {
83359         if (this._currentIndex > 0) {
83360             this.remove(this._currentIndex - 1);
83361         }
83362     }
83363     clear() {
83364         this.cut();
83365         if (this._currentIndex > 0) {
83366             this.remove(this._currentIndex - 1);
83367         }
83368     }
83369     cut() {
83370         while (this._trajectory.length - 1 > this._currentIndex) {
83371             this._trajectory.pop();
83372             this._trajectoryTransforms.pop();
83373             this._trajectoryCameras.pop();
83374         }
83375     }
83376     set(images) {
83377         this._setTrajectory(images);
83378         this._setCurrentImage();
83379         this._setReference(this._currentImage);
83380         this._setTrajectories();
83381         this._setCurrentCamera();
83382     }
83383     getCenter() {
83384         return this._currentImage != null ?
83385             this.currentTransform.projectBasic(this._camera.lookat.toArray()) :
83386             [0.5, 0.5];
83387     }
83388     setTransitionMode(mode) {
83389         this._transitionMode = mode;
83390     }
83391     _getAlpha() { return 1; }
83392     _getStateTransitionAlpha() { return 1; }
83393     _setCurrent() {
83394         this._setCurrentImage();
83395         let referenceReset = this._setReference(this._currentImage);
83396         if (referenceReset) {
83397             this._setTrajectories();
83398         }
83399         this._setCurrentCamera();
83400     }
83401     _setCurrentCamera() {
83402         this._currentCamera = this._trajectoryCameras[this._currentIndex].clone();
83403         this._previousCamera = this._currentIndex > 0 ?
83404             this._trajectoryCameras[this._currentIndex - 1].clone() :
83405             this._currentCamera.clone();
83406     }
83407     _motionlessTransition() {
83408         let imagesSet = this._currentImage != null && this._previousImage != null;
83409         return imagesSet && (this._transitionMode === TransitionMode.Instantaneous || !(this._currentImage.merged &&
83410             this._previousImage.merged &&
83411             this._withinOriginalDistance() &&
83412             this._sameConnectedComponent()));
83413     }
83414     _setReference(image) {
83415         // do not reset reference if image is within threshold distance
83416         if (Math.abs(image.lngLat.lat - this.reference.lat) < this._referenceThreshold &&
83417             Math.abs(image.lngLat.lng - this.reference.lng) < this._referenceThreshold) {
83418             return false;
83419         }
83420         // do not reset reference if previous image exist and transition is with motion
83421         if (this._previousImage != null && !this._motionlessTransition()) {
83422             return false;
83423         }
83424         this._reference.lat = image.lngLat.lat;
83425         this._reference.lng = image.lngLat.lng;
83426         this._reference.alt = image.computedAltitude;
83427         return true;
83428     }
83429     _setCurrentImage() {
83430         this._currentImage = this._trajectory.length > 0 ?
83431             this._trajectory[this._currentIndex] :
83432             null;
83433         this._previousImage = this._currentIndex > 0 ?
83434             this._trajectory[this._currentIndex - 1] :
83435             null;
83436     }
83437     _setTrajectory(images) {
83438         if (images.length < 1) {
83439             throw new ArgumentMapillaryError("Trajectory can not be empty");
83440         }
83441         if (this._currentImage != null) {
83442             this._trajectory = [this._currentImage].concat(images);
83443             this._currentIndex = 1;
83444         }
83445         else {
83446             this._trajectory = images.slice();
83447             this._currentIndex = 0;
83448         }
83449     }
83450     _setTrajectories() {
83451         this._trajectoryTransforms.length = 0;
83452         this._trajectoryCameras.length = 0;
83453         this._appendToTrajectories(this._trajectory);
83454     }
83455     _appendToTrajectories(images) {
83456         for (let image of images) {
83457             if (!image.assetsCached) {
83458                 throw new ArgumentMapillaryError("Assets must be cached when image is added to trajectory");
83459             }
83460             let translation = this._imageToTranslation(image, this.reference);
83461             let transform = new Transform(image.exifOrientation, image.width, image.height, image.scale, image.rotation, translation, image.image, undefined, image.cameraParameters, image.cameraType);
83462             this._trajectoryTransforms.push(transform);
83463             this._trajectoryCameras.push(new Camera(transform));
83464         }
83465     }
83466     _prependToTrajectories(images) {
83467         for (let image of images.reverse()) {
83468             if (!image.assetsCached) {
83469                 throw new ArgumentMapillaryError("Assets must be cached when added to trajectory");
83470             }
83471             let translation = this._imageToTranslation(image, this.reference);
83472             let transform = new Transform(image.exifOrientation, image.width, image.height, image.scale, image.rotation, translation, image.image, undefined, image.cameraParameters, image.cameraType);
83473             this._trajectoryTransforms.unshift(transform);
83474             this._trajectoryCameras.unshift(new Camera(transform));
83475         }
83476     }
83477     _imageToTranslation(image, reference) {
83478         return computeTranslation({ alt: image.computedAltitude, lat: image.lngLat.lat, lng: image.lngLat.lng }, image.rotation, reference);
83479     }
83480     _sameConnectedComponent() {
83481         let current = this._currentImage;
83482         let previous = this._previousImage;
83483         return !!current && !!previous &&
83484             current.mergeId === previous.mergeId;
83485     }
83486     _withinOriginalDistance() {
83487         let current = this._currentImage;
83488         let previous = this._previousImage;
83489         if (!current || !previous) {
83490             return true;
83491         }
83492         // 50 km/h moves 28m in 2s
83493         let distance = this._spatial.distanceFromLngLat(current.originalLngLat.lng, current.originalLngLat.lat, previous.originalLngLat.lng, previous.originalLngLat.lat);
83494         return distance < 25;
83495     }
83496 }
83497
83498 class CustomState extends StateBase {
83499     constructor(state) {
83500         super(state);
83501     }
83502     setViewMatrix(viewMatrix) {
83503         const viewMatrixInverse = new Matrix4()
83504             .fromArray(viewMatrix)
83505             .invert();
83506         const me = viewMatrixInverse.elements;
83507         const eye = new Vector3(me[12], me[13], me[14]);
83508         const forward = new Vector3(-me[8], -me[9], -me[10]);
83509         const up = new Vector3(me[4], me[5], me[6]);
83510         const camera = this._camera;
83511         camera.position.copy(eye);
83512         camera.lookat.copy(eye
83513             .clone()
83514             .add(forward));
83515         camera.up.copy(up);
83516         const focal = 0.5 / Math.tan(Math.PI / 3);
83517         camera.focal = focal;
83518     }
83519 }
83520
83521 class EarthState extends StateBase {
83522     constructor(state) {
83523         super(state);
83524         this._transition = 0;
83525         const eye = this._camera.position.clone();
83526         const forward = this._camera.lookat
83527             .clone()
83528             .sub(eye)
83529             .normalize();
83530         const xy = Math.sqrt(forward.x * forward.x + forward.y * forward.y);
83531         const angle = Math.atan2(forward.z, xy);
83532         const lookat = new Vector3();
83533         if (angle > -Math.PI / 45) {
83534             lookat.copy(eye);
83535             eye.add(new Vector3(forward.x, forward.y, 0)
83536                 .multiplyScalar(-50));
83537             eye.z = 30;
83538         }
83539         else {
83540             // Target a point on invented ground and keep forward direction
83541             const l0 = eye.clone();
83542             const n = new Vector3(0, 0, 1);
83543             const p0 = new Vector3(0, 0, -2);
83544             const d = new Vector3().subVectors(p0, l0).dot(n) / forward.dot(n);
83545             const maxDistance = 10000;
83546             const intersection = l0
83547                 .clone()
83548                 .add(forward.
83549                 clone()
83550                 .multiplyScalar(Math.min(maxDistance, d)));
83551             lookat.copy(intersection);
83552             const t = eye
83553                 .clone()
83554                 .sub(intersection)
83555                 .normalize();
83556             eye.copy(intersection.add(t.multiplyScalar(Math.max(50, t.length()))));
83557         }
83558         const eye1 = this._camera.position.clone();
83559         const lookat1 = eye1.clone().add(forward.clone().normalize().multiplyScalar(10));
83560         const up1 = this._camera.up.clone();
83561         const eye0 = lookat1.clone();
83562         const lookat0 = eye0.clone().add(forward.clone().normalize().multiplyScalar(10));
83563         const up0 = up1.clone();
83564         const eye2 = eye.clone();
83565         const lookat2 = lookat.clone();
83566         const up2 = new Vector3(0, 0, 1);
83567         const eye3 = eye.clone().add(lookat2.clone().sub(eye2).normalize().multiplyScalar(-10));
83568         const lookat3 = lookat2.clone();
83569         const up3 = up2.clone();
83570         this._curveE = new CatmullRomCurve3([eye0, eye1, eye2, eye3]);
83571         this._curveL = new CatmullRomCurve3([lookat0, lookat1, lookat2, lookat3]);
83572         this._curveU = new CatmullRomCurve3([up0, up1, up2, up3]);
83573         this._zoom0 = this._zoom;
83574         this._zoom1 = 0;
83575         this._camera.focal = 0.5 / Math.tan(Math.PI / 4);
83576     }
83577     get _isTransitioning() {
83578         return this._transition < 1;
83579     }
83580     dolly(delta) {
83581         if (this._isTransitioning) {
83582             return;
83583         }
83584         const camera = this._camera;
83585         const offset = camera.position
83586             .clone()
83587             .sub(camera.lookat);
83588         const length = offset.length();
83589         const scaled = length * Math.pow(2, -delta);
83590         const clipped = Math.max(1, Math.min(scaled, 4000));
83591         offset.normalize();
83592         offset.multiplyScalar(clipped);
83593         camera.position
83594             .copy(camera.lookat)
83595             .add(offset);
83596     }
83597     orbit(rotation) {
83598         if (this._isTransitioning) {
83599             return;
83600         }
83601         const camera = this._camera;
83602         const q = new Quaternion()
83603             .setFromUnitVectors(camera.up, new Vector3(0, 0, 1));
83604         const qInverse = q
83605             .clone()
83606             .invert();
83607         const offset = camera.position
83608             .clone()
83609             .sub(camera.lookat);
83610         offset.applyQuaternion(q);
83611         const length = offset.length();
83612         let phi = Math.atan2(offset.y, offset.x);
83613         phi += rotation.phi;
83614         let theta = Math.atan2(Math.sqrt(offset.x * offset.x + offset.y * offset.y), offset.z);
83615         theta += rotation.theta;
83616         const threshold = Math.PI / 36;
83617         theta = Math.max(threshold, Math.min(Math.PI / 2 - threshold, theta));
83618         offset.x = Math.sin(theta) * Math.cos(phi);
83619         offset.y = Math.sin(theta) * Math.sin(phi);
83620         offset.z = Math.cos(theta);
83621         offset.applyQuaternion(qInverse);
83622         camera.position
83623             .copy(camera.lookat)
83624             .add(offset.multiplyScalar(length));
83625     }
83626     truck(direction) {
83627         if (this._isTransitioning) {
83628             return;
83629         }
83630         const camera = this._camera;
83631         camera.position
83632             .add(new Vector3().fromArray(direction));
83633         camera.lookat
83634             .add(new Vector3().fromArray(direction));
83635     }
83636     update(delta) {
83637         if (!this._isTransitioning) {
83638             return;
83639         }
83640         this._transition = Math.min(this._transition + 2 * delta / 3, 1);
83641         const sta = MathUtils.smootherstep(this._transition, 0, 1);
83642         const t = (sta + 1) / 3;
83643         const eye = this._curveE.getPoint(t);
83644         const lookat = this._curveL.getPoint(t);
83645         const up = this._curveU.getPoint(t);
83646         this._camera.position.copy(eye);
83647         this._camera.lookat.copy(lookat);
83648         this._camera.up.copy(up);
83649         this._zoom = MathUtils.lerp(this._zoom0, this._zoom1, sta);
83650         this._stateTransitionAlpha = sta;
83651     }
83652     _getStateTransitionAlpha() {
83653         return this._stateTransitionAlpha;
83654     }
83655 }
83656
83657 class EulerRotationDelta {
83658     constructor(phi, theta) {
83659         this._phi = phi;
83660         this._theta = theta;
83661     }
83662     get phi() {
83663         return this._phi;
83664     }
83665     set phi(value) {
83666         this._phi = value;
83667     }
83668     get theta() {
83669         return this._theta;
83670     }
83671     set theta(value) {
83672         this._theta = value;
83673     }
83674     get isZero() {
83675         return this._phi === 0 && this._theta === 0;
83676     }
83677     copy(delta) {
83678         this._phi = delta.phi;
83679         this._theta = delta.theta;
83680     }
83681     lerp(other, alpha) {
83682         this._phi = (1 - alpha) * this._phi + alpha * other.phi;
83683         this._theta = (1 - alpha) * this._theta + alpha * other.theta;
83684     }
83685     multiply(value) {
83686         this._phi *= value;
83687         this._theta *= value;
83688     }
83689     threshold(value) {
83690         this._phi = Math.abs(this._phi) > value ? this._phi : 0;
83691         this._theta = Math.abs(this._theta) > value ? this._theta : 0;
83692     }
83693     lengthSquared() {
83694         return this._phi * this._phi + this._theta * this._theta;
83695     }
83696     reset() {
83697         this._phi = 0;
83698         this._theta = 0;
83699     }
83700 }
83701
83702 class InteractiveStateBase extends StateBase {
83703     constructor(state) {
83704         super(state);
83705         this._animationSpeed = 1 / 40;
83706         this._rotationDelta = new EulerRotationDelta(0, 0);
83707         this._requestedRotationDelta = null;
83708         this._basicRotation = [0, 0];
83709         this._requestedBasicRotation = null;
83710         this._requestedBasicRotationUnbounded = null;
83711         this._rotationAcceleration = 0.86;
83712         this._rotationIncreaseAlpha = 0.97;
83713         this._rotationDecreaseAlpha = 0.9;
83714         this._rotationThreshold = 1e-3;
83715         this._unboundedRotationAlpha = 0.8;
83716         this._desiredZoom = state.zoom;
83717         this._minZoom = 0;
83718         this._maxZoom = 3;
83719         this._lookatDepth = 10;
83720         this._desiredLookat = null;
83721         this._desiredCenter = null;
83722     }
83723     rotate(rotationDelta) {
83724         if (this._currentImage == null) {
83725             return;
83726         }
83727         if (rotationDelta.phi === 0 && rotationDelta.theta === 0) {
83728             return;
83729         }
83730         this._desiredZoom = this._zoom;
83731         this._desiredLookat = null;
83732         this._requestedBasicRotation = null;
83733         if (this._requestedRotationDelta != null) {
83734             this._requestedRotationDelta.phi = this._requestedRotationDelta.phi + rotationDelta.phi;
83735             this._requestedRotationDelta.theta = this._requestedRotationDelta.theta + rotationDelta.theta;
83736         }
83737         else {
83738             this._requestedRotationDelta = new EulerRotationDelta(rotationDelta.phi, rotationDelta.theta);
83739         }
83740     }
83741     rotateUnbounded(delta) {
83742         if (this._currentImage == null) {
83743             return;
83744         }
83745         this._requestedBasicRotation = null;
83746         this._requestedRotationDelta = null;
83747         this._applyRotation(delta, this._currentCamera);
83748         this._applyRotation(delta, this._previousCamera);
83749         if (!this._desiredLookat) {
83750             return;
83751         }
83752         const q = new Quaternion().setFromUnitVectors(this._currentCamera.up, new Vector3(0, 0, 1));
83753         const qInverse = q.clone().invert();
83754         const offset = new Vector3()
83755             .copy(this._desiredLookat)
83756             .sub(this._camera.position)
83757             .applyQuaternion(q);
83758         const length = offset.length();
83759         let phi = Math.atan2(offset.y, offset.x);
83760         phi += delta.phi;
83761         let theta = Math.atan2(Math.sqrt(offset.x * offset.x + offset.y * offset.y), offset.z);
83762         theta += delta.theta;
83763         theta = Math.max(0.1, Math.min(Math.PI - 0.1, theta));
83764         offset.x = Math.sin(theta) * Math.cos(phi);
83765         offset.y = Math.sin(theta) * Math.sin(phi);
83766         offset.z = Math.cos(theta);
83767         offset.applyQuaternion(qInverse);
83768         this._desiredLookat
83769             .copy(this._camera.position)
83770             .add(offset.multiplyScalar(length));
83771     }
83772     rotateWithoutInertia(rotationDelta) {
83773         if (this._currentImage == null) {
83774             return;
83775         }
83776         this._desiredZoom = this._zoom;
83777         this._desiredLookat = null;
83778         this._requestedBasicRotation = null;
83779         this._requestedRotationDelta = null;
83780         const threshold = Math.PI / (10 * Math.pow(2, this._zoom));
83781         const delta = {
83782             phi: this._spatial.clamp(rotationDelta.phi, -threshold, threshold),
83783             theta: this._spatial.clamp(rotationDelta.theta, -threshold, threshold),
83784         };
83785         this._applyRotation(delta, this._currentCamera);
83786         this._applyRotation(delta, this._previousCamera);
83787     }
83788     rotateBasic(basicRotation) {
83789         if (this._currentImage == null) {
83790             return;
83791         }
83792         this._desiredZoom = this._zoom;
83793         this._desiredLookat = null;
83794         this._requestedRotationDelta = null;
83795         if (this._requestedBasicRotation != null) {
83796             this._requestedBasicRotation[0] += basicRotation[0];
83797             this._requestedBasicRotation[1] += basicRotation[1];
83798             let threshold = 0.05 / Math.pow(2, this._zoom);
83799             this._requestedBasicRotation[0] =
83800                 this._spatial.clamp(this._requestedBasicRotation[0], -threshold, threshold);
83801             this._requestedBasicRotation[1] =
83802                 this._spatial.clamp(this._requestedBasicRotation[1], -threshold, threshold);
83803         }
83804         else {
83805             this._requestedBasicRotation = basicRotation.slice();
83806         }
83807     }
83808     rotateBasicUnbounded(basicRotation) {
83809         if (this._currentImage == null) {
83810             return;
83811         }
83812         if (this._requestedBasicRotationUnbounded != null) {
83813             this._requestedBasicRotationUnbounded[0] += basicRotation[0];
83814             this._requestedBasicRotationUnbounded[1] += basicRotation[1];
83815         }
83816         else {
83817             this._requestedBasicRotationUnbounded = basicRotation.slice();
83818         }
83819     }
83820     rotateBasicWithoutInertia(basic) {
83821         if (this._currentImage == null) {
83822             return;
83823         }
83824         this._desiredZoom = this._zoom;
83825         this._desiredLookat = null;
83826         this._requestedRotationDelta = null;
83827         this._requestedBasicRotation = null;
83828         const threshold = 0.05 / Math.pow(2, this._zoom);
83829         const basicRotation = basic.slice();
83830         basicRotation[0] = this._spatial.clamp(basicRotation[0], -threshold, threshold);
83831         basicRotation[1] = this._spatial.clamp(basicRotation[1], -threshold, threshold);
83832         this._applyRotationBasic(basicRotation);
83833     }
83834     rotateToBasic(basic) {
83835         if (this._currentImage == null) {
83836             return;
83837         }
83838         this._desiredZoom = this._zoom;
83839         this._desiredLookat = null;
83840         basic[0] = this._spatial.clamp(basic[0], 0, 1);
83841         basic[1] = this._spatial.clamp(basic[1], 0, 1);
83842         let lookat = this.currentTransform.unprojectBasic(basic, this._lookatDepth);
83843         this._currentCamera.lookat.fromArray(lookat);
83844     }
83845     zoomIn(delta, reference) {
83846         if (this._currentImage == null) {
83847             return;
83848         }
83849         this._desiredZoom = Math.max(this._minZoom, Math.min(this._maxZoom, this._desiredZoom + delta));
83850         let currentCenter = this.currentTransform.projectBasic(this._currentCamera.lookat.toArray());
83851         let currentCenterX = currentCenter[0];
83852         let currentCenterY = currentCenter[1];
83853         let zoom0 = Math.pow(2, this._zoom);
83854         let zoom1 = Math.pow(2, this._desiredZoom);
83855         let refX = reference[0];
83856         let refY = reference[1];
83857         if (isSpherical(this.currentTransform.cameraType)) {
83858             if (refX - currentCenterX > 0.5) {
83859                 refX = refX - 1;
83860             }
83861             else if (currentCenterX - refX > 0.5) {
83862                 refX = 1 + refX;
83863             }
83864         }
83865         let newCenterX = refX - zoom0 / zoom1 * (refX - currentCenterX);
83866         let newCenterY = refY - zoom0 / zoom1 * (refY - currentCenterY);
83867         if (isSpherical(this._currentImage.cameraType)) {
83868             newCenterX = this._spatial
83869                 .wrap(newCenterX + this._basicRotation[0], 0, 1);
83870             newCenterY = this._spatial
83871                 .clamp(newCenterY + this._basicRotation[1], 0.05, 0.95);
83872         }
83873         else {
83874             newCenterX = this._spatial.clamp(newCenterX, 0, 1);
83875             newCenterY = this._spatial.clamp(newCenterY, 0, 1);
83876         }
83877         this._desiredLookat = new Vector3()
83878             .fromArray(this.currentTransform.unprojectBasic([newCenterX, newCenterY], this._lookatDepth));
83879     }
83880     setCenter(center) {
83881         this._desiredLookat = null;
83882         this._requestedRotationDelta = null;
83883         this._requestedBasicRotation = null;
83884         this._desiredZoom = this._zoom;
83885         let clamped = [
83886             this._spatial.clamp(center[0], 0, 1),
83887             this._spatial.clamp(center[1], 0, 1),
83888         ];
83889         if (this._currentImage == null) {
83890             this._desiredCenter = clamped;
83891             return;
83892         }
83893         this._desiredCenter = null;
83894         let currentLookat = new Vector3()
83895             .fromArray(this.currentTransform.unprojectBasic(clamped, this._lookatDepth));
83896         let previousTransform = this.previousTransform != null ?
83897             this.previousTransform :
83898             this.currentTransform;
83899         let previousLookat = new Vector3()
83900             .fromArray(previousTransform.unprojectBasic(clamped, this._lookatDepth));
83901         this._currentCamera.lookat.copy(currentLookat);
83902         this._previousCamera.lookat.copy(previousLookat);
83903     }
83904     setZoom(zoom) {
83905         this._desiredLookat = null;
83906         this._requestedRotationDelta = null;
83907         this._requestedBasicRotation = null;
83908         this._zoom = this._spatial.clamp(zoom, this._minZoom, this._maxZoom);
83909         this._desiredZoom = this._zoom;
83910     }
83911     _applyRotation(delta, camera) {
83912         if (camera == null) {
83913             return;
83914         }
83915         let q = new Quaternion().setFromUnitVectors(camera.up, new Vector3(0, 0, 1));
83916         let qInverse = q.clone().invert();
83917         let offset = new Vector3();
83918         offset.copy(camera.lookat).sub(camera.position);
83919         offset.applyQuaternion(q);
83920         let length = offset.length();
83921         let phi = Math.atan2(offset.y, offset.x);
83922         phi += delta.phi;
83923         let theta = Math.atan2(Math.sqrt(offset.x * offset.x + offset.y * offset.y), offset.z);
83924         theta += delta.theta;
83925         theta = Math.max(0.1, Math.min(Math.PI - 0.1, theta));
83926         offset.x = Math.sin(theta) * Math.cos(phi);
83927         offset.y = Math.sin(theta) * Math.sin(phi);
83928         offset.z = Math.cos(theta);
83929         offset.applyQuaternion(qInverse);
83930         camera.lookat.copy(camera.position).add(offset.multiplyScalar(length));
83931     }
83932     _applyRotationBasic(basicRotation) {
83933         let currentImage = this._currentImage;
83934         let previousImage = this._previousImage != null ?
83935             this.previousImage :
83936             this.currentImage;
83937         let currentCamera = this._currentCamera;
83938         let previousCamera = this._previousCamera;
83939         let currentTransform = this.currentTransform;
83940         let previousTransform = this.previousTransform != null ?
83941             this.previousTransform :
83942             this.currentTransform;
83943         let currentBasic = currentTransform.projectBasic(currentCamera.lookat.toArray());
83944         let previousBasic = previousTransform.projectBasic(previousCamera.lookat.toArray());
83945         if (isSpherical(currentImage.cameraType)) {
83946             currentBasic[0] = this._spatial.wrap(currentBasic[0] + basicRotation[0], 0, 1);
83947             currentBasic[1] = this._spatial.clamp(currentBasic[1] + basicRotation[1], 0.05, 0.95);
83948         }
83949         else {
83950             currentBasic[0] = this._spatial.clamp(currentBasic[0] + basicRotation[0], 0, 1);
83951             currentBasic[1] = this._spatial.clamp(currentBasic[1] + basicRotation[1], 0, 1);
83952         }
83953         if (isSpherical(previousImage.cameraType)) {
83954             previousBasic[0] = this._spatial.wrap(previousBasic[0] + basicRotation[0], 0, 1);
83955             previousBasic[1] = this._spatial.clamp(previousBasic[1] + basicRotation[1], 0.05, 0.95);
83956         }
83957         else {
83958             previousBasic[0] = this._spatial.clamp(previousBasic[0] + basicRotation[0], 0, 1);
83959             previousBasic[1] = this._spatial.clamp(currentBasic[1] + basicRotation[1], 0, 1);
83960         }
83961         let currentLookat = currentTransform.unprojectBasic(currentBasic, this._lookatDepth);
83962         currentCamera.lookat.fromArray(currentLookat);
83963         let previousLookat = previousTransform.unprojectBasic(previousBasic, this._lookatDepth);
83964         previousCamera.lookat.fromArray(previousLookat);
83965     }
83966     _updateZoom(animationSpeed) {
83967         let diff = this._desiredZoom - this._zoom;
83968         let sign = diff > 0 ? 1 : diff < 0 ? -1 : 0;
83969         if (diff === 0) {
83970             return;
83971         }
83972         else if (Math.abs(diff) < 2e-3) {
83973             this._zoom = this._desiredZoom;
83974             if (this._desiredLookat != null) {
83975                 this._desiredLookat = null;
83976             }
83977         }
83978         else {
83979             this._zoom += sign * Math.max(Math.abs(5 * animationSpeed * diff), 2e-3);
83980         }
83981     }
83982     _updateLookat(animationSpeed) {
83983         if (this._desiredLookat === null) {
83984             return;
83985         }
83986         let diff = this._desiredLookat.distanceToSquared(this._currentCamera.lookat);
83987         if (Math.abs(diff) < 1e-6) {
83988             this._currentCamera.lookat.copy(this._desiredLookat);
83989             this._desiredLookat = null;
83990         }
83991         else {
83992             this._currentCamera.lookat.lerp(this._desiredLookat, 5 * animationSpeed);
83993         }
83994     }
83995     _updateRotation() {
83996         if (this._requestedRotationDelta != null) {
83997             let length = this._rotationDelta.lengthSquared();
83998             let requestedLength = this._requestedRotationDelta.lengthSquared();
83999             if (requestedLength > length) {
84000                 this._rotationDelta.lerp(this._requestedRotationDelta, this._rotationIncreaseAlpha);
84001             }
84002             else {
84003                 this._rotationDelta.lerp(this._requestedRotationDelta, this._rotationDecreaseAlpha);
84004             }
84005             this._requestedRotationDelta = null;
84006             return;
84007         }
84008         if (this._rotationDelta.isZero) {
84009             return;
84010         }
84011         const alpha = isSpherical(this.currentImage.cameraType) ?
84012             1 : this._alpha;
84013         this._rotationDelta.multiply(this._rotationAcceleration * alpha);
84014         this._rotationDelta.threshold(this._rotationThreshold);
84015     }
84016     _updateRotationBasic() {
84017         if (this._requestedBasicRotation != null) {
84018             let x = this._basicRotation[0];
84019             let y = this._basicRotation[1];
84020             let reqX = this._requestedBasicRotation[0];
84021             let reqY = this._requestedBasicRotation[1];
84022             if (Math.abs(reqX) > Math.abs(x)) {
84023                 this._basicRotation[0] = (1 - this._rotationIncreaseAlpha) * x + this._rotationIncreaseAlpha * reqX;
84024             }
84025             else {
84026                 this._basicRotation[0] = (1 - this._rotationDecreaseAlpha) * x + this._rotationDecreaseAlpha * reqX;
84027             }
84028             if (Math.abs(reqY) > Math.abs(y)) {
84029                 this._basicRotation[1] = (1 - this._rotationIncreaseAlpha) * y + this._rotationIncreaseAlpha * reqY;
84030             }
84031             else {
84032                 this._basicRotation[1] = (1 - this._rotationDecreaseAlpha) * y + this._rotationDecreaseAlpha * reqY;
84033             }
84034             this._requestedBasicRotation = null;
84035             return;
84036         }
84037         if (this._requestedBasicRotationUnbounded != null) {
84038             let reqX = this._requestedBasicRotationUnbounded[0];
84039             let reqY = this._requestedBasicRotationUnbounded[1];
84040             if (Math.abs(reqX) > 0) {
84041                 this._basicRotation[0] = (1 - this._unboundedRotationAlpha) * this._basicRotation[0] + this._unboundedRotationAlpha * reqX;
84042             }
84043             if (Math.abs(reqY) > 0) {
84044                 this._basicRotation[1] = (1 - this._unboundedRotationAlpha) * this._basicRotation[1] + this._unboundedRotationAlpha * reqY;
84045             }
84046             if (this._desiredLookat != null) {
84047                 let desiredBasicLookat = this.currentTransform.projectBasic(this._desiredLookat.toArray());
84048                 desiredBasicLookat[0] += reqX;
84049                 desiredBasicLookat[1] += reqY;
84050                 this._desiredLookat = new Vector3()
84051                     .fromArray(this.currentTransform.unprojectBasic(desiredBasicLookat, this._lookatDepth));
84052             }
84053             this._requestedBasicRotationUnbounded = null;
84054         }
84055         if (this._basicRotation[0] === 0 && this._basicRotation[1] === 0) {
84056             return;
84057         }
84058         this._basicRotation[0] = this._rotationAcceleration * this._basicRotation[0];
84059         this._basicRotation[1] = this._rotationAcceleration * this._basicRotation[1];
84060         if (Math.abs(this._basicRotation[0]) < this._rotationThreshold / Math.pow(2, this._zoom) &&
84061             Math.abs(this._basicRotation[1]) < this._rotationThreshold / Math.pow(2, this._zoom)) {
84062             this._basicRotation = [0, 0];
84063         }
84064     }
84065     _clearRotation() {
84066         if (isSpherical(this._currentImage.cameraType)) {
84067             return;
84068         }
84069         if (this._requestedRotationDelta != null) {
84070             this._requestedRotationDelta = null;
84071         }
84072         if (!this._rotationDelta.isZero) {
84073             this._rotationDelta.reset();
84074         }
84075         if (this._requestedBasicRotation != null) {
84076             this._requestedBasicRotation = null;
84077         }
84078         if (this._basicRotation[0] > 0 || this._basicRotation[1] > 0) {
84079             this._basicRotation = [0, 0];
84080         }
84081     }
84082     _setDesiredCenter() {
84083         if (this._desiredCenter == null) {
84084             return;
84085         }
84086         let lookatDirection = new Vector3()
84087             .fromArray(this.currentTransform.unprojectBasic(this._desiredCenter, this._lookatDepth))
84088             .sub(this._currentCamera.position);
84089         this._currentCamera.lookat.copy(this._currentCamera.position.clone().add(lookatDirection));
84090         this._previousCamera.lookat.copy(this._previousCamera.position.clone().add(lookatDirection));
84091         this._desiredCenter = null;
84092     }
84093     _setDesiredZoom() {
84094         this._desiredZoom =
84095             isSpherical(this._currentImage.cameraType) ||
84096                 this._previousImage == null ?
84097                 this._zoom : 0;
84098     }
84099 }
84100
84101 class InteractiveWaitingState extends InteractiveStateBase {
84102     constructor(state) {
84103         super(state);
84104         this._adjustCameras();
84105         this._motionless = this._motionlessTransition();
84106     }
84107     prepend(images) {
84108         super.prepend(images);
84109         this._motionless = this._motionlessTransition();
84110     }
84111     set(images) {
84112         super.set(images);
84113         this._motionless = this._motionlessTransition();
84114     }
84115     move(delta) {
84116         this._alpha = Math.max(0, Math.min(1, this._alpha + delta));
84117     }
84118     moveTo(position) {
84119         this._alpha = Math.max(0, Math.min(1, position));
84120     }
84121     update(delta) {
84122         this._updateRotation();
84123         if (!this._rotationDelta.isZero) {
84124             this._applyRotation(this._rotationDelta, this._previousCamera);
84125             this._applyRotation(this._rotationDelta, this._currentCamera);
84126         }
84127         this._updateRotationBasic();
84128         if (this._basicRotation[0] !== 0 || this._basicRotation[1] !== 0) {
84129             this._applyRotationBasic(this._basicRotation);
84130         }
84131         let animationSpeed = this._animationSpeed * delta / 1e-1 * 6;
84132         this._updateZoom(animationSpeed);
84133         this._updateLookat(animationSpeed);
84134         this._camera.lerpCameras(this._previousCamera, this._currentCamera, this.alpha);
84135     }
84136     _getAlpha() {
84137         return this._motionless ? Math.round(this._alpha) : this._alpha;
84138     }
84139     _setCurrentCamera() {
84140         super._setCurrentCamera();
84141         this._adjustCameras();
84142     }
84143     _adjustCameras() {
84144         if (this._previousImage == null) {
84145             return;
84146         }
84147         if (isSpherical(this._currentImage.cameraType)) {
84148             let lookat = this._camera.lookat.clone().sub(this._camera.position);
84149             this._currentCamera.lookat.copy(lookat.clone().add(this._currentCamera.position));
84150         }
84151         if (isSpherical(this._previousImage.cameraType)) {
84152             let lookat = this._currentCamera.lookat.clone().sub(this._currentCamera.position);
84153             this._previousCamera.lookat.copy(lookat.clone().add(this._previousCamera.position));
84154         }
84155     }
84156 }
84157
84158 class TraversingState extends InteractiveStateBase {
84159     constructor(state) {
84160         super(state);
84161         this._adjustCameras();
84162         this._motionless = this._motionlessTransition();
84163         this._baseAlpha = this._alpha;
84164         this._speedCoefficient = 1;
84165         this._smoothing = false;
84166     }
84167     append(images) {
84168         let emptyTrajectory = this._trajectory.length === 0;
84169         if (emptyTrajectory) {
84170             this._resetTransition();
84171         }
84172         super.append(images);
84173         if (emptyTrajectory) {
84174             this._setDesiredCenter();
84175             this._setDesiredZoom();
84176         }
84177     }
84178     prepend(images) {
84179         let emptyTrajectory = this._trajectory.length === 0;
84180         if (emptyTrajectory) {
84181             this._resetTransition();
84182         }
84183         super.prepend(images);
84184         if (emptyTrajectory) {
84185             this._setDesiredCenter();
84186             this._setDesiredZoom();
84187         }
84188     }
84189     set(images) {
84190         super.set(images);
84191         this._desiredLookat = null;
84192         this._resetTransition();
84193         this._clearRotation();
84194         this._setDesiredCenter();
84195         this._setDesiredZoom();
84196         if (this._trajectory.length < 3) {
84197             this._smoothing = true;
84198         }
84199     }
84200     setSpeed(speed) {
84201         this._speedCoefficient = this._spatial.clamp(speed, 0, 10);
84202     }
84203     update(delta) {
84204         if (this._alpha === 1 && this._currentIndex + this._alpha < this._trajectory.length) {
84205             this._currentIndex += 1;
84206             this._smoothing = this._trajectory.length < 3 &&
84207                 this._currentIndex + 1 === this._trajectory.length;
84208             this._setCurrent();
84209             this._resetTransition();
84210             this._clearRotation();
84211             this._desiredZoom =
84212                 isSpherical(this._currentImage.cameraType) ?
84213                     this._zoom : 0;
84214             this._desiredLookat = null;
84215         }
84216         let animationSpeed = this._animationSpeed * delta / 1e-1 * 6;
84217         this._baseAlpha = Math.min(1, this._baseAlpha + this._speedCoefficient * animationSpeed);
84218         if (this._smoothing) {
84219             this._alpha = MathUtils.smootherstep(this._baseAlpha, 0, 1);
84220         }
84221         else {
84222             this._alpha = this._baseAlpha;
84223         }
84224         this._updateRotation();
84225         if (!this._rotationDelta.isZero) {
84226             this._applyRotation(this._rotationDelta, this._previousCamera);
84227             this._applyRotation(this._rotationDelta, this._currentCamera);
84228         }
84229         this._updateRotationBasic();
84230         if (this._basicRotation[0] !== 0 || this._basicRotation[1] !== 0) {
84231             this._applyRotationBasic(this._basicRotation);
84232         }
84233         this._updateZoom(animationSpeed);
84234         this._updateLookat(animationSpeed);
84235         this._camera.lerpCameras(this._previousCamera, this._currentCamera, this.alpha);
84236     }
84237     _getAlpha() {
84238         return this._motionless ? Math.ceil(this._alpha) : this._alpha;
84239     }
84240     _setCurrentCamera() {
84241         super._setCurrentCamera();
84242         this._adjustCameras();
84243     }
84244     _adjustCameras() {
84245         if (this._previousImage == null) {
84246             return;
84247         }
84248         let lookat = this._camera.lookat.clone().sub(this._camera.position);
84249         this._previousCamera.lookat.copy(lookat.clone().add(this._previousCamera.position));
84250         if (isSpherical(this._currentImage.cameraType)) {
84251             this._currentCamera.lookat.copy(lookat.clone().add(this._currentCamera.position));
84252         }
84253     }
84254     _resetTransition() {
84255         this._alpha = 0;
84256         this._baseAlpha = 0;
84257         this._motionless = this._motionlessTransition();
84258     }
84259 }
84260
84261 class WaitingState extends StateBase {
84262     constructor(state) {
84263         super(state);
84264         this._zoom = 0;
84265         this._adjustCameras();
84266         this._motionless = this._motionlessTransition();
84267     }
84268     prepend(images) {
84269         super.prepend(images);
84270         this._motionless = this._motionlessTransition();
84271     }
84272     set(images) {
84273         super.set(images);
84274         this._motionless = this._motionlessTransition();
84275     }
84276     move(delta) {
84277         this._alpha = Math.max(0, Math.min(1, this._alpha + delta));
84278     }
84279     moveTo(position) {
84280         this._alpha = Math.max(0, Math.min(1, position));
84281     }
84282     update() {
84283         this._camera.lerpCameras(this._previousCamera, this._currentCamera, this.alpha);
84284     }
84285     _getAlpha() {
84286         return this._motionless ? Math.round(this._alpha) : this._alpha;
84287     }
84288     _setCurrentCamera() {
84289         super._setCurrentCamera();
84290         this._adjustCameras();
84291     }
84292     _adjustCameras() {
84293         if (this._previousImage == null) {
84294             return;
84295         }
84296         if (isSpherical(this._currentImage.cameraType)) {
84297             let lookat = this._camera.lookat.clone().sub(this._camera.position);
84298             this._currentCamera.lookat.copy(lookat.clone().add(this._currentCamera.position));
84299         }
84300         if (isSpherical(this._previousImage.cameraType)) {
84301             let lookat = this._currentCamera.lookat.clone().sub(this._currentCamera.position);
84302             this._previousCamera.lookat.copy(lookat.clone().add(this._previousCamera.position));
84303         }
84304     }
84305 }
84306
84307 class StateTransitionMatrix {
84308     constructor() {
84309         const custom = State[State.Custom];
84310         const earth = State[State.Earth];
84311         const traverse = State[State.Traversing];
84312         const wait = State[State.Waiting];
84313         const waitInteractively = State[State.WaitingInteractively];
84314         this._creators = new Map();
84315         const creator = this._creators;
84316         creator.set(custom, CustomState);
84317         creator.set(earth, EarthState);
84318         creator.set(traverse, TraversingState);
84319         creator.set(wait, WaitingState);
84320         creator.set(waitInteractively, InteractiveWaitingState);
84321         this._transitions = new Map();
84322         const transitions = this._transitions;
84323         transitions.set(custom, [earth, traverse]);
84324         transitions.set(earth, [custom, traverse]);
84325         transitions.set(traverse, [custom, earth, wait, waitInteractively]);
84326         transitions.set(wait, [traverse, waitInteractively]);
84327         transitions.set(waitInteractively, [traverse, wait]);
84328     }
84329     getState(state) {
84330         if (state instanceof CustomState) {
84331             return State.Custom;
84332         }
84333         else if (state instanceof EarthState) {
84334             return State.Earth;
84335         }
84336         else if (state instanceof TraversingState) {
84337             return State.Traversing;
84338         }
84339         else if (state instanceof WaitingState) {
84340             return State.Waiting;
84341         }
84342         else if (state instanceof InteractiveWaitingState) {
84343             return State.WaitingInteractively;
84344         }
84345         throw new Error("Invalid state instance");
84346     }
84347     generate(state, options) {
84348         const concreteState = this._creators.get(State[state]);
84349         return new concreteState(options);
84350     }
84351     transition(state, to) {
84352         if (!this.validate(state, to)) {
84353             throw new Error("Invalid transition");
84354         }
84355         return this.generate(to, state);
84356     }
84357     validate(state, to) {
84358         const source = State[this.getState(state)];
84359         const target = State[to];
84360         const transitions = this._transitions;
84361         return transitions.has(source) &&
84362             transitions.get(source).includes(target);
84363     }
84364 }
84365
84366 class StateContext {
84367     constructor(state, transitionMode) {
84368         this._transitions = new StateTransitionMatrix();
84369         this._state = this._transitions.generate(state, {
84370             alpha: 1,
84371             camera: new Camera(),
84372             currentIndex: -1,
84373             reference: { alt: 0, lat: 0, lng: 0 },
84374             trajectory: [],
84375             transitionMode: transitionMode == null ? TransitionMode.Default : transitionMode,
84376             zoom: 0,
84377         });
84378     }
84379     get state() {
84380         return this._transitions.getState(this._state);
84381     }
84382     get reference() {
84383         return this._state.reference;
84384     }
84385     get alpha() {
84386         return this._state.alpha;
84387     }
84388     get stateTransitionAlpha() {
84389         return this._state.stateTransitionAlpha;
84390     }
84391     get camera() {
84392         return this._state.camera;
84393     }
84394     get zoom() {
84395         return this._state.zoom;
84396     }
84397     get currentImage() {
84398         return this._state.currentImage;
84399     }
84400     get previousImage() {
84401         return this._state.previousImage;
84402     }
84403     get currentCamera() {
84404         return this._state.currentCamera;
84405     }
84406     get currentTransform() {
84407         return this._state.currentTransform;
84408     }
84409     get previousTransform() {
84410         return this._state.previousTransform;
84411     }
84412     get trajectory() {
84413         return this._state.trajectory;
84414     }
84415     get currentIndex() {
84416         return this._state.currentIndex;
84417     }
84418     get lastImage() {
84419         return this._state.trajectory[this._state.trajectory.length - 1];
84420     }
84421     get imagesAhead() {
84422         return this._state.trajectory.length - 1 - this._state.currentIndex;
84423     }
84424     get motionless() {
84425         return this._state.motionless;
84426     }
84427     custom() {
84428         this._transition(State.Custom);
84429     }
84430     earth() {
84431         this._transition(State.Earth);
84432     }
84433     traverse() {
84434         this._transition(State.Traversing);
84435     }
84436     wait() {
84437         this._transition(State.Waiting);
84438     }
84439     waitInteractively() {
84440         this._transition(State.WaitingInteractively);
84441     }
84442     getCenter() {
84443         return this._state.getCenter();
84444     }
84445     setCenter(center) {
84446         this._state.setCenter(center);
84447     }
84448     setZoom(zoom) {
84449         this._state.setZoom(zoom);
84450     }
84451     update(delta) {
84452         this._state.update(delta);
84453     }
84454     append(images) {
84455         this._state.append(images);
84456     }
84457     prepend(images) {
84458         this._state.prepend(images);
84459     }
84460     remove(n) {
84461         this._state.remove(n);
84462     }
84463     clear() {
84464         this._state.clear();
84465     }
84466     clearPrior() {
84467         this._state.clearPrior();
84468     }
84469     cut() {
84470         this._state.cut();
84471     }
84472     set(images) {
84473         this._state.set(images);
84474     }
84475     setViewMatrix(matrix) {
84476         this._state.setViewMatrix(matrix);
84477     }
84478     rotate(delta) {
84479         this._state.rotate(delta);
84480     }
84481     rotateUnbounded(delta) {
84482         this._state.rotateUnbounded(delta);
84483     }
84484     rotateWithoutInertia(delta) {
84485         this._state.rotateWithoutInertia(delta);
84486     }
84487     rotateBasic(basicRotation) {
84488         this._state.rotateBasic(basicRotation);
84489     }
84490     rotateBasicUnbounded(basicRotation) {
84491         this._state.rotateBasicUnbounded(basicRotation);
84492     }
84493     rotateBasicWithoutInertia(basicRotation) {
84494         this._state.rotateBasicWithoutInertia(basicRotation);
84495     }
84496     rotateToBasic(basic) {
84497         this._state.rotateToBasic(basic);
84498     }
84499     move(delta) {
84500         this._state.move(delta);
84501     }
84502     moveTo(delta) {
84503         this._state.moveTo(delta);
84504     }
84505     zoomIn(delta, reference) {
84506         this._state.zoomIn(delta, reference);
84507     }
84508     setSpeed(speed) {
84509         this._state.setSpeed(speed);
84510     }
84511     setTransitionMode(mode) {
84512         this._state.setTransitionMode(mode);
84513     }
84514     dolly(delta) {
84515         this._state.dolly(delta);
84516     }
84517     orbit(rotation) {
84518         this._state.orbit(rotation);
84519     }
84520     truck(direction) {
84521         this._state.truck(direction);
84522     }
84523     _transition(to) {
84524         if (!this._transitions.validate(this._state, to)) {
84525             const from = this._transitions.getState(this._state);
84526             console.warn(`Transition not valid (${State[from]} - ${State[to]})`);
84527             return;
84528         }
84529         const state = this._transitions.transition(this._state, to);
84530         this._state = state;
84531     }
84532 }
84533
84534 class StateService {
84535     constructor(initialState, transitionMode) {
84536         this._appendImage$ = new Subject();
84537         this._clock = new Clock();
84538         this._subscriptions = new SubscriptionHolder();
84539         const subs = this._subscriptions;
84540         this._start$ = new Subject();
84541         this._frame$ = new Subject();
84542         this._contextOperation$ = new BehaviorSubject((context) => {
84543             return context;
84544         });
84545         this._context$ = this._contextOperation$.pipe(scan((context, operation) => {
84546             return operation(context);
84547         }, new StateContext(initialState, transitionMode)), publishReplay(1), refCount());
84548         this._state$ = this._context$.pipe(map((context) => {
84549             return context.state;
84550         }), distinctUntilChanged(), publishReplay(1), refCount());
84551         this._currentState$ = this._frame$.pipe(withLatestFrom(this._context$, (frameId, context) => {
84552             return [frameId, context];
84553         }), filter((fc) => {
84554             return fc[1].currentImage != null;
84555         }), tap((fc) => {
84556             fc[1].update(this._clock.getDelta());
84557         }), map((fc) => {
84558             return { fps: 60, id: fc[0], state: fc[1] };
84559         }), share());
84560         this._lastState$ = this._currentState$.pipe(publishReplay(1), refCount());
84561         let imageChanged$ = this._currentState$.pipe(distinctUntilChanged(undefined, (f) => {
84562             return f.state.currentImage.id;
84563         }), publishReplay(1), refCount());
84564         let imageChangedSubject$ = new Subject();
84565         subs.push(imageChanged$
84566             .subscribe(imageChangedSubject$));
84567         this._currentId$ = new BehaviorSubject(null);
84568         subs.push(imageChangedSubject$.pipe(map((f) => {
84569             return f.state.currentImage.id;
84570         }))
84571             .subscribe(this._currentId$));
84572         this._currentImage$ = imageChangedSubject$.pipe(map((f) => {
84573             return f.state.currentImage;
84574         }), publishReplay(1), refCount());
84575         this._currentCamera$ = imageChangedSubject$.pipe(map((f) => {
84576             return f.state.currentCamera;
84577         }), publishReplay(1), refCount());
84578         this._currentTransform$ = imageChangedSubject$.pipe(map((f) => {
84579             return f.state.currentTransform;
84580         }), publishReplay(1), refCount());
84581         this._reference$ = imageChangedSubject$.pipe(map((f) => {
84582             return f.state.reference;
84583         }), distinctUntilChanged((r1, r2) => {
84584             return r1.lat === r2.lat && r1.lng === r2.lng;
84585         }, (reference) => {
84586             return { lat: reference.lat, lng: reference.lng };
84587         }), publishReplay(1), refCount());
84588         this._currentImageExternal$ = imageChanged$.pipe(map((f) => {
84589             return f.state.currentImage;
84590         }), publishReplay(1), refCount());
84591         subs.push(this._appendImage$.pipe(map((image) => {
84592             return (context) => {
84593                 context.append([image]);
84594                 return context;
84595             };
84596         }))
84597             .subscribe(this._contextOperation$));
84598         this._inMotionOperation$ = new Subject();
84599         subs.push(imageChanged$.pipe(map(() => {
84600             return true;
84601         }))
84602             .subscribe(this._inMotionOperation$));
84603         subs.push(this._inMotionOperation$.pipe(distinctUntilChanged(), filter((moving) => {
84604             return moving;
84605         }), switchMap(() => {
84606             return this._currentState$.pipe(filter((frame) => {
84607                 return frame.state.imagesAhead === 0;
84608             }), map((frame) => {
84609                 return [frame.state.camera.clone(), frame.state.zoom];
84610             }), pairwise(), map((pair) => {
84611                 let c1 = pair[0][0];
84612                 let c2 = pair[1][0];
84613                 let z1 = pair[0][1];
84614                 let z2 = pair[1][1];
84615                 return c1.diff(c2) > 1e-5 || Math.abs(z1 - z2) > 1e-5;
84616             }), first((changed) => {
84617                 return !changed;
84618             }));
84619         }))
84620             .subscribe(this._inMotionOperation$));
84621         this._inMotion$ = this._inMotionOperation$.pipe(distinctUntilChanged(), publishReplay(1), refCount());
84622         this._inTranslationOperation$ = new Subject();
84623         subs.push(imageChanged$.pipe(map(() => {
84624             return true;
84625         }))
84626             .subscribe(this._inTranslationOperation$));
84627         subs.push(this._inTranslationOperation$.pipe(distinctUntilChanged(), filter((inTranslation) => {
84628             return inTranslation;
84629         }), switchMap(() => {
84630             return this._currentState$.pipe(filter((frame) => {
84631                 return frame.state.imagesAhead === 0;
84632             }), map((frame) => {
84633                 return frame.state.camera.position.clone();
84634             }), pairwise(), map((pair) => {
84635                 return pair[0].distanceToSquared(pair[1]) !== 0;
84636             }), first((changed) => {
84637                 return !changed;
84638             }));
84639         }))
84640             .subscribe(this._inTranslationOperation$));
84641         this._inTranslation$ = this._inTranslationOperation$.pipe(distinctUntilChanged(), publishReplay(1), refCount());
84642         subs.push(this._state$.subscribe(() => { }));
84643         subs.push(this._currentImage$.subscribe(() => { }));
84644         subs.push(this._currentCamera$.subscribe(() => { }));
84645         subs.push(this._currentTransform$.subscribe(() => { }));
84646         subs.push(this._reference$.subscribe(() => { }));
84647         subs.push(this._currentImageExternal$.subscribe(() => { }));
84648         subs.push(this._lastState$.subscribe(() => { }));
84649         subs.push(this._inMotion$.subscribe(() => { }));
84650         subs.push(this._inTranslation$.subscribe(() => { }));
84651         this._frameId = null;
84652         this._frameGenerator = new FrameGenerator(window);
84653     }
84654     get currentState$() {
84655         return this._currentState$;
84656     }
84657     get currentImage$() {
84658         return this._currentImage$;
84659     }
84660     get currentId$() {
84661         return this._currentId$;
84662     }
84663     get currentImageExternal$() {
84664         return this._currentImageExternal$;
84665     }
84666     get currentCamera$() {
84667         return this._currentCamera$;
84668     }
84669     get currentTransform$() {
84670         return this._currentTransform$;
84671     }
84672     get state$() {
84673         return this._state$;
84674     }
84675     get reference$() {
84676         return this._reference$;
84677     }
84678     get inMotion$() {
84679         return this._inMotion$;
84680     }
84681     get inTranslation$() {
84682         return this._inTranslation$;
84683     }
84684     get appendImage$() {
84685         return this._appendImage$;
84686     }
84687     dispose() {
84688         this.stop();
84689         this._subscriptions.unsubscribe();
84690     }
84691     custom() {
84692         this._inMotionOperation$.next(true);
84693         this._invokeContextOperation((context) => {
84694             context.custom();
84695         });
84696     }
84697     earth() {
84698         this._inMotionOperation$.next(true);
84699         this._invokeContextOperation((context) => { context.earth(); });
84700     }
84701     traverse() {
84702         this._inMotionOperation$.next(true);
84703         this._invokeContextOperation((context) => { context.traverse(); });
84704     }
84705     wait() {
84706         this._invokeContextOperation((context) => { context.wait(); });
84707     }
84708     waitInteractively() {
84709         this._invokeContextOperation((context) => { context.waitInteractively(); });
84710     }
84711     appendImagess(images) {
84712         this._invokeContextOperation((context) => { context.append(images); });
84713     }
84714     prependImages(images) {
84715         this._invokeContextOperation((context) => { context.prepend(images); });
84716     }
84717     removeImages(n) {
84718         this._invokeContextOperation((context) => { context.remove(n); });
84719     }
84720     clearImages() {
84721         this._invokeContextOperation((context) => { context.clear(); });
84722     }
84723     clearPriorImages() {
84724         this._invokeContextOperation((context) => { context.clearPrior(); });
84725     }
84726     cutImages() {
84727         this._invokeContextOperation((context) => { context.cut(); });
84728     }
84729     setImages(images) {
84730         this._invokeContextOperation((context) => { context.set(images); });
84731     }
84732     setViewMatrix(matrix) {
84733         this._inMotionOperation$.next(true);
84734         this._invokeContextOperation((context) => { context.setViewMatrix(matrix); });
84735     }
84736     rotate(delta) {
84737         this._inMotionOperation$.next(true);
84738         this._invokeContextOperation((context) => { context.rotate(delta); });
84739     }
84740     rotateUnbounded(delta) {
84741         this._inMotionOperation$.next(true);
84742         this._invokeContextOperation((context) => { context.rotateUnbounded(delta); });
84743     }
84744     rotateWithoutInertia(delta) {
84745         this._inMotionOperation$.next(true);
84746         this._invokeContextOperation((context) => { context.rotateWithoutInertia(delta); });
84747     }
84748     rotateBasic(basicRotation) {
84749         this._inMotionOperation$.next(true);
84750         this._invokeContextOperation((context) => { context.rotateBasic(basicRotation); });
84751     }
84752     rotateBasicUnbounded(basicRotation) {
84753         this._inMotionOperation$.next(true);
84754         this._invokeContextOperation((context) => { context.rotateBasicUnbounded(basicRotation); });
84755     }
84756     rotateBasicWithoutInertia(basicRotation) {
84757         this._inMotionOperation$.next(true);
84758         this._invokeContextOperation((context) => { context.rotateBasicWithoutInertia(basicRotation); });
84759     }
84760     rotateToBasic(basic) {
84761         this._inMotionOperation$.next(true);
84762         this._invokeContextOperation((context) => { context.rotateToBasic(basic); });
84763     }
84764     move(delta) {
84765         this._inMotionOperation$.next(true);
84766         this._invokeContextOperation((context) => { context.move(delta); });
84767     }
84768     moveTo(position) {
84769         this._inMotionOperation$.next(true);
84770         this._invokeContextOperation((context) => { context.moveTo(position); });
84771     }
84772     dolly(delta) {
84773         this._inMotionOperation$.next(true);
84774         this._invokeContextOperation((context) => { context.dolly(delta); });
84775     }
84776     orbit(rotation) {
84777         this._inMotionOperation$.next(true);
84778         this._invokeContextOperation((context) => { context.orbit(rotation); });
84779     }
84780     truck(direction) {
84781         this._inMotionOperation$.next(true);
84782         this._invokeContextOperation((context) => { context.truck(direction); });
84783     }
84784     /**
84785      * Change zoom level while keeping the reference point position approximately static.
84786      *
84787      * @parameter {number} delta - Change in zoom level.
84788      * @parameter {Array<number>} reference - Reference point in basic coordinates.
84789      */
84790     zoomIn(delta, reference) {
84791         this._inMotionOperation$.next(true);
84792         this._invokeContextOperation((context) => { context.zoomIn(delta, reference); });
84793     }
84794     getCenter() {
84795         return this._lastState$.pipe(first(), map((frame) => {
84796             return frame.state.getCenter();
84797         }));
84798     }
84799     getZoom() {
84800         return this._lastState$.pipe(first(), map((frame) => {
84801             return frame.state.zoom;
84802         }));
84803     }
84804     setCenter(center) {
84805         this._inMotionOperation$.next(true);
84806         this._invokeContextOperation((context) => { context.setCenter(center); });
84807     }
84808     setSpeed(speed) {
84809         this._invokeContextOperation((context) => { context.setSpeed(speed); });
84810     }
84811     setTransitionMode(mode) {
84812         this._invokeContextOperation((context) => { context.setTransitionMode(mode); });
84813     }
84814     setZoom(zoom) {
84815         this._inMotionOperation$.next(true);
84816         this._invokeContextOperation((context) => { context.setZoom(zoom); });
84817     }
84818     start() {
84819         this._clock.start();
84820         if (this._frameId == null) {
84821             this._start$.next(null);
84822             this._frameId = this._frameGenerator.requestAnimationFrame(this._frame.bind(this));
84823             this._frame$.next(this._frameId);
84824         }
84825     }
84826     stop() {
84827         this._clock.stop();
84828         if (this._frameId != null) {
84829             this._frameGenerator.cancelAnimationFrame(this._frameId);
84830             this._frameId = null;
84831         }
84832     }
84833     _invokeContextOperation(action) {
84834         this._contextOperation$
84835             .next((context) => {
84836             action(context);
84837             return context;
84838         });
84839     }
84840     _frame() {
84841         this._frameId = this._frameGenerator.requestAnimationFrame(this._frame.bind(this));
84842         this._frame$.next(this._frameId);
84843     }
84844 }
84845
84846 function cameraControlsToState(cameraControls) {
84847     switch (cameraControls) {
84848         case CameraControls.Custom:
84849             return State.Custom;
84850         case CameraControls.Earth:
84851             return State.Earth;
84852         case CameraControls.Street:
84853             return State.Traversing;
84854         default:
84855             return null;
84856     }
84857 }
84858
84859 class Navigator {
84860     constructor(options, api, graphService, loadingService, stateService, cacheService, playService, panService) {
84861         var _a;
84862         if (api) {
84863             this._api = api;
84864         }
84865         else if (options.dataProvider) {
84866             this._api = new APIWrapper(options.dataProvider);
84867         }
84868         else {
84869             this._api = new APIWrapper(new GraphDataProvider({
84870                 accessToken: options.accessToken,
84871             }));
84872         }
84873         this._graphService = graphService !== null && graphService !== void 0 ? graphService : new GraphService(new Graph(this.api));
84874         this._loadingName = "navigator";
84875         this._loadingService = loadingService !== null && loadingService !== void 0 ? loadingService : new LoadingService();
84876         const cameraControls = (_a = options.cameraControls) !== null && _a !== void 0 ? _a : CameraControls.Street;
84877         this._stateService = stateService !== null && stateService !== void 0 ? stateService : new StateService(cameraControlsToState(cameraControls), options.transitionMode);
84878         this._cacheService = cacheService !== null && cacheService !== void 0 ? cacheService : new CacheService(this._graphService, this._stateService, this._api);
84879         this._playService = playService !== null && playService !== void 0 ? playService : new PlayService(this._graphService, this._stateService);
84880         this._panService = panService !== null && panService !== void 0 ? panService : new PanService(this._graphService, this._stateService, options.combinedPanning);
84881         this._idRequested$ = new BehaviorSubject(null);
84882         this._movedToId$ = new BehaviorSubject(null);
84883         this._request$ = null;
84884         this._requestSubscription = null;
84885         this._imageRequestSubscription = null;
84886     }
84887     get api() {
84888         return this._api;
84889     }
84890     get cacheService() {
84891         return this._cacheService;
84892     }
84893     get graphService() {
84894         return this._graphService;
84895     }
84896     get loadingService() {
84897         return this._loadingService;
84898     }
84899     get movedToId$() {
84900         return this._movedToId$;
84901     }
84902     get panService() {
84903         return this._panService;
84904     }
84905     get playService() {
84906         return this._playService;
84907     }
84908     get stateService() {
84909         return this._stateService;
84910     }
84911     dispose() {
84912         this._abortRequest("viewer removed");
84913         this._cacheService.stop();
84914         this._graphService.dispose();
84915         this._panService.dispose();
84916         this._playService.dispose();
84917         this._stateService.dispose();
84918     }
84919     moveTo$(id) {
84920         this._abortRequest(`to id ${id}`);
84921         this._loadingService.startLoading(this._loadingName);
84922         const image$ = this._moveTo$(id);
84923         return this._makeRequest$(image$);
84924     }
84925     moveDir$(direction) {
84926         this._abortRequest(`in dir ${NavigationDirection[direction]}`);
84927         this._loadingService.startLoading(this._loadingName);
84928         const image$ = this.stateService.currentImage$.pipe(first(), mergeMap((image) => {
84929             return ([NavigationDirection.Next, NavigationDirection.Prev].indexOf(direction) > -1 ?
84930                 image.sequenceEdges$ :
84931                 image.spatialEdges$).pipe(first(), map((status) => {
84932                 for (let edge of status.edges) {
84933                     if (edge.data.direction === direction) {
84934                         return edge.target;
84935                     }
84936                 }
84937                 return null;
84938             }));
84939         }), mergeMap((directionId) => {
84940             if (directionId == null) {
84941                 this._loadingService.stopLoading(this._loadingName);
84942                 return throwError(new Error(`Direction (${direction}) does not exist for current image.`));
84943             }
84944             return this._moveTo$(directionId);
84945         }));
84946         return this._makeRequest$(image$);
84947     }
84948     setFilter$(filter) {
84949         this._stateService.clearImages();
84950         return this._movedToId$.pipe(first(), mergeMap((id) => {
84951             if (id != null) {
84952                 return this._trajectoryIds$().pipe(mergeMap((ids) => {
84953                     return this._graphService.setFilter$(filter).pipe(mergeMap(() => {
84954                         return this._cacheIds$(ids);
84955                     }));
84956                 }), last());
84957             }
84958             return this._idRequested$.pipe(first(), mergeMap((requestedId) => {
84959                 if (requestedId != null) {
84960                     return this._graphService.setFilter$(filter).pipe(mergeMap(() => {
84961                         return this._graphService.cacheImage$(requestedId);
84962                     }));
84963                 }
84964                 return this._graphService.setFilter$(filter).pipe(map(() => {
84965                     return undefined;
84966                 }));
84967             }));
84968         }), map(() => {
84969             return undefined;
84970         }));
84971     }
84972     setAccessToken$(accessToken) {
84973         this._abortRequest("to set user token");
84974         this._stateService.clearImages();
84975         return this._movedToId$.pipe(first(), tap(() => {
84976             this._api.setAccessToken(accessToken);
84977         }), mergeMap((id) => {
84978             return id == null ?
84979                 this._graphService.reset$([]) :
84980                 this._trajectoryIds$().pipe(mergeMap((ids) => {
84981                     return this._graphService.reset$(ids).pipe(mergeMap(() => {
84982                         return this._cacheIds$(ids);
84983                     }));
84984                 }), last(), map(() => {
84985                     return undefined;
84986                 }));
84987         }));
84988     }
84989     _cacheIds$(ids) {
84990         const cacheImages$ = ids
84991             .map((id) => {
84992             return this._graphService.cacheImage$(id);
84993         });
84994         return from(cacheImages$).pipe(mergeAll());
84995     }
84996     _abortRequest(reason) {
84997         if (this._requestSubscription != null) {
84998             this._requestSubscription.unsubscribe();
84999             this._requestSubscription = null;
85000         }
85001         if (this._imageRequestSubscription != null) {
85002             this._imageRequestSubscription.unsubscribe();
85003             this._imageRequestSubscription = null;
85004         }
85005         if (this._request$ != null) {
85006             if (!(this._request$.isStopped || this._request$.hasError)) {
85007                 this._request$.error(new CancelMapillaryError(`Request aborted by a subsequent request ${reason}.`));
85008             }
85009             this._request$ = null;
85010         }
85011     }
85012     _makeRequest$(image$) {
85013         const request$ = new ReplaySubject(1);
85014         this._requestSubscription = request$
85015             .subscribe(undefined, () => { });
85016         this._request$ = request$;
85017         this._imageRequestSubscription = image$
85018             .subscribe((image) => {
85019             this._request$ = null;
85020             request$.next(image);
85021             request$.complete();
85022         }, (error) => {
85023             this._request$ = null;
85024             request$.error(error);
85025         });
85026         return request$;
85027     }
85028     _moveTo$(id) {
85029         this._idRequested$.next(id);
85030         return this._graphService.cacheImage$(id).pipe(tap((image) => {
85031             this._stateService.setImages([image]);
85032             this._movedToId$.next(image.id);
85033         }), finalize(() => {
85034             this._loadingService.stopLoading(this._loadingName);
85035         }));
85036     }
85037     _trajectoryIds$() {
85038         return this._stateService.currentState$.pipe(first(), map((frame) => {
85039             return frame.state.trajectory
85040                 .map((image) => {
85041                 return image.id;
85042             });
85043         }));
85044     }
85045 }
85046
85047 class Projection {
85048     constructor(viewportCoords, spatial) {
85049         this._spatial = spatial !== null && spatial !== void 0 ? spatial : new Spatial();
85050         this._viewportCoords = viewportCoords !== null && viewportCoords !== void 0 ? viewportCoords : new ViewportCoords();
85051     }
85052     basicToCanvas(basicPoint, container, render, transform) {
85053         return this._viewportCoords
85054             .basicToCanvasSafe(basicPoint[0], basicPoint[1], container, transform, render.perspective);
85055     }
85056     canvasToBasic(canvasPoint, container, render, transform) {
85057         let basicPoint = this._viewportCoords
85058             .canvasToBasic(canvasPoint[0], canvasPoint[1], container, transform, render.perspective);
85059         if (basicPoint[0] < 0 ||
85060             basicPoint[0] > 1 ||
85061             basicPoint[1] < 0 ||
85062             basicPoint[1] > 1) {
85063             basicPoint = null;
85064         }
85065         return basicPoint;
85066     }
85067     eventToUnprojection(event, container, render, reference, transform) {
85068         const pixelPoint = this._viewportCoords
85069             .canvasPosition(event, container);
85070         return this.canvasToUnprojection(pixelPoint, container, render, reference, transform);
85071     }
85072     canvasToUnprojection(canvasPoint, container, render, reference, transform) {
85073         const canvasX = canvasPoint[0];
85074         const canvasY = canvasPoint[1];
85075         const [viewportX, viewportY] = this._viewportCoords
85076             .canvasToViewport(canvasX, canvasY, container);
85077         const point3d = new Vector3(viewportX, viewportY, 1)
85078             .unproject(render.perspective);
85079         let basicPoint = transform
85080             .projectBasic(point3d.toArray());
85081         if (basicPoint[0] < 0 ||
85082             basicPoint[0] > 1 ||
85083             basicPoint[1] < 0 ||
85084             basicPoint[1] > 1) {
85085             basicPoint = null;
85086         }
85087         const direction3d = point3d
85088             .clone()
85089             .sub(render.camera.position)
85090             .normalize();
85091         const dist = -2 / direction3d.z;
85092         let lngLat = null;
85093         if (dist > 0 && dist < 100 && !!basicPoint) {
85094             const point = direction3d
85095                 .clone()
85096                 .multiplyScalar(dist)
85097                 .add(render.camera.position);
85098             const [lng, lat] = enuToGeodetic(point.x, point.y, point.z, reference.lng, reference.lat, reference.alt);
85099             lngLat = { lat, lng };
85100         }
85101         const unprojection = {
85102             basicPoint: basicPoint,
85103             lngLat: lngLat,
85104             pixelPoint: [canvasX, canvasY],
85105         };
85106         return unprojection;
85107     }
85108     cameraToLngLat(render, reference) {
85109         const position = render.camera.position;
85110         const [lng, lat] = enuToGeodetic(position.x, position.y, position.z, reference.lng, reference.lat, reference.alt);
85111         return { lat, lng };
85112     }
85113     lngLatToCanvas(lngLat, container, render, reference) {
85114         const point3d = geodeticToEnu(lngLat.lng, lngLat.lat, 0, reference.lng, reference.lat, reference.alt);
85115         const canvas = this._viewportCoords
85116             .projectToCanvasSafe(point3d, container, render.perspective);
85117         return canvas;
85118     }
85119     distanceBetweenLngLats(lngLat1, lngLat2) {
85120         return this._spatial
85121             .distanceFromLngLat(lngLat1.lng, lngLat1.lat, lngLat2.lng, lngLat2.lat);
85122     }
85123 }
85124
85125 class Observer {
85126     constructor(viewer, navigator, container) {
85127         this._subscriptions = new SubscriptionHolder();
85128         this._emitSubscriptions = new SubscriptionHolder();
85129         this._container = container;
85130         this._viewer = viewer;
85131         this._navigator = navigator;
85132         this._projection = new Projection();
85133         this._started = false;
85134         this._navigable$ = new Subject();
85135         const subs = this._subscriptions;
85136         // load, navigable, dataloading should always emit,
85137         // also when cover is activated.
85138         subs.push(this._navigable$
85139             .subscribe((navigable) => {
85140             const type = "navigable";
85141             const event = {
85142                 navigable,
85143                 target: this._viewer,
85144                 type,
85145             };
85146             this._viewer.fire(type, event);
85147         }));
85148         subs.push(this._navigator.loadingService.loading$
85149             .subscribe((loading) => {
85150             const type = "dataloading";
85151             const event = {
85152                 loading,
85153                 target: this._viewer,
85154                 type,
85155             };
85156             this._viewer.fire(type, event);
85157         }));
85158         subs.push(this._container.glRenderer.opaqueRender$
85159             .pipe(first())
85160             .subscribe(() => {
85161             const type = "load";
85162             const event = {
85163                 target: this._viewer,
85164                 type,
85165             };
85166             this._viewer.fire(type, event);
85167         }));
85168     }
85169     get started() {
85170         return this._started;
85171     }
85172     get navigable$() {
85173         return this._navigable$;
85174     }
85175     get projection() {
85176         return this._projection;
85177     }
85178     dispose() {
85179         this.stopEmit();
85180         this._subscriptions.unsubscribe();
85181     }
85182     project$(lngLat) {
85183         return combineLatest(this._container.renderService.renderCamera$, this._navigator.stateService.currentImage$, this._navigator.stateService.reference$).pipe(first(), map(([render, image, reference]) => {
85184             if (this._projection
85185                 .distanceBetweenLngLats(lngLat, image.lngLat) > 1000) {
85186                 return null;
85187             }
85188             const canvasPoint = this._projection.lngLatToCanvas(lngLat, this._container.container, render, reference);
85189             return !!canvasPoint ?
85190                 [Math.round(canvasPoint[0]), Math.round(canvasPoint[1])] :
85191                 null;
85192         }));
85193     }
85194     projectBasic$(basicPoint) {
85195         return combineLatest(this._container.renderService.renderCamera$, this._navigator.stateService.currentTransform$).pipe(first(), map(([render, transform]) => {
85196             const canvasPoint = this._projection.basicToCanvas(basicPoint, this._container.container, render, transform);
85197             return !!canvasPoint ?
85198                 [Math.round(canvasPoint[0]), Math.round(canvasPoint[1])] :
85199                 null;
85200         }));
85201     }
85202     startEmit() {
85203         if (this._started) {
85204             return;
85205         }
85206         this._started = true;
85207         const subs = this._emitSubscriptions;
85208         subs.push(this._navigator.stateService.currentImageExternal$
85209             .subscribe((image) => {
85210             const type = "image";
85211             const event = {
85212                 image,
85213                 target: this._viewer,
85214                 type,
85215             };
85216             this._viewer.fire(type, event);
85217         }));
85218         subs.push(this._navigator.stateService.currentImageExternal$.pipe(switchMap((image) => {
85219             return image.sequenceEdges$;
85220         }))
85221             .subscribe((status) => {
85222             const type = "sequenceedges";
85223             const event = {
85224                 status,
85225                 target: this._viewer,
85226                 type,
85227             };
85228             this._viewer.fire(type, event);
85229         }));
85230         subs.push(this._navigator.stateService.currentImageExternal$.pipe(switchMap((image) => {
85231             return image.spatialEdges$;
85232         }))
85233             .subscribe((status) => {
85234             const type = "spatialedges";
85235             const event = {
85236                 status,
85237                 target: this._viewer,
85238                 type,
85239             };
85240             this._viewer.fire(type, event);
85241         }));
85242         subs.push(this._navigator.stateService.reference$
85243             .subscribe((reference) => {
85244             const type = "reference";
85245             const event = {
85246                 reference,
85247                 target: this._viewer,
85248                 type,
85249             };
85250             this._viewer.fire(type, event);
85251         }));
85252         subs.push(combineLatest(this._navigator.stateService.inMotion$, this._container.mouseService.active$, this._container.touchService.active$).pipe(map((values) => {
85253             return values[0] || values[1] || values[2];
85254         }), distinctUntilChanged())
85255             .subscribe((started) => {
85256             const type = started ? "movestart" : "moveend";
85257             const event = {
85258                 target: this._viewer,
85259                 type,
85260             };
85261             this._viewer.fire(type, event);
85262         }));
85263         subs.push(this._container.renderService.bearing$.pipe(auditTime(100), distinctUntilChanged((b1, b2) => {
85264             return Math.abs(b2 - b1) < 1;
85265         }))
85266             .subscribe((bearing) => {
85267             const type = "bearing";
85268             const event = {
85269                 bearing,
85270                 target: this._viewer,
85271                 type,
85272             };
85273             this._viewer.fire(type, event);
85274         }));
85275         const mouseMove$ = this._container.mouseService.active$.pipe(switchMap((active) => {
85276             return active ?
85277                 empty() :
85278                 this._container.mouseService.mouseMove$;
85279         }));
85280         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$))
85281             .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]) => {
85282             const unprojection = this._projection.eventToUnprojection(event, this._container.container, render, reference, transform);
85283             const basicPoint = state === State.Traversing ?
85284                 unprojection.basicPoint : null;
85285             return {
85286                 basicPoint,
85287                 lngLat: unprojection.lngLat,
85288                 originalEvent: event,
85289                 pixelPoint: unprojection.pixelPoint,
85290                 target: this._viewer,
85291                 type: type,
85292             };
85293         }))
85294             .subscribe((event) => {
85295             this._viewer.fire(event.type, event);
85296         }));
85297         subs.push(this._container.renderService.renderCamera$.pipe(distinctUntilChanged(([x1, y1], [x2, y2]) => {
85298             return this._closeTo(x1, x2, 1e-2) &&
85299                 this._closeTo(y1, y2, 1e-2);
85300         }, (rc) => {
85301             return rc.camera.position.toArray();
85302         }))
85303             .subscribe(() => {
85304             const type = "position";
85305             const event = {
85306                 target: this._viewer,
85307                 type,
85308             };
85309             this._viewer.fire(type, event);
85310         }));
85311         subs.push(this._container.renderService.renderCamera$.pipe(distinctUntilChanged(([phi1, theta1], [phi2, theta2]) => {
85312             return this._closeTo(phi1, phi2, 1e-3) &&
85313                 this._closeTo(theta1, theta2, 1e-3);
85314         }, (rc) => {
85315             return [rc.rotation.phi, rc.rotation.theta];
85316         }))
85317             .subscribe(() => {
85318             const type = "pov";
85319             const event = {
85320                 target: this._viewer,
85321                 type,
85322             };
85323             this._viewer.fire(type, event);
85324         }));
85325         subs.push(this._container.renderService.renderCamera$.pipe(distinctUntilChanged((fov1, fov2) => {
85326             return this._closeTo(fov1, fov2, 1e-2);
85327         }, (rc) => {
85328             return rc.perspective.fov;
85329         }))
85330             .subscribe(() => {
85331             const type = "fov";
85332             const event = {
85333                 target: this._viewer,
85334                 type,
85335             };
85336             this._viewer.fire(type, event);
85337         }));
85338     }
85339     stopEmit() {
85340         if (!this.started) {
85341             return;
85342         }
85343         this._emitSubscriptions.unsubscribe();
85344         this._started = false;
85345     }
85346     unproject$(canvasPoint) {
85347         return combineLatest(this._container.renderService.renderCamera$, this._navigator.stateService.reference$, this._navigator.stateService.currentTransform$).pipe(first(), map(([render, reference, transform]) => {
85348             const unprojection = this._projection.canvasToUnprojection(canvasPoint, this._container.container, render, reference, transform);
85349             return unprojection.lngLat;
85350         }));
85351     }
85352     unprojectBasic$(canvasPoint) {
85353         return combineLatest(this._container.renderService.renderCamera$, this._navigator.stateService.currentTransform$).pipe(first(), map(([render, transform]) => {
85354             return this._projection.canvasToBasic(canvasPoint, this._container.container, render, transform);
85355         }));
85356     }
85357     _closeTo(v1, v2, absoluteTolerance) {
85358         return Math.abs(v1 - v2) <= absoluteTolerance;
85359     }
85360     _mapMouseEvent$(type, mouseEvent$) {
85361         return mouseEvent$.pipe(map((event) => {
85362             return [type, event];
85363         }));
85364     }
85365 }
85366
85367 class CustomRenderer {
85368     constructor(_container, _navigator) {
85369         this._container = _container;
85370         this._navigator = _navigator;
85371         this._renderers = {};
85372     }
85373     add(renderer, viewer) {
85374         const subs = new SubscriptionHolder();
85375         this._renderers[renderer.id] = { subs, renderer };
85376         subs.push(combineLatest([
85377             this._container.glRenderer.webGLRenderer$,
85378             this._navigator.stateService.reference$,
85379         ])
85380             .pipe(take(1))
85381             .subscribe(([gl, reference]) => {
85382             renderer.onAdd(viewer, reference, gl.getContext());
85383         }));
85384         subs.push(this._container.glRenderer.opaqueRender$
85385             .pipe(withLatestFrom(this._container.renderService.renderCamera$, this._container.glRenderer.webGLRenderer$))
85386             .subscribe(([, renderCamera, glRenderer]) => {
85387             const context = glRenderer.getContext();
85388             const viewMatrix = renderCamera.perspective.matrixWorldInverse;
85389             const projectionMatrix = renderCamera.perspective.projectionMatrix;
85390             renderer.render(context, viewMatrix.toArray(), projectionMatrix.toArray());
85391         }));
85392         subs.push(this._navigator.stateService.reference$
85393             .pipe(skip(1))
85394             .subscribe((reference) => {
85395             renderer.onReference(viewer, reference);
85396         }));
85397     }
85398     dispose(viewer) {
85399         for (const id of Object.keys(this._renderers)) {
85400             this.remove(id, viewer);
85401         }
85402     }
85403     has(id) {
85404         return id in this._renderers;
85405     }
85406     remove(id, viewer) {
85407         this._renderers[id].subs.unsubscribe();
85408         const renderer = this._renderers[id].renderer;
85409         delete this._renderers[id];
85410         this._container.glRenderer.webGLRenderer$
85411             .subscribe((gl) => {
85412             renderer.onRemove(viewer, gl.getContext());
85413         });
85414     }
85415 }
85416
85417 class CustomCameraControls {
85418     constructor(_container, _navigator) {
85419         this._container = _container;
85420         this._navigator = _navigator;
85421         this._controls = null;
85422         this._subscriptions = new SubscriptionHolder();
85423     }
85424     attach(controls, viewer) {
85425         if (this._controls) {
85426             throw new MapillaryError('Custom camera controls already attached');
85427         }
85428         this._controls = controls;
85429         const attach$ = new Subject();
85430         const active$ = attach$
85431             .pipe(switchMap(() => {
85432             return this._navigator.stateService.state$;
85433         }), map((state) => {
85434             return state === State.Custom;
85435         }), distinctUntilChanged());
85436         const subs = this._subscriptions;
85437         subs.push(active$
85438             .pipe(startWith(false), pairwise(), withLatestFrom(this._navigator.stateService.reference$, this._container.renderService.renderCamera$))
85439             .subscribe(([[deactivate, activate], ref, cam]) => {
85440             if (activate) {
85441                 controls.onActivate(viewer, cam.perspective.matrixWorldInverse.toArray(), cam.perspective.projectionMatrix.toArray(), ref);
85442             }
85443             else if (deactivate) {
85444                 controls.onDeactivate(viewer);
85445             }
85446         }));
85447         subs.push(active$
85448             .pipe(switchMap(active => {
85449             return active ?
85450                 this._navigator.stateService.currentState$
85451                     .pipe(skip(1)) :
85452                 empty();
85453         }))
85454             .subscribe(frame => {
85455             controls.onAnimationFrame(viewer, frame.id);
85456         }));
85457         subs.push(active$
85458             .pipe(switchMap(active => {
85459             return active ?
85460                 this._navigator.stateService.reference$
85461                     .pipe(skip(1)) :
85462                 empty();
85463         }))
85464             .subscribe(ref => controls.onReference(viewer, ref)));
85465         subs.push(active$
85466             .pipe(switchMap(active => {
85467             return active ?
85468                 this._container.renderService.size$
85469                     .pipe(skip(1)) :
85470                 empty();
85471         }))
85472             .subscribe(() => controls.onResize(viewer)));
85473         subs.push(combineLatest([
85474             // Include to ensure GL renderer has been initialized
85475             this._container.glRenderer.webGLRenderer$,
85476             this._container.renderService.renderCamera$,
85477             this._navigator.stateService.reference$,
85478             this._navigator.stateService.state$,
85479         ])
85480             .pipe(first())
85481             .subscribe(() => {
85482             const projectionMatrixCallback = (projectionMatrix) => {
85483                 if (!this._controls ||
85484                     controls !== this._controls) {
85485                     return;
85486                 }
85487                 this._updateProjectionMatrix(projectionMatrix);
85488             };
85489             const viewMatrixCallback = (viewMatrix) => {
85490                 if (!this._controls ||
85491                     controls !== this._controls) {
85492                     return;
85493                 }
85494                 this._updateViewMatrix(viewMatrix);
85495             };
85496             controls.onAttach(viewer, viewMatrixCallback, projectionMatrixCallback);
85497             attach$.next();
85498             attach$.complete();
85499         }));
85500     }
85501     detach(viewer) {
85502         const controls = this._controls;
85503         this._controls = null;
85504         this._subscriptions.unsubscribe();
85505         return new Promise(resolve => {
85506             this._navigator.stateService.state$
85507                 .pipe(take(1))
85508                 .subscribe(state => {
85509                 if (!controls) {
85510                     resolve(null);
85511                     return;
85512                 }
85513                 if (state === State.Custom) {
85514                     controls.onDeactivate(viewer);
85515                 }
85516                 controls.onDetach(viewer);
85517                 resolve(controls);
85518             });
85519         });
85520     }
85521     dispose(viewer) {
85522         this.detach(viewer);
85523     }
85524     has(controls) {
85525         return !!this._controls && controls === this._controls;
85526     }
85527     _updateProjectionMatrix(projectionMatrix) {
85528         this._navigator.stateService.state$
85529             .pipe(first())
85530             .subscribe(state => {
85531             if (state !== State.Custom) {
85532                 const message = "Incorrect camera control mode for " +
85533                     "projection matrix update";
85534                 console.warn(message);
85535                 return;
85536             }
85537             this._container.renderService.projectionMatrix$
85538                 .next(projectionMatrix);
85539         });
85540     }
85541     _updateViewMatrix(viewMatrix) {
85542         this._navigator.stateService.state$
85543             .pipe(first())
85544             .subscribe(state => {
85545             if (state !== State.Custom) {
85546                 const message = "Incorrect camera control mode for " +
85547                     "view matrix update";
85548                 console.warn(message);
85549                 return;
85550             }
85551             this._navigator.stateService.setViewMatrix(viewMatrix);
85552         });
85553     }
85554 }
85555
85556 /**
85557  * @class Viewer
85558  *
85559  * @classdesc The Viewer object represents the navigable image viewer.
85560  * Create a Viewer by specifying a container, client ID, image ID and
85561  * other options. The viewer exposes methods and events for programmatic
85562  * interaction.
85563  *
85564  * In the case of asynchronous methods, MapillaryJS returns promises to
85565  * the results. Notifications are always emitted through JavaScript events.
85566  */
85567 class Viewer extends EventEmitter {
85568     /**
85569      * Create a new viewer instance.
85570      *
85571      * @description The `Viewer` object represents the street imagery
85572      * viewer on your web page. It exposes methods and properties that
85573      * you can use to programatically change the view, and fires
85574      * events as users interact with it.
85575      *
85576      * It is possible to initialize the viewer with or
85577      * without a ID.
85578      *
85579      * When you want to show a specific image in the viewer from
85580      * the start you should initialize it with a ID.
85581      *
85582      * When you do not know the first image ID at implementation
85583      * time, e.g. in a map-viewer application you should initialize
85584      * the viewer without a ID and call `moveTo` instead.
85585      *
85586      * When initializing with an ID the viewer is bound to that ID
85587      * until the image for that ID has been successfully loaded.
85588      * Also, a cover with the image of the ID will be shown.
85589      * If the data for that ID can not be loaded because the ID is
85590      * faulty or other errors occur it is not possible to navigate
85591      * to another ID because the viewer is not navigable. The viewer
85592      * becomes navigable when the data for the ID has been loaded and
85593      * the image is shown in the viewer. This way of initializing
85594      * the viewer is mostly for embedding in blog posts and similar
85595      * where one wants to show a specific image initially.
85596      *
85597      * If the viewer is initialized without a ID (with null or
85598      * undefined) it is not bound to any particular ID and it is
85599      * possible to move to any ID with `viewer.moveTo("<my-image-id>")`.
85600      * If the first move to a ID fails it is possible to move to another
85601      * ID. The viewer will show a black background until a move
85602      * succeeds. This way of intitializing is suited for a map-viewer
85603      * application when the initial ID is not known at implementation
85604      * time.
85605      *
85606      * @param {ViewerOptions} options - Optional configuration object
85607      * specifying Viewer's and the components' initial setup.
85608      *
85609      * @example
85610      * ```js
85611      * var viewer = new Viewer({
85612      *     accessToken: "<my-access-token>",
85613      *     container: "<my-container-id>",
85614      * });
85615      * ```
85616      */
85617     constructor(options) {
85618         super();
85619         this._navigator =
85620             new Navigator(options);
85621         this._container =
85622             new Container(options, this._navigator.stateService);
85623         this._observer =
85624             new Observer(this, this._navigator, this._container);
85625         this._componentController =
85626             new ComponentController(this._container, this._navigator, this._observer, options.imageId, options.component);
85627         this._customRenderer =
85628             new CustomRenderer(this._container, this._navigator);
85629         this._customCameraControls =
85630             new CustomCameraControls(this._container, this._navigator);
85631     }
85632     /**
85633      * Returns the data provider used by the viewer to fetch
85634      * all contracts, ents, and buffers.
85635      *
85636      * @description The viewer's data provider can be set
85637      * upon initialization through the {@link ViewerOptions.dataProvider}
85638      * property.
85639      *
85640      * @returns {IDataProvider} The viewer's data provider.
85641      */
85642     get dataProvider() {
85643         return this._navigator.api.data;
85644     }
85645     /**
85646      * Return a boolean indicating if the viewer is in a navigable state.
85647      *
85648      * @description The navigable state indicates if the viewer supports
85649      * moving, i.e. calling the {@link moveTo} and {@link moveDir}
85650      * methods or changing the authentication state,
85651      * i.e. calling {@link setAccessToken}. The viewer will not be in a navigable
85652      * state if the cover is activated and the viewer has been supplied a ID.
85653      * When the cover is deactivated or the viewer is activated without being
85654      * supplied a ID it will be navigable.
85655      *
85656      * @returns {boolean} Boolean indicating whether the viewer is navigable.
85657      */
85658     get isNavigable() {
85659         return this._componentController.navigable;
85660     }
85661     /**
85662      * Activate the combined panning functionality.
85663      *
85664      * @description The combined panning functionality is active by default.
85665      */
85666     activateCombinedPanning() {
85667         this._navigator.panService.enable();
85668     }
85669     /**
85670      * Activate a component.
85671      *
85672      * @param {ComponentName | FallbackComponentName} name - Name of
85673      * the component which will become active.
85674      *
85675      * @example
85676      * ```js
85677      * viewer.activateComponent("marker");
85678      * ```
85679      */
85680     activateComponent(name) {
85681         this._componentController.activate(name);
85682     }
85683     /**
85684      * Activate the cover (deactivates all other components).
85685      */
85686     activateCover() {
85687         this._componentController.activateCover();
85688     }
85689     /**
85690      * Add a custom renderer to the viewer's rendering pipeline.
85691      *
85692      * @description During a render pass, custom renderers
85693      * are called in the order they were added.
85694      *
85695      * @param renderer - The custom renderer implementation.
85696      */
85697     addCustomRenderer(renderer) {
85698         this._customRenderer.add(renderer, this);
85699     }
85700     /**
85701      * Attach custom camera controls to control the viewer's
85702      * camera pose and projection.
85703      *
85704      * @description Custom camera controls allow the API user
85705      * to move the viewer's camera freely and define the camera
85706      * projection. These camera properties are used
85707      * to render the viewer 3D scene directly into the
85708      * viewer's GL context.
85709      *
85710      * Only a single custom camera control instance can be
85711      * attached to the viewer. A new custom camera control
85712      * instance can be attached after detaching a previous
85713      * one.
85714      *
85715      * Set the viewer's camera controls to
85716      * {@link CameraControls.Custom} to activate attached
85717      * camera controls. If {@link CameraControls.Custom}
85718      * has already been set when a custom camera control
85719      * instance is attached, it will be activated immediately.
85720      *
85721      * Set the viewer's camera controls to any other
85722      * {@link CameraControls} mode to deactivate the
85723      * custom camera controls.
85724      *
85725      * @param controls - The custom camera controls implementation.
85726      *
85727      * @throws {MapillaryError} When camera controls attached
85728      * are already attached to the viewer.
85729      */
85730     attachCustomCameraControls(controls) {
85731         this._customCameraControls.attach(controls, this);
85732     }
85733     /**
85734      * Deactivate the combined panning functionality.
85735      *
85736      * @description Deactivating the combined panning functionality
85737      * could be needed in scenarios involving sequence only navigation.
85738      */
85739     deactivateCombinedPanning() {
85740         this._navigator.panService.disable();
85741     }
85742     /**
85743      * Deactivate a component.
85744      *
85745      * @param {ComponentName | FallbackComponentName} name - Name
85746      * of component which become inactive.
85747      *
85748      * @example
85749      * ```js
85750      * viewer.deactivateComponent("pointer");
85751      * ```
85752      */
85753     deactivateComponent(name) {
85754         this._componentController.deactivate(name);
85755     }
85756     /**
85757      * Deactivate the cover (activates all components marked as active).
85758      */
85759     deactivateCover() {
85760         this._componentController.deactivateCover();
85761     }
85762     /**
85763      * Detach a previously attached custom camera control
85764      * instance from the viewer.
85765      *
85766      * @description If no custom camera control instance
85767      * has previously been attached, calling this method
85768      * has no effect.
85769      *
85770      * Already attached custom camera controls need to
85771      * be detached before attaching another custom camera
85772      * control instance.
85773      */
85774     detachCustomCameraControls() {
85775         return this._customCameraControls.detach(this);
85776     }
85777     fire(type, event) {
85778         super.fire(type, event);
85779     }
85780     /**
85781      * Get the bearing of the current viewer camera.
85782      *
85783      * @description The bearing depends on how the camera
85784      * is currently rotated and does not correspond
85785      * to the compass angle of the current image if the view
85786      * has been panned.
85787      *
85788      * Bearing is measured in degrees clockwise with respect to
85789      * north.
85790      *
85791      * @returns {Promise<number>} Promise to the bearing
85792      * of the current viewer camera.
85793      *
85794      * @example
85795      * ```js
85796      * viewer.getBearing().then(b => { console.log(b); });
85797      * ```
85798      */
85799     getBearing() {
85800         return new Promise((resolve, reject) => {
85801             this._container.renderService.bearing$.pipe(first())
85802                 .subscribe((bearing) => {
85803                 resolve(bearing);
85804             }, (error) => {
85805                 reject(error);
85806             });
85807         });
85808     }
85809     /**
85810      * Get the viewer's camera control mode.
85811      *
85812      * @description The camera control mode determines
85813      * how the camera is controlled when the viewer
85814      * receives pointer and keyboard input.
85815      *
85816      * @returns {CameraControls} controls - Camera control mode.
85817      *
85818      * @example
85819      * ```js
85820      * viewer.getCameraControls().then(c => { console.log(c); });
85821      * ```
85822      */
85823     getCameraControls() {
85824         return new Promise((resolve, reject) => {
85825             this._navigator.stateService.state$.pipe(first())
85826                 .subscribe((state) => {
85827                 switch (state) {
85828                     case State.Custom:
85829                         resolve(CameraControls.Custom);
85830                         break;
85831                     case State.Earth:
85832                         resolve(CameraControls.Earth);
85833                         break;
85834                     default:
85835                         resolve(CameraControls.Street);
85836                         break;
85837                 }
85838             }, (error) => {
85839                 reject(error);
85840             });
85841         });
85842     }
85843     /**
85844      * Returns the viewer's canvas element.
85845      *
85846      * @description This is the element onto which the viewer renders
85847      * the WebGL content.
85848      *
85849      * @returns {HTMLCanvasElement} The viewer's canvas element, or
85850      * null or not initialized.
85851      */
85852     getCanvas() {
85853         return this._container.canvas;
85854     }
85855     /**
85856      * Returns the HTML element containing the viewer's canvas element.
85857      *
85858      * @description This is the element to which event bindings for viewer
85859      * interactivity (such as panning and zooming) are attached.
85860      *
85861      * @returns {HTMLDivElement} The container for the viewer's
85862      * canvas element.
85863      */
85864     getCanvasContainer() {
85865         return this._container.canvasContainer;
85866     }
85867     /**
85868      * Get the basic coordinates of the current image that is
85869      * at the center of the viewport.
85870      *
85871      * @description Basic coordinates are 2D coordinates on the [0, 1] interval
85872      * and have the origin point, (0, 0), at the top left corner and the
85873      * maximum value, (1, 1), at the bottom right corner of the original
85874      * image.
85875      *
85876      * @returns {Promise<number[]>} Promise to the basic coordinates
85877      * of the current image at the center for the viewport.
85878      *
85879      * @example
85880      * ```js
85881      * viewer.getCenter().then(c => { console.log(c); });
85882      * ```
85883      */
85884     getCenter() {
85885         return new Promise((resolve, reject) => {
85886             this._navigator.stateService.getCenter()
85887                 .subscribe((center) => {
85888                 resolve(center);
85889             }, (error) => {
85890                 reject(error);
85891             });
85892         });
85893     }
85894     /**
85895      * Get a component.
85896      *
85897      * @param {string} name - Name of component.
85898      * @returns {Component} The requested component.
85899      *
85900      * @example
85901      * ```js
85902      * var pointerComponent = viewer.getComponent("pointer");
85903      * ```
85904      */
85905     getComponent(name) {
85906         return this._componentController.get(name);
85907     }
85908     /**
85909      * Returns the viewer's containing HTML element.
85910      *
85911      * @returns {HTMLElement} The viewer's container.
85912      */
85913     getContainer() {
85914         return this._container.container;
85915     }
85916     /**
85917      * Get the viewer's current vertical field of view.
85918      *
85919      * @description The vertical field of view rendered on the viewer canvas
85920      * measured in degrees.
85921      *
85922      * @returns {Promise<number>} Promise to the current field of view
85923      * of the viewer camera.
85924      *
85925      * @example
85926      * ```js
85927      * viewer.getFieldOfView().then(fov => { console.log(fov); });
85928      * ```
85929      */
85930     getFieldOfView() {
85931         return new Promise((resolve, reject) => {
85932             this._container.renderService.renderCamera$.pipe(first())
85933                 .subscribe((rc) => {
85934                 resolve(rc.perspective.fov);
85935             }, (error) => {
85936                 reject(error);
85937             });
85938         });
85939     }
85940     /**
85941      * Get the viewer's current image.
85942      *
85943      * @returns {Promise<Image>} Promise to the current image.
85944      *
85945      * @example
85946      * ```js
85947      * viewer.getImage().then(image => { console.log(image.id); });
85948      * ```
85949      */
85950     getImage() {
85951         return new Promise((resolve, reject) => {
85952             this._navigator.stateService.currentImage$.pipe(first())
85953                 .subscribe((image) => { resolve(image); }, (error) => { reject(error); });
85954         });
85955     }
85956     /**
85957      * Get the viewer's current point of view.
85958      *
85959      * @returns {Promise<PointOfView>} Promise to the current point of view
85960      * of the viewer camera.
85961      *
85962      * @example
85963      * ```js
85964      * viewer.getPointOfView().then(pov => { console.log(pov); });
85965      * ```
85966      */
85967     getPointOfView() {
85968         return new Promise((resolve, reject) => {
85969             combineLatest(this._container.renderService.renderCamera$, this._container.renderService.bearing$).pipe(first())
85970                 .subscribe(([rc, bearing]) => {
85971                 resolve({
85972                     bearing: bearing,
85973                     tilt: rc.getTilt(),
85974                 });
85975             }, (error) => {
85976                 reject(error);
85977             });
85978         });
85979     }
85980     /**
85981      * Get the viewer's current position
85982      *
85983      * @returns {Promise<LngLat>} Promise to the viewers's current
85984      * position.
85985      *
85986      * @example
85987      * ```js
85988      * viewer.getPosition().then(pos => { console.log(pos); });
85989      * ```
85990      */
85991     getPosition() {
85992         return new Promise((resolve, reject) => {
85993             combineLatest(this._container.renderService.renderCamera$, this._navigator.stateService.reference$).pipe(first())
85994                 .subscribe(([render, reference]) => {
85995                 resolve(this._observer.projection.cameraToLngLat(render, reference));
85996             }, (error) => {
85997                 reject(error);
85998             });
85999         });
86000     }
86001     /**
86002      * Get the viewer's current reference position.
86003      *
86004      * @description The reference position specifies the origin in
86005      * the viewer's topocentric coordinate system.
86006      *
86007      * @returns {Promise<LngLatAlt>} Promise to the reference position.
86008      *
86009      * @example
86010      * ```js
86011      * viewer.getReference().then(reference => { console.log(reference); });
86012      * ```
86013      */
86014     getReference() {
86015         return new Promise((resolve, reject) => {
86016             this._navigator.stateService.reference$.pipe(first())
86017                 .subscribe((reference) => { resolve(reference); }, (error) => { reject(error); });
86018         });
86019     }
86020     /**
86021      * Get the image's current zoom level.
86022      *
86023      * @returns {Promise<number>} Promise to the viewers's current
86024      * zoom level.
86025      *
86026      * @example
86027      * ```js
86028      * viewer.getZoom().then(z => { console.log(z); });
86029      * ```
86030      */
86031     getZoom() {
86032         return new Promise((resolve, reject) => {
86033             this._navigator.stateService.getZoom()
86034                 .subscribe((zoom) => {
86035                 resolve(zoom);
86036             }, (error) => {
86037                 reject(error);
86038             });
86039         });
86040     }
86041     /**
86042      * Check if a controls instance is the camera controls that are
86043      * currently attached to the viewer.
86044      *
86045      * @param {ICustomCameraControls} controls - Camera controls instance.
86046      * @returns {boolean} Value indicating whether the controls instance
86047      * is currently attached.
86048      */
86049     hasCustomCameraControls(controls) {
86050         return this._customCameraControls.has(controls);
86051     }
86052     /**
86053      * Check if a custom renderer has been added to the viewer's
86054      * rendering pipeline.
86055      *
86056      * @param {string} id - Unique ID of the custom renderer.
86057      * @returns {boolean} Value indicating whether the customer
86058      * renderer has been added.
86059      */
86060     hasCustomRenderer(rendererId) {
86061         return this._customRenderer.has(rendererId);
86062     }
86063     /**
86064      * Navigate in a given direction.
86065      *
86066      * @param {NavigationDirection} direction - Direction in which which to move.
86067      * @returns {Promise<Image>} Promise to the image that was navigated to.
86068      * @throws If the current image does not have the edge direction
86069      * or the edges has not yet been cached.
86070      * @throws Propagates any IO errors to the caller.
86071      * @throws When viewer is not navigable.
86072      * @throws {@link CancelMapillaryError} When a subsequent move request
86073      * is made before the move dir call has completed.
86074      *
86075      * @example
86076      * ```js
86077      * viewer.moveDir(NavigationDirection.Next).then(
86078      *     image => { console.log(image); },
86079      *     error => { console.error(error); });
86080      * ```
86081      */
86082     moveDir(direction) {
86083         const moveDir$ = this.isNavigable ?
86084             this._navigator.moveDir$(direction) :
86085             throwError(new Error("Calling moveDir is not supported when viewer is not navigable."));
86086         return new Promise((resolve, reject) => {
86087             moveDir$.subscribe((image) => {
86088                 resolve(image);
86089             }, (error) => {
86090                 reject(error);
86091             });
86092         });
86093     }
86094     /**
86095      * Navigate to a given image ID.
86096      *
86097      * @param {string} imageId - Id of the image to move to.
86098      * @returns {Promise<Image>} Promise to the image that was navigated to.
86099      * @throws Propagates any IO errors to the caller.
86100      * @throws When viewer is not navigable.
86101      * @throws {@link CancelMapillaryError} When a subsequent
86102      * move request is made before the move to ID call has completed.
86103      *
86104      * @example
86105      * ```js
86106      * viewer.moveTo("<my-image-id>").then(
86107      *     image => { console.log(image); },
86108      *     error => { console.error(error); });
86109      * ```
86110      */
86111     moveTo(imageId) {
86112         const moveTo$ = this.isNavigable ?
86113             this._navigator.moveTo$(imageId) :
86114             throwError(new Error("Calling moveTo is not supported when viewer is not navigable."));
86115         return new Promise((resolve, reject) => {
86116             moveTo$.subscribe((image) => {
86117                 resolve(image);
86118             }, (error) => {
86119                 reject(error);
86120             });
86121         });
86122     }
86123     off(type, handler) {
86124         super.off(type, handler);
86125     }
86126     on(type, handler) {
86127         super.on(type, handler);
86128     }
86129     /**
86130      * Project geodetic coordinates to canvas pixel coordinates.
86131      *
86132      * @description The geodetic coordinates may not always correspond to pixel
86133      * coordinates, e.g. if the geodetic coordinates have a position behind the
86134      * viewer camera. In the case of no correspondence the returned value will
86135      * be `null`.
86136      *
86137      * If the distance from the viewer camera position to the provided
86138      * longitude-latitude is more than 1000 meters `null` will be returned.
86139      *
86140      * The projection is performed from the ground plane, i.e.
86141      * the altitude with respect to the ground plane for the geodetic
86142      * point is zero.
86143      *
86144      * Note that whenever the camera moves, the result of the method will be
86145      * different.
86146      *
86147      * @param {LngLat} lngLat - Geographical coordinates to project.
86148      * @returns {Promise<Array<number>>} Promise to the pixel coordinates corresponding
86149      * to the lngLat.
86150      *
86151      * @example
86152      * ```js
86153      * viewer.project({ lat: 0, lng: 0 })
86154      *     .then(pixelPoint => {
86155      *          if (!pixelPoint) {
86156      *              console.log("no correspondence");
86157      *          }
86158      *
86159      *          console.log(pixelPoint);
86160      *     });
86161      * ```
86162      */
86163     project(lngLat) {
86164         return new Promise((resolve, reject) => {
86165             this._observer.project$(lngLat)
86166                 .subscribe((pixelPoint) => {
86167                 resolve(pixelPoint);
86168             }, (error) => {
86169                 reject(error);
86170             });
86171         });
86172     }
86173     /**
86174      * Project basic image coordinates for the current image to canvas pixel
86175      * coordinates.
86176      *
86177      * @description The basic image coordinates may not always correspond to a
86178      * pixel point that lies in the visible area of the viewer container. In the
86179      * case of no correspondence the returned value can be `null`.
86180      *
86181      *
86182      * @param {Array<number>} basicPoint - Basic images coordinates to project.
86183      * @returns {Promise<Array<number>>} Promise to the pixel coordinates corresponding
86184      * to the basic image point.
86185      *
86186      * @example
86187      * ```js
86188      * viewer.projectFromBasic([0.3, 0.7])
86189      *     .then(pixelPoint => { console.log(pixelPoint); });
86190      * ```
86191      */
86192     projectFromBasic(basicPoint) {
86193         return new Promise((resolve, reject) => {
86194             this._observer.projectBasic$(basicPoint)
86195                 .subscribe((pixelPoint) => {
86196                 resolve(pixelPoint);
86197             }, (error) => {
86198                 reject(error);
86199             });
86200         });
86201     }
86202     /**
86203      * Clean up and release all internal resources associated with
86204      * this viewer.
86205      *
86206      * @description This includes DOM elements, event bindings, and
86207      * WebGL resources.
86208      *
86209      * Use this method when you are done using the viewer and wish to
86210      * ensure that it no longer consumes browser resources. Afterwards,
86211      * you must not call any other methods on the viewer.
86212      *
86213      * @fires remove
86214      *
86215      * @example
86216      * ```js
86217      * viewer.remove();
86218      * ```
86219      */
86220     remove() {
86221         this._customRenderer.dispose(this);
86222         this._customCameraControls.dispose(this);
86223         this._observer.dispose();
86224         this._componentController.remove();
86225         this._navigator.dispose();
86226         this._container.remove();
86227         const type = "remove";
86228         const event = {
86229             target: this,
86230             type,
86231         };
86232         this.fire(type, event);
86233     }
86234     /**
86235      * Remove a custom renderer from the viewer's rendering pipeline.
86236      *
86237      * @param id - Unique ID of the custom renderer.
86238      */
86239     removeCustomRenderer(rendererId) {
86240         this._customRenderer.remove(rendererId, this);
86241     }
86242     /**
86243      * Detect the viewer's new width and height and resize it
86244      * manually.
86245      *
86246      * @description The components will also detect the viewer's
86247      * new size and resize their rendered elements if needed.
86248      *
86249      * When the {@link ViewerOptions.trackResize} option is
86250      * set to true, the viewer will automatically resize
86251      * when the browser window is resized. If any other
86252      * custom behavior is preferred, the option should be set
86253      * to false and the {@link Viewer.resize} method should
86254      * be called on demand.
86255      *
86256      * @example
86257      * ```js
86258      * viewer.resize();
86259      * ```
86260      */
86261     resize() {
86262         this._container.renderService.resize$.next();
86263     }
86264     /**
86265      * Set the viewer's camera control mode.
86266      *
86267      * @description The camera control mode determines
86268      * how the camera is controlled when the viewer
86269      * receives pointer and keyboard input.
86270      *
86271      * Changing the camera control mode is not possible
86272      * when the slider component is active and attempts
86273      * to do so will be ignored.
86274      *
86275      * @param {CameraControls} controls - Camera control mode.
86276      *
86277      * @example
86278      * ```js
86279      * viewer.setCameraControls(CameraControls.Street);
86280      * ```
86281      */
86282     setCameraControls(controls) {
86283         const state = cameraControlsToState(controls);
86284         if (state === State.Traversing) {
86285             this._navigator.stateService.traverse();
86286         }
86287         else if (state === State.Earth) {
86288             this._navigator.stateService.earth();
86289         }
86290         else if (state === State.Custom) {
86291             this._navigator.stateService.custom();
86292         }
86293         else {
86294             console.warn(`Unsupported camera control transition (${controls})`);
86295         }
86296     }
86297     /**
86298      * Set the basic coordinates of the current image to be in the
86299      * center of the viewport.
86300      *
86301      * @description Basic coordinates are 2D coordinates on the [0, 1] interval
86302      * and has the origin point, (0, 0), at the top left corner and the
86303      * maximum value, (1, 1), at the bottom right corner of the original
86304      * image.
86305      *
86306      * @param {number[]} The basic coordinates of the current
86307      * image to be at the center for the viewport.
86308      *
86309      * @example
86310      * ```js
86311      * viewer.setCenter([0.5, 0.5]);
86312      * ```
86313      */
86314     setCenter(center) {
86315         this._navigator.stateService.setCenter(center);
86316     }
86317     /**
86318      * Set the viewer's current vertical field of view.
86319      *
86320      * @description Sets the vertical field of view rendered
86321      * on the viewer canvas measured in degrees. The value
86322      * will be clamped to be able to set a valid zoom level
86323      * based on the projection model of the current image and
86324      * the viewer's current render mode.
86325      *
86326      * @param {number} fov - Vertical field of view in degrees.
86327      *
86328      * @example
86329      * ```js
86330      * viewer.setFieldOfView(45);
86331      * ```
86332      */
86333     setFieldOfView(fov) {
86334         this._container.renderService.renderCamera$.pipe(first())
86335             .subscribe((rc) => {
86336             const zoom = rc.fovToZoom(fov);
86337             this._navigator.stateService.setZoom(zoom);
86338         });
86339     }
86340     /**
86341      * Set the filter selecting images to use when calculating
86342      * the spatial edges.
86343      *
86344      * @description The following filter types are supported:
86345      *
86346      * Comparison
86347      *
86348      * `["==", key, value]` equality: `image[key] = value`
86349      *
86350      * `["!=", key, value]` inequality: `image[key] ≠ value`
86351      *
86352      * `["<", key, value]` less than: `image[key] < value`
86353      *
86354      * `["<=", key, value]` less than or equal: `image[key] ≤ value`
86355      *
86356      * `[">", key, value]` greater than: `image[key] > value`
86357      *
86358      * `[">=", key, value]` greater than or equal: `image[key] ≥ value`
86359      *
86360      * Set membership
86361      *
86362      * `["in", key, v0, ..., vn]` set inclusion: `image[key] ∈ {v0, ..., vn}`
86363      *
86364      * `["!in", key, v0, ..., vn]` set exclusion: `image[key] ∉ {v0, ..., vn}`
86365      *
86366      * Combining
86367      *
86368      * `["all", f0, ..., fn]` logical `AND`: `f0 ∧ ... ∧ fn`
86369      *
86370      * A key must be a string that identifies a property name of a
86371      * simple {@link Image} property, i.e. a key of the {@link FilterKey}
86372      * type. A value must be a string, number, or
86373      * boolean. Strictly-typed comparisons are used. The values
86374      * `f0, ..., fn` of the combining filter must be filter expressions.
86375      *
86376      * Clear the filter by setting it to null or empty array.
86377      *
86378      * Commonly used filter properties (see the {@link Image} class
86379      * documentation for a full list of properties that can be used
86380      * in a filter) are shown the the example code.
86381      *
86382      * @param {FilterExpression} [filter] - The filter expression.
86383      * Applied filter is cleared if omitted.
86384      * @returns {Promise<void>} Promise that resolves after filter is applied.
86385      *
86386      * @example
86387      * ```js
86388      * // Examples
86389      * viewer.setFilter(["==", "cameraType", "spherical"]);
86390      * viewer.setFilter([">=", "capturedAt", <my-time-stamp>]);
86391      * viewer.setFilter(["in", "sequenceId", "<sequence-id-1>", "<sequence-id-2>"]);
86392      * ```
86393      */
86394     setFilter(filter) {
86395         return new Promise((resolve, reject) => {
86396             this._navigator.setFilter$(filter)
86397                 .subscribe(() => {
86398                 resolve(undefined);
86399             }, (error) => {
86400                 reject(error);
86401             });
86402         });
86403     }
86404     /**
86405      * Set the viewer's render mode.
86406      *
86407      * @param {RenderMode} renderMode - Render mode.
86408      *
86409      * @example
86410      * ```js
86411      * viewer.setRenderMode(RenderMode.Letterbox);
86412      * ```
86413      */
86414     setRenderMode(renderMode) {
86415         this._container.renderService.renderMode$.next(renderMode);
86416     }
86417     /**
86418      * Set the viewer's transition mode.
86419      *
86420      * @param {TransitionMode} transitionMode - Transition mode.
86421      *
86422      * @example
86423      * ```js
86424      * viewer.setTransitionMode(TransitionMode.Instantaneous);
86425      * ```
86426      */
86427     setTransitionMode(transitionMode) {
86428         this._navigator.stateService.setTransitionMode(transitionMode);
86429     }
86430     /**
86431      * Set an access token for authenticated API requests of protected
86432      * resources.
86433      *
86434      * The token may be a user access token or a client access token.
86435      *
86436      * @description When the supplied user token is null or undefined,
86437      * any previously set user bearer token will be cleared and the
86438      * viewer will make unauthenticated requests.
86439      *
86440      * Calling setAccessToken aborts all outstanding move requests.
86441      * The promises of those move requests will be rejected with a
86442      * {@link CancelMapillaryError} the rejections need to be caught.
86443      *
86444      * Calling setAccessToken also resets the complete viewer cache
86445      * so it should not be called repeatedly.
86446      *
86447      * @param {string} [accessToken] accessToken - Optional user
86448      * access token or client access token.
86449      * @returns {Promise<void>} Promise that resolves after token
86450      * is set.
86451      *
86452      * @throws When viewer is not navigable.
86453      *
86454      * @example
86455      * ```js
86456      * viewer.setAccessToken("<my access token>")
86457      *     .then(() => { console.log("user token set"); });
86458      * ```
86459      */
86460     setAccessToken(accessToken) {
86461         const setAccessToken$ = this.isNavigable ?
86462             this._navigator.setAccessToken$(accessToken) :
86463             throwError(new Error("Calling setAccessToken is not supported when viewer is not navigable."));
86464         return new Promise((resolve, reject) => {
86465             setAccessToken$
86466                 .subscribe(() => {
86467                 resolve(undefined);
86468             }, (error) => {
86469                 reject(error);
86470             });
86471         });
86472     }
86473     /**
86474      * Set the image's current zoom level.
86475      *
86476      * @description Possible zoom level values are on the [0, 3] interval.
86477      * Zero means zooming out to fit the image to the view whereas three
86478      * shows the highest level of detail.
86479      *
86480      * @param {number} The image's current zoom level.
86481      *
86482      * @example
86483      * ```js
86484      * viewer.setZoom(2);
86485      * ```
86486      */
86487     setZoom(zoom) {
86488         this._navigator.stateService.setZoom(zoom);
86489     }
86490     /**
86491      * Trigger the rendering of a single frame.
86492      *
86493      * @description Use this method with custom renderers to
86494      * force the viewer to rerender when the custom content
86495      * changes. Calling this multiple times before the next
86496      * frame is rendered will still result in only a single
86497      * frame being rendered.
86498      */
86499     triggerRerender() {
86500         this._container.glRenderer.triggerRerender();
86501     }
86502     /**
86503      * Unproject canvas pixel coordinates to geodetic
86504      * coordinates.
86505      *
86506      * @description The pixel point may not always correspond to geodetic
86507      * coordinates. In the case of no correspondence the returned value will
86508      * be `null`.
86509      *
86510      * The unprojection to a lngLat will be performed towards the ground plane, i.e.
86511      * the altitude with respect to the ground plane for the returned lngLat is zero.
86512      *
86513      * @param {Array<number>} pixelPoint - Pixel coordinates to unproject.
86514      * @returns {Promise<LngLat>} Promise to the lngLat corresponding to the pixel point.
86515      *
86516      * @example
86517      * ```js
86518      * viewer.unproject([100, 100])
86519      *     .then(lngLat => { console.log(lngLat); });
86520      * ```
86521      */
86522     unproject(pixelPoint) {
86523         return new Promise((resolve, reject) => {
86524             this._observer.unproject$(pixelPoint)
86525                 .subscribe((lngLat) => {
86526                 resolve(lngLat);
86527             }, (error) => {
86528                 reject(error);
86529             });
86530         });
86531     }
86532     /**
86533      * Unproject canvas pixel coordinates to basic image coordinates for the
86534      * current image.
86535      *
86536      * @description The pixel point may not always correspond to basic image
86537      * coordinates. In the case of no correspondence the returned value will
86538      * be `null`.
86539      *
86540      * @param {Array<number>} pixelPoint - Pixel coordinates to unproject.
86541      * @returns {Promise<LngLat>} Promise to the basic coordinates corresponding
86542      * to the pixel point.
86543      *
86544      * @example
86545      * ```js
86546      * viewer.unprojectToBasic([100, 100])
86547      *     .then(basicPoint => { console.log(basicPoint); });
86548      * ```
86549      */
86550     unprojectToBasic(pixelPoint) {
86551         return new Promise((resolve, reject) => {
86552             this._observer.unprojectBasic$(pixelPoint)
86553                 .subscribe((basicPoint) => {
86554                 resolve(basicPoint);
86555             }, (error) => {
86556                 reject(error);
86557             });
86558         });
86559     }
86560 }
86561
86562 /**
86563  * Internal bootstrap
86564  *
86565  * This is a workaround to make the CommonJS unit testing
86566  * work with Jest. Once Jest/Node supports ES6 modules
86567  * fully this should be removed. GeoRBush is registered
86568  * here only to avoid loading it during
86569  * unit tests.
86570  */
86571 Graph.register(GeoRBush);
86572 MarkerSet.register(GeoRBush);
86573 ComponentService.registerCover(CoverComponent);
86574 ComponentService.register(AttributionComponent);
86575 ComponentService.register(BearingComponent);
86576 ComponentService.register(CacheComponent);
86577 ComponentService.register(DirectionComponent);
86578 ComponentService.register(ImageComponent);
86579 ComponentService.register(KeyboardComponent);
86580 ComponentService.register(MarkerComponent);
86581 ComponentService.register(PointerComponent);
86582 ComponentService.register(PopupComponent);
86583 ComponentService.register(SequenceComponent);
86584 ComponentService.register(SliderComponent);
86585 ComponentService.register(SpatialComponent);
86586 ComponentService.register(TagComponent);
86587 ComponentService.register(ZoomComponent);
86588 ComponentService.register(ImageFallbackComponent);
86589 ComponentService.register(NavigationFallbackComponent);
86590
86591 export { Alignment, ArgumentMapillaryError, BearingComponent, CacheComponent, CameraControls, CameraVisualizationMode, CancelMapillaryError, CircleMarker, Component, ComponentSize, DataProviderBase, DirectionComponent, DragPanHandler, EventEmitter, ExtremePointTag, Geometry, GeometryProviderBase, GeometryTagError, GraphDataProvider, GraphMapillaryError, Image$1 as Image, KeyPlayHandler, KeySequenceNavigationHandler, KeySpatialNavigationHandler, KeyZoomHandler, KeyboardComponent, MapillaryError, Marker, MarkerComponent, NavigationDirection, OriginalPositionMode, OutlineTag, PointGeometry, PointVisualizationMode, 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, ecefToEnu, ecefToGeodetic, enuToEcef, enuToGeodetic, fetchArrayBuffer, geodeticToEcef, geodeticToEnu, isFallbackSupported, isSupported, readMeshPbf };
86592 //# sourceMappingURL=mapillary.module.js.map