@needle-tools/gltf-progressive 2.1.0-alpha.3 → 2.1.0-alpha.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,12 @@ All notable changes to this package will be documented in this file.
4
4
  The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5
5
  and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [2.1.0-alpha.5] - 2025-01-30
8
+ - Add: initial support for Orthographic cameras
9
+
10
+ ## [2.1.0-alpha.4] - 2025-01-29
11
+ - Fix: LOD not loading if the max texture resolution is too small
12
+
7
13
  ## [2.1.0-alpha.3] - 2025-01-21
8
14
  - Change: Load Draco and KTX loaders as soon as possible
9
15
  - Fix: Make `GET` request to draco endpoint with 1 byte range instead of HEAD request. The HEAD request did return the whole draco loader.
@@ -9,7 +9,7 @@ var m = (o, e, t) => (Te(o, e, "read from private field"), t ? t.call(o) : e.get
9
9
  throw TypeError("Cannot add the same private member more than once");
10
10
  e instanceof WeakSet ? e.add(o) : e.set(o, t);
11
11
  }, U = (o, e, t, s) => (Te(o, e, "write to private field"), s ? s.call(o, t) : e.set(o, t), t);
12
- import { BufferGeometry as ge, Mesh as Q, Material as Xe, Texture as se, TextureLoader as Ke, Matrix4 as Ae, Clock as Ye, MeshStandardMaterial as He, Sphere as Je, Box3 as Ee, Vector3 as N } from "three";
12
+ import { BufferGeometry as ge, Mesh as Q, Material as Xe, Texture as se, TextureLoader as Ke, Matrix4 as Ae, Clock as Ye, MeshStandardMaterial as He, Sphere as Je, Box3 as Pe, Vector3 as z } from "three";
13
13
  import { GLTFLoader as be } from "three/examples/jsm/loaders/GLTFLoader.js";
14
14
  import { MeshoptDecoder as Qe } from "three/examples/jsm/libs/meshopt_decoder.module.js";
15
15
  import { DRACOLoader as Ze } from "three/examples/jsm/loaders/DRACOLoader.js";
@@ -118,7 +118,7 @@ function ct(o) {
118
118
  e.setAttribute(t, o.getAttribute(t));
119
119
  return e.setIndex(o.getIndex()), e;
120
120
  }
121
- const Y = new Array(), z = "NEEDLE_progressive", L = le("debugprogressive"), De = Symbol("needle-progressive-texture"), oe = /* @__PURE__ */ new Map(), Se = /* @__PURE__ */ new Set();
121
+ const Y = new Array(), V = "NEEDLE_progressive", L = le("debugprogressive"), De = Symbol("needle-progressive-texture"), oe = /* @__PURE__ */ new Map(), Se = /* @__PURE__ */ new Set();
122
122
  if (L) {
123
123
  let o = function() {
124
124
  e += 1, console.log("Toggle LOD level", e, oe), oe.forEach((n, r) => {
@@ -142,7 +142,7 @@ if (L) {
142
142
  }));
143
143
  });
144
144
  }
145
- function Pe(o, e, t) {
145
+ function Ee(o, e, t) {
146
146
  var n;
147
147
  if (!L)
148
148
  return;
@@ -159,7 +159,7 @@ const v = class {
159
159
  var s, n;
160
160
  if (this._isLoadingMesh)
161
161
  return null;
162
- const t = (n = (s = this.parser.json.meshes[e]) == null ? void 0 : s.extensions) == null ? void 0 : n[z];
162
+ const t = (n = (s = this.parser.json.meshes[e]) == null ? void 0 : s.extensions) == null ? void 0 : n[V];
163
163
  return t ? (this._isLoadingMesh = !0, this.parser.getDependency("mesh", e).then((r) => {
164
164
  var i;
165
165
  return this._isLoadingMesh = !1, r && v.registerMesh(this.url, t.guid, r, (i = t.lods) == null ? void 0 : i.length, void 0, t), r;
@@ -169,7 +169,7 @@ const v = class {
169
169
  }
170
170
  /** The name of the extension */
171
171
  get name() {
172
- return z;
172
+ return V;
173
173
  }
174
174
  static getMeshLODInformation(e) {
175
175
  const t = this.getAssignedLODInformation(e);
@@ -278,7 +278,7 @@ const v = class {
278
278
  const a = r.index || 0;
279
279
  i = i[a];
280
280
  }
281
- return e["LOD:requested level"] === t && (delete e["LOD:requested level"], i && n != i && ((i == null ? void 0 : i.isBufferGeometry) ? (e.geometry = i, L && Pe(e, "geometry", r.url)) : L && console.error("Invalid LOD geometry", i))), i;
281
+ return e["LOD:requested level"] === t && (delete e["LOD:requested level"], i && n != i && ((i == null ? void 0 : i.isBufferGeometry) ? (e.geometry = i, L && Ee(e, "geometry", r.url)) : L && console.error("Invalid LOD geometry", i))), i;
282
282
  }).catch((i) => (console.error("Error loading mesh LOD", e, i), null));
283
283
  } else
284
284
  L && console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh", e);
@@ -355,7 +355,7 @@ const v = class {
355
355
  }
356
356
  if (L && n && s) {
357
357
  const i = this.getAssignedLODInformation(e);
358
- i && Pe(s, n, i.url);
358
+ i && Ee(s, n, i.url);
359
359
  }
360
360
  }
361
361
  return r;
@@ -369,7 +369,7 @@ const v = class {
369
369
  return L && console.log("AFTER", this.url, e), (t = this.parser.json.textures) == null || t.forEach((n, r) => {
370
370
  var i;
371
371
  if (n != null && n.extensions) {
372
- const a = n == null ? void 0 : n.extensions[z];
372
+ const a = n == null ? void 0 : n.extensions[V];
373
373
  if (a) {
374
374
  if (!a.lods) {
375
375
  L && console.warn("Texture has no LODs", a);
@@ -389,7 +389,7 @@ const v = class {
389
389
  }
390
390
  }), (s = this.parser.json.meshes) == null || s.forEach((n, r) => {
391
391
  if (n != null && n.extensions) {
392
- const i = n == null ? void 0 : n.extensions[z];
392
+ const i = n == null ? void 0 : n.extensions[V];
393
393
  if (i && i.lods) {
394
394
  for (const a of this.parser.associations.keys())
395
395
  if (a.isMesh) {
@@ -413,9 +413,9 @@ const v = class {
413
413
  }
414
414
  if (i || (i = v.lodInfos.get(r)), i) {
415
415
  if (t > 0) {
416
- let M = !1;
416
+ let D = !1;
417
417
  const w = Array.isArray(i.lods);
418
- if (w && t >= i.lods.length ? M = !0 : w || (M = !0), M)
418
+ if (w && t >= i.lods.length ? D = !0 : w || (D = !0), D)
419
419
  return this.lowresCache.get(r);
420
420
  }
421
421
  const g = Array.isArray(i.lods) ? (a = i.lods[t]) == null ? void 0 : a.path : i.lods;
@@ -425,81 +425,81 @@ const v = class {
425
425
  if (p.endsWith(".glb") || p.endsWith(".gltf")) {
426
426
  if (!i.guid)
427
427
  return console.warn("missing pointer for glb/gltf texture", i), null;
428
- const M = p + "_" + i.guid, w = this.previouslyLoaded.get(M);
428
+ const D = p + "_" + i.guid, w = this.previouslyLoaded.get(D);
429
429
  if (w !== void 0) {
430
- s && console.log(`LOD ${t} was already loading/loaded: ${M}`);
430
+ s && console.log(`LOD ${t} was already loading/loaded: ${D}`);
431
431
  let h = await w.catch((F) => (console.error(`Error loading LOD ${t} from ${p}
432
432
  `, F), null)), R = !1;
433
- if (h == null || (h instanceof se && e instanceof se ? (l = h.image) != null && l.data || (u = h.source) != null && u.data ? h = this.copySettings(e, h) : (R = !0, this.previouslyLoaded.delete(M)) : h instanceof ge && e instanceof ge && ((c = h.attributes.position) != null && c.array || (R = !0, this.previouslyLoaded.delete(M)))), !R)
433
+ if (h == null || (h instanceof se && e instanceof se ? (l = h.image) != null && l.data || (u = h.source) != null && u.data ? h = this.copySettings(e, h) : (R = !0, this.previouslyLoaded.delete(D)) : h instanceof ge && e instanceof ge && ((c = h.attributes.position) != null && c.array || (R = !0, this.previouslyLoaded.delete(D)))), !R)
434
434
  return h;
435
435
  }
436
436
  const x = i, $ = new Promise(async (h, R) => {
437
437
  const F = new be();
438
- $e(F), L && (await new Promise((A) => setTimeout(A, 1e3)), s && console.warn("Start loading (delayed) " + p, x.guid));
438
+ $e(F), L && (await new Promise((b) => setTimeout(b, 1e3)), s && console.warn("Start loading (delayed) " + p, x.guid));
439
439
  let k = p;
440
440
  if (x && Array.isArray(x.lods)) {
441
- const A = x.lods[t];
442
- A.hash && (k += "?v=" + A.hash);
441
+ const b = x.lods[t];
442
+ b.hash && (k += "?v=" + b.hash);
443
443
  }
444
- const S = await F.loadAsync(k).catch((A) => (console.error(`Error loading LOD ${t} from ${p}
445
- `, A), null));
446
- if (!S)
444
+ const A = await F.loadAsync(k).catch((b) => (console.error(`Error loading LOD ${t} from ${p}
445
+ `, b), null));
446
+ if (!A)
447
447
  return null;
448
- const q = S.parser;
448
+ const N = A.parser;
449
449
  s && console.log("Loading finished " + p, x.guid);
450
- let T = 0;
451
- if (S.parser.json.textures) {
452
- let A = !1;
453
- for (const f of S.parser.json.textures) {
450
+ let S = 0;
451
+ if (A.parser.json.textures) {
452
+ let b = !1;
453
+ for (const f of A.parser.json.textures) {
454
454
  if (f != null && f.extensions) {
455
- const y = f == null ? void 0 : f.extensions[z];
455
+ const y = f == null ? void 0 : f.extensions[V];
456
456
  if (y != null && y.guid && y.guid === x.guid) {
457
- A = !0;
457
+ b = !0;
458
458
  break;
459
459
  }
460
460
  }
461
- T++;
461
+ S++;
462
462
  }
463
- if (A) {
464
- let f = await q.getDependency("texture", T);
465
- return f && v.assignLODInformation(n.url, f, r, t, void 0, void 0), s && console.log('change "' + e.name + '" → "' + f.name + '"', p, T, f, M), e instanceof se && (f = this.copySettings(e, f)), f && (f.guid = x.guid), h(f);
463
+ if (b) {
464
+ let f = await N.getDependency("texture", S);
465
+ return f && v.assignLODInformation(n.url, f, r, t, void 0, void 0), s && console.log('change "' + e.name + '" → "' + f.name + '"', p, S, f, D), e instanceof se && (f = this.copySettings(e, f)), f && (f.guid = x.guid), h(f);
466
466
  } else
467
- L && console.warn("Could not find texture with guid", x.guid, S.parser.json);
467
+ L && console.warn("Could not find texture with guid", x.guid, A.parser.json);
468
468
  }
469
- if (T = 0, S.parser.json.meshes) {
470
- let A = !1;
471
- for (const f of S.parser.json.meshes) {
469
+ if (S = 0, A.parser.json.meshes) {
470
+ let b = !1;
471
+ for (const f of A.parser.json.meshes) {
472
472
  if (f != null && f.extensions) {
473
- const y = f == null ? void 0 : f.extensions[z];
473
+ const y = f == null ? void 0 : f.extensions[V];
474
474
  if (y != null && y.guid && y.guid === x.guid) {
475
- A = !0;
475
+ b = !0;
476
476
  break;
477
477
  }
478
478
  }
479
- T++;
479
+ S++;
480
480
  }
481
- if (A) {
482
- const f = await q.getDependency("mesh", T), y = x;
483
- if (s && console.log(`Loaded Mesh "${f.name}"`, p, T, f, M), f.isMesh === !0) {
481
+ if (b) {
482
+ const f = await N.getDependency("mesh", S), y = x;
483
+ if (s && console.log(`Loaded Mesh "${f.name}"`, p, S, f, D), f.isMesh === !0) {
484
484
  const O = f.geometry;
485
485
  return v.assignLODInformation(n.url, O, r, t, void 0, y.density), h(O);
486
486
  } else {
487
487
  const O = new Array();
488
- for (let b = 0; b < f.children.length; b++) {
489
- const E = f.children[b];
490
- if (E.isMesh === !0) {
491
- const X = E.geometry;
492
- v.assignLODInformation(n.url, X, r, t, b, y.density), O.push(X);
488
+ for (let T = 0; T < f.children.length; T++) {
489
+ const P = f.children[T];
490
+ if (P.isMesh === !0) {
491
+ const X = P.geometry;
492
+ v.assignLODInformation(n.url, X, r, t, T, y.density), O.push(X);
493
493
  }
494
494
  }
495
495
  return h(O);
496
496
  }
497
497
  } else
498
- L && console.warn("Could not find mesh with guid", x.guid, S.parser.json);
498
+ L && console.warn("Could not find mesh with guid", x.guid, A.parser.json);
499
499
  }
500
500
  return h(null);
501
501
  });
502
- return this.previouslyLoaded.set(M, $), await $;
502
+ return this.previouslyLoaded.set(D, $), await $;
503
503
  } else if (e instanceof se) {
504
504
  s && console.log("Load texture from uri: " + p);
505
505
  const w = await new Ke().loadAsync(p);
@@ -573,8 +573,8 @@ class ut {
573
573
  }
574
574
  }
575
575
  const I = le("debugprogressive"), ft = le("noprogressive"), we = Symbol("Needle:LODSManager"), ve = Symbol("Needle:LODState"), Z = Symbol("Needle:CurrentLOD"), G = { mesh_lod: -1, texture_lod: -1 };
576
- var C, V, ye, j, ee, me, W;
577
- const P = class {
576
+ var C, W, ye, j, ee, me, q;
577
+ const E = class {
578
578
  // readonly plugins: NEEDLE_progressive_plugin[] = [];
579
579
  constructor(e, t) {
580
580
  d(this, "context");
@@ -603,21 +603,21 @@ const P = class {
603
603
  */
604
604
  d(this, "manual", !1);
605
605
  d(this, "_lodchangedlisteners", []);
606
- K(this, V, void 0);
606
+ K(this, W, void 0);
607
607
  K(this, ye, new Ye());
608
608
  K(this, j, 0);
609
609
  K(this, ee, 0);
610
610
  K(this, me, 0);
611
- K(this, W, 0);
611
+ K(this, q, 0);
612
612
  d(this, "_fpsBuffer", [60, 60, 60, 60, 60]);
613
613
  // private testIfLODLevelsAreAvailable() {
614
614
  d(this, "_sphere", new Je());
615
- d(this, "_tempBox", new Ee());
616
- d(this, "_tempBox2", new Ee());
615
+ d(this, "_tempBox", new Pe());
616
+ d(this, "_tempBox2", new Pe());
617
617
  d(this, "tempMatrix", new Ae());
618
- d(this, "_tempWorldPosition", new N());
619
- d(this, "_tempBoxSize", new N());
620
- d(this, "_tempBox2Size", new N());
618
+ d(this, "_tempWorldPosition", new z());
619
+ d(this, "_tempBoxSize", new z());
620
+ d(this, "_tempBox2Size", new z());
621
621
  this.renderer = e, this.context = { ...t };
622
622
  }
623
623
  /** @internal */
@@ -639,7 +639,7 @@ const P = class {
639
639
  static get(e, t) {
640
640
  if (e[we])
641
641
  return console.debug("[gltf-progressive] LODsManager already exists for this renderer"), e[we];
642
- const s = new P(e, {
642
+ const s = new E(e, {
643
643
  engine: "unknown",
644
644
  ...t
645
645
  });
@@ -662,21 +662,21 @@ const P = class {
662
662
  * Enable the LODsManager. This will replace the render method of the renderer with a method that updates the LODs.
663
663
  */
664
664
  enable() {
665
- if (m(this, V))
665
+ if (m(this, W))
666
666
  return;
667
667
  console.debug("[gltf-progressive] Enabling LODsManager for renderer");
668
668
  let e = 0;
669
- U(this, V, this.renderer.render);
669
+ U(this, W, this.renderer.render);
670
670
  const t = this;
671
671
  Ge(this.renderer), this.renderer.render = function(s, n) {
672
672
  const r = t.renderer.getRenderTarget();
673
- (r == null || "isXRRenderTarget" in r && r.isXRRenderTarget) && (e = 0, U(t, j, m(t, j) + 1), U(t, ee, m(t, ye).getDelta()), U(t, me, m(t, me) + m(t, ee)), t._fpsBuffer.shift(), t._fpsBuffer.push(1 / m(t, ee)), U(t, W, t._fpsBuffer.reduce((a, l) => a + l) / t._fpsBuffer.length), I && m(t, j) % 200 === 0 && console.log("FPS", Math.round(m(t, W)), "Interval:", m(t, C)));
673
+ (r == null || "isXRRenderTarget" in r && r.isXRRenderTarget) && (e = 0, U(t, j, m(t, j) + 1), U(t, ee, m(t, ye).getDelta()), U(t, me, m(t, me) + m(t, ee)), t._fpsBuffer.shift(), t._fpsBuffer.push(1 / m(t, ee)), U(t, q, t._fpsBuffer.reduce((a, l) => a + l) / t._fpsBuffer.length), I && m(t, j) % 200 === 0 && console.log("FPS", Math.round(m(t, q)), "Interval:", m(t, C)));
674
674
  const i = e++;
675
- m(t, V).call(this, s, n), t.onAfterRender(s, n, i);
675
+ m(t, W).call(this, s, n), t.onAfterRender(s, n, i);
676
676
  };
677
677
  }
678
678
  disable() {
679
- m(this, V) && (console.debug("[gltf-progressive] Disabling LODsManager for renderer"), this.renderer.render = m(this, V), U(this, V, void 0));
679
+ m(this, W) && (console.debug("[gltf-progressive] Disabling LODsManager for renderer"), this.renderer.render = m(this, W), U(this, W, void 0));
680
680
  }
681
681
  update(e, t) {
682
682
  this.internalUpdate(e, t);
@@ -691,7 +691,7 @@ const P = class {
691
691
  (a.name === "EffectMaterial" || a.name === "CopyShader") && (i = !1);
692
692
  }
693
693
  if ((t.parent && t.parent.type === "CubeCamera" || s >= 1 && t.type === "OrthographicCamera") && (i = !1), i) {
694
- if (ft || (this.updateInterval === "auto" ? m(this, W) < 40 && m(this, C) < 10 ? (U(this, C, m(this, C) + 1), I && console.warn("↓ Reducing LOD updates", m(this, C), m(this, W).toFixed(0))) : m(this, W) >= 60 && m(this, C) > 1 && (U(this, C, m(this, C) - 1), I && console.warn("↑ Increasing LOD updates", m(this, C), m(this, W).toFixed(0))) : U(this, C, this.updateInterval), m(this, C) > 0 && m(this, j) % m(this, C) != 0))
694
+ if (ft || (this.updateInterval === "auto" ? m(this, q) < 40 && m(this, C) < 10 ? (U(this, C, m(this, C) + 1), I && console.warn("↓ Reducing LOD updates", m(this, C), m(this, q).toFixed(0))) : m(this, q) >= 60 && m(this, C) > 1 && (U(this, C, m(this, C) - 1), I && console.warn("↑ Increasing LOD updates", m(this, C), m(this, q).toFixed(0))) : U(this, C, this.updateInterval), m(this, C) > 0 && m(this, j) % m(this, C) != 0))
695
695
  return;
696
696
  this.internalUpdate(e, t);
697
697
  }
@@ -720,8 +720,8 @@ const P = class {
720
720
  }
721
721
  if (I === "color" && c.material && !c.object.progressive_debug_color) {
722
722
  c.object.progressive_debug_color = !0;
723
- const p = Math.random() * 16777215, M = new He({ color: p });
724
- c.object.material = M;
723
+ const p = Math.random() * 16777215, D = new He({ color: p });
724
+ c.object.material = D;
725
725
  }
726
726
  const g = c.object;
727
727
  (g instanceof Q || g.isMesh) && this.updateLODs(e, t, g, r);
@@ -807,8 +807,8 @@ const P = class {
807
807
  let a = 10 + 1, l = !1;
808
808
  if (I && t["DEBUG:LOD"] != null)
809
809
  return t["DEBUG:LOD"];
810
- const u = _.getMeshLODInformation(t.geometry), c = u == null ? void 0 : u.lods, g = c && c.length > 0, p = _.getMaterialMinMaxLODsCount(t.material), M = (p == null ? void 0 : p.min_count) != 1 / 0 && p.min_count > 0 && p.max_count > 0;
811
- if (!g && !M) {
810
+ const u = _.getMeshLODInformation(t.geometry), c = u == null ? void 0 : u.lods, g = c && c.length > 0, p = _.getMaterialMinMaxLODsCount(t.material), D = (p == null ? void 0 : p.min_count) != 1 / 0 && p.min_count > 0 && p.max_count > 0;
811
+ if (!g && !D) {
812
812
  r.mesh_lod = 0, r.texture_lod = 0;
813
813
  return;
814
814
  }
@@ -816,17 +816,17 @@ const P = class {
816
816
  const w = this.renderer.domElement.clientHeight || this.renderer.domElement.height;
817
817
  let x = t.geometry.boundingBox;
818
818
  if (t.type === "SkinnedMesh") {
819
- const D = t;
820
- if (!D.boundingBox)
821
- D.computeBoundingBox();
819
+ const M = t;
820
+ if (!M.boundingBox)
821
+ M.computeBoundingBox();
822
822
  else if (s.frames % 30 === 0) {
823
- const h = ce(D), R = D.geometry;
824
- h && (D.geometry = h), D.computeBoundingBox(), D.geometry = R;
823
+ const h = ce(M), R = M.geometry;
824
+ h && (M.geometry = h), M.computeBoundingBox(), M.geometry = R;
825
825
  }
826
- x = D.boundingBox;
826
+ x = M.boundingBox;
827
827
  }
828
- if (x && e.isPerspectiveCamera) {
829
- const D = e;
828
+ if (x) {
829
+ const M = e;
830
830
  if (t.geometry.attributes.color && t.geometry.attributes.color.count < 100 && t.geometry.boundingSphere) {
831
831
  this._sphere.copy(t.geometry.boundingSphere), this._sphere.applyMatrix4(t.matrixWorld);
832
832
  const f = e.getWorldPosition(this._tempWorldPosition);
@@ -835,48 +835,48 @@ const P = class {
835
835
  return;
836
836
  }
837
837
  }
838
- if (this._tempBox.copy(x), this._tempBox.applyMatrix4(t.matrixWorld), P.isInside(this._tempBox, this.projectionScreenMatrix)) {
838
+ if (this._tempBox.copy(x), this._tempBox.applyMatrix4(t.matrixWorld), M.isPerspectiveCamera && E.isInside(this._tempBox, this.projectionScreenMatrix)) {
839
839
  r.mesh_lod = 0, r.texture_lod = 0;
840
840
  return;
841
841
  }
842
- if (this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled && D.fov > 70) {
842
+ if (this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled && M.isPerspectiveCamera && M.fov > 70) {
843
843
  const f = this._tempBox.min, y = this._tempBox.max;
844
- let O = f.x, b = f.y, E = y.x, X = y.y;
844
+ let O = f.x, T = f.y, P = y.x, X = y.y;
845
845
  const ue = 2, Le = 1.5, fe = (f.x + y.x) * 0.5, de = (f.y + y.y) * 0.5;
846
- O = (O - fe) * ue + fe, b = (b - de) * ue + de, E = (E - fe) * ue + fe, X = (X - de) * ue + de;
847
- const ze = O < 0 && E > 0 ? 0 : Math.min(Math.abs(f.x), Math.abs(y.x)), Ve = b < 0 && X > 0 ? 0 : Math.min(Math.abs(f.y), Math.abs(y.y)), xe = Math.max(ze, Ve);
846
+ O = (O - fe) * ue + fe, T = (T - de) * ue + de, P = (P - fe) * ue + fe, X = (X - de) * ue + de;
847
+ const ze = O < 0 && P > 0 ? 0 : Math.min(Math.abs(f.x), Math.abs(y.x)), Ve = T < 0 && X > 0 ? 0 : Math.min(Math.abs(f.y), Math.abs(y.y)), xe = Math.max(ze, Ve);
848
848
  s.lastCentrality = (Le - xe) * (Le - xe) * (Le - xe);
849
849
  } else
850
850
  s.lastCentrality = 1;
851
851
  const h = this._tempBox.getSize(this._tempBoxSize);
852
- h.multiplyScalar(0.5), screen.availHeight > 0 && w > 0 && h.multiplyScalar(w / screen.availHeight), h.x *= D.aspect;
852
+ h.multiplyScalar(0.5), screen.availHeight > 0 && w > 0 && h.multiplyScalar(w / screen.availHeight), e.isPerspectiveCamera ? h.x *= e.aspect : e.isOrthographicCamera;
853
853
  const R = e.matrixWorldInverse, F = this._tempBox2;
854
854
  F.copy(x), F.applyMatrix4(t.matrixWorld), F.applyMatrix4(R);
855
- const k = F.getSize(this._tempBox2Size), S = Math.max(k.x, k.y);
856
- if (Math.max(h.x, h.y) != 0 && S != 0 && (h.z = k.z / Math.max(k.x, k.y) * Math.max(h.x, h.y)), s.lastScreenCoverage = Math.max(h.x, h.y, h.z), s.lastScreenspaceVolume.copy(h), s.lastScreenCoverage *= s.lastCentrality, I && P.debugDrawLine) {
855
+ const k = F.getSize(this._tempBox2Size), A = Math.max(k.x, k.y);
856
+ if (Math.max(h.x, h.y) != 0 && A != 0 && (h.z = k.z / Math.max(k.x, k.y) * Math.max(h.x, h.y)), s.lastScreenCoverage = Math.max(h.x, h.y, h.z), s.lastScreenspaceVolume.copy(h), s.lastScreenCoverage *= s.lastCentrality, I && E.debugDrawLine) {
857
857
  const f = this.tempMatrix.copy(this.projectionScreenMatrix);
858
858
  f.invert();
859
- const y = P.corner0, O = P.corner1, b = P.corner2, E = P.corner3;
860
- y.copy(this._tempBox.min), O.copy(this._tempBox.max), O.x = y.x, b.copy(this._tempBox.max), b.y = y.y, E.copy(this._tempBox.max);
861
- const X = (y.z + E.z) * 0.5;
862
- y.z = O.z = b.z = E.z = X, y.applyMatrix4(f), O.applyMatrix4(f), b.applyMatrix4(f), E.applyMatrix4(f), P.debugDrawLine(y, O, 255), P.debugDrawLine(y, b, 255), P.debugDrawLine(O, E, 255), P.debugDrawLine(b, E, 255);
859
+ const y = E.corner0, O = E.corner1, T = E.corner2, P = E.corner3;
860
+ y.copy(this._tempBox.min), O.copy(this._tempBox.max), O.x = y.x, T.copy(this._tempBox.max), T.y = y.y, P.copy(this._tempBox.max);
861
+ const X = (y.z + P.z) * 0.5;
862
+ y.z = O.z = T.z = P.z = X, y.applyMatrix4(f), O.applyMatrix4(f), T.applyMatrix4(f), P.applyMatrix4(f), E.debugDrawLine(y, O, 255), E.debugDrawLine(y, T, 255), E.debugDrawLine(O, P, 255), E.debugDrawLine(T, P, 255);
863
863
  }
864
- let T = 999;
864
+ let S = 999;
865
865
  if (c && s.lastScreenCoverage > 0) {
866
866
  for (let f = 0; f < c.length; f++)
867
867
  if (c[f].density / s.lastScreenCoverage < n) {
868
- T = f;
868
+ S = f;
869
869
  break;
870
870
  }
871
871
  }
872
- T < a && (a = T, l = !0);
872
+ S < a && (a = S, l = !0);
873
873
  }
874
874
  if (l ? r.mesh_lod = a : r.mesh_lod = s.lastLodLevel_Mesh, I && r.mesh_lod != s.lastLodLevel_Mesh) {
875
875
  const h = c == null ? void 0 : c[r.mesh_lod];
876
876
  h && console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} → ${r.mesh_lod} (${h.density.toFixed(0)}) - ${t.name}`);
877
877
  }
878
- if (M) {
879
- const D = "saveData" in globalThis.navigator && globalThis.navigator.saveData === !0;
878
+ if (D) {
879
+ const M = "saveData" in globalThis.navigator && globalThis.navigator.saveData === !0;
880
880
  if (s.lastLodLevel_Texture < 0) {
881
881
  if (r.texture_lod = p.max_count - 1, I) {
882
882
  const h = p.lods[p.max_count - 1];
@@ -887,12 +887,13 @@ const P = class {
887
887
  let R = s.lastScreenCoverage * 4;
888
888
  (($ = this.context) == null ? void 0 : $.engine) === "model-viewer" && (R *= 1.5);
889
889
  const k = w / window.devicePixelRatio * R;
890
- for (let S = p.lods.length - 1; S >= 0; S--) {
891
- let q = p.lods[S];
892
- if (!(D && q.max_height >= 2048) && !(nt() && q.max_height > 4096) && q.max_height > k) {
893
- if (r.texture_lod = S, r.texture_lod < s.lastLodLevel_Texture) {
894
- const T = q.max_height;
895
- I && console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${r.texture_lod} = ${T}px
890
+ let A = !1;
891
+ for (let N = p.lods.length - 1; N >= 0; N--) {
892
+ let S = p.lods[N];
893
+ if (!(M && S.max_height >= 2048) && !(nt() && S.max_height > 4096) && (S.max_height > k || !A && N === 0)) {
894
+ if (A = !0, r.texture_lod = N, r.texture_lod < s.lastLodLevel_Texture) {
895
+ const b = S.max_height;
896
+ I && console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${r.texture_lod} = ${b}px
896
897
  Screensize: ${k.toFixed(0)}px, Coverage: ${(100 * s.lastScreenCoverage).toFixed(2)}%, Volume ${h.toFixed(1)}
897
898
  ${t.name}`);
898
899
  }
@@ -904,17 +905,17 @@ ${t.name}`);
904
905
  r.texture_lod = 0;
905
906
  }
906
907
  };
907
- let B = P;
908
- C = new WeakMap(), V = new WeakMap(), ye = new WeakMap(), j = new WeakMap(), ee = new WeakMap(), me = new WeakMap(), W = new WeakMap(), /** Assign a function to draw debug lines for the LODs. This function will be called with the start and end position of the line and the color of the line when the `debugprogressive` query parameter is set.
908
+ let B = E;
909
+ C = new WeakMap(), W = new WeakMap(), ye = new WeakMap(), j = new WeakMap(), ee = new WeakMap(), me = new WeakMap(), q = new WeakMap(), /** Assign a function to draw debug lines for the LODs. This function will be called with the start and end position of the line and the color of the line when the `debugprogressive` query parameter is set.
909
910
  */
910
- d(B, "debugDrawLine"), d(B, "corner0", new N()), d(B, "corner1", new N()), d(B, "corner2", new N()), d(B, "corner3", new N()), d(B, "_tempPtInside", new N());
911
+ d(B, "debugDrawLine"), d(B, "corner0", new z()), d(B, "corner1", new z()), d(B, "corner2", new z()), d(B, "corner3", new z()), d(B, "_tempPtInside", new z());
911
912
  class dt {
912
913
  constructor() {
913
914
  d(this, "frames", 0);
914
915
  d(this, "lastLodLevel_Mesh", -1);
915
916
  d(this, "lastLodLevel_Texture", -1);
916
917
  d(this, "lastScreenCoverage", 0);
917
- d(this, "lastScreenspaceVolume", new N());
918
+ d(this, "lastScreenspaceVolume", new z());
918
919
  d(this, "lastCentrality", 0);
919
920
  }
920
921
  }
@@ -1016,19 +1017,19 @@ class pt {
1016
1017
  return;
1017
1018
  l[he] = !0, l.userData && (l.userData.LOD = -1);
1018
1019
  const u = Object.keys(l);
1019
- for (let M = 0; M < u.length; M++) {
1020
- const w = u[M], x = l[w];
1020
+ for (let D = 0; D < u.length; D++) {
1021
+ const w = u[D], x = l[w];
1021
1022
  if ((x == null ? void 0 : x.isTexture) === !0) {
1022
1023
  const $ = (g = (c = x.userData) == null ? void 0 : c.associations) == null ? void 0 : g.textures;
1023
1024
  if ($ == null)
1024
1025
  continue;
1025
- const D = s.parser.json.textures[$];
1026
- if (!D) {
1026
+ const M = s.parser.json.textures[$];
1027
+ if (!M) {
1027
1028
  console.warn("Texture data not found for texture index " + $);
1028
1029
  continue;
1029
1030
  }
1030
- if ((p = D == null ? void 0 : D.extensions) != null && p[z]) {
1031
- const h = D.extensions[z];
1031
+ if ((p = M == null ? void 0 : M.extensions) != null && p[V]) {
1032
+ const h = M.extensions[V];
1032
1033
  h && r && _.registerTexture(r, x, h.lods.length, $, h);
1033
1034
  }
1034
1035
  }
@@ -1050,7 +1051,7 @@ class pt {
1050
1051
  const s = this.tryGetCurrentModelViewer(e), n = this.getUrl(s);
1051
1052
  if (!n)
1052
1053
  return;
1053
- const r = (a = (i = t.userData) == null ? void 0 : i.gltfExtensions) == null ? void 0 : a[z];
1054
+ const r = (a = (i = t.userData) == null ? void 0 : i.gltfExtensions) == null ? void 0 : a[V];
1054
1055
  if (r && n) {
1055
1056
  const l = t.uuid;
1056
1057
  _.registerMesh(n, l, t, 0, r.lods.length, r);
@@ -1083,7 +1084,7 @@ if (!ot) {
1083
1084
  globalThis.Needle[e] = o[e];
1084
1085
  }
1085
1086
  export {
1086
- z as EXTENSION_NAME,
1087
+ V as EXTENSION_NAME,
1087
1088
  B as LODsManager,
1088
1089
  _ as NEEDLE_progressive,
1089
1090
  ke as VERSION,
@@ -1,8 +1,8 @@
1
- var Ue=Object.defineProperty,ze=(t,e,s)=>e in t?Ue(t,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):t[e]=s,c=(t,e,s)=>(ze(t,typeof e!="symbol"?e+"":e,s),s),Te=(t,e,s)=>{if(!e.has(t))throw TypeError("Cannot "+s)},v=(t,e,s)=>(Te(t,e,"read from private field"),s?s.call(t):e.get(t)),V=(t,e,s)=>{if(e.has(t))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(t):e.set(t,s)},G=(t,e,s,o)=>(Te(t,e,"write to private field"),o?o.call(t,s):e.set(t,s),s);import{BufferGeometry as le,Mesh as q,Material as Ve,Texture as ee,TextureLoader as qe,Matrix4 as Ee,Clock as Xe,MeshStandardMaterial as He,Sphere as Ke,Box3 as Ae,Vector3 as N}from"three";import{GLTFLoader as me}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as Ye}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as Je}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as Qe}from"three/examples/jsm/loaders/KTX2Loader.js";const pe="";globalThis.GLTF_PROGRESSIVE_VERSION=pe,console.debug(`[gltf-progressive] version ${pe}`);let Y="https://www.gstatic.com/draco/versioned/decoders/1.5.7/",te="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";const Ze=Y,et=te,tt=new URL(Y+"draco_decoder.js");fetch(tt,{method:"GET",headers:{Range:"bytes=0-1"}}).catch(t=>{Y===Ze&&(Y="./include/draco/"),te===et&&(te="./include/ktx2/")}).finally(()=>{Ie()});function st(t){Y=t}function rt(t){te=t}let X,ue,H;function Ie(){X||(X=new Je,X.setDecoderPath(Y),X.setDecoderConfig({type:"js"}),X.preload()),H||(H=new Qe,H.setTranscoderPath(te),H.init()),ue||(ue=Ye)}function ye(t){return Ie(),t?H.detectSupport(t):t!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:X,ktx2Loader:H,meshoptDecoder:ue}}function ve(t){t.dracoLoader||t.setDRACOLoader(X),t.ktx2Loader||t.setKTX2Loader(H),t.meshoptDecoder||t.setMeshoptDecoder(ue)}const xe=new WeakMap;function Le(t,e){let s=xe.get(t);s?s=Object.assign(s,e):s=e,xe.set(t,s)}const Pe=me.prototype.load;function nt(...t){const e=xe.get(this);let s=t[0];const o=new URL(s,window.location.href);if(o.hostname.endsWith("needle.tools")){const r=e?.progressive!==void 0?e.progressive:!0,n=e!=null&&e.usecase?e.usecase:"default";r?this.requestHeader.Accept=`*/*;progressive=allowed;usecase=${n}`:this.requestHeader.Accept=`*/*;usecase=${n}`,s=o.toString()}return t[0]=s,Pe?.call(this,...t)}me.prototype.load=nt,se("debugprogressive");function se(t){if(typeof window>"u")return!1;const e=new URL(window.location.href).searchParams.get(t);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function ot(t,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||t===void 0)return e;const s=t.lastIndexOf("/");if(s>=0){const o=t.substring(0,s+1);for(;o.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return o+e}return e}let ce;function it(){return ce!==void 0||(ce=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),se("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",ce)),ce}const at=typeof window>"u"&&typeof document>"u",Me=Symbol("needle:raycast-mesh");function J(t){return t?.[Me]instanceof le?t[Me]:null}function ke(t,e){if((t.type==="Mesh"||t.type==="SkinnedMesh")&&!J(t)){const s=lt(e);s.userData={isRaycastMesh:!0},t[Me]=s}}function Be(t=!0){if(t){if(re)return;const e=re=q.prototype.raycast;q.prototype.raycast=function(s,o){const r=this,n=J(r);let i;n&&r.isMesh&&(i=r.geometry,r.geometry=n),e.call(this,s,o),i&&(r.geometry=i)}}else{if(!re)return;q.prototype.raycast=re,re=null}}let re=null;function lt(t){const e=new le;for(const s in t.attributes)e.setAttribute(s,t.getAttribute(s));return e.setIndex(t.getIndex()),e}const $=new Array,j="NEEDLE_progressive",x=se("debugprogressive"),De=Symbol("needle-progressive-texture"),ne=new Map,we=new Set;if(x){let t=function(){e+=1,console.log("Toggle LOD level",e,ne),ne.forEach((r,n)=>{for(const i of r.keys){const l=n[i];if(l!=null){if(l.isBufferGeometry===!0){const u=S.getMeshLODInformation(l),a=u?Math.min(e,u.lods.length):0;n["DEBUG:LOD"]=e,S.assignMeshLOD(n,a),u&&(s=Math.max(s,u.lods.length-1))}else if(n.isMaterial===!0){n["DEBUG:LOD"]=e,S.assignTextureLOD(n,e);break}}}}),e>=s&&(e=-1)},e=-1,s=2,o=!1;window.addEventListener("keyup",r=>{r.key==="p"&&t(),r.key==="w"&&(o=!o,we&&we.forEach(n=>{n.name!="BackgroundCubeMaterial"&&n.glyphMap==null&&"wireframe"in n&&(n.wireframe=o)}))})}function Re(t,e,s){var o;if(!x)return;ne.has(t)||ne.set(t,{keys:[],sourceId:s});const r=ne.get(t);((o=r?.keys)==null?void 0:o.includes(e))==!1&&r.keys.push(e)}const w=class{constructor(t,e){c(this,"parser"),c(this,"url"),c(this,"_isLoadingMesh"),c(this,"loadMesh",s=>{var o,r;if(this._isLoadingMesh)return null;const n=(r=(o=this.parser.json.meshes[s])==null?void 0:o.extensions)==null?void 0:r[j];return n?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",s).then(i=>{var l;return this._isLoadingMesh=!1,i&&w.registerMesh(this.url,n.guid,i,(l=n.lods)==null?void 0:l.length,void 0,n),i})):null}),x&&console.log("Progressive extension registered for",e),this.parser=t,this.url=e}get name(){return j}static getMeshLODInformation(t){const e=this.getAssignedLODInformation(t);return e!=null&&e.key?this.lodInfos.get(e.key):null}static getMaterialMinMaxLODsCount(t,e){const s=this,o="LODS:minmax",r=t[o];if(r!=null)return r;if(e||(e={min_count:1/0,max_count:0,lods:[]}),Array.isArray(t)){for(const i of t)this.getMaterialMinMaxLODsCount(i,e);return t[o]=e,e}if(x==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const i=t;for(const l of Object.keys(i.uniforms)){const u=i.uniforms[l].value;u?.isTexture===!0&&n(u,e)}}else if(t.isMaterial)for(const i of Object.keys(t)){const l=t[i];l?.isTexture===!0&&n(l,e)}return t[o]=e,e;function n(i,l){const u=s.getAssignedLODInformation(i);if(u){const a=s.lodInfos.get(u.key);if(a&&a.lods){l.min_count=Math.min(l.min_count,a.lods.length),l.max_count=Math.max(l.max_count,a.lods.length);for(let f=0;f<a.lods.length;f++){const g=a.lods[f];g.width&&(l.lods[f]=l.lods[f]||{min_height:1/0,max_height:0},l.lods[f].min_height=Math.min(l.lods[f].min_height,g.height),l.lods[f].max_height=Math.max(l.lods[f].max_height,g.height))}}}}}static hasLODLevelAvailable(t,e){var s;if(Array.isArray(t)){for(const n of t)if(this.hasLODLevelAvailable(n,e))return!0;return!1}if(t.isMaterial===!0){for(const n of Object.keys(t)){const i=t[n];if(i&&i.isTexture&&this.hasLODLevelAvailable(i,e))return!0}return!1}else if(t.isGroup===!0){for(const n of t.children)if(n.isMesh===!0&&this.hasLODLevelAvailable(n,e))return!0}let o,r;if(t.isMesh?o=t.geometry:(t.isBufferGeometry||t.isTexture)&&(o=t),o&&(s=o?.userData)!=null&&s.LODS){const n=o.userData.LODS;if(r=this.lodInfos.get(n.key),e===void 0)return r!=null;if(r)return Array.isArray(r.lods)?e<r.lods.length:e===0}return!1}static assignMeshLOD(t,e){var s;if(!t)return Promise.resolve(null);if(t instanceof q||t.isMesh===!0){const o=t.geometry,r=this.getAssignedLODInformation(o);if(!r)return Promise.resolve(null);for(const n of $)(s=n.onBeforeGetLODMesh)==null||s.call(n,t,e);return t["LOD:requested level"]=e,w.getOrLoadLOD(o,e).then(n=>{if(Array.isArray(n)){const i=r.index||0;n=n[i]}return t["LOD:requested level"]===e&&(delete t["LOD:requested level"],n&&o!=n&&(n?.isBufferGeometry?(t.geometry=n,x&&Re(t,"geometry",r.url)):x&&console.error("Invalid LOD geometry",n))),n}).catch(n=>(console.error("Error loading mesh LOD",t,n),null))}else x&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",t);return Promise.resolve(null)}static assignTextureLOD(t,e=0){if(!t)return Promise.resolve(null);if(t.isMesh===!0){const s=t;if(Array.isArray(s.material)){const o=new Array;for(const r of s.material){const n=this.assignTextureLOD(r,e);o.push(n)}return Promise.all(o).then(r=>{const n=new Array;for(const i of r)Array.isArray(i)&&n.push(...i);return n})}else return this.assignTextureLOD(s.material,e)}if(t instanceof Ve||t.isMaterial===!0){const s=t,o=[],r=new Array;if(x&&we.add(s),s.uniforms&&(s.isRawShaderMaterial||s.isShaderMaterial===!0)){const n=s;for(const i of Object.keys(n.uniforms)){const l=n.uniforms[i].value;if(l?.isTexture===!0){const u=this.assignTextureLODForSlot(l,e,s,i).then(a=>(a&&n.uniforms[i].value!=a&&(n.uniforms[i].value=a,n.uniformsNeedUpdate=!0),a));o.push(u),r.push(i)}}}else for(const n of Object.keys(s)){const i=s[n];if(i?.isTexture===!0){const l=this.assignTextureLODForSlot(i,e,s,n);o.push(l),r.push(n)}}return Promise.all(o).then(n=>{const i=new Array;for(let l=0;l<n.length;l++){const u=n[l],a=r[l];u&&u.isTexture===!0?i.push({material:s,slot:a,texture:u,level:e}):i.push({material:s,slot:a,texture:null,level:e})}return i})}if(t instanceof ee||t.isTexture===!0){const s=t;return this.assignTextureLODForSlot(s,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,s,o){return t?.isTexture!==!0?Promise.resolve(null):o==="glyphMap"?Promise.resolve(t):w.getOrLoadLOD(t,e).then(r=>{if(Array.isArray(r))return null;if(r?.isTexture===!0){if(r!=t){if(s&&o){const n=s[o];if(n){const i=this.getAssignedLODInformation(n);if(i&&i?.level<e)return x==="verbose"&&console.warn("Assigned texture level is already higher: ",i.level,e,s,n,r),null}s[o]=r}if(x&&o&&s){const n=this.getAssignedLODInformation(t);n&&Re(s,o,n.url)}}return r}else x=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(r=>(console.error("Error loading LOD",t,r),null))}afterRoot(t){var e,s;return x&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((o,r)=>{var n;if(o!=null&&o.extensions){const i=o?.extensions[j];if(i){if(!i.lods){x&&console.warn("Texture has no LODs",i);return}let l=!1;for(const u of this.parser.associations.keys())if(u.isTexture===!0){const a=this.parser.associations.get(u);a?.textures===r&&(l=!0,w.registerTexture(this.url,u,(n=i.lods)==null?void 0:n.length,r,i))}l||this.parser.getDependency("texture",r).then(u=>{var a;u&&w.registerTexture(this.url,u,(a=i.lods)==null?void 0:a.length,r,i)})}}}),(s=this.parser.json.meshes)==null||s.forEach((o,r)=>{if(o!=null&&o.extensions){const n=o?.extensions[j];if(n&&n.lods){for(const i of this.parser.associations.keys())if(i.isMesh){const l=this.parser.associations.get(i);l?.meshes===r&&w.registerMesh(this.url,n.guid,i,n.lods.length,l.primitives,n)}}}}),null}static async getOrLoadLOD(t,e){var s,o,r,n;const i=x=="verbose",l=t.userData.LODS;if(!l)return null;const u=l?.key;let a;if(t.isTexture===!0){const f=t;f.source&&f.source[De]&&(a=f.source[De])}if(a||(a=w.lodInfos.get(u)),a){if(e>0){let p=!1;const A=Array.isArray(a.lods);if(A&&e>=a.lods.length?p=!0:A||(p=!0),p)return this.lowresCache.get(u)}const f=Array.isArray(a.lods)?(s=a.lods[e])==null?void 0:s.path:a.lods;if(!f)return x&&!a["missing:uri"]&&(a["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,a)),null;const g=ot(l.url,f);if(g.endsWith(".glb")||g.endsWith(".gltf")){if(!a.guid)return console.warn("missing pointer for glb/gltf texture",a),null;const p=g+"_"+a.guid,A=this.previouslyLoaded.get(p);if(A!==void 0){i&&console.log(`LOD ${e} was already loading/loaded: ${p}`);let d=await A.catch(b=>(console.error(`Error loading LOD ${e} from ${g}
2
- `,b),null)),O=!1;if(d==null||(d instanceof ee&&t instanceof ee?(o=d.image)!=null&&o.data||(r=d.source)!=null&&r.data?d=this.copySettings(t,d):(O=!0,this.previouslyLoaded.delete(p)):d instanceof le&&t instanceof le&&((n=d.attributes.position)!=null&&n.array||(O=!0,this.previouslyLoaded.delete(p)))),!O)return d}const D=a,L=new Promise(async(d,O)=>{const b=new me;ve(b),x&&(await new Promise(m=>setTimeout(m,1e3)),i&&console.warn("Start loading (delayed) "+g,D.guid));let I=g;if(D&&Array.isArray(D.lods)){const m=D.lods[e];m.hash&&(I+="?v="+m.hash)}const T=await b.loadAsync(I).catch(m=>(console.error(`Error loading LOD ${e} from ${g}
3
- `,m),null));if(!T)return null;const W=T.parser;i&&console.log("Loading finished "+g,D.guid);let y=0;if(T.parser.json.textures){let m=!1;for(const h of T.parser.json.textures){if(h!=null&&h.extensions){const M=h?.extensions[j];if(M!=null&&M.guid&&M.guid===D.guid){m=!0;break}}y++}if(m){let h=await W.getDependency("texture",y);return h&&w.assignLODInformation(l.url,h,u,e,void 0,void 0),i&&console.log('change "'+t.name+'" \u2192 "'+h.name+'"',g,y,h,p),t instanceof ee&&(h=this.copySettings(t,h)),h&&(h.guid=D.guid),d(h)}else x&&console.warn("Could not find texture with guid",D.guid,T.parser.json)}if(y=0,T.parser.json.meshes){let m=!1;for(const h of T.parser.json.meshes){if(h!=null&&h.extensions){const M=h?.extensions[j];if(M!=null&&M.guid&&M.guid===D.guid){m=!0;break}}y++}if(m){const h=await W.getDependency("mesh",y),M=D;if(i&&console.log(`Loaded Mesh "${h.name}"`,g,y,h,p),h.isMesh===!0){const _=h.geometry;return w.assignLODInformation(l.url,_,u,e,void 0,M.density),d(_)}else{const _=new Array;for(let C=0;C<h.children.length;C++){const z=h.children[C];if(z.isMesh===!0){const K=z.geometry;w.assignLODInformation(l.url,K,u,e,C,M.density),_.push(K)}}return d(_)}}else x&&console.warn("Could not find mesh with guid",D.guid,T.parser.json)}return d(null)});return this.previouslyLoaded.set(p,L),await L}else if(t instanceof ee){i&&console.log("Load texture from uri: "+g);const p=await new qe().loadAsync(g);return p?(p.guid=a.guid,p.flipY=!1,p.needsUpdate=!0,p.colorSpace=t.colorSpace,i&&console.log(a,p)):x&&console.warn("failed loading",g),p}}else x&&console.warn(`Can not load LOD ${e}: no LOD info found for "${u}" ${t.name}`,t.type);return null}static assignLODInformation(t,e,s,o,r,n){if(!e)return;e.userData||(e.userData={});const i=new ut(t,s,o,r,n);e.userData.LODS=i}static getAssignedLODInformation(t){var e;return((e=t?.userData)==null?void 0:e.LODS)||null}static copySettings(t,e){return e=e.clone(),x&&console.warn(`Copying texture settings
1
+ var Ue=Object.defineProperty,ze=(t,e,s)=>e in t?Ue(t,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):t[e]=s,c=(t,e,s)=>(ze(t,typeof e!="symbol"?e+"":e,s),s),Te=(t,e,s)=>{if(!e.has(t))throw TypeError("Cannot "+s)},x=(t,e,s)=>(Te(t,e,"read from private field"),s?s.call(t):e.get(t)),V=(t,e,s)=>{if(e.has(t))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(t):e.set(t,s)},G=(t,e,s,o)=>(Te(t,e,"write to private field"),o?o.call(t,s):e.set(t,s),s);import{BufferGeometry as le,Mesh as q,Material as Ve,Texture as ee,TextureLoader as qe,Matrix4 as Ee,Clock as Xe,MeshStandardMaterial as He,Sphere as Ke,Box3 as Ae,Vector3 as W}from"three";import{GLTFLoader as me}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as Ye}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as Je}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as Qe}from"three/examples/jsm/loaders/KTX2Loader.js";const pe="";globalThis.GLTF_PROGRESSIVE_VERSION=pe,console.debug(`[gltf-progressive] version ${pe}`);let Y="https://www.gstatic.com/draco/versioned/decoders/1.5.7/",te="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";const Ze=Y,et=te,tt=new URL(Y+"draco_decoder.js");fetch(tt,{method:"GET",headers:{Range:"bytes=0-1"}}).catch(t=>{Y===Ze&&(Y="./include/draco/"),te===et&&(te="./include/ktx2/")}).finally(()=>{Pe()});function st(t){Y=t}function rt(t){te=t}let X,ue,H;function Pe(){X||(X=new Je,X.setDecoderPath(Y),X.setDecoderConfig({type:"js"}),X.preload()),H||(H=new Qe,H.setTranscoderPath(te),H.init()),ue||(ue=Ye)}function ve(t){return Pe(),t?H.detectSupport(t):t!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:X,ktx2Loader:H,meshoptDecoder:ue}}function ye(t){t.dracoLoader||t.setDRACOLoader(X),t.ktx2Loader||t.setKTX2Loader(H),t.meshoptDecoder||t.setMeshoptDecoder(ue)}const xe=new WeakMap;function Le(t,e){let s=xe.get(t);s?s=Object.assign(s,e):s=e,xe.set(t,s)}const Ie=me.prototype.load;function nt(...t){const e=xe.get(this);let s=t[0];const o=new URL(s,window.location.href);if(o.hostname.endsWith("needle.tools")){const r=e?.progressive!==void 0?e.progressive:!0,n=e!=null&&e.usecase?e.usecase:"default";r?this.requestHeader.Accept=`*/*;progressive=allowed;usecase=${n}`:this.requestHeader.Accept=`*/*;usecase=${n}`,s=o.toString()}return t[0]=s,Ie?.call(this,...t)}me.prototype.load=nt,se("debugprogressive");function se(t){if(typeof window>"u")return!1;const e=new URL(window.location.href).searchParams.get(t);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function ot(t,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||t===void 0)return e;const s=t.lastIndexOf("/");if(s>=0){const o=t.substring(0,s+1);for(;o.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return o+e}return e}let ce;function it(){return ce!==void 0||(ce=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),se("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",ce)),ce}const at=typeof window>"u"&&typeof document>"u",Me=Symbol("needle:raycast-mesh");function J(t){return t?.[Me]instanceof le?t[Me]:null}function ke(t,e){if((t.type==="Mesh"||t.type==="SkinnedMesh")&&!J(t)){const s=lt(e);s.userData={isRaycastMesh:!0},t[Me]=s}}function Be(t=!0){if(t){if(re)return;const e=re=q.prototype.raycast;q.prototype.raycast=function(s,o){const r=this,n=J(r);let i;n&&r.isMesh&&(i=r.geometry,r.geometry=n),e.call(this,s,o),i&&(r.geometry=i)}}else{if(!re)return;q.prototype.raycast=re,re=null}}let re=null;function lt(t){const e=new le;for(const s in t.attributes)e.setAttribute(s,t.getAttribute(s));return e.setIndex(t.getIndex()),e}const $=new Array,N="NEEDLE_progressive",L=se("debugprogressive"),De=Symbol("needle-progressive-texture"),ne=new Map,we=new Set;if(L){let t=function(){e+=1,console.log("Toggle LOD level",e,ne),ne.forEach((r,n)=>{for(const i of r.keys){const l=n[i];if(l!=null){if(l.isBufferGeometry===!0){const u=T.getMeshLODInformation(l),a=u?Math.min(e,u.lods.length):0;n["DEBUG:LOD"]=e,T.assignMeshLOD(n,a),u&&(s=Math.max(s,u.lods.length-1))}else if(n.isMaterial===!0){n["DEBUG:LOD"]=e,T.assignTextureLOD(n,e);break}}}}),e>=s&&(e=-1)},e=-1,s=2,o=!1;window.addEventListener("keyup",r=>{r.key==="p"&&t(),r.key==="w"&&(o=!o,we&&we.forEach(n=>{n.name!="BackgroundCubeMaterial"&&n.glyphMap==null&&"wireframe"in n&&(n.wireframe=o)}))})}function Ce(t,e,s){var o;if(!L)return;ne.has(t)||ne.set(t,{keys:[],sourceId:s});const r=ne.get(t);((o=r?.keys)==null?void 0:o.includes(e))==!1&&r.keys.push(e)}const w=class{constructor(t,e){c(this,"parser"),c(this,"url"),c(this,"_isLoadingMesh"),c(this,"loadMesh",s=>{var o,r;if(this._isLoadingMesh)return null;const n=(r=(o=this.parser.json.meshes[s])==null?void 0:o.extensions)==null?void 0:r[N];return n?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",s).then(i=>{var l;return this._isLoadingMesh=!1,i&&w.registerMesh(this.url,n.guid,i,(l=n.lods)==null?void 0:l.length,void 0,n),i})):null}),L&&console.log("Progressive extension registered for",e),this.parser=t,this.url=e}get name(){return N}static getMeshLODInformation(t){const e=this.getAssignedLODInformation(t);return e!=null&&e.key?this.lodInfos.get(e.key):null}static getMaterialMinMaxLODsCount(t,e){const s=this,o="LODS:minmax",r=t[o];if(r!=null)return r;if(e||(e={min_count:1/0,max_count:0,lods:[]}),Array.isArray(t)){for(const i of t)this.getMaterialMinMaxLODsCount(i,e);return t[o]=e,e}if(L==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const i=t;for(const l of Object.keys(i.uniforms)){const u=i.uniforms[l].value;u?.isTexture===!0&&n(u,e)}}else if(t.isMaterial)for(const i of Object.keys(t)){const l=t[i];l?.isTexture===!0&&n(l,e)}return t[o]=e,e;function n(i,l){const u=s.getAssignedLODInformation(i);if(u){const a=s.lodInfos.get(u.key);if(a&&a.lods){l.min_count=Math.min(l.min_count,a.lods.length),l.max_count=Math.max(l.max_count,a.lods.length);for(let f=0;f<a.lods.length;f++){const g=a.lods[f];g.width&&(l.lods[f]=l.lods[f]||{min_height:1/0,max_height:0},l.lods[f].min_height=Math.min(l.lods[f].min_height,g.height),l.lods[f].max_height=Math.max(l.lods[f].max_height,g.height))}}}}}static hasLODLevelAvailable(t,e){var s;if(Array.isArray(t)){for(const n of t)if(this.hasLODLevelAvailable(n,e))return!0;return!1}if(t.isMaterial===!0){for(const n of Object.keys(t)){const i=t[n];if(i&&i.isTexture&&this.hasLODLevelAvailable(i,e))return!0}return!1}else if(t.isGroup===!0){for(const n of t.children)if(n.isMesh===!0&&this.hasLODLevelAvailable(n,e))return!0}let o,r;if(t.isMesh?o=t.geometry:(t.isBufferGeometry||t.isTexture)&&(o=t),o&&(s=o?.userData)!=null&&s.LODS){const n=o.userData.LODS;if(r=this.lodInfos.get(n.key),e===void 0)return r!=null;if(r)return Array.isArray(r.lods)?e<r.lods.length:e===0}return!1}static assignMeshLOD(t,e){var s;if(!t)return Promise.resolve(null);if(t instanceof q||t.isMesh===!0){const o=t.geometry,r=this.getAssignedLODInformation(o);if(!r)return Promise.resolve(null);for(const n of $)(s=n.onBeforeGetLODMesh)==null||s.call(n,t,e);return t["LOD:requested level"]=e,w.getOrLoadLOD(o,e).then(n=>{if(Array.isArray(n)){const i=r.index||0;n=n[i]}return t["LOD:requested level"]===e&&(delete t["LOD:requested level"],n&&o!=n&&(n?.isBufferGeometry?(t.geometry=n,L&&Ce(t,"geometry",r.url)):L&&console.error("Invalid LOD geometry",n))),n}).catch(n=>(console.error("Error loading mesh LOD",t,n),null))}else L&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",t);return Promise.resolve(null)}static assignTextureLOD(t,e=0){if(!t)return Promise.resolve(null);if(t.isMesh===!0){const s=t;if(Array.isArray(s.material)){const o=new Array;for(const r of s.material){const n=this.assignTextureLOD(r,e);o.push(n)}return Promise.all(o).then(r=>{const n=new Array;for(const i of r)Array.isArray(i)&&n.push(...i);return n})}else return this.assignTextureLOD(s.material,e)}if(t instanceof Ve||t.isMaterial===!0){const s=t,o=[],r=new Array;if(L&&we.add(s),s.uniforms&&(s.isRawShaderMaterial||s.isShaderMaterial===!0)){const n=s;for(const i of Object.keys(n.uniforms)){const l=n.uniforms[i].value;if(l?.isTexture===!0){const u=this.assignTextureLODForSlot(l,e,s,i).then(a=>(a&&n.uniforms[i].value!=a&&(n.uniforms[i].value=a,n.uniformsNeedUpdate=!0),a));o.push(u),r.push(i)}}}else for(const n of Object.keys(s)){const i=s[n];if(i?.isTexture===!0){const l=this.assignTextureLODForSlot(i,e,s,n);o.push(l),r.push(n)}}return Promise.all(o).then(n=>{const i=new Array;for(let l=0;l<n.length;l++){const u=n[l],a=r[l];u&&u.isTexture===!0?i.push({material:s,slot:a,texture:u,level:e}):i.push({material:s,slot:a,texture:null,level:e})}return i})}if(t instanceof ee||t.isTexture===!0){const s=t;return this.assignTextureLODForSlot(s,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,s,o){return t?.isTexture!==!0?Promise.resolve(null):o==="glyphMap"?Promise.resolve(t):w.getOrLoadLOD(t,e).then(r=>{if(Array.isArray(r))return null;if(r?.isTexture===!0){if(r!=t){if(s&&o){const n=s[o];if(n){const i=this.getAssignedLODInformation(n);if(i&&i?.level<e)return L==="verbose"&&console.warn("Assigned texture level is already higher: ",i.level,e,s,n,r),null}s[o]=r}if(L&&o&&s){const n=this.getAssignedLODInformation(t);n&&Ce(s,o,n.url)}}return r}else L=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(r=>(console.error("Error loading LOD",t,r),null))}afterRoot(t){var e,s;return L&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((o,r)=>{var n;if(o!=null&&o.extensions){const i=o?.extensions[N];if(i){if(!i.lods){L&&console.warn("Texture has no LODs",i);return}let l=!1;for(const u of this.parser.associations.keys())if(u.isTexture===!0){const a=this.parser.associations.get(u);a?.textures===r&&(l=!0,w.registerTexture(this.url,u,(n=i.lods)==null?void 0:n.length,r,i))}l||this.parser.getDependency("texture",r).then(u=>{var a;u&&w.registerTexture(this.url,u,(a=i.lods)==null?void 0:a.length,r,i)})}}}),(s=this.parser.json.meshes)==null||s.forEach((o,r)=>{if(o!=null&&o.extensions){const n=o?.extensions[N];if(n&&n.lods){for(const i of this.parser.associations.keys())if(i.isMesh){const l=this.parser.associations.get(i);l?.meshes===r&&w.registerMesh(this.url,n.guid,i,n.lods.length,l.primitives,n)}}}}),null}static async getOrLoadLOD(t,e){var s,o,r,n;const i=L=="verbose",l=t.userData.LODS;if(!l)return null;const u=l?.key;let a;if(t.isTexture===!0){const f=t;f.source&&f.source[De]&&(a=f.source[De])}if(a||(a=w.lodInfos.get(u)),a){if(e>0){let v=!1;const A=Array.isArray(a.lods);if(A&&e>=a.lods.length?v=!0:A||(v=!0),v)return this.lowresCache.get(u)}const f=Array.isArray(a.lods)?(s=a.lods[e])==null?void 0:s.path:a.lods;if(!f)return L&&!a["missing:uri"]&&(a["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,a)),null;const g=ot(l.url,f);if(g.endsWith(".glb")||g.endsWith(".gltf")){if(!a.guid)return console.warn("missing pointer for glb/gltf texture",a),null;const v=g+"_"+a.guid,A=this.previouslyLoaded.get(v);if(A!==void 0){i&&console.log(`LOD ${e} was already loading/loaded: ${v}`);let d=await A.catch(b=>(console.error(`Error loading LOD ${e} from ${g}
2
+ `,b),null)),O=!1;if(d==null||(d instanceof ee&&t instanceof ee?(o=d.image)!=null&&o.data||(r=d.source)!=null&&r.data?d=this.copySettings(t,d):(O=!0,this.previouslyLoaded.delete(v)):d instanceof le&&t instanceof le&&((n=d.attributes.position)!=null&&n.array||(O=!0,this.previouslyLoaded.delete(v)))),!O)return d}const D=a,y=new Promise(async(d,O)=>{const b=new me;ye(b),L&&(await new Promise(p=>setTimeout(p,1e3)),i&&console.warn("Start loading (delayed) "+g,D.guid));let I=g;if(D&&Array.isArray(D.lods)){const p=D.lods[e];p.hash&&(I+="?v="+p.hash)}const _=await b.loadAsync(I).catch(p=>(console.error(`Error loading LOD ${e} from ${g}
3
+ `,p),null));if(!_)return null;const k=_.parser;i&&console.log("Loading finished "+g,D.guid);let m=0;if(_.parser.json.textures){let p=!1;for(const h of _.parser.json.textures){if(h!=null&&h.extensions){const M=h?.extensions[N];if(M!=null&&M.guid&&M.guid===D.guid){p=!0;break}}m++}if(p){let h=await k.getDependency("texture",m);return h&&w.assignLODInformation(l.url,h,u,e,void 0,void 0),i&&console.log('change "'+t.name+'" \u2192 "'+h.name+'"',g,m,h,v),t instanceof ee&&(h=this.copySettings(t,h)),h&&(h.guid=D.guid),d(h)}else L&&console.warn("Could not find texture with guid",D.guid,_.parser.json)}if(m=0,_.parser.json.meshes){let p=!1;for(const h of _.parser.json.meshes){if(h!=null&&h.extensions){const M=h?.extensions[N];if(M!=null&&M.guid&&M.guid===D.guid){p=!0;break}}m++}if(p){const h=await k.getDependency("mesh",m),M=D;if(i&&console.log(`Loaded Mesh "${h.name}"`,g,m,h,v),h.isMesh===!0){const S=h.geometry;return w.assignLODInformation(l.url,S,u,e,void 0,M.density),d(S)}else{const S=new Array;for(let j=0;j<h.children.length;j++){const z=h.children[j];if(z.isMesh===!0){const K=z.geometry;w.assignLODInformation(l.url,K,u,e,j,M.density),S.push(K)}}return d(S)}}else L&&console.warn("Could not find mesh with guid",D.guid,_.parser.json)}return d(null)});return this.previouslyLoaded.set(v,y),await y}else if(t instanceof ee){i&&console.log("Load texture from uri: "+g);const v=await new qe().loadAsync(g);return v?(v.guid=a.guid,v.flipY=!1,v.needsUpdate=!0,v.colorSpace=t.colorSpace,i&&console.log(a,v)):L&&console.warn("failed loading",g),v}}else L&&console.warn(`Can not load LOD ${e}: no LOD info found for "${u}" ${t.name}`,t.type);return null}static assignLODInformation(t,e,s,o,r,n){if(!e)return;e.userData||(e.userData={});const i=new ut(t,s,o,r,n);e.userData.LODS=i}static getAssignedLODInformation(t){var e;return((e=t?.userData)==null?void 0:e.LODS)||null}static copySettings(t,e){return e=e.clone(),L&&console.warn(`Copying texture settings
4
4
  `,t.uuid,`
5
- `,e.uuid),e.offset=t.offset,e.repeat=t.repeat,e.colorSpace=t.colorSpace,e.magFilter=t.magFilter,e.minFilter=t.minFilter,e.wrapS=t.wrapS,e.wrapT=t.wrapT,e.flipY=t.flipY,e.anisotropy=t.anisotropy,e.mipmaps||(e.generateMipmaps=t.generateMipmaps),e}};let S=w;c(S,"registerTexture",(t,e,s,o,r)=>{if(x&&console.log("> Progressive: register texture",o,e.name,e.uuid,e,r),!e){x&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[De]=r);const n=r.guid;w.assignLODInformation(t,e,n,s,o,void 0),w.lodInfos.set(n,r),w.lowresCache.set(n,e)}),c(S,"registerMesh",(t,e,s,o,r,n)=>{var i;x&&console.log("> Progressive: register mesh",r,s.name,n,s.uuid,s);const l=s.geometry;if(!l){x&&console.warn("gltf-progressive: Register mesh without geometry");return}l.userData||(l.userData={}),w.assignLODInformation(t,l,e,o,r,n.density),w.lodInfos.set(e,n);let u=w.lowresCache.get(e);u?u.push(s.geometry):u=[s.geometry],w.lowresCache.set(e,u),o>0&&!J(s)&&ke(s,l);for(const a of $)(i=a.onRegisteredNewMesh)==null||i.call(a,s,n)}),c(S,"lodInfos",new Map),c(S,"previouslyLoaded",new Map),c(S,"lowresCache",new Map);class ut{constructor(e,s,o,r,n){c(this,"url"),c(this,"key"),c(this,"level"),c(this,"index"),c(this,"density"),this.url=e,this.key=s,this.level=o,r!=null&&(this.index=r),n!=null&&(this.density=n)}}const k=se("debugprogressive"),ct=se("noprogressive"),Oe=Symbol("Needle:LODSManager"),be=Symbol("Needle:LODState"),Q=Symbol("Needle:CurrentLOD"),B={mesh_lod:-1,texture_lod:-1};var E,F,_e,Z,oe,de,U;const P=class{constructor(t,e){c(this,"context"),c(this,"renderer"),c(this,"projectionScreenMatrix",new Ee),c(this,"targetTriangleDensity",2e5),c(this,"updateInterval","auto"),V(this,E,1),c(this,"pause",!1),c(this,"manual",!1),c(this,"_lodchangedlisteners",[]),V(this,F,void 0),V(this,_e,new Xe),V(this,Z,0),V(this,oe,0),V(this,de,0),V(this,U,0),c(this,"_fpsBuffer",[60,60,60,60,60]),c(this,"_sphere",new Ke),c(this,"_tempBox",new Ae),c(this,"_tempBox2",new Ae),c(this,"tempMatrix",new Ee),c(this,"_tempWorldPosition",new N),c(this,"_tempBoxSize",new N),c(this,"_tempBox2Size",new N),this.renderer=t,this.context={...e}}static getObjectLODState(t){return t[be]}static addPlugin(t){$.push(t)}static removePlugin(t){const e=$.indexOf(t);e>=0&&$.splice(e,1)}static get(t,e){if(t[Oe])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[Oe];const s=new P(t,{engine:"unknown",...e});return t[Oe]=s,s}get plugins(){return $}addEventListener(t,e){t==="changed"&&this._lodchangedlisteners.push(e)}removeEventListener(t,e){if(t==="changed"){const s=this._lodchangedlisteners.indexOf(e);s>=0&&this._lodchangedlisteners.splice(s,1)}}enable(){if(v(this,F))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let t=0;G(this,F,this.renderer.render);const e=this;ye(this.renderer),this.renderer.render=function(s,o){const r=e.renderer.getRenderTarget();(r==null||"isXRRenderTarget"in r&&r.isXRRenderTarget)&&(t=0,G(e,Z,v(e,Z)+1),G(e,oe,v(e,_e).getDelta()),G(e,de,v(e,de)+v(e,oe)),e._fpsBuffer.shift(),e._fpsBuffer.push(1/v(e,oe)),G(e,U,e._fpsBuffer.reduce((i,l)=>i+l)/e._fpsBuffer.length),k&&v(e,Z)%200===0&&console.log("FPS",Math.round(v(e,U)),"Interval:",v(e,E)));const n=t++;v(e,F).call(this,s,o),e.onAfterRender(s,o,n)}}disable(){v(this,F)&&(console.debug("[gltf-progressive] Disabling LODsManager for renderer"),this.renderer.render=v(this,F),G(this,F,void 0))}update(t,e){this.internalUpdate(t,e)}onAfterRender(t,e,s){if(this.pause)return;const o=this.renderer.renderLists.get(t,0).opaque;let r=!0;if(o.length===1){const n=o[0].material;(n.name==="EffectMaterial"||n.name==="CopyShader")&&(r=!1)}if((e.parent&&e.parent.type==="CubeCamera"||s>=1&&e.type==="OrthographicCamera")&&(r=!1),r){if(ct||(this.updateInterval==="auto"?v(this,U)<40&&v(this,E)<10?(G(this,E,v(this,E)+1),k&&console.warn("\u2193 Reducing LOD updates",v(this,E),v(this,U).toFixed(0))):v(this,U)>=60&&v(this,E)>1&&(G(this,E,v(this,E)-1),k&&console.warn("\u2191 Increasing LOD updates",v(this,E),v(this,U).toFixed(0))):G(this,E,this.updateInterval),v(this,E)>0&&v(this,Z)%v(this,E)!=0))return;this.internalUpdate(t,e)}}internalUpdate(t,e){var s,o;const r=this.renderer.renderLists.get(t,0),n=r.opaque;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse);const i=this.targetTriangleDensity;for(const a of n){if(a.material&&(((s=a.geometry)==null?void 0:s.type)==="BoxGeometry"||((o=a.geometry)==null?void 0:o.type)==="BufferGeometry")&&(a.material.name==="SphericalGaussianBlur"||a.material.name=="BackgroundCubeMaterial"||a.material.name==="CubemapFromEquirect"||a.material.name==="EquirectangularToCubeUV")){k&&(a.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(a.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",a,a.material.name,a.material.type)));continue}switch(a.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}if(k==="color"&&a.material&&!a.object.progressive_debug_color){a.object.progressive_debug_color=!0;const g=Math.random()*16777215,p=new He({color:g});a.object.material=p}const f=a.object;(f instanceof q||f.isMesh)&&this.updateLODs(t,e,f,i)}const l=r.transparent;for(const a of l){const f=a.object;(f instanceof q||f.isMesh)&&this.updateLODs(t,e,f,i)}const u=r.transmissive;for(const a of u){const f=a.object;(f instanceof q||f.isMesh)&&this.updateLODs(t,e,f,i)}}updateLODs(t,e,s,o){var r,n;s.userData||(s.userData={});let i=s[be];if(i||(i=new dt,s[be]=i),i.frames++<2)return;for(const u of $)(r=u.onBeforeUpdateLOD)==null||r.call(u,this.renderer,t,e,s);this.calculateLodLevel(e,s,i,o,B),B.mesh_lod=Math.round(B.mesh_lod),B.texture_lod=Math.round(B.texture_lod),B.mesh_lod>=0&&this.loadProgressiveMeshes(s,B.mesh_lod);let l=B.texture_lod;if(s.material&&l>=0){const u=s["DEBUG:LOD"];u!=null&&(l=u),this.loadProgressiveTextures(s.material,l)}for(const u of $)(n=u.onAfterUpdatedLOD)==null||n.call(u,this.renderer,t,e,s,B);i.lastLodLevel_Mesh=B.mesh_lod,i.lastLodLevel_Texture=B.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const o of t)this.loadProgressiveTextures(o,e);return}let s=!1;(t[Q]===void 0||e<t[Q])&&(s=!0),s&&(t[Q]=e,S.assignTextureLOD(t,e).then(o=>{this._lodchangedlisteners.forEach(r=>r({type:"texture",level:e,object:t}))}))}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);if(t[Q]!==e){t[Q]=e;const s=t.geometry;return S.assignMeshLOD(t,e).then(o=>(o&&t[Q]==e&&s!=t.geometry&&this._lodchangedlisteners.forEach(r=>r({type:"mesh",level:e,object:t})),o))}return Promise.resolve(null)}static isInside(t,e){const s=t.min,o=t.max,r=(s.x+o.x)*.5,n=(s.y+o.y)*.5;return this._tempPtInside.set(r,n,s.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,s,o,r){var n;if(!e){r.mesh_lod=-1,r.texture_lod=-1;return}if(!t){r.mesh_lod=-1,r.texture_lod=-1;return}let i=10+1,l=!1;if(k&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const u=S.getMeshLODInformation(e.geometry),a=u?.lods,f=a&&a.length>0,g=S.getMaterialMinMaxLODsCount(e.material),p=g?.min_count!=1/0&&g.min_count>0&&g.max_count>0;if(!f&&!p){r.mesh_lod=0,r.texture_lod=0;return}f||(l=!0,i=0);const A=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let D=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const L=e;if(!L.boundingBox)L.computeBoundingBox();else if(s.frames%30===0){const d=J(L),O=L.geometry;d&&(L.geometry=d),L.computeBoundingBox(),L.geometry=O}D=L.boundingBox}if(D&&t.isPerspectiveCamera){const L=t;if(e.geometry.attributes.color&&e.geometry.attributes.color.count<100&&e.geometry.boundingSphere){this._sphere.copy(e.geometry.boundingSphere),this._sphere.applyMatrix4(e.matrixWorld);const y=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(y)){r.mesh_lod=0,r.texture_lod=0;return}}if(this._tempBox.copy(D),this._tempBox.applyMatrix4(e.matrixWorld),P.isInside(this._tempBox,this.projectionScreenMatrix)){r.mesh_lod=0,r.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&L.fov>70){const y=this._tempBox.min,m=this._tempBox.max;let h=y.x,M=y.y,_=m.x,C=m.y;const z=2,K=1.5,ie=(y.x+m.x)*.5,ae=(y.y+m.y)*.5;h=(h-ie)*z+ie,M=(M-ae)*z+ae,_=(_-ie)*z+ie,C=(C-ae)*z+ae;const $e=h<0&&_>0?0:Math.min(Math.abs(y.x),Math.abs(m.x)),Fe=M<0&&C>0?0:Math.min(Math.abs(y.y),Math.abs(m.y)),ge=Math.max($e,Fe);s.lastCentrality=(K-ge)*(K-ge)*(K-ge)}else s.lastCentrality=1;const d=this._tempBox.getSize(this._tempBoxSize);d.multiplyScalar(.5),screen.availHeight>0&&A>0&&d.multiplyScalar(A/screen.availHeight),d.x*=L.aspect;const O=t.matrixWorldInverse,b=this._tempBox2;b.copy(D),b.applyMatrix4(e.matrixWorld),b.applyMatrix4(O);const I=b.getSize(this._tempBox2Size),T=Math.max(I.x,I.y);if(Math.max(d.x,d.y)!=0&&T!=0&&(d.z=I.z/Math.max(I.x,I.y)*Math.max(d.x,d.y)),s.lastScreenCoverage=Math.max(d.x,d.y,d.z),s.lastScreenspaceVolume.copy(d),s.lastScreenCoverage*=s.lastCentrality,k&&P.debugDrawLine){const y=this.tempMatrix.copy(this.projectionScreenMatrix);y.invert();const m=P.corner0,h=P.corner1,M=P.corner2,_=P.corner3;m.copy(this._tempBox.min),h.copy(this._tempBox.max),h.x=m.x,M.copy(this._tempBox.max),M.y=m.y,_.copy(this._tempBox.max);const C=(m.z+_.z)*.5;m.z=h.z=M.z=_.z=C,m.applyMatrix4(y),h.applyMatrix4(y),M.applyMatrix4(y),_.applyMatrix4(y),P.debugDrawLine(m,h,255),P.debugDrawLine(m,M,255),P.debugDrawLine(h,_,255),P.debugDrawLine(M,_,255)}let W=999;if(a&&s.lastScreenCoverage>0){for(let y=0;y<a.length;y++)if(a[y].density/s.lastScreenCoverage<o){W=y;break}}W<i&&(i=W,l=!0)}if(l?r.mesh_lod=i:r.mesh_lod=s.lastLodLevel_Mesh,k&&r.mesh_lod!=s.lastLodLevel_Mesh){const L=a?.[r.mesh_lod];L&&console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} \u2192 ${r.mesh_lod} (${L.density.toFixed(0)}) - ${e.name}`)}if(p){const L="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(s.lastLodLevel_Texture<0){if(r.texture_lod=g.max_count-1,k){const d=g.lods[g.max_count-1];k&&console.log(`First Texture LOD ${r.texture_lod} (${d.max_height}px) - ${e.name}`)}}else{const d=s.lastScreenspaceVolume.x+s.lastScreenspaceVolume.y+s.lastScreenspaceVolume.z;let O=s.lastScreenCoverage*4;((n=this.context)==null?void 0:n.engine)==="model-viewer"&&(O*=1.5);const b=A/window.devicePixelRatio*O;for(let I=g.lods.length-1;I>=0;I--){let T=g.lods[I];if(!(L&&T.max_height>=2048)&&!(it()&&T.max_height>4096)&&T.max_height>b){if(r.texture_lod=I,r.texture_lod<s.lastLodLevel_Texture){const W=T.max_height;k&&console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} \u2192 ${r.texture_lod} = ${W}px
5
+ `,e.uuid),e.offset=t.offset,e.repeat=t.repeat,e.colorSpace=t.colorSpace,e.magFilter=t.magFilter,e.minFilter=t.minFilter,e.wrapS=t.wrapS,e.wrapT=t.wrapT,e.flipY=t.flipY,e.anisotropy=t.anisotropy,e.mipmaps||(e.generateMipmaps=t.generateMipmaps),e}};let T=w;c(T,"registerTexture",(t,e,s,o,r)=>{if(L&&console.log("> Progressive: register texture",o,e.name,e.uuid,e,r),!e){L&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[De]=r);const n=r.guid;w.assignLODInformation(t,e,n,s,o,void 0),w.lodInfos.set(n,r),w.lowresCache.set(n,e)}),c(T,"registerMesh",(t,e,s,o,r,n)=>{var i;L&&console.log("> Progressive: register mesh",r,s.name,n,s.uuid,s);const l=s.geometry;if(!l){L&&console.warn("gltf-progressive: Register mesh without geometry");return}l.userData||(l.userData={}),w.assignLODInformation(t,l,e,o,r,n.density),w.lodInfos.set(e,n);let u=w.lowresCache.get(e);u?u.push(s.geometry):u=[s.geometry],w.lowresCache.set(e,u),o>0&&!J(s)&&ke(s,l);for(const a of $)(i=a.onRegisteredNewMesh)==null||i.call(a,s,n)}),c(T,"lodInfos",new Map),c(T,"previouslyLoaded",new Map),c(T,"lowresCache",new Map);class ut{constructor(e,s,o,r,n){c(this,"url"),c(this,"key"),c(this,"level"),c(this,"index"),c(this,"density"),this.url=e,this.key=s,this.level=o,r!=null&&(this.index=r),n!=null&&(this.density=n)}}const B=se("debugprogressive"),ct=se("noprogressive"),Oe=Symbol("Needle:LODSManager"),be=Symbol("Needle:LODState"),Q=Symbol("Needle:CurrentLOD"),C={mesh_lod:-1,texture_lod:-1};var E,F,_e,Z,oe,de,U;const P=class{constructor(t,e){c(this,"context"),c(this,"renderer"),c(this,"projectionScreenMatrix",new Ee),c(this,"targetTriangleDensity",2e5),c(this,"updateInterval","auto"),V(this,E,1),c(this,"pause",!1),c(this,"manual",!1),c(this,"_lodchangedlisteners",[]),V(this,F,void 0),V(this,_e,new Xe),V(this,Z,0),V(this,oe,0),V(this,de,0),V(this,U,0),c(this,"_fpsBuffer",[60,60,60,60,60]),c(this,"_sphere",new Ke),c(this,"_tempBox",new Ae),c(this,"_tempBox2",new Ae),c(this,"tempMatrix",new Ee),c(this,"_tempWorldPosition",new W),c(this,"_tempBoxSize",new W),c(this,"_tempBox2Size",new W),this.renderer=t,this.context={...e}}static getObjectLODState(t){return t[be]}static addPlugin(t){$.push(t)}static removePlugin(t){const e=$.indexOf(t);e>=0&&$.splice(e,1)}static get(t,e){if(t[Oe])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[Oe];const s=new P(t,{engine:"unknown",...e});return t[Oe]=s,s}get plugins(){return $}addEventListener(t,e){t==="changed"&&this._lodchangedlisteners.push(e)}removeEventListener(t,e){if(t==="changed"){const s=this._lodchangedlisteners.indexOf(e);s>=0&&this._lodchangedlisteners.splice(s,1)}}enable(){if(x(this,F))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let t=0;G(this,F,this.renderer.render);const e=this;ve(this.renderer),this.renderer.render=function(s,o){const r=e.renderer.getRenderTarget();(r==null||"isXRRenderTarget"in r&&r.isXRRenderTarget)&&(t=0,G(e,Z,x(e,Z)+1),G(e,oe,x(e,_e).getDelta()),G(e,de,x(e,de)+x(e,oe)),e._fpsBuffer.shift(),e._fpsBuffer.push(1/x(e,oe)),G(e,U,e._fpsBuffer.reduce((i,l)=>i+l)/e._fpsBuffer.length),B&&x(e,Z)%200===0&&console.log("FPS",Math.round(x(e,U)),"Interval:",x(e,E)));const n=t++;x(e,F).call(this,s,o),e.onAfterRender(s,o,n)}}disable(){x(this,F)&&(console.debug("[gltf-progressive] Disabling LODsManager for renderer"),this.renderer.render=x(this,F),G(this,F,void 0))}update(t,e){this.internalUpdate(t,e)}onAfterRender(t,e,s){if(this.pause)return;const o=this.renderer.renderLists.get(t,0).opaque;let r=!0;if(o.length===1){const n=o[0].material;(n.name==="EffectMaterial"||n.name==="CopyShader")&&(r=!1)}if((e.parent&&e.parent.type==="CubeCamera"||s>=1&&e.type==="OrthographicCamera")&&(r=!1),r){if(ct||(this.updateInterval==="auto"?x(this,U)<40&&x(this,E)<10?(G(this,E,x(this,E)+1),B&&console.warn("\u2193 Reducing LOD updates",x(this,E),x(this,U).toFixed(0))):x(this,U)>=60&&x(this,E)>1&&(G(this,E,x(this,E)-1),B&&console.warn("\u2191 Increasing LOD updates",x(this,E),x(this,U).toFixed(0))):G(this,E,this.updateInterval),x(this,E)>0&&x(this,Z)%x(this,E)!=0))return;this.internalUpdate(t,e)}}internalUpdate(t,e){var s,o;const r=this.renderer.renderLists.get(t,0),n=r.opaque;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse);const i=this.targetTriangleDensity;for(const a of n){if(a.material&&(((s=a.geometry)==null?void 0:s.type)==="BoxGeometry"||((o=a.geometry)==null?void 0:o.type)==="BufferGeometry")&&(a.material.name==="SphericalGaussianBlur"||a.material.name=="BackgroundCubeMaterial"||a.material.name==="CubemapFromEquirect"||a.material.name==="EquirectangularToCubeUV")){B&&(a.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(a.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",a,a.material.name,a.material.type)));continue}switch(a.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}if(B==="color"&&a.material&&!a.object.progressive_debug_color){a.object.progressive_debug_color=!0;const g=Math.random()*16777215,v=new He({color:g});a.object.material=v}const f=a.object;(f instanceof q||f.isMesh)&&this.updateLODs(t,e,f,i)}const l=r.transparent;for(const a of l){const f=a.object;(f instanceof q||f.isMesh)&&this.updateLODs(t,e,f,i)}const u=r.transmissive;for(const a of u){const f=a.object;(f instanceof q||f.isMesh)&&this.updateLODs(t,e,f,i)}}updateLODs(t,e,s,o){var r,n;s.userData||(s.userData={});let i=s[be];if(i||(i=new dt,s[be]=i),i.frames++<2)return;for(const u of $)(r=u.onBeforeUpdateLOD)==null||r.call(u,this.renderer,t,e,s);this.calculateLodLevel(e,s,i,o,C),C.mesh_lod=Math.round(C.mesh_lod),C.texture_lod=Math.round(C.texture_lod),C.mesh_lod>=0&&this.loadProgressiveMeshes(s,C.mesh_lod);let l=C.texture_lod;if(s.material&&l>=0){const u=s["DEBUG:LOD"];u!=null&&(l=u),this.loadProgressiveTextures(s.material,l)}for(const u of $)(n=u.onAfterUpdatedLOD)==null||n.call(u,this.renderer,t,e,s,C);i.lastLodLevel_Mesh=C.mesh_lod,i.lastLodLevel_Texture=C.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const o of t)this.loadProgressiveTextures(o,e);return}let s=!1;(t[Q]===void 0||e<t[Q])&&(s=!0),s&&(t[Q]=e,T.assignTextureLOD(t,e).then(o=>{this._lodchangedlisteners.forEach(r=>r({type:"texture",level:e,object:t}))}))}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);if(t[Q]!==e){t[Q]=e;const s=t.geometry;return T.assignMeshLOD(t,e).then(o=>(o&&t[Q]==e&&s!=t.geometry&&this._lodchangedlisteners.forEach(r=>r({type:"mesh",level:e,object:t})),o))}return Promise.resolve(null)}static isInside(t,e){const s=t.min,o=t.max,r=(s.x+o.x)*.5,n=(s.y+o.y)*.5;return this._tempPtInside.set(r,n,s.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,s,o,r){var n;if(!e){r.mesh_lod=-1,r.texture_lod=-1;return}if(!t){r.mesh_lod=-1,r.texture_lod=-1;return}let i=10+1,l=!1;if(B&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const u=T.getMeshLODInformation(e.geometry),a=u?.lods,f=a&&a.length>0,g=T.getMaterialMinMaxLODsCount(e.material),v=g?.min_count!=1/0&&g.min_count>0&&g.max_count>0;if(!f&&!v){r.mesh_lod=0,r.texture_lod=0;return}f||(l=!0,i=0);const A=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let D=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const y=e;if(!y.boundingBox)y.computeBoundingBox();else if(s.frames%30===0){const d=J(y),O=y.geometry;d&&(y.geometry=d),y.computeBoundingBox(),y.geometry=O}D=y.boundingBox}if(D){const y=t;if(e.geometry.attributes.color&&e.geometry.attributes.color.count<100&&e.geometry.boundingSphere){this._sphere.copy(e.geometry.boundingSphere),this._sphere.applyMatrix4(e.matrixWorld);const m=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(m)){r.mesh_lod=0,r.texture_lod=0;return}}if(this._tempBox.copy(D),this._tempBox.applyMatrix4(e.matrixWorld),y.isPerspectiveCamera&&P.isInside(this._tempBox,this.projectionScreenMatrix)){r.mesh_lod=0,r.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&y.isPerspectiveCamera&&y.fov>70){const m=this._tempBox.min,p=this._tempBox.max;let h=m.x,M=m.y,S=p.x,j=p.y;const z=2,K=1.5,ie=(m.x+p.x)*.5,ae=(m.y+p.y)*.5;h=(h-ie)*z+ie,M=(M-ae)*z+ae,S=(S-ie)*z+ie,j=(j-ae)*z+ae;const $e=h<0&&S>0?0:Math.min(Math.abs(m.x),Math.abs(p.x)),Fe=M<0&&j>0?0:Math.min(Math.abs(m.y),Math.abs(p.y)),ge=Math.max($e,Fe);s.lastCentrality=(K-ge)*(K-ge)*(K-ge)}else s.lastCentrality=1;const d=this._tempBox.getSize(this._tempBoxSize);d.multiplyScalar(.5),screen.availHeight>0&&A>0&&d.multiplyScalar(A/screen.availHeight),t.isPerspectiveCamera?d.x*=t.aspect:t.isOrthographicCamera;const O=t.matrixWorldInverse,b=this._tempBox2;b.copy(D),b.applyMatrix4(e.matrixWorld),b.applyMatrix4(O);const I=b.getSize(this._tempBox2Size),_=Math.max(I.x,I.y);if(Math.max(d.x,d.y)!=0&&_!=0&&(d.z=I.z/Math.max(I.x,I.y)*Math.max(d.x,d.y)),s.lastScreenCoverage=Math.max(d.x,d.y,d.z),s.lastScreenspaceVolume.copy(d),s.lastScreenCoverage*=s.lastCentrality,B&&P.debugDrawLine){const m=this.tempMatrix.copy(this.projectionScreenMatrix);m.invert();const p=P.corner0,h=P.corner1,M=P.corner2,S=P.corner3;p.copy(this._tempBox.min),h.copy(this._tempBox.max),h.x=p.x,M.copy(this._tempBox.max),M.y=p.y,S.copy(this._tempBox.max);const j=(p.z+S.z)*.5;p.z=h.z=M.z=S.z=j,p.applyMatrix4(m),h.applyMatrix4(m),M.applyMatrix4(m),S.applyMatrix4(m),P.debugDrawLine(p,h,255),P.debugDrawLine(p,M,255),P.debugDrawLine(h,S,255),P.debugDrawLine(M,S,255)}let k=999;if(a&&s.lastScreenCoverage>0){for(let m=0;m<a.length;m++)if(a[m].density/s.lastScreenCoverage<o){k=m;break}}k<i&&(i=k,l=!0)}if(l?r.mesh_lod=i:r.mesh_lod=s.lastLodLevel_Mesh,B&&r.mesh_lod!=s.lastLodLevel_Mesh){const y=a?.[r.mesh_lod];y&&console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} \u2192 ${r.mesh_lod} (${y.density.toFixed(0)}) - ${e.name}`)}if(v){const y="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(s.lastLodLevel_Texture<0){if(r.texture_lod=g.max_count-1,B){const d=g.lods[g.max_count-1];B&&console.log(`First Texture LOD ${r.texture_lod} (${d.max_height}px) - ${e.name}`)}}else{const d=s.lastScreenspaceVolume.x+s.lastScreenspaceVolume.y+s.lastScreenspaceVolume.z;let O=s.lastScreenCoverage*4;((n=this.context)==null?void 0:n.engine)==="model-viewer"&&(O*=1.5);const b=A/window.devicePixelRatio*O;let I=!1;for(let _=g.lods.length-1;_>=0;_--){let k=g.lods[_];if(!(y&&k.max_height>=2048)&&!(it()&&k.max_height>4096)&&(k.max_height>b||!I&&_===0)){if(I=!0,r.texture_lod=_,r.texture_lod<s.lastLodLevel_Texture){const m=k.max_height;B&&console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} \u2192 ${r.texture_lod} = ${m}px
6
6
  Screensize: ${b.toFixed(0)}px, Coverage: ${(100*s.lastScreenCoverage).toFixed(2)}%, Volume ${d.toFixed(1)}
7
- ${e.name}`)}break}}}}else r.texture_lod=0}};let R=P;E=new WeakMap,F=new WeakMap,_e=new WeakMap,Z=new WeakMap,oe=new WeakMap,de=new WeakMap,U=new WeakMap,c(R,"debugDrawLine"),c(R,"corner0",new N),c(R,"corner1",new N),c(R,"corner2",new N),c(R,"corner3",new N),c(R,"_tempPtInside",new N);class dt{constructor(){c(this,"frames",0),c(this,"lastLodLevel_Mesh",-1),c(this,"lastLodLevel_Texture",-1),c(this,"lastScreenCoverage",0),c(this,"lastScreenspaceVolume",new N),c(this,"lastCentrality",0)}}const Ce=Symbol("NEEDLE_mesh_lod"),he=Symbol("NEEDLE_texture_lod");let fe=null;function Se(){const t=ht();t&&(t.mapURLs(function(e){return je(),e}),je(),fe?.disconnect(),fe=new MutationObserver(e=>{e.forEach(s=>{s.addedNodes.forEach(o=>{o instanceof HTMLElement&&o.tagName.toLowerCase()==="model-viewer"&&Ne(o)})})}),fe.observe(document,{childList:!0,subtree:!0}))}function ht(){return typeof customElements>"u"?null:customElements.get("model-viewer")||(customElements.whenDefined("model-viewer").then(()=>{console.debug("[gltf-progressive] model-viewer defined"),Se()}),null)}function je(){typeof document>"u"||document.querySelectorAll("model-viewer").forEach(t=>{Ne(t)})}const Ge=new WeakSet;let ft=0;function Ne(t){if(!t||Ge.has(t))return null;Ge.add(t),console.debug("[gltf-progressive] found new model-viewer..."+ ++ft+`
8
- `,t.getAttribute("src"));let e=null,s=null,o=null;for(let r=t;r!=null;r=Object.getPrototypeOf(r)){const n=Object.getOwnPropertySymbols(r),i=n.find(a=>a.toString()=="Symbol(renderer)"),l=n.find(a=>a.toString()=="Symbol(scene)"),u=n.find(a=>a.toString()=="Symbol(needsRender)");!e&&i!=null&&(e=t[i].threeRenderer),!s&&l!=null&&(s=t[l]),!o&&u!=null&&(o=t[u])}if(e&&s){let r=function(){if(o){let i=0,l=setInterval(()=>{if(i++>5){clearInterval(l);return}o?.call(t)},300)}};console.debug("[gltf-progressive] setup model-viewer");const n=R.get(e,{engine:"model-viewer"});return R.addPlugin(new gt),n.enable(),n.addEventListener("changed",()=>{o?.call(t)}),t.addEventListener("model-visibility",i=>{i.detail.visible&&o?.call(t)}),t.addEventListener("load",()=>{r()}),()=>{n.disable()}}return null}class gt{constructor(){c(this,"_didWarnAboutMissingUrl",!1)}onBeforeUpdateLOD(e,s,o,r){this.tryParseMeshLOD(s,r),this.tryParseTextureLOD(s,r)}getUrl(e){if(!e)return null;let s=e.getAttribute("src");return s||(s=e.src),s||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",e),this._didWarnAboutMissingUrl=!0),s}tryGetCurrentGLTF(e){return e._currentGLTF}tryGetCurrentModelViewer(e){return e.element}tryParseTextureLOD(e,s){if(s[he]==!0)return;s[he]=!0;const o=this.tryGetCurrentGLTF(e),r=this.tryGetCurrentModelViewer(e),n=this.getUrl(r);if(n&&o&&s.material){let i=function(u){var a,f,g;if(u[he]==!0)return;u[he]=!0,u.userData&&(u.userData.LOD=-1);const p=Object.keys(u);for(let A=0;A<p.length;A++){const D=p[A],L=u[D];if(L?.isTexture===!0){const d=(f=(a=L.userData)==null?void 0:a.associations)==null?void 0:f.textures;if(d==null)continue;const O=o.parser.json.textures[d];if(!O){console.warn("Texture data not found for texture index "+d);continue}if((g=O?.extensions)!=null&&g[j]){const b=O.extensions[j];b&&n&&S.registerTexture(n,L,b.lods.length,d,b)}}}};const l=s.material;if(Array.isArray(l))for(const u of l)i(u);else i(l)}}tryParseMeshLOD(e,s){var o,r;if(s[Ce]==!0)return;s[Ce]=!0;const n=this.tryGetCurrentModelViewer(e),i=this.getUrl(n);if(!i)return;const l=(r=(o=s.userData)==null?void 0:o.gltfExtensions)==null?void 0:r[j];if(l&&i){const u=s.uuid;S.registerMesh(i,u,s,0,l.lods.length,l)}}}function We(t,e,s,o){ye(e),ve(s),Le(s,{progressive:!0,...o?.hints}),s.register(n=>new S(n,t));const r=R.get(e);return o?.enableLODsManager!==!1&&r.enable(),r}if(Se(),!at){const t={gltfProgressive:{useNeedleProgressive:We,LODsManager:R,configureLoader:Le,getRaycastMesh:J,useRaycastMeshes:Be}};if(!globalThis.Needle)globalThis.Needle=t;else for(const e in t)globalThis.Needle[e]=t[e]}export{j as EXTENSION_NAME,R as LODsManager,S as NEEDLE_progressive,pe as VERSION,ve as addDracoAndKTX2Loaders,Le as configureLoader,ye as createLoaders,J as getRaycastMesh,Se as patchModelViewer,ke as registerRaycastMesh,st as setDracoDecoderLocation,rt as setKTX2TranscoderLocation,We as useNeedleProgressive,Be as useRaycastMeshes};
7
+ ${e.name}`)}break}}}}else r.texture_lod=0}};let R=P;E=new WeakMap,F=new WeakMap,_e=new WeakMap,Z=new WeakMap,oe=new WeakMap,de=new WeakMap,U=new WeakMap,c(R,"debugDrawLine"),c(R,"corner0",new W),c(R,"corner1",new W),c(R,"corner2",new W),c(R,"corner3",new W),c(R,"_tempPtInside",new W);class dt{constructor(){c(this,"frames",0),c(this,"lastLodLevel_Mesh",-1),c(this,"lastLodLevel_Texture",-1),c(this,"lastScreenCoverage",0),c(this,"lastScreenspaceVolume",new W),c(this,"lastCentrality",0)}}const Re=Symbol("NEEDLE_mesh_lod"),he=Symbol("NEEDLE_texture_lod");let fe=null;function Se(){const t=ht();t&&(t.mapURLs(function(e){return je(),e}),je(),fe?.disconnect(),fe=new MutationObserver(e=>{e.forEach(s=>{s.addedNodes.forEach(o=>{o instanceof HTMLElement&&o.tagName.toLowerCase()==="model-viewer"&&Ge(o)})})}),fe.observe(document,{childList:!0,subtree:!0}))}function ht(){return typeof customElements>"u"?null:customElements.get("model-viewer")||(customElements.whenDefined("model-viewer").then(()=>{console.debug("[gltf-progressive] model-viewer defined"),Se()}),null)}function je(){typeof document>"u"||document.querySelectorAll("model-viewer").forEach(t=>{Ge(t)})}const Ne=new WeakSet;let ft=0;function Ge(t){if(!t||Ne.has(t))return null;Ne.add(t),console.debug("[gltf-progressive] found new model-viewer..."+ ++ft+`
8
+ `,t.getAttribute("src"));let e=null,s=null,o=null;for(let r=t;r!=null;r=Object.getPrototypeOf(r)){const n=Object.getOwnPropertySymbols(r),i=n.find(a=>a.toString()=="Symbol(renderer)"),l=n.find(a=>a.toString()=="Symbol(scene)"),u=n.find(a=>a.toString()=="Symbol(needsRender)");!e&&i!=null&&(e=t[i].threeRenderer),!s&&l!=null&&(s=t[l]),!o&&u!=null&&(o=t[u])}if(e&&s){let r=function(){if(o){let i=0,l=setInterval(()=>{if(i++>5){clearInterval(l);return}o?.call(t)},300)}};console.debug("[gltf-progressive] setup model-viewer");const n=R.get(e,{engine:"model-viewer"});return R.addPlugin(new gt),n.enable(),n.addEventListener("changed",()=>{o?.call(t)}),t.addEventListener("model-visibility",i=>{i.detail.visible&&o?.call(t)}),t.addEventListener("load",()=>{r()}),()=>{n.disable()}}return null}class gt{constructor(){c(this,"_didWarnAboutMissingUrl",!1)}onBeforeUpdateLOD(e,s,o,r){this.tryParseMeshLOD(s,r),this.tryParseTextureLOD(s,r)}getUrl(e){if(!e)return null;let s=e.getAttribute("src");return s||(s=e.src),s||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",e),this._didWarnAboutMissingUrl=!0),s}tryGetCurrentGLTF(e){return e._currentGLTF}tryGetCurrentModelViewer(e){return e.element}tryParseTextureLOD(e,s){if(s[he]==!0)return;s[he]=!0;const o=this.tryGetCurrentGLTF(e),r=this.tryGetCurrentModelViewer(e),n=this.getUrl(r);if(n&&o&&s.material){let i=function(u){var a,f,g;if(u[he]==!0)return;u[he]=!0,u.userData&&(u.userData.LOD=-1);const v=Object.keys(u);for(let A=0;A<v.length;A++){const D=v[A],y=u[D];if(y?.isTexture===!0){const d=(f=(a=y.userData)==null?void 0:a.associations)==null?void 0:f.textures;if(d==null)continue;const O=o.parser.json.textures[d];if(!O){console.warn("Texture data not found for texture index "+d);continue}if((g=O?.extensions)!=null&&g[N]){const b=O.extensions[N];b&&n&&T.registerTexture(n,y,b.lods.length,d,b)}}}};const l=s.material;if(Array.isArray(l))for(const u of l)i(u);else i(l)}}tryParseMeshLOD(e,s){var o,r;if(s[Re]==!0)return;s[Re]=!0;const n=this.tryGetCurrentModelViewer(e),i=this.getUrl(n);if(!i)return;const l=(r=(o=s.userData)==null?void 0:o.gltfExtensions)==null?void 0:r[N];if(l&&i){const u=s.uuid;T.registerMesh(i,u,s,0,l.lods.length,l)}}}function We(t,e,s,o){ve(e),ye(s),Le(s,{progressive:!0,...o?.hints}),s.register(n=>new T(n,t));const r=R.get(e);return o?.enableLODsManager!==!1&&r.enable(),r}if(Se(),!at){const t={gltfProgressive:{useNeedleProgressive:We,LODsManager:R,configureLoader:Le,getRaycastMesh:J,useRaycastMeshes:Be}};if(!globalThis.Needle)globalThis.Needle=t;else for(const e in t)globalThis.Needle[e]=t[e]}export{N as EXTENSION_NAME,R as LODsManager,T as NEEDLE_progressive,pe as VERSION,ye as addDracoAndKTX2Loaders,Le as configureLoader,ve as createLoaders,J as getRaycastMesh,Se as patchModelViewer,ke as registerRaycastMesh,st as setDracoDecoderLocation,rt as setKTX2TranscoderLocation,We as useNeedleProgressive,Be as useRaycastMeshes};
@@ -1,8 +1,8 @@
1
- "use strict";var Ue=Object.defineProperty;var ze=(n,e,t)=>e in n?Ue(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var d=(n,e,t)=>(ze(n,typeof e!="symbol"?e+"":e,t),t),Ee=(n,e,t)=>{if(!e.has(n))throw TypeError("Cannot "+t)};var L=(n,e,t)=>(Ee(n,e,"read from private field"),t?t.call(n):e.get(n)),K=(n,e,t)=>{if(e.has(n))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(n):e.set(n,t)},N=(n,e,t,s)=>(Ee(n,e,"write to private field"),s?s.call(n,t):e.set(n,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const p=require("three"),_e=require("three/examples/jsm/loaders/GLTFLoader.js"),We=require("three/examples/jsm/libs/meshopt_decoder.module.js"),qe=require("three/examples/jsm/loaders/DRACOLoader.js"),Xe=require("three/examples/jsm/loaders/KTX2Loader.js"),Oe="";globalThis.GLTF_PROGRESSIVE_VERSION=Oe;console.debug(`[gltf-progressive] version ${Oe}`);let ee="https://www.gstatic.com/draco/versioned/decoders/1.5.7/",ne="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";const Ke=ee,Ye=ne,He=new URL(ee+"draco_decoder.js");fetch(He,{method:"GET",headers:{Range:"bytes=0-1"}}).catch(n=>{ee===Ke&&(ee="./include/draco/"),ne===Ye&&(ne="./include/ktx2/")}).finally(()=>{ke()});function je(n){ee=n}function Je(n){ne=n}let H,de,j;function ke(){H||(H=new qe.DRACOLoader,H.setDecoderPath(ee),H.setDecoderConfig({type:"js"}),H.preload()),j||(j=new Xe.KTX2Loader,j.setTranscoderPath(ne),j.init()),de||(de=We.MeshoptDecoder)}function Se(n){return ke(),n?j.detectSupport(n):n!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:H,ktx2Loader:j,meshoptDecoder:de}}function be(n){n.dracoLoader||n.setDRACOLoader(H),n.ktx2Loader||n.setKTX2Loader(j),n.meshoptDecoder||n.setMeshoptDecoder(de)}const De=new WeakMap;function Te(n,e){let t=De.get(n);t?t=Object.assign(t,e):t=e,De.set(n,t)}const me=_e.GLTFLoader.prototype.load;function Qe(...n){const e=De.get(this);let t=n[0];const s=new URL(t,window.location.href);if(s.hostname.endsWith("needle.tools")){const r=(e==null?void 0:e.progressive)!==void 0?e.progressive:!0,i=e!=null&&e.usecase?e.usecase:"default";r?this.requestHeader.Accept=`*/*;progressive=allowed;usecase=${i}`:this.requestHeader.Accept=`*/*;usecase=${i}`,t=s.toString()}return n[0]=t,me==null?void 0:me.call(this,...n)}_e.GLTFLoader.prototype.load=Qe;ae("debugprogressive");function ae(n){if(typeof window>"u")return!1;const t=new URL(window.location.href).searchParams.get(n);return t==null||t==="0"||t==="false"?!1:t===""?!0:t}function Ze(n,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||n===void 0)return e;const t=n.lastIndexOf("/");if(t>=0){const s=n.substring(0,t+1);for(;s.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return s+e}return e}let se;function et(){return se!==void 0||(se=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),ae("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",se)),se}const tt=typeof window>"u"&&typeof document>"u",we=Symbol("needle:raycast-mesh");function te(n){return(n==null?void 0:n[we])instanceof p.BufferGeometry?n[we]:null}function Ie(n,e){if((n.type==="Mesh"||n.type==="SkinnedMesh")&&!te(n)){const s=st(e);s.userData={isRaycastMesh:!0},n[we]=s}}function Ge(n=!0){if(n){if(re)return;const e=re=p.Mesh.prototype.raycast;p.Mesh.prototype.raycast=function(t,s){const o=this,r=te(o);let i;r&&o.isMesh&&(i=o.geometry,o.geometry=r),e.call(this,t,s),i&&(o.geometry=i)}}else{if(!re)return;p.Mesh.prototype.raycast=re,re=null}}let re=null;function st(n){const e=new p.BufferGeometry;for(const t in n.attributes)e.setAttribute(t,n.getAttribute(t));return e.setIndex(n.getIndex()),e}const Y=new Array,U="NEEDLE_progressive",x=ae("debugprogressive"),Le=Symbol("needle-progressive-texture"),oe=new Map,ve=new Set;if(x){let n=function(){e+=1,console.log("Toggle LOD level",e,oe),oe.forEach((o,r)=>{for(const i of o.keys){const a=r[i];if(a!=null){if(a.isBufferGeometry===!0){const l=O.getMeshLODInformation(a),u=l?Math.min(e,l.lods.length):0;r["DEBUG:LOD"]=e,O.assignMeshLOD(r,u),l&&(t=Math.max(t,l.lods.length-1))}else if(r.isMaterial===!0){r["DEBUG:LOD"]=e,O.assignTextureLOD(r,e);break}}}}),e>=t&&(e=-1)},e=-1,t=2,s=!1;window.addEventListener("keyup",o=>{o.key==="p"&&n(),o.key==="w"&&(s=!s,ve&&ve.forEach(r=>{r.name!="BackgroundCubeMaterial"&&r.glyphMap==null&&"wireframe"in r&&(r.wireframe=s)}))})}function Pe(n,e,t){var o;if(!x)return;oe.has(n)||oe.set(n,{keys:[],sourceId:t});const s=oe.get(n);((o=s==null?void 0:s.keys)==null?void 0:o.includes(e))==!1&&s.keys.push(e)}const _=class{constructor(e,t){d(this,"parser");d(this,"url");d(this,"_isLoadingMesh");d(this,"loadMesh",e=>{var s,o;if(this._isLoadingMesh)return null;const t=(o=(s=this.parser.json.meshes[e])==null?void 0:s.extensions)==null?void 0:o[U];return t?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",e).then(r=>{var i;return this._isLoadingMesh=!1,r&&_.registerMesh(this.url,t.guid,r,(i=t.lods)==null?void 0:i.length,void 0,t),r})):null});x&&console.log("Progressive extension registered for",t),this.parser=e,this.url=t}get name(){return U}static getMeshLODInformation(e){const t=this.getAssignedLODInformation(e);return t!=null&&t.key?this.lodInfos.get(t.key):null}static getMaterialMinMaxLODsCount(e,t){const s=this,o="LODS:minmax",r=e[o];if(r!=null)return r;if(t||(t={min_count:1/0,max_count:0,lods:[]}),Array.isArray(e)){for(const a of e)this.getMaterialMinMaxLODsCount(a,t);return e[o]=t,t}if(x==="verbose"&&console.log("getMaterialMinMaxLODsCount",e),e.type==="ShaderMaterial"||e.type==="RawShaderMaterial"){const a=e;for(const l of Object.keys(a.uniforms)){const u=a.uniforms[l].value;(u==null?void 0:u.isTexture)===!0&&i(u,t)}}else if(e.isMaterial)for(const a of Object.keys(e)){const l=e[a];(l==null?void 0:l.isTexture)===!0&&i(l,t)}return e[o]=t,t;function i(a,l){const u=s.getAssignedLODInformation(a);if(u){const c=s.lodInfos.get(u.key);if(c&&c.lods){l.min_count=Math.min(l.min_count,c.lods.length),l.max_count=Math.max(l.max_count,c.lods.length);for(let g=0;g<c.lods.length;g++){const y=c.lods[g];y.width&&(l.lods[g]=l.lods[g]||{min_height:1/0,max_height:0},l.lods[g].min_height=Math.min(l.lods[g].min_height,y.height),l.lods[g].max_height=Math.max(l.lods[g].max_height,y.height))}}}}}static hasLODLevelAvailable(e,t){var r;if(Array.isArray(e)){for(const i of e)if(this.hasLODLevelAvailable(i,t))return!0;return!1}if(e.isMaterial===!0){for(const i of Object.keys(e)){const a=e[i];if(a&&a.isTexture&&this.hasLODLevelAvailable(a,t))return!0}return!1}else if(e.isGroup===!0){for(const i of e.children)if(i.isMesh===!0&&this.hasLODLevelAvailable(i,t))return!0}let s,o;if(e.isMesh?s=e.geometry:(e.isBufferGeometry||e.isTexture)&&(s=e),s&&(r=s==null?void 0:s.userData)!=null&&r.LODS){const i=s.userData.LODS;if(o=this.lodInfos.get(i.key),t===void 0)return o!=null;if(o)return Array.isArray(o.lods)?t<o.lods.length:t===0}return!1}static assignMeshLOD(e,t){var s;if(!e)return Promise.resolve(null);if(e instanceof p.Mesh||e.isMesh===!0){const o=e.geometry,r=this.getAssignedLODInformation(o);if(!r)return Promise.resolve(null);for(const i of Y)(s=i.onBeforeGetLODMesh)==null||s.call(i,e,t);return e["LOD:requested level"]=t,_.getOrLoadLOD(o,t).then(i=>{if(Array.isArray(i)){const a=r.index||0;i=i[a]}return e["LOD:requested level"]===t&&(delete e["LOD:requested level"],i&&o!=i&&((i==null?void 0:i.isBufferGeometry)?(e.geometry=i,x&&Pe(e,"geometry",r.url)):x&&console.error("Invalid LOD geometry",i))),i}).catch(i=>(console.error("Error loading mesh LOD",e,i),null))}else x&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",e);return Promise.resolve(null)}static assignTextureLOD(e,t=0){if(!e)return Promise.resolve(null);if(e.isMesh===!0){const s=e;if(Array.isArray(s.material)){const o=new Array;for(const r of s.material){const i=this.assignTextureLOD(r,t);o.push(i)}return Promise.all(o).then(r=>{const i=new Array;for(const a of r)Array.isArray(a)&&i.push(...a);return i})}else return this.assignTextureLOD(s.material,t)}if(e instanceof p.Material||e.isMaterial===!0){const s=e,o=[],r=new Array;if(x&&ve.add(s),s.uniforms&&(s.isRawShaderMaterial||s.isShaderMaterial===!0)){const i=s;for(const a of Object.keys(i.uniforms)){const l=i.uniforms[a].value;if((l==null?void 0:l.isTexture)===!0){const u=this.assignTextureLODForSlot(l,t,s,a).then(c=>(c&&i.uniforms[a].value!=c&&(i.uniforms[a].value=c,i.uniformsNeedUpdate=!0),c));o.push(u),r.push(a)}}}else for(const i of Object.keys(s)){const a=s[i];if((a==null?void 0:a.isTexture)===!0){const l=this.assignTextureLODForSlot(a,t,s,i);o.push(l),r.push(i)}}return Promise.all(o).then(i=>{const a=new Array;for(let l=0;l<i.length;l++){const u=i[l],c=r[l];u&&u.isTexture===!0?a.push({material:s,slot:c,texture:u,level:t}):a.push({material:s,slot:c,texture:null,level:t})}return a})}if(e instanceof p.Texture||e.isTexture===!0){const s=e;return this.assignTextureLODForSlot(s,t,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(e,t,s,o){return(e==null?void 0:e.isTexture)!==!0?Promise.resolve(null):o==="glyphMap"?Promise.resolve(e):_.getOrLoadLOD(e,t).then(r=>{if(Array.isArray(r))return null;if((r==null?void 0:r.isTexture)===!0){if(r!=e){if(s&&o){const i=s[o];if(i){const a=this.getAssignedLODInformation(i);if(a&&(a==null?void 0:a.level)<t)return x==="verbose"&&console.warn("Assigned texture level is already higher: ",a.level,t,s,i,r),null}s[o]=r}if(x&&o&&s){const i=this.getAssignedLODInformation(e);i&&Pe(s,o,i.url)}}return r}else x=="verbose"&&console.warn("No LOD found for",e,t);return null}).catch(r=>(console.error("Error loading LOD",e,r),null))}afterRoot(e){var t,s;return x&&console.log("AFTER",this.url,e),(t=this.parser.json.textures)==null||t.forEach((o,r)=>{var i;if(o!=null&&o.extensions){const a=o==null?void 0:o.extensions[U];if(a){if(!a.lods){x&&console.warn("Texture has no LODs",a);return}let l=!1;for(const u of this.parser.associations.keys())if(u.isTexture===!0){const c=this.parser.associations.get(u);(c==null?void 0:c.textures)===r&&(l=!0,_.registerTexture(this.url,u,(i=a.lods)==null?void 0:i.length,r,a))}l||this.parser.getDependency("texture",r).then(u=>{var c;u&&_.registerTexture(this.url,u,(c=a.lods)==null?void 0:c.length,r,a)})}}}),(s=this.parser.json.meshes)==null||s.forEach((o,r)=>{if(o!=null&&o.extensions){const i=o==null?void 0:o.extensions[U];if(i&&i.lods){for(const a of this.parser.associations.keys())if(a.isMesh){const l=this.parser.associations.get(a);(l==null?void 0:l.meshes)===r&&_.registerMesh(this.url,i.guid,a,i.lods.length,l.primitives,i)}}}}),null}static async getOrLoadLOD(e,t){var a,l,u,c;const s=x=="verbose",o=e.userData.LODS;if(!o)return null;const r=o==null?void 0:o.key;let i;if(e.isTexture===!0){const g=e;g.source&&g.source[Le]&&(i=g.source[Le])}if(i||(i=_.lodInfos.get(r)),i){if(t>0){let D=!1;const v=Array.isArray(i.lods);if(v&&t>=i.lods.length?D=!0:v||(D=!0),D)return this.lowresCache.get(r)}const g=Array.isArray(i.lods)?(a=i.lods[t])==null?void 0:a.path:i.lods;if(!g)return x&&!i["missing:uri"]&&(i["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+t,i)),null;const y=Ze(o.url,g);if(y.endsWith(".glb")||y.endsWith(".gltf")){if(!i.guid)return console.warn("missing pointer for glb/gltf texture",i),null;const D=y+"_"+i.guid,v=this.previouslyLoaded.get(D);if(v!==void 0){s&&console.log(`LOD ${t} was already loading/loaded: ${D}`);let h=await v.catch($=>(console.error(`Error loading LOD ${t} from ${y}
2
- `,$),null)),k=!1;if(h==null||(h instanceof p.Texture&&e instanceof p.Texture?(l=h.image)!=null&&l.data||(u=h.source)!=null&&u.data?h=this.copySettings(e,h):(k=!0,this.previouslyLoaded.delete(D)):h instanceof p.BufferGeometry&&e instanceof p.BufferGeometry&&((c=h.attributes.position)!=null&&c.array||(k=!0,this.previouslyLoaded.delete(D)))),!k)return h}const M=i,V=new Promise(async(h,k)=>{const $=new _e.GLTFLoader;be($),x&&(await new Promise(E=>setTimeout(E,1e3)),s&&console.warn("Start loading (delayed) "+y,M.guid));let I=y;if(M&&Array.isArray(M.lods)){const E=M.lods[t];E.hash&&(I+="?v="+E.hash)}const b=await $.loadAsync(I).catch(E=>(console.error(`Error loading LOD ${t} from ${y}
3
- `,E),null));if(!b)return null;const q=b.parser;s&&console.log("Loading finished "+y,M.guid);let A=0;if(b.parser.json.textures){let E=!1;for(const f of b.parser.json.textures){if(f!=null&&f.extensions){const m=f==null?void 0:f.extensions[U];if(m!=null&&m.guid&&m.guid===M.guid){E=!0;break}}A++}if(E){let f=await q.getDependency("texture",A);return f&&_.assignLODInformation(o.url,f,r,t,void 0,void 0),s&&console.log('change "'+e.name+'" → "'+f.name+'"',y,A,f,D),e instanceof p.Texture&&(f=this.copySettings(e,f)),f&&(f.guid=M.guid),h(f)}else x&&console.warn("Could not find texture with guid",M.guid,b.parser.json)}if(A=0,b.parser.json.meshes){let E=!1;for(const f of b.parser.json.meshes){if(f!=null&&f.extensions){const m=f==null?void 0:f.extensions[U];if(m!=null&&m.guid&&m.guid===M.guid){E=!0;break}}A++}if(E){const f=await q.getDependency("mesh",A),m=M;if(s&&console.log(`Loaded Mesh "${f.name}"`,y,A,f,D),f.isMesh===!0){const S=f.geometry;return _.assignLODInformation(o.url,S,r,t,void 0,m.density),h(S)}else{const S=new Array;for(let T=0;T<f.children.length;T++){const P=f.children[T];if(P.isMesh===!0){const X=P.geometry;_.assignLODInformation(o.url,X,r,t,T,m.density),S.push(X)}}return h(S)}}else x&&console.warn("Could not find mesh with guid",M.guid,b.parser.json)}return h(null)});return this.previouslyLoaded.set(D,V),await V}else if(e instanceof p.Texture){s&&console.log("Load texture from uri: "+y);const v=await new p.TextureLoader().loadAsync(y);return v?(v.guid=i.guid,v.flipY=!1,v.needsUpdate=!0,v.colorSpace=e.colorSpace,s&&console.log(i,v)):x&&console.warn("failed loading",y),v}}else x&&console.warn(`Can not load LOD ${t}: no LOD info found for "${r}" ${e.name}`,e.type);return null}static assignLODInformation(e,t,s,o,r,i){if(!t)return;t.userData||(t.userData={});const a=new rt(e,s,o,r,i);t.userData.LODS=a}static getAssignedLODInformation(e){var t;return((t=e==null?void 0:e.userData)==null?void 0:t.LODS)||null}static copySettings(e,t){return t=t.clone(),x&&console.warn(`Copying texture settings
1
+ "use strict";var Ue=Object.defineProperty;var ze=(n,e,t)=>e in n?Ue(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var d=(n,e,t)=>(ze(n,typeof e!="symbol"?e+"":e,t),t),Ee=(n,e,t)=>{if(!e.has(n))throw TypeError("Cannot "+t)};var L=(n,e,t)=>(Ee(n,e,"read from private field"),t?t.call(n):e.get(n)),K=(n,e,t)=>{if(e.has(n))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(n):e.set(n,t)},N=(n,e,t,s)=>(Ee(n,e,"write to private field"),s?s.call(n,t):e.set(n,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const p=require("three"),_e=require("three/examples/jsm/loaders/GLTFLoader.js"),We=require("three/examples/jsm/libs/meshopt_decoder.module.js"),qe=require("three/examples/jsm/loaders/DRACOLoader.js"),Xe=require("three/examples/jsm/loaders/KTX2Loader.js"),Oe="";globalThis.GLTF_PROGRESSIVE_VERSION=Oe;console.debug(`[gltf-progressive] version ${Oe}`);let ee="https://www.gstatic.com/draco/versioned/decoders/1.5.7/",ne="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";const Ke=ee,Ye=ne,He=new URL(ee+"draco_decoder.js");fetch(He,{method:"GET",headers:{Range:"bytes=0-1"}}).catch(n=>{ee===Ke&&(ee="./include/draco/"),ne===Ye&&(ne="./include/ktx2/")}).finally(()=>{ke()});function je(n){ee=n}function Je(n){ne=n}let H,de,j;function ke(){H||(H=new qe.DRACOLoader,H.setDecoderPath(ee),H.setDecoderConfig({type:"js"}),H.preload()),j||(j=new Xe.KTX2Loader,j.setTranscoderPath(ne),j.init()),de||(de=We.MeshoptDecoder)}function Se(n){return ke(),n?j.detectSupport(n):n!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:H,ktx2Loader:j,meshoptDecoder:de}}function be(n){n.dracoLoader||n.setDRACOLoader(H),n.ktx2Loader||n.setKTX2Loader(j),n.meshoptDecoder||n.setMeshoptDecoder(de)}const De=new WeakMap;function Te(n,e){let t=De.get(n);t?t=Object.assign(t,e):t=e,De.set(n,t)}const me=_e.GLTFLoader.prototype.load;function Qe(...n){const e=De.get(this);let t=n[0];const s=new URL(t,window.location.href);if(s.hostname.endsWith("needle.tools")){const r=(e==null?void 0:e.progressive)!==void 0?e.progressive:!0,i=e!=null&&e.usecase?e.usecase:"default";r?this.requestHeader.Accept=`*/*;progressive=allowed;usecase=${i}`:this.requestHeader.Accept=`*/*;usecase=${i}`,t=s.toString()}return n[0]=t,me==null?void 0:me.call(this,...n)}_e.GLTFLoader.prototype.load=Qe;ae("debugprogressive");function ae(n){if(typeof window>"u")return!1;const t=new URL(window.location.href).searchParams.get(n);return t==null||t==="0"||t==="false"?!1:t===""?!0:t}function Ze(n,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||n===void 0)return e;const t=n.lastIndexOf("/");if(t>=0){const s=n.substring(0,t+1);for(;s.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return s+e}return e}let se;function et(){return se!==void 0||(se=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),ae("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",se)),se}const tt=typeof window>"u"&&typeof document>"u",we=Symbol("needle:raycast-mesh");function te(n){return(n==null?void 0:n[we])instanceof p.BufferGeometry?n[we]:null}function Ie(n,e){if((n.type==="Mesh"||n.type==="SkinnedMesh")&&!te(n)){const s=st(e);s.userData={isRaycastMesh:!0},n[we]=s}}function Ge(n=!0){if(n){if(re)return;const e=re=p.Mesh.prototype.raycast;p.Mesh.prototype.raycast=function(t,s){const o=this,r=te(o);let i;r&&o.isMesh&&(i=o.geometry,o.geometry=r),e.call(this,t,s),i&&(o.geometry=i)}}else{if(!re)return;p.Mesh.prototype.raycast=re,re=null}}let re=null;function st(n){const e=new p.BufferGeometry;for(const t in n.attributes)e.setAttribute(t,n.getAttribute(t));return e.setIndex(n.getIndex()),e}const Y=new Array,U="NEEDLE_progressive",x=ae("debugprogressive"),Le=Symbol("needle-progressive-texture"),oe=new Map,ve=new Set;if(x){let n=function(){e+=1,console.log("Toggle LOD level",e,oe),oe.forEach((o,r)=>{for(const i of o.keys){const a=r[i];if(a!=null){if(a.isBufferGeometry===!0){const l=O.getMeshLODInformation(a),u=l?Math.min(e,l.lods.length):0;r["DEBUG:LOD"]=e,O.assignMeshLOD(r,u),l&&(t=Math.max(t,l.lods.length-1))}else if(r.isMaterial===!0){r["DEBUG:LOD"]=e,O.assignTextureLOD(r,e);break}}}}),e>=t&&(e=-1)},e=-1,t=2,s=!1;window.addEventListener("keyup",o=>{o.key==="p"&&n(),o.key==="w"&&(s=!s,ve&&ve.forEach(r=>{r.name!="BackgroundCubeMaterial"&&r.glyphMap==null&&"wireframe"in r&&(r.wireframe=s)}))})}function Pe(n,e,t){var o;if(!x)return;oe.has(n)||oe.set(n,{keys:[],sourceId:t});const s=oe.get(n);((o=s==null?void 0:s.keys)==null?void 0:o.includes(e))==!1&&s.keys.push(e)}const _=class{constructor(e,t){d(this,"parser");d(this,"url");d(this,"_isLoadingMesh");d(this,"loadMesh",e=>{var s,o;if(this._isLoadingMesh)return null;const t=(o=(s=this.parser.json.meshes[e])==null?void 0:s.extensions)==null?void 0:o[U];return t?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",e).then(r=>{var i;return this._isLoadingMesh=!1,r&&_.registerMesh(this.url,t.guid,r,(i=t.lods)==null?void 0:i.length,void 0,t),r})):null});x&&console.log("Progressive extension registered for",t),this.parser=e,this.url=t}get name(){return U}static getMeshLODInformation(e){const t=this.getAssignedLODInformation(e);return t!=null&&t.key?this.lodInfos.get(t.key):null}static getMaterialMinMaxLODsCount(e,t){const s=this,o="LODS:minmax",r=e[o];if(r!=null)return r;if(t||(t={min_count:1/0,max_count:0,lods:[]}),Array.isArray(e)){for(const a of e)this.getMaterialMinMaxLODsCount(a,t);return e[o]=t,t}if(x==="verbose"&&console.log("getMaterialMinMaxLODsCount",e),e.type==="ShaderMaterial"||e.type==="RawShaderMaterial"){const a=e;for(const l of Object.keys(a.uniforms)){const u=a.uniforms[l].value;(u==null?void 0:u.isTexture)===!0&&i(u,t)}}else if(e.isMaterial)for(const a of Object.keys(e)){const l=e[a];(l==null?void 0:l.isTexture)===!0&&i(l,t)}return e[o]=t,t;function i(a,l){const u=s.getAssignedLODInformation(a);if(u){const c=s.lodInfos.get(u.key);if(c&&c.lods){l.min_count=Math.min(l.min_count,c.lods.length),l.max_count=Math.max(l.max_count,c.lods.length);for(let g=0;g<c.lods.length;g++){const y=c.lods[g];y.width&&(l.lods[g]=l.lods[g]||{min_height:1/0,max_height:0},l.lods[g].min_height=Math.min(l.lods[g].min_height,y.height),l.lods[g].max_height=Math.max(l.lods[g].max_height,y.height))}}}}}static hasLODLevelAvailable(e,t){var r;if(Array.isArray(e)){for(const i of e)if(this.hasLODLevelAvailable(i,t))return!0;return!1}if(e.isMaterial===!0){for(const i of Object.keys(e)){const a=e[i];if(a&&a.isTexture&&this.hasLODLevelAvailable(a,t))return!0}return!1}else if(e.isGroup===!0){for(const i of e.children)if(i.isMesh===!0&&this.hasLODLevelAvailable(i,t))return!0}let s,o;if(e.isMesh?s=e.geometry:(e.isBufferGeometry||e.isTexture)&&(s=e),s&&(r=s==null?void 0:s.userData)!=null&&r.LODS){const i=s.userData.LODS;if(o=this.lodInfos.get(i.key),t===void 0)return o!=null;if(o)return Array.isArray(o.lods)?t<o.lods.length:t===0}return!1}static assignMeshLOD(e,t){var s;if(!e)return Promise.resolve(null);if(e instanceof p.Mesh||e.isMesh===!0){const o=e.geometry,r=this.getAssignedLODInformation(o);if(!r)return Promise.resolve(null);for(const i of Y)(s=i.onBeforeGetLODMesh)==null||s.call(i,e,t);return e["LOD:requested level"]=t,_.getOrLoadLOD(o,t).then(i=>{if(Array.isArray(i)){const a=r.index||0;i=i[a]}return e["LOD:requested level"]===t&&(delete e["LOD:requested level"],i&&o!=i&&((i==null?void 0:i.isBufferGeometry)?(e.geometry=i,x&&Pe(e,"geometry",r.url)):x&&console.error("Invalid LOD geometry",i))),i}).catch(i=>(console.error("Error loading mesh LOD",e,i),null))}else x&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",e);return Promise.resolve(null)}static assignTextureLOD(e,t=0){if(!e)return Promise.resolve(null);if(e.isMesh===!0){const s=e;if(Array.isArray(s.material)){const o=new Array;for(const r of s.material){const i=this.assignTextureLOD(r,t);o.push(i)}return Promise.all(o).then(r=>{const i=new Array;for(const a of r)Array.isArray(a)&&i.push(...a);return i})}else return this.assignTextureLOD(s.material,t)}if(e instanceof p.Material||e.isMaterial===!0){const s=e,o=[],r=new Array;if(x&&ve.add(s),s.uniforms&&(s.isRawShaderMaterial||s.isShaderMaterial===!0)){const i=s;for(const a of Object.keys(i.uniforms)){const l=i.uniforms[a].value;if((l==null?void 0:l.isTexture)===!0){const u=this.assignTextureLODForSlot(l,t,s,a).then(c=>(c&&i.uniforms[a].value!=c&&(i.uniforms[a].value=c,i.uniformsNeedUpdate=!0),c));o.push(u),r.push(a)}}}else for(const i of Object.keys(s)){const a=s[i];if((a==null?void 0:a.isTexture)===!0){const l=this.assignTextureLODForSlot(a,t,s,i);o.push(l),r.push(i)}}return Promise.all(o).then(i=>{const a=new Array;for(let l=0;l<i.length;l++){const u=i[l],c=r[l];u&&u.isTexture===!0?a.push({material:s,slot:c,texture:u,level:t}):a.push({material:s,slot:c,texture:null,level:t})}return a})}if(e instanceof p.Texture||e.isTexture===!0){const s=e;return this.assignTextureLODForSlot(s,t,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(e,t,s,o){return(e==null?void 0:e.isTexture)!==!0?Promise.resolve(null):o==="glyphMap"?Promise.resolve(e):_.getOrLoadLOD(e,t).then(r=>{if(Array.isArray(r))return null;if((r==null?void 0:r.isTexture)===!0){if(r!=e){if(s&&o){const i=s[o];if(i){const a=this.getAssignedLODInformation(i);if(a&&(a==null?void 0:a.level)<t)return x==="verbose"&&console.warn("Assigned texture level is already higher: ",a.level,t,s,i,r),null}s[o]=r}if(x&&o&&s){const i=this.getAssignedLODInformation(e);i&&Pe(s,o,i.url)}}return r}else x=="verbose"&&console.warn("No LOD found for",e,t);return null}).catch(r=>(console.error("Error loading LOD",e,r),null))}afterRoot(e){var t,s;return x&&console.log("AFTER",this.url,e),(t=this.parser.json.textures)==null||t.forEach((o,r)=>{var i;if(o!=null&&o.extensions){const a=o==null?void 0:o.extensions[U];if(a){if(!a.lods){x&&console.warn("Texture has no LODs",a);return}let l=!1;for(const u of this.parser.associations.keys())if(u.isTexture===!0){const c=this.parser.associations.get(u);(c==null?void 0:c.textures)===r&&(l=!0,_.registerTexture(this.url,u,(i=a.lods)==null?void 0:i.length,r,a))}l||this.parser.getDependency("texture",r).then(u=>{var c;u&&_.registerTexture(this.url,u,(c=a.lods)==null?void 0:c.length,r,a)})}}}),(s=this.parser.json.meshes)==null||s.forEach((o,r)=>{if(o!=null&&o.extensions){const i=o==null?void 0:o.extensions[U];if(i&&i.lods){for(const a of this.parser.associations.keys())if(a.isMesh){const l=this.parser.associations.get(a);(l==null?void 0:l.meshes)===r&&_.registerMesh(this.url,i.guid,a,i.lods.length,l.primitives,i)}}}}),null}static async getOrLoadLOD(e,t){var a,l,u,c;const s=x=="verbose",o=e.userData.LODS;if(!o)return null;const r=o==null?void 0:o.key;let i;if(e.isTexture===!0){const g=e;g.source&&g.source[Le]&&(i=g.source[Le])}if(i||(i=_.lodInfos.get(r)),i){if(t>0){let w=!1;const v=Array.isArray(i.lods);if(v&&t>=i.lods.length?w=!0:v||(w=!0),w)return this.lowresCache.get(r)}const g=Array.isArray(i.lods)?(a=i.lods[t])==null?void 0:a.path:i.lods;if(!g)return x&&!i["missing:uri"]&&(i["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+t,i)),null;const y=Ze(o.url,g);if(y.endsWith(".glb")||y.endsWith(".gltf")){if(!i.guid)return console.warn("missing pointer for glb/gltf texture",i),null;const w=y+"_"+i.guid,v=this.previouslyLoaded.get(w);if(v!==void 0){s&&console.log(`LOD ${t} was already loading/loaded: ${w}`);let h=await v.catch($=>(console.error(`Error loading LOD ${t} from ${y}
2
+ `,$),null)),k=!1;if(h==null||(h instanceof p.Texture&&e instanceof p.Texture?(l=h.image)!=null&&l.data||(u=h.source)!=null&&u.data?h=this.copySettings(e,h):(k=!0,this.previouslyLoaded.delete(w)):h instanceof p.BufferGeometry&&e instanceof p.BufferGeometry&&((c=h.attributes.position)!=null&&c.array||(k=!0,this.previouslyLoaded.delete(w)))),!k)return h}const M=i,V=new Promise(async(h,k)=>{const $=new _e.GLTFLoader;be($),x&&(await new Promise(T=>setTimeout(T,1e3)),s&&console.warn("Start loading (delayed) "+y,M.guid));let I=y;if(M&&Array.isArray(M.lods)){const T=M.lods[t];T.hash&&(I+="?v="+T.hash)}const E=await $.loadAsync(I).catch(T=>(console.error(`Error loading LOD ${t} from ${y}
3
+ `,T),null));if(!E)return null;const z=E.parser;s&&console.log("Loading finished "+y,M.guid);let b=0;if(E.parser.json.textures){let T=!1;for(const f of E.parser.json.textures){if(f!=null&&f.extensions){const m=f==null?void 0:f.extensions[U];if(m!=null&&m.guid&&m.guid===M.guid){T=!0;break}}b++}if(T){let f=await z.getDependency("texture",b);return f&&_.assignLODInformation(o.url,f,r,t,void 0,void 0),s&&console.log('change "'+e.name+'" → "'+f.name+'"',y,b,f,w),e instanceof p.Texture&&(f=this.copySettings(e,f)),f&&(f.guid=M.guid),h(f)}else x&&console.warn("Could not find texture with guid",M.guid,E.parser.json)}if(b=0,E.parser.json.meshes){let T=!1;for(const f of E.parser.json.meshes){if(f!=null&&f.extensions){const m=f==null?void 0:f.extensions[U];if(m!=null&&m.guid&&m.guid===M.guid){T=!0;break}}b++}if(T){const f=await z.getDependency("mesh",b),m=M;if(s&&console.log(`Loaded Mesh "${f.name}"`,y,b,f,w),f.isMesh===!0){const S=f.geometry;return _.assignLODInformation(o.url,S,r,t,void 0,m.density),h(S)}else{const S=new Array;for(let A=0;A<f.children.length;A++){const P=f.children[A];if(P.isMesh===!0){const X=P.geometry;_.assignLODInformation(o.url,X,r,t,A,m.density),S.push(X)}}return h(S)}}else x&&console.warn("Could not find mesh with guid",M.guid,E.parser.json)}return h(null)});return this.previouslyLoaded.set(w,V),await V}else if(e instanceof p.Texture){s&&console.log("Load texture from uri: "+y);const v=await new p.TextureLoader().loadAsync(y);return v?(v.guid=i.guid,v.flipY=!1,v.needsUpdate=!0,v.colorSpace=e.colorSpace,s&&console.log(i,v)):x&&console.warn("failed loading",y),v}}else x&&console.warn(`Can not load LOD ${t}: no LOD info found for "${r}" ${e.name}`,e.type);return null}static assignLODInformation(e,t,s,o,r,i){if(!t)return;t.userData||(t.userData={});const a=new rt(e,s,o,r,i);t.userData.LODS=a}static getAssignedLODInformation(e){var t;return((t=e==null?void 0:e.userData)==null?void 0:t.LODS)||null}static copySettings(e,t){return t=t.clone(),x&&console.warn(`Copying texture settings
4
4
  `,e.uuid,`
5
- `,t.uuid),t.offset=e.offset,t.repeat=e.repeat,t.colorSpace=e.colorSpace,t.magFilter=e.magFilter,t.minFilter=e.minFilter,t.wrapS=e.wrapS,t.wrapT=e.wrapT,t.flipY=e.flipY,t.anisotropy=e.anisotropy,t.mipmaps||(t.generateMipmaps=e.generateMipmaps),t}};let O=_;d(O,"registerTexture",(e,t,s,o,r)=>{if(x&&console.log("> Progressive: register texture",o,t.name,t.uuid,t,r),!t){x&&console.error("gltf-progressive: Register texture without texture");return}t.source&&(t.source[Le]=r);const i=r.guid;_.assignLODInformation(e,t,i,s,o,void 0),_.lodInfos.set(i,r),_.lowresCache.set(i,t)}),d(O,"registerMesh",(e,t,s,o,r,i)=>{var u;x&&console.log("> Progressive: register mesh",r,s.name,i,s.uuid,s);const a=s.geometry;if(!a){x&&console.warn("gltf-progressive: Register mesh without geometry");return}a.userData||(a.userData={}),_.assignLODInformation(e,a,t,o,r,i.density),_.lodInfos.set(t,i);let l=_.lowresCache.get(t);l?l.push(s.geometry):l=[s.geometry],_.lowresCache.set(t,l),o>0&&!te(s)&&Ie(s,a);for(const c of Y)(u=c.onRegisteredNewMesh)==null||u.call(c,s,i)}),d(O,"lodInfos",new Map),d(O,"previouslyLoaded",new Map),d(O,"lowresCache",new Map);class rt{constructor(e,t,s,o,r){d(this,"url");d(this,"key");d(this,"level");d(this,"index");d(this,"density");this.url=e,this.key=t,this.level=s,o!=null&&(this.index=o),r!=null&&(this.density=r)}}const G=ae("debugprogressive"),it=ae("noprogressive"),xe=Symbol("Needle:LODSManager"),Me=Symbol("Needle:LODState"),J=Symbol("Needle:CurrentLOD"),F={mesh_lod:-1,texture_lod:-1};var B,z,he,Q,Z,ge,W;const C=class{constructor(e,t){d(this,"context");d(this,"renderer");d(this,"projectionScreenMatrix",new p.Matrix4);d(this,"targetTriangleDensity",2e5);d(this,"updateInterval","auto");K(this,B,1);d(this,"pause",!1);d(this,"manual",!1);d(this,"_lodchangedlisteners",[]);K(this,z,void 0);K(this,he,new p.Clock);K(this,Q,0);K(this,Z,0);K(this,ge,0);K(this,W,0);d(this,"_fpsBuffer",[60,60,60,60,60]);d(this,"_sphere",new p.Sphere);d(this,"_tempBox",new p.Box3);d(this,"_tempBox2",new p.Box3);d(this,"tempMatrix",new p.Matrix4);d(this,"_tempWorldPosition",new p.Vector3);d(this,"_tempBoxSize",new p.Vector3);d(this,"_tempBox2Size",new p.Vector3);this.renderer=e,this.context={...t}}static getObjectLODState(e){return e[Me]}static addPlugin(e){Y.push(e)}static removePlugin(e){const t=Y.indexOf(e);t>=0&&Y.splice(t,1)}static get(e,t){if(e[xe])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),e[xe];const s=new C(e,{engine:"unknown",...t});return e[xe]=s,s}get plugins(){return Y}addEventListener(e,t){e==="changed"&&this._lodchangedlisteners.push(t)}removeEventListener(e,t){if(e==="changed"){const s=this._lodchangedlisteners.indexOf(t);s>=0&&this._lodchangedlisteners.splice(s,1)}}enable(){if(L(this,z))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let e=0;N(this,z,this.renderer.render);const t=this;Se(this.renderer),this.renderer.render=function(s,o){const r=t.renderer.getRenderTarget();(r==null||"isXRRenderTarget"in r&&r.isXRRenderTarget)&&(e=0,N(t,Q,L(t,Q)+1),N(t,Z,L(t,he).getDelta()),N(t,ge,L(t,ge)+L(t,Z)),t._fpsBuffer.shift(),t._fpsBuffer.push(1/L(t,Z)),N(t,W,t._fpsBuffer.reduce((a,l)=>a+l)/t._fpsBuffer.length),G&&L(t,Q)%200===0&&console.log("FPS",Math.round(L(t,W)),"Interval:",L(t,B)));const i=e++;L(t,z).call(this,s,o),t.onAfterRender(s,o,i)}}disable(){L(this,z)&&(console.debug("[gltf-progressive] Disabling LODsManager for renderer"),this.renderer.render=L(this,z),N(this,z,void 0))}update(e,t){this.internalUpdate(e,t)}onAfterRender(e,t,s){if(this.pause)return;const r=this.renderer.renderLists.get(e,0).opaque;let i=!0;if(r.length===1){const a=r[0].material;(a.name==="EffectMaterial"||a.name==="CopyShader")&&(i=!1)}if((t.parent&&t.parent.type==="CubeCamera"||s>=1&&t.type==="OrthographicCamera")&&(i=!1),i){if(it||(this.updateInterval==="auto"?L(this,W)<40&&L(this,B)<10?(N(this,B,L(this,B)+1),G&&console.warn("↓ Reducing LOD updates",L(this,B),L(this,W).toFixed(0))):L(this,W)>=60&&L(this,B)>1&&(N(this,B,L(this,B)-1),G&&console.warn("↑ Increasing LOD updates",L(this,B),L(this,W).toFixed(0))):N(this,B,this.updateInterval),L(this,B)>0&&L(this,Q)%L(this,B)!=0))return;this.internalUpdate(e,t)}}internalUpdate(e,t){var l,u;const s=this.renderer.renderLists.get(e,0),o=s.opaque;this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse);const r=this.targetTriangleDensity;for(const c of o){if(c.material&&(((l=c.geometry)==null?void 0:l.type)==="BoxGeometry"||((u=c.geometry)==null?void 0:u.type)==="BufferGeometry")&&(c.material.name==="SphericalGaussianBlur"||c.material.name=="BackgroundCubeMaterial"||c.material.name==="CubemapFromEquirect"||c.material.name==="EquirectangularToCubeUV")){G&&(c.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(c.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",c,c.material.name,c.material.type)));continue}switch(c.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}if(G==="color"&&c.material&&!c.object.progressive_debug_color){c.object.progressive_debug_color=!0;const y=Math.random()*16777215,D=new p.MeshStandardMaterial({color:y});c.object.material=D}const g=c.object;(g instanceof p.Mesh||g.isMesh)&&this.updateLODs(e,t,g,r)}const i=s.transparent;for(const c of i){const g=c.object;(g instanceof p.Mesh||g.isMesh)&&this.updateLODs(e,t,g,r)}const a=s.transmissive;for(const c of a){const g=c.object;(g instanceof p.Mesh||g.isMesh)&&this.updateLODs(e,t,g,r)}}updateLODs(e,t,s,o){var a,l;s.userData||(s.userData={});let r=s[Me];if(r||(r=new ot,s[Me]=r),r.frames++<2)return;for(const u of Y)(a=u.onBeforeUpdateLOD)==null||a.call(u,this.renderer,e,t,s);this.calculateLodLevel(t,s,r,o,F),F.mesh_lod=Math.round(F.mesh_lod),F.texture_lod=Math.round(F.texture_lod),F.mesh_lod>=0&&this.loadProgressiveMeshes(s,F.mesh_lod);let i=F.texture_lod;if(s.material&&i>=0){const u=s["DEBUG:LOD"];u!=null&&(i=u),this.loadProgressiveTextures(s.material,i)}for(const u of Y)(l=u.onAfterUpdatedLOD)==null||l.call(u,this.renderer,e,t,s,F);r.lastLodLevel_Mesh=F.mesh_lod,r.lastLodLevel_Texture=F.texture_lod}loadProgressiveTextures(e,t){if(!e)return;if(Array.isArray(e)){for(const o of e)this.loadProgressiveTextures(o,t);return}let s=!1;(e[J]===void 0||t<e[J])&&(s=!0),s&&(e[J]=t,O.assignTextureLOD(e,t).then(o=>{this._lodchangedlisteners.forEach(r=>r({type:"texture",level:t,object:e}))}))}loadProgressiveMeshes(e,t){if(!e)return Promise.resolve(null);if(e[J]!==t){e[J]=t;const s=e.geometry;return O.assignMeshLOD(e,t).then(o=>(o&&e[J]==t&&s!=e.geometry&&this._lodchangedlisteners.forEach(r=>r({type:"mesh",level:t,object:e})),o))}return Promise.resolve(null)}static isInside(e,t){const s=e.min,o=e.max,r=(s.x+o.x)*.5,i=(s.y+o.y)*.5;return this._tempPtInside.set(r,i,s.z).applyMatrix4(t).z<0}calculateLodLevel(e,t,s,o,r){var V;if(!t){r.mesh_lod=-1,r.texture_lod=-1;return}if(!e){r.mesh_lod=-1,r.texture_lod=-1;return}let a=10+1,l=!1;if(G&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const u=O.getMeshLODInformation(t.geometry),c=u==null?void 0:u.lods,g=c&&c.length>0,y=O.getMaterialMinMaxLODsCount(t.material),D=(y==null?void 0:y.min_count)!=1/0&&y.min_count>0&&y.max_count>0;if(!g&&!D){r.mesh_lod=0,r.texture_lod=0;return}g||(l=!0,a=0);const v=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let M=t.geometry.boundingBox;if(t.type==="SkinnedMesh"){const w=t;if(!w.boundingBox)w.computeBoundingBox();else if(s.frames%30===0){const h=te(w),k=w.geometry;h&&(w.geometry=h),w.computeBoundingBox(),w.geometry=k}M=w.boundingBox}if(M&&e.isPerspectiveCamera){const w=e;if(t.geometry.attributes.color&&t.geometry.attributes.color.count<100&&t.geometry.boundingSphere){this._sphere.copy(t.geometry.boundingSphere),this._sphere.applyMatrix4(t.matrixWorld);const f=e.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(f)){r.mesh_lod=0,r.texture_lod=0;return}}if(this._tempBox.copy(M),this._tempBox.applyMatrix4(t.matrixWorld),C.isInside(this._tempBox,this.projectionScreenMatrix)){r.mesh_lod=0,r.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&w.fov>70){const f=this._tempBox.min,m=this._tempBox.max;let S=f.x,T=f.y,P=m.x,X=m.y;const le=2,pe=1.5,ce=(f.x+m.x)*.5,ue=(f.y+m.y)*.5;S=(S-ce)*le+ce,T=(T-ue)*le+ue,P=(P-ce)*le+ce,X=(X-ue)*le+ue;const $e=S<0&&P>0?0:Math.min(Math.abs(f.x),Math.abs(m.x)),Ne=T<0&&X>0?0:Math.min(Math.abs(f.y),Math.abs(m.y)),ye=Math.max($e,Ne);s.lastCentrality=(pe-ye)*(pe-ye)*(pe-ye)}else s.lastCentrality=1;const h=this._tempBox.getSize(this._tempBoxSize);h.multiplyScalar(.5),screen.availHeight>0&&v>0&&h.multiplyScalar(v/screen.availHeight),h.x*=w.aspect;const k=e.matrixWorldInverse,$=this._tempBox2;$.copy(M),$.applyMatrix4(t.matrixWorld),$.applyMatrix4(k);const I=$.getSize(this._tempBox2Size),b=Math.max(I.x,I.y);if(Math.max(h.x,h.y)!=0&&b!=0&&(h.z=I.z/Math.max(I.x,I.y)*Math.max(h.x,h.y)),s.lastScreenCoverage=Math.max(h.x,h.y,h.z),s.lastScreenspaceVolume.copy(h),s.lastScreenCoverage*=s.lastCentrality,G&&C.debugDrawLine){const f=this.tempMatrix.copy(this.projectionScreenMatrix);f.invert();const m=C.corner0,S=C.corner1,T=C.corner2,P=C.corner3;m.copy(this._tempBox.min),S.copy(this._tempBox.max),S.x=m.x,T.copy(this._tempBox.max),T.y=m.y,P.copy(this._tempBox.max);const X=(m.z+P.z)*.5;m.z=S.z=T.z=P.z=X,m.applyMatrix4(f),S.applyMatrix4(f),T.applyMatrix4(f),P.applyMatrix4(f),C.debugDrawLine(m,S,255),C.debugDrawLine(m,T,255),C.debugDrawLine(S,P,255),C.debugDrawLine(T,P,255)}let A=999;if(c&&s.lastScreenCoverage>0){for(let f=0;f<c.length;f++)if(c[f].density/s.lastScreenCoverage<o){A=f;break}}A<a&&(a=A,l=!0)}if(l?r.mesh_lod=a:r.mesh_lod=s.lastLodLevel_Mesh,G&&r.mesh_lod!=s.lastLodLevel_Mesh){const h=c==null?void 0:c[r.mesh_lod];h&&console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} → ${r.mesh_lod} (${h.density.toFixed(0)}) - ${t.name}`)}if(D){const w="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(s.lastLodLevel_Texture<0){if(r.texture_lod=y.max_count-1,G){const h=y.lods[y.max_count-1];G&&console.log(`First Texture LOD ${r.texture_lod} (${h.max_height}px) - ${t.name}`)}}else{const h=s.lastScreenspaceVolume.x+s.lastScreenspaceVolume.y+s.lastScreenspaceVolume.z;let k=s.lastScreenCoverage*4;((V=this.context)==null?void 0:V.engine)==="model-viewer"&&(k*=1.5);const I=v/window.devicePixelRatio*k;for(let b=y.lods.length-1;b>=0;b--){let q=y.lods[b];if(!(w&&q.max_height>=2048)&&!(et()&&q.max_height>4096)&&q.max_height>I){if(r.texture_lod=b,r.texture_lod<s.lastLodLevel_Texture){const A=q.max_height;G&&console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${r.texture_lod} = ${A}px
5
+ `,t.uuid),t.offset=e.offset,t.repeat=e.repeat,t.colorSpace=e.colorSpace,t.magFilter=e.magFilter,t.minFilter=e.minFilter,t.wrapS=e.wrapS,t.wrapT=e.wrapT,t.flipY=e.flipY,t.anisotropy=e.anisotropy,t.mipmaps||(t.generateMipmaps=e.generateMipmaps),t}};let O=_;d(O,"registerTexture",(e,t,s,o,r)=>{if(x&&console.log("> Progressive: register texture",o,t.name,t.uuid,t,r),!t){x&&console.error("gltf-progressive: Register texture without texture");return}t.source&&(t.source[Le]=r);const i=r.guid;_.assignLODInformation(e,t,i,s,o,void 0),_.lodInfos.set(i,r),_.lowresCache.set(i,t)}),d(O,"registerMesh",(e,t,s,o,r,i)=>{var u;x&&console.log("> Progressive: register mesh",r,s.name,i,s.uuid,s);const a=s.geometry;if(!a){x&&console.warn("gltf-progressive: Register mesh without geometry");return}a.userData||(a.userData={}),_.assignLODInformation(e,a,t,o,r,i.density),_.lodInfos.set(t,i);let l=_.lowresCache.get(t);l?l.push(s.geometry):l=[s.geometry],_.lowresCache.set(t,l),o>0&&!te(s)&&Ie(s,a);for(const c of Y)(u=c.onRegisteredNewMesh)==null||u.call(c,s,i)}),d(O,"lodInfos",new Map),d(O,"previouslyLoaded",new Map),d(O,"lowresCache",new Map);class rt{constructor(e,t,s,o,r){d(this,"url");d(this,"key");d(this,"level");d(this,"index");d(this,"density");this.url=e,this.key=t,this.level=s,o!=null&&(this.index=o),r!=null&&(this.density=r)}}const G=ae("debugprogressive"),it=ae("noprogressive"),xe=Symbol("Needle:LODSManager"),Me=Symbol("Needle:LODState"),J=Symbol("Needle:CurrentLOD"),F={mesh_lod:-1,texture_lod:-1};var B,W,he,Q,Z,ge,q;const C=class{constructor(e,t){d(this,"context");d(this,"renderer");d(this,"projectionScreenMatrix",new p.Matrix4);d(this,"targetTriangleDensity",2e5);d(this,"updateInterval","auto");K(this,B,1);d(this,"pause",!1);d(this,"manual",!1);d(this,"_lodchangedlisteners",[]);K(this,W,void 0);K(this,he,new p.Clock);K(this,Q,0);K(this,Z,0);K(this,ge,0);K(this,q,0);d(this,"_fpsBuffer",[60,60,60,60,60]);d(this,"_sphere",new p.Sphere);d(this,"_tempBox",new p.Box3);d(this,"_tempBox2",new p.Box3);d(this,"tempMatrix",new p.Matrix4);d(this,"_tempWorldPosition",new p.Vector3);d(this,"_tempBoxSize",new p.Vector3);d(this,"_tempBox2Size",new p.Vector3);this.renderer=e,this.context={...t}}static getObjectLODState(e){return e[Me]}static addPlugin(e){Y.push(e)}static removePlugin(e){const t=Y.indexOf(e);t>=0&&Y.splice(t,1)}static get(e,t){if(e[xe])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),e[xe];const s=new C(e,{engine:"unknown",...t});return e[xe]=s,s}get plugins(){return Y}addEventListener(e,t){e==="changed"&&this._lodchangedlisteners.push(t)}removeEventListener(e,t){if(e==="changed"){const s=this._lodchangedlisteners.indexOf(t);s>=0&&this._lodchangedlisteners.splice(s,1)}}enable(){if(L(this,W))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let e=0;N(this,W,this.renderer.render);const t=this;Se(this.renderer),this.renderer.render=function(s,o){const r=t.renderer.getRenderTarget();(r==null||"isXRRenderTarget"in r&&r.isXRRenderTarget)&&(e=0,N(t,Q,L(t,Q)+1),N(t,Z,L(t,he).getDelta()),N(t,ge,L(t,ge)+L(t,Z)),t._fpsBuffer.shift(),t._fpsBuffer.push(1/L(t,Z)),N(t,q,t._fpsBuffer.reduce((a,l)=>a+l)/t._fpsBuffer.length),G&&L(t,Q)%200===0&&console.log("FPS",Math.round(L(t,q)),"Interval:",L(t,B)));const i=e++;L(t,W).call(this,s,o),t.onAfterRender(s,o,i)}}disable(){L(this,W)&&(console.debug("[gltf-progressive] Disabling LODsManager for renderer"),this.renderer.render=L(this,W),N(this,W,void 0))}update(e,t){this.internalUpdate(e,t)}onAfterRender(e,t,s){if(this.pause)return;const r=this.renderer.renderLists.get(e,0).opaque;let i=!0;if(r.length===1){const a=r[0].material;(a.name==="EffectMaterial"||a.name==="CopyShader")&&(i=!1)}if((t.parent&&t.parent.type==="CubeCamera"||s>=1&&t.type==="OrthographicCamera")&&(i=!1),i){if(it||(this.updateInterval==="auto"?L(this,q)<40&&L(this,B)<10?(N(this,B,L(this,B)+1),G&&console.warn("↓ Reducing LOD updates",L(this,B),L(this,q).toFixed(0))):L(this,q)>=60&&L(this,B)>1&&(N(this,B,L(this,B)-1),G&&console.warn("↑ Increasing LOD updates",L(this,B),L(this,q).toFixed(0))):N(this,B,this.updateInterval),L(this,B)>0&&L(this,Q)%L(this,B)!=0))return;this.internalUpdate(e,t)}}internalUpdate(e,t){var l,u;const s=this.renderer.renderLists.get(e,0),o=s.opaque;this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse);const r=this.targetTriangleDensity;for(const c of o){if(c.material&&(((l=c.geometry)==null?void 0:l.type)==="BoxGeometry"||((u=c.geometry)==null?void 0:u.type)==="BufferGeometry")&&(c.material.name==="SphericalGaussianBlur"||c.material.name=="BackgroundCubeMaterial"||c.material.name==="CubemapFromEquirect"||c.material.name==="EquirectangularToCubeUV")){G&&(c.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(c.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",c,c.material.name,c.material.type)));continue}switch(c.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}if(G==="color"&&c.material&&!c.object.progressive_debug_color){c.object.progressive_debug_color=!0;const y=Math.random()*16777215,w=new p.MeshStandardMaterial({color:y});c.object.material=w}const g=c.object;(g instanceof p.Mesh||g.isMesh)&&this.updateLODs(e,t,g,r)}const i=s.transparent;for(const c of i){const g=c.object;(g instanceof p.Mesh||g.isMesh)&&this.updateLODs(e,t,g,r)}const a=s.transmissive;for(const c of a){const g=c.object;(g instanceof p.Mesh||g.isMesh)&&this.updateLODs(e,t,g,r)}}updateLODs(e,t,s,o){var a,l;s.userData||(s.userData={});let r=s[Me];if(r||(r=new ot,s[Me]=r),r.frames++<2)return;for(const u of Y)(a=u.onBeforeUpdateLOD)==null||a.call(u,this.renderer,e,t,s);this.calculateLodLevel(t,s,r,o,F),F.mesh_lod=Math.round(F.mesh_lod),F.texture_lod=Math.round(F.texture_lod),F.mesh_lod>=0&&this.loadProgressiveMeshes(s,F.mesh_lod);let i=F.texture_lod;if(s.material&&i>=0){const u=s["DEBUG:LOD"];u!=null&&(i=u),this.loadProgressiveTextures(s.material,i)}for(const u of Y)(l=u.onAfterUpdatedLOD)==null||l.call(u,this.renderer,e,t,s,F);r.lastLodLevel_Mesh=F.mesh_lod,r.lastLodLevel_Texture=F.texture_lod}loadProgressiveTextures(e,t){if(!e)return;if(Array.isArray(e)){for(const o of e)this.loadProgressiveTextures(o,t);return}let s=!1;(e[J]===void 0||t<e[J])&&(s=!0),s&&(e[J]=t,O.assignTextureLOD(e,t).then(o=>{this._lodchangedlisteners.forEach(r=>r({type:"texture",level:t,object:e}))}))}loadProgressiveMeshes(e,t){if(!e)return Promise.resolve(null);if(e[J]!==t){e[J]=t;const s=e.geometry;return O.assignMeshLOD(e,t).then(o=>(o&&e[J]==t&&s!=e.geometry&&this._lodchangedlisteners.forEach(r=>r({type:"mesh",level:t,object:e})),o))}return Promise.resolve(null)}static isInside(e,t){const s=e.min,o=e.max,r=(s.x+o.x)*.5,i=(s.y+o.y)*.5;return this._tempPtInside.set(r,i,s.z).applyMatrix4(t).z<0}calculateLodLevel(e,t,s,o,r){var V;if(!t){r.mesh_lod=-1,r.texture_lod=-1;return}if(!e){r.mesh_lod=-1,r.texture_lod=-1;return}let a=10+1,l=!1;if(G&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const u=O.getMeshLODInformation(t.geometry),c=u==null?void 0:u.lods,g=c&&c.length>0,y=O.getMaterialMinMaxLODsCount(t.material),w=(y==null?void 0:y.min_count)!=1/0&&y.min_count>0&&y.max_count>0;if(!g&&!w){r.mesh_lod=0,r.texture_lod=0;return}g||(l=!0,a=0);const v=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let M=t.geometry.boundingBox;if(t.type==="SkinnedMesh"){const D=t;if(!D.boundingBox)D.computeBoundingBox();else if(s.frames%30===0){const h=te(D),k=D.geometry;h&&(D.geometry=h),D.computeBoundingBox(),D.geometry=k}M=D.boundingBox}if(M){const D=e;if(t.geometry.attributes.color&&t.geometry.attributes.color.count<100&&t.geometry.boundingSphere){this._sphere.copy(t.geometry.boundingSphere),this._sphere.applyMatrix4(t.matrixWorld);const f=e.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(f)){r.mesh_lod=0,r.texture_lod=0;return}}if(this._tempBox.copy(M),this._tempBox.applyMatrix4(t.matrixWorld),D.isPerspectiveCamera&&C.isInside(this._tempBox,this.projectionScreenMatrix)){r.mesh_lod=0,r.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&D.isPerspectiveCamera&&D.fov>70){const f=this._tempBox.min,m=this._tempBox.max;let S=f.x,A=f.y,P=m.x,X=m.y;const le=2,pe=1.5,ce=(f.x+m.x)*.5,ue=(f.y+m.y)*.5;S=(S-ce)*le+ce,A=(A-ue)*le+ue,P=(P-ce)*le+ce,X=(X-ue)*le+ue;const $e=S<0&&P>0?0:Math.min(Math.abs(f.x),Math.abs(m.x)),Ne=A<0&&X>0?0:Math.min(Math.abs(f.y),Math.abs(m.y)),ye=Math.max($e,Ne);s.lastCentrality=(pe-ye)*(pe-ye)*(pe-ye)}else s.lastCentrality=1;const h=this._tempBox.getSize(this._tempBoxSize);h.multiplyScalar(.5),screen.availHeight>0&&v>0&&h.multiplyScalar(v/screen.availHeight),e.isPerspectiveCamera?h.x*=e.aspect:e.isOrthographicCamera;const k=e.matrixWorldInverse,$=this._tempBox2;$.copy(M),$.applyMatrix4(t.matrixWorld),$.applyMatrix4(k);const I=$.getSize(this._tempBox2Size),E=Math.max(I.x,I.y);if(Math.max(h.x,h.y)!=0&&E!=0&&(h.z=I.z/Math.max(I.x,I.y)*Math.max(h.x,h.y)),s.lastScreenCoverage=Math.max(h.x,h.y,h.z),s.lastScreenspaceVolume.copy(h),s.lastScreenCoverage*=s.lastCentrality,G&&C.debugDrawLine){const f=this.tempMatrix.copy(this.projectionScreenMatrix);f.invert();const m=C.corner0,S=C.corner1,A=C.corner2,P=C.corner3;m.copy(this._tempBox.min),S.copy(this._tempBox.max),S.x=m.x,A.copy(this._tempBox.max),A.y=m.y,P.copy(this._tempBox.max);const X=(m.z+P.z)*.5;m.z=S.z=A.z=P.z=X,m.applyMatrix4(f),S.applyMatrix4(f),A.applyMatrix4(f),P.applyMatrix4(f),C.debugDrawLine(m,S,255),C.debugDrawLine(m,A,255),C.debugDrawLine(S,P,255),C.debugDrawLine(A,P,255)}let b=999;if(c&&s.lastScreenCoverage>0){for(let f=0;f<c.length;f++)if(c[f].density/s.lastScreenCoverage<o){b=f;break}}b<a&&(a=b,l=!0)}if(l?r.mesh_lod=a:r.mesh_lod=s.lastLodLevel_Mesh,G&&r.mesh_lod!=s.lastLodLevel_Mesh){const h=c==null?void 0:c[r.mesh_lod];h&&console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} → ${r.mesh_lod} (${h.density.toFixed(0)}) - ${t.name}`)}if(w){const D="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(s.lastLodLevel_Texture<0){if(r.texture_lod=y.max_count-1,G){const h=y.lods[y.max_count-1];G&&console.log(`First Texture LOD ${r.texture_lod} (${h.max_height}px) - ${t.name}`)}}else{const h=s.lastScreenspaceVolume.x+s.lastScreenspaceVolume.y+s.lastScreenspaceVolume.z;let k=s.lastScreenCoverage*4;((V=this.context)==null?void 0:V.engine)==="model-viewer"&&(k*=1.5);const I=v/window.devicePixelRatio*k;let E=!1;for(let z=y.lods.length-1;z>=0;z--){let b=y.lods[z];if(!(D&&b.max_height>=2048)&&!(et()&&b.max_height>4096)&&(b.max_height>I||!E&&z===0)){if(E=!0,r.texture_lod=z,r.texture_lod<s.lastLodLevel_Texture){const T=b.max_height;G&&console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${r.texture_lod} = ${T}px
6
6
  Screensize: ${I.toFixed(0)}px, Coverage: ${(100*s.lastScreenCoverage).toFixed(2)}%, Volume ${h.toFixed(1)}
7
- ${t.name}`)}break}}}}else r.texture_lod=0}};let R=C;B=new WeakMap,z=new WeakMap,he=new WeakMap,Q=new WeakMap,Z=new WeakMap,ge=new WeakMap,W=new WeakMap,d(R,"debugDrawLine"),d(R,"corner0",new p.Vector3),d(R,"corner1",new p.Vector3),d(R,"corner2",new p.Vector3),d(R,"corner3",new p.Vector3),d(R,"_tempPtInside",new p.Vector3);class ot{constructor(){d(this,"frames",0);d(this,"lastLodLevel_Mesh",-1);d(this,"lastLodLevel_Texture",-1);d(this,"lastScreenCoverage",0);d(this,"lastScreenspaceVolume",new p.Vector3);d(this,"lastCentrality",0)}}const Ce=Symbol("NEEDLE_mesh_lod"),fe=Symbol("NEEDLE_texture_lod");let ie=null;function Ae(){const n=nt();n&&(n.mapURLs(function(e){return Be(),e}),Be(),ie==null||ie.disconnect(),ie=new MutationObserver(e=>{e.forEach(t=>{t.addedNodes.forEach(s=>{s instanceof HTMLElement&&s.tagName.toLowerCase()==="model-viewer"&&Fe(s)})})}),ie.observe(document,{childList:!0,subtree:!0}))}function nt(){if(typeof customElements>"u")return null;const n=customElements.get("model-viewer");return n||(customElements.whenDefined("model-viewer").then(()=>{console.debug("[gltf-progressive] model-viewer defined"),Ae()}),null)}function Be(){if(typeof document>"u")return;document.querySelectorAll("model-viewer").forEach(e=>{Fe(e)})}const Re=new WeakSet;let at=0;function Fe(n){if(!n||Re.has(n))return null;Re.add(n),console.debug("[gltf-progressive] found new model-viewer..."+ ++at+`
8
- `,n.getAttribute("src"));let e=null,t=null,s=null;for(let o=n;o!=null;o=Object.getPrototypeOf(o)){const r=Object.getOwnPropertySymbols(o),i=r.find(u=>u.toString()=="Symbol(renderer)"),a=r.find(u=>u.toString()=="Symbol(scene)"),l=r.find(u=>u.toString()=="Symbol(needsRender)");!e&&i!=null&&(e=n[i].threeRenderer),!t&&a!=null&&(t=n[a]),!s&&l!=null&&(s=n[l])}if(e&&t){let o=function(){if(s){let i=0,a=setInterval(()=>{if(i++>5){clearInterval(a);return}s==null||s.call(n)},300)}};console.debug("[gltf-progressive] setup model-viewer");const r=R.get(e,{engine:"model-viewer"});return R.addPlugin(new lt),r.enable(),r.addEventListener("changed",()=>{s==null||s.call(n)}),n.addEventListener("model-visibility",i=>{i.detail.visible&&(s==null||s.call(n))}),n.addEventListener("load",()=>{o()}),()=>{r.disable()}}return null}class lt{constructor(){d(this,"_didWarnAboutMissingUrl",!1)}onBeforeUpdateLOD(e,t,s,o){this.tryParseMeshLOD(t,o),this.tryParseTextureLOD(t,o)}getUrl(e){if(!e)return null;let t=e.getAttribute("src");return t||(t=e.src),t||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",e),this._didWarnAboutMissingUrl=!0),t}tryGetCurrentGLTF(e){return e._currentGLTF}tryGetCurrentModelViewer(e){return e.element}tryParseTextureLOD(e,t){if(t[fe]==!0)return;t[fe]=!0;const s=this.tryGetCurrentGLTF(e),o=this.tryGetCurrentModelViewer(e),r=this.getUrl(o);if(r&&s&&t.material){let i=function(l){var c,g,y;if(l[fe]==!0)return;l[fe]=!0,l.userData&&(l.userData.LOD=-1);const u=Object.keys(l);for(let D=0;D<u.length;D++){const v=u[D],M=l[v];if((M==null?void 0:M.isTexture)===!0){const V=(g=(c=M.userData)==null?void 0:c.associations)==null?void 0:g.textures;if(V==null)continue;const w=s.parser.json.textures[V];if(!w){console.warn("Texture data not found for texture index "+V);continue}if((y=w==null?void 0:w.extensions)!=null&&y[U]){const h=w.extensions[U];h&&r&&O.registerTexture(r,M,h.lods.length,V,h)}}}};const a=t.material;if(Array.isArray(a))for(const l of a)i(l);else i(a)}}tryParseMeshLOD(e,t){var i,a;if(t[Ce]==!0)return;t[Ce]=!0;const s=this.tryGetCurrentModelViewer(e),o=this.getUrl(s);if(!o)return;const r=(a=(i=t.userData)==null?void 0:i.gltfExtensions)==null?void 0:a[U];if(r&&o){const l=t.uuid;O.registerMesh(o,l,t,0,r.lods.length,r)}}}function Ve(n,e,t,s){Se(e),be(t),Te(t,{progressive:!0,...s==null?void 0:s.hints}),t.register(r=>new O(r,n));const o=R.get(e);return(s==null?void 0:s.enableLODsManager)!==!1&&o.enable(),o}Ae();if(!tt){const n={gltfProgressive:{useNeedleProgressive:Ve,LODsManager:R,configureLoader:Te,getRaycastMesh:te,useRaycastMeshes:Ge}};if(!globalThis.Needle)globalThis.Needle=n;else for(const e in n)globalThis.Needle[e]=n[e]}exports.EXTENSION_NAME=U;exports.LODsManager=R;exports.NEEDLE_progressive=O;exports.VERSION=Oe;exports.addDracoAndKTX2Loaders=be;exports.configureLoader=Te;exports.createLoaders=Se;exports.getRaycastMesh=te;exports.patchModelViewer=Ae;exports.registerRaycastMesh=Ie;exports.setDracoDecoderLocation=je;exports.setKTX2TranscoderLocation=Je;exports.useNeedleProgressive=Ve;exports.useRaycastMeshes=Ge;
7
+ ${t.name}`)}break}}}}else r.texture_lod=0}};let R=C;B=new WeakMap,W=new WeakMap,he=new WeakMap,Q=new WeakMap,Z=new WeakMap,ge=new WeakMap,q=new WeakMap,d(R,"debugDrawLine"),d(R,"corner0",new p.Vector3),d(R,"corner1",new p.Vector3),d(R,"corner2",new p.Vector3),d(R,"corner3",new p.Vector3),d(R,"_tempPtInside",new p.Vector3);class ot{constructor(){d(this,"frames",0);d(this,"lastLodLevel_Mesh",-1);d(this,"lastLodLevel_Texture",-1);d(this,"lastScreenCoverage",0);d(this,"lastScreenspaceVolume",new p.Vector3);d(this,"lastCentrality",0)}}const Ce=Symbol("NEEDLE_mesh_lod"),fe=Symbol("NEEDLE_texture_lod");let ie=null;function Ae(){const n=nt();n&&(n.mapURLs(function(e){return Be(),e}),Be(),ie==null||ie.disconnect(),ie=new MutationObserver(e=>{e.forEach(t=>{t.addedNodes.forEach(s=>{s instanceof HTMLElement&&s.tagName.toLowerCase()==="model-viewer"&&Fe(s)})})}),ie.observe(document,{childList:!0,subtree:!0}))}function nt(){if(typeof customElements>"u")return null;const n=customElements.get("model-viewer");return n||(customElements.whenDefined("model-viewer").then(()=>{console.debug("[gltf-progressive] model-viewer defined"),Ae()}),null)}function Be(){if(typeof document>"u")return;document.querySelectorAll("model-viewer").forEach(e=>{Fe(e)})}const Re=new WeakSet;let at=0;function Fe(n){if(!n||Re.has(n))return null;Re.add(n),console.debug("[gltf-progressive] found new model-viewer..."+ ++at+`
8
+ `,n.getAttribute("src"));let e=null,t=null,s=null;for(let o=n;o!=null;o=Object.getPrototypeOf(o)){const r=Object.getOwnPropertySymbols(o),i=r.find(u=>u.toString()=="Symbol(renderer)"),a=r.find(u=>u.toString()=="Symbol(scene)"),l=r.find(u=>u.toString()=="Symbol(needsRender)");!e&&i!=null&&(e=n[i].threeRenderer),!t&&a!=null&&(t=n[a]),!s&&l!=null&&(s=n[l])}if(e&&t){let o=function(){if(s){let i=0,a=setInterval(()=>{if(i++>5){clearInterval(a);return}s==null||s.call(n)},300)}};console.debug("[gltf-progressive] setup model-viewer");const r=R.get(e,{engine:"model-viewer"});return R.addPlugin(new lt),r.enable(),r.addEventListener("changed",()=>{s==null||s.call(n)}),n.addEventListener("model-visibility",i=>{i.detail.visible&&(s==null||s.call(n))}),n.addEventListener("load",()=>{o()}),()=>{r.disable()}}return null}class lt{constructor(){d(this,"_didWarnAboutMissingUrl",!1)}onBeforeUpdateLOD(e,t,s,o){this.tryParseMeshLOD(t,o),this.tryParseTextureLOD(t,o)}getUrl(e){if(!e)return null;let t=e.getAttribute("src");return t||(t=e.src),t||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",e),this._didWarnAboutMissingUrl=!0),t}tryGetCurrentGLTF(e){return e._currentGLTF}tryGetCurrentModelViewer(e){return e.element}tryParseTextureLOD(e,t){if(t[fe]==!0)return;t[fe]=!0;const s=this.tryGetCurrentGLTF(e),o=this.tryGetCurrentModelViewer(e),r=this.getUrl(o);if(r&&s&&t.material){let i=function(l){var c,g,y;if(l[fe]==!0)return;l[fe]=!0,l.userData&&(l.userData.LOD=-1);const u=Object.keys(l);for(let w=0;w<u.length;w++){const v=u[w],M=l[v];if((M==null?void 0:M.isTexture)===!0){const V=(g=(c=M.userData)==null?void 0:c.associations)==null?void 0:g.textures;if(V==null)continue;const D=s.parser.json.textures[V];if(!D){console.warn("Texture data not found for texture index "+V);continue}if((y=D==null?void 0:D.extensions)!=null&&y[U]){const h=D.extensions[U];h&&r&&O.registerTexture(r,M,h.lods.length,V,h)}}}};const a=t.material;if(Array.isArray(a))for(const l of a)i(l);else i(a)}}tryParseMeshLOD(e,t){var i,a;if(t[Ce]==!0)return;t[Ce]=!0;const s=this.tryGetCurrentModelViewer(e),o=this.getUrl(s);if(!o)return;const r=(a=(i=t.userData)==null?void 0:i.gltfExtensions)==null?void 0:a[U];if(r&&o){const l=t.uuid;O.registerMesh(o,l,t,0,r.lods.length,r)}}}function Ve(n,e,t,s){Se(e),be(t),Te(t,{progressive:!0,...s==null?void 0:s.hints}),t.register(r=>new O(r,n));const o=R.get(e);return(s==null?void 0:s.enableLODsManager)!==!1&&o.enable(),o}Ae();if(!tt){const n={gltfProgressive:{useNeedleProgressive:Ve,LODsManager:R,configureLoader:Te,getRaycastMesh:te,useRaycastMeshes:Ge}};if(!globalThis.Needle)globalThis.Needle=n;else for(const e in n)globalThis.Needle[e]=n[e]}exports.EXTENSION_NAME=U;exports.LODsManager=R;exports.NEEDLE_progressive=O;exports.VERSION=Oe;exports.addDracoAndKTX2Loaders=be;exports.configureLoader=Te;exports.createLoaders=Se;exports.getRaycastMesh=te;exports.patchModelViewer=Ae;exports.registerRaycastMesh=Ie;exports.setDracoDecoderLocation=je;exports.setKTX2TranscoderLocation=Je;exports.useNeedleProgressive=Ve;exports.useRaycastMeshes=Ge;
@@ -456,7 +456,7 @@ export class LODsManager {
456
456
  }
457
457
  boundingBox = skinnedMesh.boundingBox;
458
458
  }
459
- if (boundingBox && camera.isPerspectiveCamera) {
459
+ if (boundingBox) {
460
460
  const cam = camera;
461
461
  // hack: if the mesh has vertex colors, has less than 100 vertices we always select the highest LOD
462
462
  if (mesh.geometry.attributes.color && mesh.geometry.attributes.color.count < 100) {
@@ -481,7 +481,7 @@ export class LODsManager {
481
481
  // High distortions would lead to lower LOD levels.
482
482
  // "Centrality" of the calculated screen-space bounding box could be a factor here –
483
483
  // what's the distance of the bounding box to the center of the screen?
484
- if (LODsManager.isInside(this._tempBox, this.projectionScreenMatrix)) {
484
+ if (cam.isPerspectiveCamera && LODsManager.isInside(this._tempBox, this.projectionScreenMatrix)) {
485
485
  result.mesh_lod = 0;
486
486
  result.texture_lod = 0;
487
487
  return;
@@ -489,7 +489,7 @@ export class LODsManager {
489
489
  this._tempBox.applyMatrix4(this.projectionScreenMatrix);
490
490
  // TODO might need to be adjusted for cameras that are rendered during an XR session but are
491
491
  // actually not XR cameras (e.g. a render texture)
492
- if (this.renderer.xr.enabled && cam.fov > 70) {
492
+ if (this.renderer.xr.enabled && (cam.isPerspectiveCamera) && cam.fov > 70) {
493
493
  // calculate centrality of the bounding box - how close is it to the screen center
494
494
  const min = this._tempBox.min;
495
495
  const max = this._tempBox.max;
@@ -522,7 +522,13 @@ export class LODsManager {
522
522
  if (canvasHeight > 0)
523
523
  boxSize.multiplyScalar(canvasHeight / screen.availHeight);
524
524
  }
525
- boxSize.x *= cam.aspect;
525
+ if (camera.isPerspectiveCamera) {
526
+ boxSize.x *= camera.aspect;
527
+ }
528
+ else if (camera.isOrthographicCamera) {
529
+ // const cam = camera as OrthographicCamera;
530
+ // boxSize.x *= cam.zoom * .01;
531
+ }
526
532
  const matView = camera.matrixWorldInverse;
527
533
  const box2 = this._tempBox2;
528
534
  box2.copy(boundingBox);
@@ -618,6 +624,7 @@ export class LODsManager {
618
624
  }
619
625
  const screenSize = canvasHeight / window.devicePixelRatio;
620
626
  const pixelSizeOnScreen = screenSize * factor;
627
+ let foundLod = false;
621
628
  for (let i = texture_lods_minmax.lods.length - 1; i >= 0; i--) {
622
629
  let lod = texture_lods_minmax.lods[i];
623
630
  if (saveDataEnabled && lod.max_height >= 2048) {
@@ -625,7 +632,8 @@ export class LODsManager {
625
632
  }
626
633
  if (isMobileDevice() && lod.max_height > 4096)
627
634
  continue; // skip 8k textures on mobile devices (for now)
628
- if (lod.max_height > pixelSizeOnScreen) {
635
+ if (lod.max_height > pixelSizeOnScreen || (!foundLod && i === 0)) {
636
+ foundLod = true;
629
637
  result.texture_lod = i;
630
638
  if (result.texture_lod < state.lastLodLevel_Texture) {
631
639
  const lod_pixel_height = lod.max_height;
package/lib/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  // replaced at build time
2
- export const version = "2.1.0-alpha.3";
2
+ export const version = "2.1.0-alpha.5";
3
3
  globalThis["GLTF_PROGRESSIVE_VERSION"] = version;
4
4
  console.debug(`[gltf-progressive] version ${version}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/gltf-progressive",
3
- "version": "2.1.0-alpha.3",
3
+ "version": "2.1.0-alpha.5",
4
4
  "description": "three.js support for loading glTF or GLB files that contain progressive loading data",
5
5
  "homepage": "https://needle.tools",
6
6
  "author": {