@needle-tools/engine 4.16.4-next.90e872e → 4.16.4-next.d7334fa

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.
Files changed (60) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/dist/gltf-progressive-BJ9OrddA.js +28272 -0
  3. package/dist/gltf-progressive-Ck_bXBr_.umd.cjs +4022 -0
  4. package/dist/gltf-progressive-CqZYu6Hx.min.js +4022 -0
  5. package/dist/loader.worker-CCrD-Ycm.js +3 -0
  6. package/dist/{materialx-CT8J50pg.js → materialx-CEJOMiVq.js} +6 -7
  7. package/dist/{materialx-BrPdNmQT.umd.cjs → materialx-CN_PDqtU.umd.cjs} +1 -1
  8. package/dist/{materialx-D_ofN96q.min.js → materialx-DZYSWLvT.min.js} +1 -1
  9. package/dist/{needle-engine.bundle-dWi9rwQU.umd.cjs → needle-engine.bundle-7jhrheqM.umd.cjs} +159 -159
  10. package/dist/{needle-engine.bundle-j_dgrIWR.min.js → needle-engine.bundle-B1vy0_5d.min.js} +137 -137
  11. package/dist/{needle-engine.bundle-CTDEd5SB.js → needle-engine.bundle-BVUJloKV.js} +4192 -4185
  12. package/dist/needle-engine.d.ts +59 -53
  13. package/dist/needle-engine.js +3 -3
  14. package/dist/needle-engine.min.js +1 -1
  15. package/dist/needle-engine.umd.cjs +1 -1
  16. package/dist/three-examples.js +3294 -4643
  17. package/dist/three-examples.min.js +13 -47
  18. package/dist/three-examples.umd.cjs +12 -46
  19. package/dist/three.js +24892 -15999
  20. package/dist/three.min.js +214 -214
  21. package/dist/three.umd.cjs +208 -208
  22. package/dist/{vendor-DZ45lcA8.min.js → vendor-BPp9F5vR.min.js} +19 -19
  23. package/dist/{vendor-BsRxp-FT.js → vendor-CQMI3jTS.js} +862 -901
  24. package/dist/{vendor-BwxpsdCm.umd.cjs → vendor-CipoooTV.umd.cjs} +20 -20
  25. package/lib/engine/engine_feature_flags.d.ts +3 -3
  26. package/lib/engine/engine_feature_flags.js +3 -5
  27. package/lib/engine/engine_feature_flags.js.map +1 -1
  28. package/lib/engine/engine_lods.d.ts +9 -1
  29. package/lib/engine/engine_lods.js +9 -1
  30. package/lib/engine/engine_lods.js.map +1 -1
  31. package/lib/engine/engine_mainloop_utils.js +49 -60
  32. package/lib/engine/engine_mainloop_utils.js.map +1 -1
  33. package/lib/engine/engine_modules.d.ts +26 -30
  34. package/lib/engine/engine_modules.js +32 -103
  35. package/lib/engine/engine_modules.js.map +1 -1
  36. package/lib/engine/engine_three_utils.js +7 -13
  37. package/lib/engine/engine_three_utils.js.map +1 -1
  38. package/lib/engine/webcomponents/needle-engine.d.ts +6 -2
  39. package/lib/engine/webcomponents/needle-engine.js +56 -41
  40. package/lib/engine/webcomponents/needle-engine.js.map +1 -1
  41. package/package.json +3 -2
  42. package/plugins/vite/alias.d.ts +1 -1
  43. package/plugins/vite/alias.js +87 -82
  44. package/plugins/vite/build-pipeline.js +4 -3
  45. package/plugins/vite/dependencies.js +7 -5
  46. package/plugins/vite/drop.js +6 -8
  47. package/plugins/vite/editor-connection.js +2 -1
  48. package/plugins/vite/index.js +12 -0
  49. package/plugins/vite/poster.js +2 -1
  50. package/plugins/vite/reload.js +7 -2
  51. package/src/engine/engine_feature_flags.ts +3 -7
  52. package/src/engine/engine_lods.ts +10 -2
  53. package/src/engine/engine_mainloop_utils.ts +54 -62
  54. package/src/engine/engine_modules.ts +39 -101
  55. package/src/engine/engine_three_utils.ts +7 -15
  56. package/src/engine/webcomponents/needle-engine.ts +62 -47
  57. package/dist/gltf-progressive-DQa78GTA.min.js +0 -10
  58. package/dist/gltf-progressive-LOFTyzy4.umd.cjs +0 -10
  59. package/dist/gltf-progressive-_wvokUUu.js +0 -1528
  60. package/dist/loader.worker-BqODMeeW.js +0 -23
@@ -1,108 +1,46 @@
1
1
 
2
- /**
3
- * External dependencies that are loaded on demand either by the engine automatically when needed or they can be loaded manually by calling the `load` function.
4
- *
5
- * Use the `ready` function to wait for the module to be loaded if you do not wand to trigger a load.
6
- *
7
- * If a module is already loaded it's also available in the `MODULE` variable.
8
- */
9
- export namespace MODULES {
10
-
11
- export namespace MaterialX {
12
- export type TYPE = typeof import("@needle-tools/materialx");
13
- export let MODULE: TYPE;
14
- export let MAYBEMODULE: TYPE | null = null;
15
-
16
- const callbacks: Array<(module: TYPE) => void> = [];
17
- /** Wait for the module to be loaded (doesn't trigger a load) */
18
- export function ready(): Promise<TYPE> {
19
- if (MODULE) return Promise.resolve(MODULE);
20
- return new Promise((resolve) => { callbacks.push(resolve); });
21
- };
22
- /** Load the module */
23
- export async function load(): Promise<TYPE> {
24
- if (MODULE) return MODULE;
25
- const module = await import("@needle-tools/materialx");
26
- MODULE = module;
27
- MAYBEMODULE = module;
28
- callbacks.forEach((callback) => callback(module));
29
- callbacks.length = 0;
30
- return module;
31
- }
32
-
33
- }
34
-
35
- export namespace RAPIER_PHYSICS {
36
- export type TYPE = typeof import("@dimforge/rapier3d-compat");
37
- export let MODULE: TYPE;
38
- export let MAYBEMODULE: TYPE | null = null;
39
-
40
- const callbacks: Array<(module: TYPE) => void> = [];
41
- /** Wait for the module to be loaded (doesn't trigger a load) */
42
- export function ready(): Promise<TYPE> {
43
- if (MODULE) return Promise.resolve(MODULE);
44
- return new Promise((resolve) => { callbacks.push(resolve); });
45
- };
46
- /** Load the module */
47
- export async function load(): Promise<TYPE> {
48
- if (MODULE) return MODULE;
49
- const module = await import("@dimforge/rapier3d-compat");
50
- MODULE = module;
51
- MAYBEMODULE = module;
52
- callbacks.forEach((callback) => callback(module));
53
- callbacks.length = 0;
54
- return module;
55
- }
56
-
57
- }
58
-
59
- export namespace POSTPROCESSING {
60
-
61
- export type TYPE = typeof import("postprocessing");
62
- export let MODULE: TYPE;
63
- export let MAYBEMODULE: TYPE | null = null;
64
-
65
- const callbacks: Array<(module: TYPE) => void> = [];
2
+ function createModule<T>(loader: () => Promise<T>) {
3
+ const callbacks: Array<(module: T) => void> = [];
4
+ const mod = {
5
+ MODULE: undefined as unknown as T,
6
+ MAYBEMODULE: null as T | null,
66
7
  /** Wait for the module to be loaded (doesn't trigger a load) */
67
- export function ready(): Promise<TYPE> {
68
- if (MODULE) return Promise.resolve(MODULE);
69
- return new Promise((resolve) => { callbacks.push(resolve); });
70
- };
71
-
8
+ ready(): Promise<T> {
9
+ if (mod.MODULE) return Promise.resolve(mod.MODULE);
10
+ return new Promise(resolve => { callbacks.push(resolve); });
11
+ },
72
12
  /** Load the module */
73
- export async function load(): Promise<TYPE> {
74
- if (MODULE) return MODULE;
75
- const module = await import("postprocessing");
76
- MODULE = module;
77
- MAYBEMODULE = module;
78
- callbacks.forEach((callback) => callback(module));
13
+ async load(): Promise<T> {
14
+ if (mod.MODULE) return mod.MODULE;
15
+ const module = await loader();
16
+ mod.MODULE = module;
17
+ mod.MAYBEMODULE = module;
18
+ for (const cb of callbacks) cb(module);
79
19
  callbacks.length = 0;
80
20
  return module;
81
21
  }
82
- }
83
-
84
- export namespace POSTPROCESSING_AO {
85
-
86
- export type TYPE = typeof import("n8ao");
87
- export let MODULE: TYPE;
88
- export let MAYBEMODULE: TYPE | null = null;
89
-
90
- const callbacks: Array<(module: TYPE) => void> = [];
91
- /** Wait for the module to be loaded (doesn't trigger a load) */
92
- export function ready(): Promise<TYPE> {
93
- if (MODULE) return Promise.resolve(MODULE);
94
- return new Promise((resolve) => { callbacks.push(resolve); });
95
- };
22
+ };
23
+ return mod;
24
+ }
96
25
 
97
- /** Load the module */
98
- export async function load(): Promise<TYPE> {
99
- if (MODULE) return MODULE;
100
- const module = await import("n8ao");
101
- MODULE = module;
102
- MAYBEMODULE = module;
103
- callbacks.forEach((callback) => callback(module));
104
- callbacks.length = 0;
105
- return module;
106
- }
107
- }
108
- }
26
+ /**
27
+ * External dependencies that are loaded on demand either by the engine automatically when needed or they can be loaded manually by calling the `load` function.
28
+ *
29
+ * Use the `ready` function to wait for the module to be loaded if you do not wand to trigger a load.
30
+ *
31
+ * If a module is already loaded it's also available in the `MODULE` variable.
32
+ */
33
+ export const MODULES = {
34
+ MaterialX: createModule<typeof import("@needle-tools/materialx")>(
35
+ () => import("@needle-tools/materialx")
36
+ ),
37
+ RAPIER_PHYSICS: createModule<typeof import("@dimforge/rapier3d-compat")>(
38
+ () => import("@dimforge/rapier3d-compat")
39
+ ),
40
+ POSTPROCESSING: createModule<typeof import("postprocessing")>(
41
+ () => import("postprocessing")
42
+ ),
43
+ POSTPROCESSING_AO: createModule<typeof import("n8ao")>(
44
+ () => import("n8ao")
45
+ ),
46
+ };
@@ -586,17 +586,12 @@ export class Graphics {
586
586
  this.scene.children.length = 0;
587
587
  this.scene.add(mesh);
588
588
 
589
- // Save state
590
589
  const renderTarget = renderer.getRenderTarget();
591
- const gl = renderer.getContext();
592
- const depthTestEnabled = gl.getParameter(gl.DEPTH_TEST);
593
- const depthWriteMask = gl.getParameter(gl.DEPTH_WRITEMASK);
594
- const depthFunc = gl.getParameter(gl.DEPTH_FUNC);
595
-
596
590
 
597
591
  // Set state
598
- if (depthTest) renderer.getContext().enable(renderer.getContext().DEPTH_TEST);
599
- else renderer.getContext().disable(renderer.getContext().DEPTH_TEST);
592
+ const gl = renderer.getContext();
593
+ if (depthTest) gl.enable(gl.DEPTH_TEST);
594
+ else gl.disable(gl.DEPTH_TEST);
600
595
  renderer.state.buffers.depth.setMask(depthWrite);
601
596
 
602
597
  renderer.setClearColor(new Color(0, 0, 0), 0);
@@ -608,13 +603,10 @@ export class Graphics {
608
603
  renderer.clear();
609
604
  renderer.render(this.scene, this.perspectiveCam);
610
605
 
611
-
612
- // Restore state
613
- renderer.setRenderTarget(renderTarget); // reset render target
614
- const depthBuffer = renderer.state.buffers.depth;
615
- depthBuffer.setTest(depthTestEnabled);
616
- depthBuffer.setMask(depthWriteMask);
617
- depthBuffer.setFunc(depthFunc);
606
+ // Restore defaults (not using gl.getParameter to save/restore — it causes a synchronous GPU-CPU stall)
607
+ renderer.setRenderTarget(renderTarget);
608
+ gl.enable(gl.DEPTH_TEST);
609
+ renderer.state.buffers.depth.setMask(true);
618
610
  }
619
611
 
620
612
  /**
@@ -168,7 +168,7 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
168
168
  */
169
169
  public get context() { return this._context; }
170
170
 
171
- private _context!: Context;
171
+ private _context?: Context;
172
172
  private _overlay_ar!: AROverlayHandler;
173
173
  private _loadingProgress01: number = 0;
174
174
  private _loadingView?: ILoadingViewHandler;
@@ -298,12 +298,10 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
298
298
 
299
299
 
300
300
  this._overlay_ar = new AROverlayHandler();
301
- this._context ??= new Context({ domElement: this }); // we might have one already if onLoad is running
301
+ this.getOrCreateContext();
302
302
  this.addEventListener("xr-session-started", this.onXRSessionStarted);
303
303
  this.onSetupDesktop();
304
304
 
305
-
306
-
307
305
  if (!this.getAttribute("src")) {
308
306
  const global = (globalThis as any)["needle:codegen_files"] as unknown as string;
309
307
  if (debug) console.log("src is null, trying to load from globalThis[\"needle:codegen_files\"]", global);
@@ -418,18 +416,23 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
418
416
  case "focus-rect":
419
417
  {
420
418
  const focus_rect = this.getAttribute("focus-rect") as HTMLElement | string | null;
421
- if (focus_rect && this._context) {
419
+ if (focus_rect) {
420
+ const context = this.getOrCreateContext();
421
+
422
422
  if (focus_rect === null) {
423
- this._context.setCameraFocusRect(null);
423
+ context.setCameraFocusRect(null);
424
424
  }
425
425
  else if (typeof focus_rect === "string" && focus_rect.length > 0) {
426
426
  const element = document.querySelector(focus_rect);
427
- this._context.setCameraFocusRect(element instanceof HTMLElement ? element : null);
427
+ if (!element) console.warn(`No element found for focus-rect selector: ${focus_rect}`);
428
+ context.setCameraFocusRect(element instanceof HTMLElement ? element : null);
428
429
  }
429
430
  else if (focus_rect instanceof HTMLElement) {
430
- this._context.setCameraFocusRect(focus_rect);
431
+ context.setCameraFocusRect(focus_rect);
432
+ }
433
+ else {
434
+ console.warn("Invalid focus-rect value. Expected a CSS selector string or an HTMLElement.", focus_rect);
431
435
  }
432
-
433
436
  }
434
437
  }
435
438
  break;
@@ -447,19 +450,22 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
447
450
  private _lastSourceFiles: Array<string> | null = null;
448
451
  private _createContextPromise: Promise<boolean> | null = null;
449
452
 
450
- private async onLoad() {
451
-
452
- if (!this.isConnected) return;
453
-
453
+ /**
454
+ * Check if we have a context. If not a new one is created.
455
+ */
456
+ private getOrCreateContext() {
454
457
  if (!this._context) {
455
458
  if (debug) console.warn("Create new context");
456
459
  this._context = new Context({ domElement: this });
457
460
  }
461
+ return this._context;
462
+ }
458
463
 
459
- if (!this._context) {
460
- console.error("Needle Engine: Context not initialized");
461
- return;
462
- }
464
+ private async onLoad() {
465
+
466
+ if (!this.isConnected) return;
467
+
468
+ const context = this.getOrCreateContext();
463
469
 
464
470
  const filesToLoad = this.getSourceFiles();
465
471
  if (!this.checkIfSourceHasChanged(filesToLoad, this._lastSourceFiles)) {
@@ -477,7 +483,7 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
477
483
 
478
484
  if (filesToLoad === null || filesToLoad === undefined || filesToLoad.length <= 0) {
479
485
  if (debug) console.warn("Clear scene", filesToLoad);
480
- this._context.clear();
486
+ context.clear();
481
487
  if (loadId !== this._loadId) return;
482
488
  }
483
489
 
@@ -491,7 +497,7 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
491
497
  this.ensureLoadStartIsRegistered();
492
498
  let useDefaultLoading = this.dispatchEvent(new CustomEvent("loadstart", {
493
499
  detail: {
494
- context: this._context,
500
+ context: context,
495
501
  alias: alias
496
502
  },
497
503
  cancelable: true
@@ -581,9 +587,9 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
581
587
 
582
588
  const currentHash = this.getAttribute("hash");
583
589
  if (currentHash !== null && currentHash !== undefined)
584
- this._context.hash = currentHash;
585
- this._context.alias = alias;
586
- this._createContextPromise = this._context.create(args);
590
+ context.hash = currentHash;
591
+ context.alias = alias;
592
+ this._createContextPromise = context.create(args);
587
593
  const success = await this._createContextPromise;
588
594
  this.applyAttributes();
589
595
 
@@ -615,42 +621,45 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
615
621
 
616
622
  // #region applyAttributes
617
623
  private applyAttributes() {
624
+
625
+ const context = this.getOrCreateContext();
626
+
618
627
  // set tonemapping if configured
619
- if (this._context?.renderer) {
628
+ if (context.renderer) {
620
629
  const threeTonemapping = nameToThreeTonemapping(this.toneMapping);
621
630
  if (threeTonemapping !== undefined) {
622
- this._context.renderer.toneMapping = threeTonemapping;
631
+ context.renderer.toneMapping = threeTonemapping;
623
632
  }
624
633
  const exposure = this.getAttribute("tone-mapping-exposure");
625
634
  if (exposure !== null && exposure !== undefined) {
626
635
  const value = parseFloat(exposure);
627
636
  if (!isNaN(value))
628
- this._context.renderer.toneMappingExposure = value;
637
+ context.renderer.toneMappingExposure = value;
629
638
  }
630
639
  }
631
640
 
632
641
  const backgroundBlurriness = this.getAttribute("background-blurriness");
633
642
  if (backgroundBlurriness !== null && backgroundBlurriness !== undefined) {
634
643
  const value = parseFloat(backgroundBlurriness);
635
- if (!isNaN(value) && this._context) {
636
- this._context.scene.backgroundBlurriness = value;
644
+ if (!isNaN(value)) {
645
+ context.scene.backgroundBlurriness = value;
637
646
  }
638
647
  }
639
648
 
640
649
  const environmentIntensity = this.getAttribute("environment-intensity");
641
- if (environmentIntensity != undefined && this._context) {
650
+ if (environmentIntensity != undefined) {
642
651
  const value = parseFloat(environmentIntensity);
643
- if (!isNaN(value) && this._context)
644
- this._context.scene.environmentIntensity = value;
652
+ if (!isNaN(value))
653
+ context.scene.environmentIntensity = value;
645
654
  }
646
655
 
647
656
  const backgroundColor = this.getAttribute("background-color");
648
- if (this._context?.renderer) {
657
+ if (context.renderer) {
649
658
  if (typeof backgroundColor === "string" && backgroundColor.length > 0) {
650
659
  const rgbaColor = RGBAColor.fromColorRepresentation(backgroundColor);
651
660
  if (debug) console.debug("<needle-engine> background-color changed, str:", backgroundColor, "→", rgbaColor)
652
- this._context.renderer.setClearColor(rgbaColor, rgbaColor.alpha);
653
- this.context.scene.background = null;
661
+ context.renderer.setClearColor(rgbaColor, rgbaColor.alpha);
662
+ context.scene.background = null;
654
663
  }
655
664
  // HACK: if we set background-color to a color and then back to null we want the background-image attribute to re-apply
656
665
  else if (this.getAttribute("background-image")) {
@@ -660,19 +669,21 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
660
669
  }
661
670
 
662
671
  private onXRSessionStarted = () => {
663
- const xrSessionMode = this.context.xrSessionMode;
672
+ const context = this.getOrCreateContext();
673
+
674
+ const xrSessionMode = context.xrSessionMode;
664
675
  if (xrSessionMode === "immersive-ar")
665
- this.onEnterAR(this.context.xrSession!);
676
+ this.onEnterAR(context.xrSession!);
666
677
  else if (xrSessionMode === "immersive-vr")
667
- this.onEnterVR(this.context.xrSession!);
678
+ this.onEnterVR(context.xrSession!);
668
679
 
669
680
  // handle session end:
670
- this.context.xrSession?.addEventListener("end", () => {
671
- this.dispatchEvent(new CustomEvent("xr-session-ended", { detail: { session: this.context.xrSession, context: this._context, sessionMode: xrSessionMode } }));
681
+ context.xrSession?.addEventListener("end", () => {
682
+ this.dispatchEvent(new CustomEvent("xr-session-ended", { detail: { session: context.xrSession, context: this._context, sessionMode: xrSessionMode } }));
672
683
  if (xrSessionMode === "immersive-ar")
673
- this.onExitAR(this.context.xrSession!);
684
+ this.onExitAR(context.xrSession!);
674
685
  else if (xrSessionMode === "immersive-vr")
675
- this.onExitVR(this.context.xrSession!);
686
+ this.onExitVR(context.xrSession!);
676
687
  });
677
688
  };
678
689
 
@@ -741,7 +752,7 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
741
752
  if (typeof fn === "function") {
742
753
  this._previouslyRegisteredMap.set(eventName, fn);
743
754
  // @ts-ignore // not sure how to type this properly
744
- this.addEventListener(eventName, evt => fn?.call(globalThis, this._context, evt));
755
+ this.addEventListener(eventName, evt => fn?.call(globalThis, this.getOrCreateContext(), evt));
745
756
  }
746
757
  }
747
758
  catch (err) {
@@ -783,35 +794,39 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
783
794
  * @internal
784
795
  */
785
796
  onEnterAR(session: XRSession) {
797
+ const context = this.getOrCreateContext();
786
798
  this.onSetupAR();
787
799
  const overlayContainer = this.getAROverlayContainer();
788
- this._overlay_ar.onBegin(this._context!, overlayContainer, session);
789
- this.dispatchEvent(new CustomEvent("enter-ar", { detail: { session: session, context: this._context, htmlContainer: this._overlay_ar?.ARContainer } }));
800
+ this._overlay_ar.onBegin(context, overlayContainer, session);
801
+ this.dispatchEvent(new CustomEvent("enter-ar", { detail: { session: session, context: context, htmlContainer: this._overlay_ar?.ARContainer } }));
790
802
  }
791
803
 
792
804
  /**
793
805
  * @internal
794
806
  */
795
807
  onExitAR(session: XRSession) {
796
- this._overlay_ar.onEnd(this._context!);
808
+ const context = this.getOrCreateContext();
809
+ this._overlay_ar.onEnd(context);
797
810
  this.onSetupDesktop();
798
- this.dispatchEvent(new CustomEvent("exit-ar", { detail: { session: session, context: this._context, htmlContainer: this._overlay_ar?.ARContainer } }));
811
+ this.dispatchEvent(new CustomEvent("exit-ar", { detail: { session: session, context: context, htmlContainer: this._overlay_ar?.ARContainer } }));
799
812
  }
800
813
 
801
814
  /**
802
815
  * @internal
803
816
  */
804
817
  onEnterVR(session: XRSession) {
818
+ const context = this.getOrCreateContext();
805
819
  this.onSetupVR();
806
- this.dispatchEvent(new CustomEvent("enter-vr", { detail: { session: session, context: this._context } }));
820
+ this.dispatchEvent(new CustomEvent("enter-vr", { detail: { session: session, context: context } }));
807
821
  }
808
822
 
809
823
  /**
810
824
  * @internal
811
825
  */
812
826
  onExitVR(session: XRSession) {
827
+ const context = this.getOrCreateContext();
813
828
  this.onSetupDesktop();
814
- this.dispatchEvent(new CustomEvent("exit-vr", { detail: { session: session, context: this._context } }));
829
+ this.dispatchEvent(new CustomEvent("exit-vr", { detail: { session: session, context: context } }));
815
830
  }
816
831
 
817
832
  private onSetupAR() {
@@ -1,10 +0,0 @@
1
- import{BufferGeometry as W,Mesh as F,Box3 as ae,Vector3 as A,Sphere as Le,CompressedTexture as Be,Texture as $,Matrix3 as Ge,InterleavedBuffer as je,InterleavedBufferAttribute as Ne,BufferAttribute as Ue,TextureLoader as We,Matrix4 as _e,Clock as Fe,MeshStandardMaterial as ze}from"./three.min.js";import{DRACOLoader as qe,KTX2Loader as Ve,MeshoptDecoder as Xe,GLTFLoader as le}from"./three-examples.min.js";const He="";globalThis.GLTF_PROGRESSIVE_VERSION=He,console.debug("[gltf-progressive] version -");let k="https://www.gstatic.com/draco/versioned/decoders/1.5.7/",z="https://cdn.needle.tools/static/three/0.179.1/basis2/";const Ke=k,Ye=z,be=new URL(k+"draco_decoder.js");be.searchParams.append("range","true"),fetch(be,{method:"GET",headers:{Range:"bytes=0-1"}}).catch(i=>{console.debug(`Failed to fetch remote Draco decoder from ${k} (offline: ${typeof navigator<"u"?navigator.onLine:"unknown"})`),k===Ke&&Me("./include/draco/"),z===Ye&&De("./include/ktx2/")}).finally(()=>{Oe()});const Qe=()=>({dracoDecoderPath:k,ktx2TranscoderPath:z});function Me(i){k=i,T&&T[ce]!=k?(console.debug("Updating Draco decoder path to "+i),T[ce]=k,T.setDecoderPath(k),T.preload()):console.debug("Setting Draco decoder path to "+i)}function De(i){z=i,I&&I.transcoderPath!=z?(console.debug("Updating KTX2 transcoder path to "+i),I.setTranscoderPath(z),I.init()):console.debug("Setting KTX2 transcoder path to "+i)}function te(i){return Oe(),i?I.detectSupport(i):i!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:T,ktx2Loader:I,meshoptDecoder:re}}function ue(i){i.dracoLoader||i.setDRACOLoader(T),i.ktx2Loader||i.setKTX2Loader(I),i.meshoptDecoder||i.setMeshoptDecoder(re)}const ce=Symbol("dracoDecoderPath");let T,re,I;function Oe(){T||(T=new qe,T[ce]=k,T.setDecoderPath(k),T.setDecoderConfig({type:"js"}),T.preload()),I||(I=new Ve,I.setTranscoderPath(z),I.init()),re||(re=Xe)}const de=new WeakMap;function he(i,t){let e=de.get(i);e?e=Object.assign(e,t):e=t,de.set(i,e)}const Je=le.prototype.load;function Ze(...i){const t=de.get(this);let e=i[0];const r=new URL(e,window.location.href);if(r.hostname.endsWith("needle.tools")){const n=t?.progressive!==void 0?t.progressive:!0,s=t?.usecase?t.usecase:"default";n?this.requestHeader.Accept=`*/*;progressive=allowed;usecase=${s}`:this.requestHeader.Accept=`*/*;usecase=${s}`,e=r.toString()}return i[0]=e,Je?.call(this,...i)}le.prototype.load=Ze,j("debugprogressive");function j(i){if(typeof window>"u")return!1;const t=new URL(window.location.href).searchParams.get(i);return t==null||t==="0"||t==="false"?!1:t===""?!0:t}function et(i,t){if(t===void 0||i===void 0||t.startsWith("./")||t.startsWith("http")||t.startsWith("data:")||t.startsWith("blob:"))return t;const e=i.lastIndexOf("/");if(e>=0){const r=i.substring(0,e+1);for(;r.endsWith("/")&&t.startsWith("/");)t=t.substring(1);return r+t}return t}function Se(){return se!==void 0||(se=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),j("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",se)),se}let se;function Te(){if(typeof window>"u")return!1;const i=new URL(window.location.href),t=i.hostname==="localhost"||/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(i.hostname);return i.hostname==="127.0.0.1"||t}class tt{constructor(t=100,e={}){this.maxConcurrent=t,this.debug=e.debug??!1,window.requestAnimationFrame(this.tick)}_running=new Map;_queue=[];debug=!1;tick=()=>{this.internalUpdate(),setTimeout(this.tick,10)};slot(t){return this.debug&&console.debug(`[PromiseQueue]: Requesting slot for key ${t}, running: ${this._running.size}, waiting: ${this._queue.length}`),new Promise(e=>{this._queue.push({key:t,resolve:e})})}add(t,e){this._running.has(t)||(this._running.set(t,e),e.finally(()=>{this._running.delete(t),this.debug&&console.debug(`[PromiseQueue]: Promise finished now running: ${this._running.size}, waiting: ${this._queue.length}. (finished ${t})`)}),this.debug&&console.debug(`[PromiseQueue]: Added new promise, now running: ${this._running.size}, waiting: ${this._queue.length}. (added ${t})`))}internalUpdate(){const t=this.maxConcurrent-this._running.size;for(let e=0;e<t&&this._queue.length>0;e++){this.debug&&console.debug(`[PromiseQueue]: Running ${this._running.size} promises, waiting for ${this._queue.length} more.`);const{key:r,resolve:n}=this._queue.shift();n({use:s=>this.add(r,s)})}}}function rt(i){const t=i.image?.width??0,e=i.image?.height??0,r=i.image?.depth??1,n=Math.floor(Math.log2(Math.max(t,e,r)))+1,s=st(i);return t*e*r*s*(1-Math.pow(.25,n))/(1-.25)}function st(i){let t=4;const e=i.format;e===1024||e===1025?t=1:e===1026||e===1027?t=2:e===1022||e===1029?t=3:(e===1023||e===1033)&&(t=4);let r=1;const n=i.type;return n===1009||n===1010?r=1:n===1011||n===1012?r=2:n===1013||n===1014||n===1015?r=4:n===1016&&(r=2),t*r}const nt=typeof window>"u"&&typeof document>"u",ge=Symbol("needle:raycast-mesh");function V(i){return i?.[ge]instanceof W?i[ge]:null}function ot(i,t){if((i.type==="Mesh"||i.type==="SkinnedMesh")&&!V(i)){const e=at(t);e.userData={isRaycastMesh:!0},i[ge]=e}}function it(i=!0){if(i){if(H)return;const t=H=F.prototype.raycast;F.prototype.raycast=function(e,r){const n=this,s=V(n);let o;s&&n.isMesh&&(o=n.geometry,n.geometry=s),t.call(this,e,r),o&&(n.geometry=o)}}else{if(!H)return;F.prototype.raycast=H,H=null}}let H=null;function at(i){const t=new W;for(const e in i.attributes)t.setAttribute(e,i.getAttribute(e));return t.setIndex(i.getIndex()),t}const N=new Array,h=j("debugprogressive");let K,q=-1;if(h){let i=function(){q+=1,q>=t&&(q=-1),console.log(`Toggle LOD level [${q}]`)},t=6;window.addEventListener("keyup",e=>{e.key==="p"&&i(),e.key==="w"&&(K=!K,console.log(`Toggle wireframe [${K}]`));const r=parseInt(e.key);!isNaN(r)&&r>=0&&(q=r,console.log(`Set LOD level to [${q}]`))})}function Pe(i){if(h&&K!==void 0)if(Array.isArray(i))for(const t of i)Pe(t);else i&&"wireframe"in i&&(i.wireframe=K===!0)}const Y=new Array;let lt=0;const ut=Se()?2:10;function ct(i){if(Y.length<ut){const e=Y.length;h&&console.warn(`[Worker] Creating new worker #${e}`);const r=ve.createWorker(i||{});return Y.push(r),r}const t=lt++%Y.length;return Y[t]}class ve{constructor(t,e){this.worker=t,this._debug=e.debug??!1,t.onmessage=r=>{const n=r.data;switch(this._debug&&console.log("[Worker] EVENT",n),n.type){case"loaded-gltf":for(const s of this._running)if(s.url===n.result.url){dt(n.result),s.resolve(n.result);const o=s.url;o.startsWith("blob:")&&URL.revokeObjectURL(o)}}},t.onerror=r=>{console.error("[Worker] Error in gltf-progressive worker:",r)},t.postMessage({type:"init"})}static async createWorker(t){const e=new Worker(URL.createObjectURL(new Blob([`import '${new URL("./loader.worker-BqODMeeW.js",import.meta.url).toString()}';`],{type:"text/javascript"})),{type:"module"});return new ve(e,t)}_running=[];_webglRenderer=null;async load(t,e){const r=Qe();let n=e?.renderer;n||(this._webglRenderer??=(async()=>{const{WebGLRenderer:l}=await import("./three.min.js").then(a=>a.THREE);return new l})(),n=await this._webglRenderer);const s=te(n).ktx2Loader.workerConfig;t instanceof URL?t=t.toString():t.startsWith("file:")?t=URL.createObjectURL(new Blob([t])):!t.startsWith("blob:")&&!t.startsWith("http:")&&!t.startsWith("https:")&&(t=new URL(t,window.location.href).toString());const o={type:"load",url:t,dracoDecoderPath:r.dracoDecoderPath,ktx2TranscoderPath:r.ktx2TranscoderPath,ktx2LoaderConfig:s};return this._debug&&console.debug("[Worker] Sending load request",o),this.worker.postMessage(o),new Promise(l=>{this._running.push({url:t.toString(),resolve:l})})}_debug=!1}function dt(i){for(const t of i.geometries){const e=t.geometry,r=new W;if(r.name=e.name||"",e.index){const n=e.index;r.setIndex(fe(n))}for(const n in e.attributes){const s=e.attributes[n],o=fe(s);r.setAttribute(n,o)}if(e.morphAttributes)for(const n in e.morphAttributes){const s=e.morphAttributes[n].map(o=>fe(o));r.morphAttributes[n]=s}if(r.morphTargetsRelative=e.morphTargetsRelative??!1,r.boundingBox=new ae,r.boundingBox.min=new A(e.boundingBox?.min.x,e.boundingBox?.min.y,e.boundingBox?.min.z),r.boundingBox.max=new A(e.boundingBox?.max.x,e.boundingBox?.max.y,e.boundingBox?.max.z),r.boundingSphere=new Le(new A(e.boundingSphere?.center.x,e.boundingSphere?.center.y,e.boundingSphere?.center.z),e.boundingSphere?.radius),e.groups)for(const n of e.groups)r.addGroup(n.start,n.count,n.materialIndex);e.userData&&(r.userData=e.userData),t.geometry=r}for(const t of i.textures){const e=t.texture;let r=null;if(e.isCompressedTexture){const n=e.mipmaps,s=e.image?.width||e.source?.data?.width||-1,o=e.image?.height||e.source?.data?.height||-1;r=new Be(n,s,o,e.format,e.type,e.mapping,e.wrapS,e.wrapT,e.magFilter,e.minFilter,e.anisotropy,e.colorSpace)}else r=new $(e.image,e.mapping,e.wrapS,e.wrapT,e.magFilter,e.minFilter,e.format,e.type,e.anisotropy,e.colorSpace),r.mipmaps=e.mipmaps,r.channel=e.channel,r.source.data=e.source.data,r.flipY=e.flipY,r.premultiplyAlpha=e.premultiplyAlpha,r.unpackAlignment=e.unpackAlignment,r.matrix=new Ge(...e.matrix.elements);if(!r){console.error("[Worker] Failed to create new texture from received data. Texture is not a CompressedTexture or Texture.");continue}t.texture=r}return i}function fe(i){let t=i;if("isInterleavedBufferAttribute"in i&&i.isInterleavedBufferAttribute){const e=i.data,r=e.array,n=new je(r,e.stride);t=new Ne(n,i.itemSize,r.byteOffset,i.normalized),t.offset=i.offset}else"isBufferAttribute"in i&&i.isBufferAttribute&&(t=new Ue(i.array,i.itemSize,i.normalized),t.usage=i.usage,t.gpuType=i.gpuType,t.updateRanges=i.updateRanges);return t}const ht=j("gltf-progressive-worker");j("gltf-progressive-reduce-mipmaps");const X=j("gltf-progressive-gc"),me=Symbol("needle-progressive-texture"),B="NEEDLE_progressive";class m{get name(){return B}static getMeshLODExtension(t){const e=this.getAssignedLODInformation(t);return e?.key?this.lodInfos.get(e.key):null}static getPrimitiveIndex(t){return this.getAssignedLODInformation(t)?.index??-1}static getMaterialMinMaxLODsCount(t,e){const r=this,n="LODS:minmax",s=t[n];if(s!=null)return s;if(e||(e={min_count:1/0,max_count:0,lods:[]}),Array.isArray(t)){for(const l of t)this.getMaterialMinMaxLODsCount(l,e);return t[n]=e,e}if(h==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const l=t;for(const a of Object.keys(l.uniforms)){const u=l.uniforms[a].value;u?.isTexture===!0&&o(u,e)}}else if(t.isMaterial)for(const l of Object.keys(t)){const a=t[l];a?.isTexture===!0&&o(a,e)}else h&&console.warn(`[getMaterialMinMaxLODsCount] Unsupported material type: ${t.type}`);return t[n]=e,e;function o(l,a){const u=r.getAssignedLODInformation(l);if(u){const w=r.lodInfos.get(u.key);if(w&&w.lods){a.min_count=Math.min(a.min_count,w.lods.length),a.max_count=Math.max(a.max_count,w.lods.length);for(let p=0;p<w.lods.length;p++){const y=w.lods[p];y.width&&(a.lods[p]=a.lods[p]||{min_height:1/0,max_height:0},a.lods[p].min_height=Math.min(a.lods[p].min_height,y.height),a.lods[p].max_height=Math.max(a.lods[p].max_height,y.height))}}}}}static hasLODLevelAvailable(t,e){if(Array.isArray(t)){for(const s of t)if(this.hasLODLevelAvailable(s,e))return!0;return!1}if(t.isMaterial===!0){for(const s of Object.keys(t)){const o=t[s];if(o&&o.isTexture&&this.hasLODLevelAvailable(o,e))return!0}return!1}else if(t.isGroup===!0){for(const s of t.children)if(s.isMesh===!0&&this.hasLODLevelAvailable(s,e))return!0}let r,n;if(t.isMesh?r=t.geometry:(t.isBufferGeometry||t.isTexture)&&(r=t),r&&r?.userData?.LODS){const s=r.userData.LODS;if(n=this.lodInfos.get(s.key),e===void 0)return n!=null;if(n)return Array.isArray(n.lods)?e<n.lods.length:e===0}return!1}static assignMeshLOD(t,e){if(!t)return Promise.resolve(null);if(t instanceof F||t.isMesh===!0){const r=t.geometry,n=this.getAssignedLODInformation(r);if(!n)return Promise.resolve(null);for(const s of N)s.onBeforeGetLODMesh?.(t,e);return t["LOD:requested level"]=e,m.getOrLoadLOD(r,e).then(s=>{if(Array.isArray(s)){const o=n.index||0;s=s[o]}return t["LOD:requested level"]===e&&(delete t["LOD:requested level"],s&&r!=s&&(s?.isBufferGeometry?t.geometry=s:h&&console.error("Invalid LOD geometry",s))),s}).catch(s=>(console.error("Error loading mesh LOD",t,s),null))}else h&&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 r=t;if(Array.isArray(r.material)){const n=new Array;for(const s of r.material){const o=this.assignTextureLOD(s,e);n.push(o)}return Promise.all(n).then(s=>{const o=new Array;for(const l of s)Array.isArray(l)&&o.push(...l);return o})}else return this.assignTextureLOD(r.material,e)}if(t.isMaterial===!0){const r=t,n=[],s=new Array;if(r.uniforms&&(r.isRawShaderMaterial||r.isShaderMaterial===!0)){const o=r;for(const l of Object.keys(o.uniforms)){const a=o.uniforms[l].value;if(a?.isTexture===!0){const u=this.assignTextureLODForSlot(a,e,r,l).then(w=>(w&&o.uniforms[l].value!=w&&(o.uniforms[l].value=w,o.uniformsNeedUpdate=!0),w));n.push(u),s.push(l)}}}else for(const o of Object.keys(r)){const l=r[o];if(l?.isTexture===!0){const a=this.assignTextureLODForSlot(l,e,r,o);n.push(a),s.push(o)}}return Promise.all(n).then(o=>{const l=new Array;for(let a=0;a<o.length;a++){const u=o[a],w=s[a];u&&u.isTexture===!0?l.push({material:r,slot:w,texture:u,level:e}):l.push({material:r,slot:w,texture:null,level:e})}return l})}if(t instanceof $||t.isTexture===!0){const r=t;return this.assignTextureLODForSlot(r,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,r,n){return t?.isTexture!==!0?Promise.resolve(null):n==="glyphMap"?Promise.resolve(t):m.getOrLoadLOD(t,e).then(s=>{if(Array.isArray(s))return console.warn("Progressive: Got an array of textures for a texture slot, this should not happen..."),null;if(s?.isTexture===!0){if(s!=t&&r&&n){const o=r[n];if(o&&!h){const l=this.getAssignedLODInformation(o);if(l&&l?.level<e)return h==="verbose"&&console.warn("Assigned texture level is already higher: ",l.level,e,r,o,s),s&&s!==o&&((h||X)&&console.log(`[gltf-progressive] Disposing rejected lower-quality texture LOD ${e} (assigned is ${l.level})`,s.uuid),s.dispose()),null}if(this.trackTextureUsage(s),o&&o!==s&&this.untrackTextureUsage(o)&&(h||X)){const l=this.getAssignedLODInformation(o);console.log(`[gltf-progressive] Disposed old texture LOD ${l?.level??"?"} \u2192 ${e} for ${r.name||r.type}.${n}`,o.uuid)}r[n]=s}return s}else h=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(s=>(console.error("Error loading LOD",t,s),null))}parser;url;constructor(t){const e=t.options.path;h&&console.log("Progressive extension registered for",e),this.parser=t,this.url=e}_isLoadingMesh;loadMesh=t=>{if(this._isLoadingMesh)return null;const e=this.parser.json.meshes[t]?.extensions?.[B];return e?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",t).then(r=>(this._isLoadingMesh=!1,r&&m.registerMesh(this.url,e.guid,r,e.lods?.length,0,e),r))):null};afterRoot(t){return h&&console.log("AFTER",this.url,t),this.parser.json.textures?.forEach((e,r)=>{if(e?.extensions){const n=e?.extensions[B];if(n){if(!n.lods){h&&console.warn("Texture has no LODs",n);return}let s=!1;for(const o of this.parser.associations.keys())o.isTexture===!0&&this.parser.associations.get(o)?.textures===r&&(s=!0,m.registerTexture(this.url,o,n.lods?.length,r,n));s||this.parser.getDependency("texture",r).then(o=>{o&&m.registerTexture(this.url,o,n.lods?.length,r,n)})}}}),this.parser.json.meshes?.forEach((e,r)=>{if(e?.extensions){const n=e?.extensions[B];if(n&&n.lods){for(const s of this.parser.associations.keys())if(s.isMesh){const o=this.parser.associations.get(s);o?.meshes===r&&m.registerMesh(this.url,n.guid,s,n.lods.length,o.primitives,n)}}}}),null}static registerTexture=(t,e,r,n,s)=>{if(!e){h&&console.error("!! gltf-progressive: Called register texture without texture");return}if(h){const l=e.image?.width||e.source?.data?.width||0,a=e.image?.height||e.source?.data?.height||0;console.log(`> gltf-progressive: register texture[${n}] "${e.name||e.uuid}", Current: ${l}x${a}, Max: ${s.lods[0]?.width}x${s.lods[0]?.height}, uuid: ${e.uuid}`,s,e)}e.source&&(e.source[me]=s);const o=s.guid;m.assignLODInformation(t,e,o,r,n),m.lodInfos.set(o,s),m.lowresCache.set(o,new WeakRef(e))};static registerMesh=(t,e,r,n,s,o)=>{const l=r.geometry;if(!l){h&&console.warn("gltf-progressive: Register mesh without geometry");return}l.userData||(l.userData={}),h&&console.log("> Progressive: register mesh "+r.name,{index:s,uuid:r.uuid},o,r),m.assignLODInformation(t,l,e,n,s),m.lodInfos.set(e,o);let a=m.lowresCache.get(e)?.deref();a?a.push(r.geometry):a=[r.geometry],m.lowresCache.set(e,new WeakRef(a)),n>0&&!V(r)&&ot(r,l);for(const u of N)u.onRegisteredNewMesh?.(r,o)};static dispose(t){if(t){this.lodInfos.delete(t);const e=this.lowresCache.get(t);if(e){const r=e.deref();if(r){if(r.isTexture){const n=r;this.textureRefCounts.delete(n.uuid),n.dispose()}else if(Array.isArray(r))for(const n of r)n.dispose()}this.lowresCache.delete(t)}for(const[r,n]of this.cache)r.includes(t)&&(this._disposeCacheEntry(n),this.cache.delete(r))}else{this.lodInfos.clear();for(const[,e]of this.lowresCache){const r=e.deref();if(r){if(r.isTexture){const n=r;this.textureRefCounts.delete(n.uuid),n.dispose()}else if(Array.isArray(r))for(const n of r)n.dispose()}}this.lowresCache.clear();for(const[,e]of this.cache)this._disposeCacheEntry(e);this.cache.clear(),this.textureRefCounts.clear()}}static _disposeCacheEntry(t){if(t instanceof WeakRef){const e=t.deref();e&&(e.isTexture&&this.textureRefCounts.delete(e.uuid),e.dispose())}else t.then(e=>{if(e)if(Array.isArray(e))for(const r of e)r.dispose();else e.isTexture&&this.textureRefCounts.delete(e.uuid),e.dispose()}).catch(()=>{})}static lodInfos=new Map;static cache=new Map;static lowresCache=new Map;static textureRefCounts=new Map;static _resourceRegistry=new FinalizationRegistry(t=>{const e=m.cache.get(t);(h||X)&&console.debug(`[gltf-progressive] Memory: Resource GC'd
2
- ${t}`),e instanceof WeakRef&&(e.deref()||(m.cache.delete(t),(h||X)&&console.log("[gltf-progressive] \u21AA Cache entry deleted (GC)")))});static trackTextureUsage(t){const e=t.uuid,r=this.textureRefCounts.get(e)||0;this.textureRefCounts.set(e,r+1),h==="verbose"&&console.log(`[gltf-progressive] Track texture ${e}, refCount: ${r} \u2192 ${r+1}`)}static untrackTextureUsage(t){const e=t.uuid,r=this.textureRefCounts.get(e);if(!r)return(h==="verbose"||X)&&s("[gltf-progressive] Memory: Untrack untracked texture (dispose immediately)",0),t.dispose(),!0;const n=r-1;if(n<=0)return this.textureRefCounts.delete(e),(h||X)&&s("[gltf-progressive] Memory: Dispose texture",n),t.dispose(),!0;return this.textureRefCounts.set(e,n),h==="verbose"&&s("[gltf-progressive] Memory: Untrack texture",n),!1;function s(o,l){let a=t.image?.width||t.source?.data?.width||0,u=t.image?.height||t.source?.data?.height||0;const w=a&&u?`${a}x${u}`:"N/A";let p="N/A";a&&u&&(p=`~${(rt(t)/(1024*1024)).toFixed(2)} MB`),console.log(`${o} \u2014 ${t.name} ${w} (${p}), refCount: ${r} \u2192 ${l}
3
- ${e}`)}}static workers=[];static _workersIndex=0;static async getOrLoadLOD(t,e){const r=h=="verbose",n=this.getAssignedLODInformation(t);if(!n)return h&&console.warn(`[gltf-progressive] No LOD information found: ${t.name}, uuid: ${t.uuid}, type: ${t.type}`,t),null;const s=n?.key;let o;if(t.isTexture===!0){const l=t;l.source&&l.source[me]&&(o=l.source[me])}if(o||(o=m.lodInfos.get(s)),!o)h&&console.warn(`Can not load LOD ${e}: no LOD info found for "${s}" ${t.name}`,t.type,m.lodInfos);else{if(e>0){let u=!1;const w=Array.isArray(o.lods);if(w&&e>=o.lods.length?u=!0:w||(u=!0),u){const p=this.lowresCache.get(s);if(p){const y=p.deref();if(y)return y;this.lowresCache.delete(s),h&&console.log(`[gltf-progressive] Lowres cache entry was GC'd: ${s}`)}return null}}const l=Array.isArray(o.lods)?o.lods[e]?.path:o.lods;if(!l)return h&&!o["missing:uri"]&&(o["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,o)),null;const a=et(n.url,l);if(a.endsWith(".glb")||a.endsWith(".gltf")){if(!o.guid)return console.warn("missing pointer for glb/gltf texture",o),null;const u=a+"_"+o.guid,w=await this.queue.slot(a),p=this.cache.get(u);if(p!==void 0)if(r&&console.log(`LOD ${e} was already loading/loaded: ${u}`),p instanceof WeakRef){const c=p.deref();if(c){let x=c,v=!1;if(x instanceof $&&t instanceof $?x.image?.data||x.source?.data?x=this.copySettings(t,x):v=!0:x instanceof W&&t instanceof W&&(x.attributes.position?.array||(v=!0)),!v)return x}this.cache.delete(u),h&&console.log(`[gltf-progressive] Re-loading GC'd/disposed resource: ${u}`)}else{let c=await p.catch(v=>(console.error(`Error loading LOD ${e} from ${a}
4
- `,v),null)),x=!1;if(c==null||(c instanceof $&&t instanceof $?c.image?.data||c.source?.data?c=this.copySettings(t,c):(x=!0,this.cache.delete(u)):c instanceof W&&t instanceof W&&(c.attributes.position?.array||(x=!0,this.cache.delete(u)))),!x)return c}if(!w.use)return h&&console.log(`LOD ${e} was aborted: ${a}`),null;const y=o,P=new Promise(async(c,x)=>{if(ht){const g=await(await ct({})).load(a);if(g.textures.length>0)for(const d of g.textures){let f=d.texture;return m.assignLODInformation(n.url,f,s,e,void 0),t instanceof $&&(f=this.copySettings(t,f)),f&&(f.guid=y.guid),c(f)}if(g.geometries.length>0){const d=new Array;for(const f of g.geometries){const L=f.geometry;m.assignLODInformation(n.url,L,s,e,f.primitiveIndex),d.push(L)}return c(d)}return c(null)}const v=new le;ue(v),h&&(await new Promise(g=>setTimeout(g,1e3)),r&&console.warn("Start loading (delayed) "+a,y.guid));let C=a;if(y&&Array.isArray(y.lods)){const g=y.lods[e];g.hash&&(C+="?v="+g.hash)}const b=await v.loadAsync(C).catch(g=>(console.error(`Error loading LOD ${e} from ${a}
5
- `,g),c(null)));if(!b)return c(null);const R=b.parser;r&&console.log("Loading finished "+a,y.guid);let M=0;if(b.parser.json.textures){let g=!1;for(const d of b.parser.json.textures){if(d?.extensions){const f=d?.extensions[B];if(f?.guid&&f.guid===y.guid){g=!0;break}}M++}if(g){let d=await R.getDependency("texture",M);return d&&m.assignLODInformation(n.url,d,s,e,void 0),r&&console.log('change "'+t.name+'" \u2192 "'+d.name+'"',a,M,d,u),t instanceof $&&(d=this.copySettings(t,d)),d&&(d.guid=y.guid),c(d)}else h&&console.warn("Could not find texture with guid",y.guid,b.parser.json)}if(M=0,b.parser.json.meshes){let g=!1;for(const d of b.parser.json.meshes){if(d?.extensions){const f=d?.extensions[B];if(f?.guid&&f.guid===y.guid){g=!0;break}}M++}if(g){const d=await R.getDependency("mesh",M);if(r&&console.log(`Loaded Mesh "${d.name}"`,a,M,d,u),d.isMesh===!0){const f=d.geometry;return m.assignLODInformation(n.url,f,s,e,0),c(f)}else{const f=new Array;for(let L=0;L<d.children.length;L++){const S=d.children[L];if(S.isMesh===!0){const G=S.geometry;m.assignLODInformation(n.url,G,s,e,L),f.push(G)}}return c(f)}}else h&&console.warn("Could not find mesh with guid",y.guid,b.parser.json)}return c(null)});this.cache.set(u,P),w.use(P);const _=await P;return _!=null?_ instanceof $?(this.cache.set(u,new WeakRef(_)),m._resourceRegistry.register(_,u)):Array.isArray(_)?this.cache.set(u,Promise.resolve(_)):this.cache.set(u,Promise.resolve(_)):this.cache.set(u,Promise.resolve(null)),_}else if(t instanceof $){r&&console.log("Load texture from uri: "+a);const u=await new We().loadAsync(a);return u?(u.guid=o.guid,u.flipY=!1,u.needsUpdate=!0,u.colorSpace=t.colorSpace,r&&console.log(o,u)):h&&console.warn("failed loading",a),u}}return null}static maxConcurrent=50;static queue=new tt(m.maxConcurrent,{debug:h!=!1});static assignLODInformation(t,e,r,n,s){if(!e)return;e.userData||(e.userData={});const o=new gt(t,r,n,s);e.userData.LODS=o,"source"in e&&typeof e.source=="object"&&(e.source.LODS=o)}static getAssignedLODInformation(t){return t?t.userData?.LODS?t.userData.LODS:"source"in t&&t.source?.LODS?t.source.LODS:null:null}static copySettings(t,e){return e?(h==="verbose"&&console.debug(`Copy texture settings
6
- `,t.uuid,`
7
- `,e.uuid),e=e.clone(),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):t}}class gt{url;key;level;index;constructor(t,e,r,n){this.url=t,this.key=e,this.level=r,n!=null&&(this.index=n)}}class pe{static addPromise=(t,e,r,n)=>{n.forEach(s=>{s.add(t,e,r)})};ready;get awaitedCount(){return this._addedCount}get resolvedCount(){return this._resolvedCount}get currentlyAwaiting(){return this._awaiting.length}_resolve;_signal;_frame_start;_frames_to_capture;_resolved=!1;_addedCount=0;_resolvedCount=0;_awaiting=[];_maxPromisesPerObject=1;constructor(t,e){const r=Math.max(e.frames??2,2);this._frame_start=e.waitForFirstCapture?void 0:t,this._frames_to_capture=r,this.ready=new Promise(n=>{this._resolve=n}),this.ready.finally(()=>{this._resolved=!0,this._awaiting.length=0}),this._signal=e.signal,this._signal?.addEventListener("abort",()=>{this.resolveNow()}),this._maxPromisesPerObject=Math.max(1,e.maxPromisesPerObject??1)}_currentFrame=0;update(t){this._currentFrame=t,this._frame_start===void 0&&this._addedCount>0&&(this._frame_start=t),(this._signal?.aborted||this._awaiting.length===0&&this._frame_start!==void 0&&t>this._frame_start+this._frames_to_capture)&&this.resolveNow()}_seen=new WeakMap;add(t,e,r){if(this._resolved){h&&console.warn("PromiseGroup: Trying to add a promise to a resolved group, ignoring.");return}if(!(this._frame_start!==void 0&&this._currentFrame>this._frame_start+this._frames_to_capture)){if(this._maxPromisesPerObject>=1)if(this._seen.has(e)){let n=this._seen.get(e);if(n>=this._maxPromisesPerObject){h&&console.warn("PromiseGroup: Already awaiting object ignoring new promise for it.");return}this._seen.set(e,n+1)}else this._seen.set(e,1);this._awaiting.push(r),this._addedCount++,r.finally(()=>{this._resolvedCount++,this._awaiting.splice(this._awaiting.indexOf(r),1)})}}resolveNow(){this._resolved||this._resolve?.({awaited_count:this._addedCount,resolved_count:this._resolvedCount,cancelled:this._signal?.aborted??!1})}}const E=j("debugprogressive"),ft=j("noprogressive"),xe=Symbol("Needle:LODSManager"),we=Symbol("Needle:LODState"),U=Symbol("Needle:CurrentLOD"),O={mesh_lod:-1,texture_lod:-1};let Q=class D{static debugDrawLine;static getObjectLODState(t){return t[we]}static addPlugin(t){N.push(t)}static removePlugin(t){const e=N.indexOf(t);e>=0&&N.splice(e,1)}static get(t,e){if(t[xe])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[xe];const r=new D(t,{engine:"unknown",...e});return t[xe]=r,r}renderer;context;projectionScreenMatrix=new _e;get plugins(){return N}overrideLodLevel=void 0;targetTriangleDensity=2e5;skinnedMeshAutoUpdateBoundsInterval=30;updateInterval="auto";#e=1;pause=!1;manual=!1;_newPromiseGroups=[];_promiseGroupIds=0;awaitLoading(t){const e=this._promiseGroupIds++,r=new pe(this.#s,{...t});this._newPromiseGroups.push(r);const n=performance.now();return r.ready.finally(()=>{const s=this._newPromiseGroups.indexOf(r);s>=0&&(this._newPromiseGroups.splice(s,1),Te()&&performance.measure("LODsManager:awaitLoading",{start:n,detail:{id:e,name:t?.name,awaited:r.awaitedCount,resolved:r.resolvedCount}}))}),r.ready}_postprocessPromiseGroups(){if(this._newPromiseGroups.length!==0)for(let t=this._newPromiseGroups.length-1;t>=0;t--)this._newPromiseGroups[t].update(this.#s)}_lodchangedlisteners=[];addEventListener(t,e){t==="changed"&&this._lodchangedlisteners.push(e)}removeEventListener(t,e){if(t==="changed"){const r=this._lodchangedlisteners.indexOf(e);r>=0&&this._lodchangedlisteners.splice(r,1)}}constructor(t,e){this.renderer=t,this.context={...e}}#t;#o=new Fe;#s=0;#n=0;#i=0;#r=0;_fpsBuffer=[60,60,60,60,60];enable(){if(this.#t)return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let t=0;this.#t=this.renderer.render;const e=this;te(this.renderer),this.renderer.render=function(r,n){const s=e.renderer.getRenderTarget();(s==null||"isXRRenderTarget"in s&&s.isXRRenderTarget)&&(t=0,e.#s+=1,e.#n=e.#o.getDelta(),e.#i+=e.#n,e._fpsBuffer.shift(),e._fpsBuffer.push(1/e.#n),e.#r=e._fpsBuffer.reduce((l,a)=>l+a)/e._fpsBuffer.length,E&&e.#s%200===0&&console.log("FPS",Math.round(e.#r),"Interval:",e.#e));const o=t++;e.#t.call(this,r,n),e.onAfterRender(r,n,o)}}disable(){this.#t&&(console.debug("[gltf-progressive] Disabling LODsManager for renderer"),this.renderer.render=this.#t,this.#t=void 0)}update(t,e){this.internalUpdate(t,e)}onAfterRender(t,e,r){if(this.pause)return;const n=this.renderer.renderLists.get(t,0).opaque;let s=!0;if(n.length===1){const o=n[0].material;(o.name==="EffectMaterial"||o.name==="CopyShader")&&(s=!1)}if((e.parent&&e.parent.type==="CubeCamera"||r>=1&&e.type==="OrthographicCamera")&&(s=!1),s){if(ft||(this.updateInterval==="auto"?this.#r<40&&this.#e<10?(this.#e+=1,E&&console.warn("\u2193 Reducing LOD updates",this.#e,this.#r.toFixed(0))):this.#r>=60&&this.#e>1&&(this.#e-=1,E&&console.warn("\u2191 Increasing LOD updates",this.#e,this.#r.toFixed(0))):this.#e=this.updateInterval,this.#e>0&&this.#s%this.#e!=0))return;this.internalUpdate(t,e),this._postprocessPromiseGroups()}}internalUpdate(t,e){const r=this.renderer.renderLists.get(t,0),n=r.opaque;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse);const s=this.targetTriangleDensity;for(const a of n){if(a.material&&(a.geometry?.type==="BoxGeometry"||a.geometry?.type==="BufferGeometry")&&(a.material.name==="SphericalGaussianBlur"||a.material.name=="BackgroundCubeMaterial"||a.material.name==="CubemapFromEquirect"||a.material.name==="EquirectangularToCubeUV")){E&&(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(E==="color"&&a.material&&!a.object.progressive_debug_color){a.object.progressive_debug_color=!0;const w=Math.random()*16777215,p=new ze({color:w});a.object.material=p}const u=a.object;(u instanceof F||u.isMesh)&&this.updateLODs(t,e,u,s)}const o=r.transparent;for(const a of o){const u=a.object;(u instanceof F||u.isMesh)&&this.updateLODs(t,e,u,s)}const l=r.transmissive;for(const a of l){const u=a.object;(u instanceof F||u.isMesh)&&this.updateLODs(t,e,u,s)}}updateLODs(t,e,r,n){r.userData||(r.userData={});let s=r[we];if(s||(s=new mt,r[we]=s),s.frames++<2)return;for(const l of N)l.onBeforeUpdateLOD?.(this.renderer,t,e,r);const o=this.overrideLodLevel!==void 0?this.overrideLodLevel:q;o>=0?(O.mesh_lod=o,O.texture_lod=o):(this.calculateLodLevel(e,r,s,n,O),O.mesh_lod=Math.round(O.mesh_lod),O.texture_lod=Math.round(O.texture_lod)),O.mesh_lod>=0&&this.loadProgressiveMeshes(r,O.mesh_lod),r.material&&O.texture_lod>=0&&this.loadProgressiveTextures(r.material,O.texture_lod,o),h&&r.material&&!r.isGizmo&&Pe(r.material);for(const l of N)l.onAfterUpdatedLOD?.(this.renderer,t,e,r,O);s.lastLodLevel_Mesh=O.mesh_lod,s.lastLodLevel_Texture=O.texture_lod}loadProgressiveTextures(t,e,r){if(!t)return;if(Array.isArray(t)){for(const s of t)this.loadProgressiveTextures(s,e);return}let n=!1;if((t[U]===void 0||e<t[U])&&(n=!0),r!==void 0&&r>=0&&(n=t[U]!=r,e=r),n){t[U]=e;const s=m.assignTextureLOD(t,e).then(o=>{this._lodchangedlisteners.forEach(l=>l({type:"texture",level:e,object:t}))});pe.addPromise("texture",t,s,this._newPromiseGroups)}}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);let r=t[U]!==e;const n=t["DEBUG:LOD"];if(n!=null&&(r=t[U]!=n,e=n),r){t[U]=e;const s=t.geometry,o=m.assignMeshLOD(t,e).then(l=>(l&&t[U]==e&&s!=t.geometry&&this._lodchangedlisteners.forEach(a=>a({type:"mesh",level:e,object:t})),l));return pe.addPromise("mesh",t,o,this._newPromiseGroups),o}return Promise.resolve(null)}_sphere=new Le;_tempBox=new ae;_tempBox2=new ae;tempMatrix=new _e;_tempWorldPosition=new A;_tempBoxSize=new A;_tempBox2Size=new A;static corner0=new A;static corner1=new A;static corner2=new A;static corner3=new A;static _tempPtInside=new A;static isInside(t,e){const r=t.min,n=t.max,s=(r.x+n.x)*.5,o=(r.y+n.y)*.5;return this._tempPtInside.set(s,o,r.z).applyMatrix4(e).z<0}static skinnedMeshBoundsFrameOffsetCounter=0;static $skinnedMeshBoundsOffset=Symbol("gltf-progressive-skinnedMeshBoundsOffset");calculateLodLevel(t,e,r,n,s){if(!e){s.mesh_lod=-1,s.texture_lod=-1;return}if(!t){s.mesh_lod=-1,s.texture_lod=-1;return}let o=10+1,l=!1;if(E&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const a=m.getMeshLODExtension(e.geometry)?.lods,u=m.getPrimitiveIndex(e.geometry),w=a&&a.length>0,p=m.getMaterialMinMaxLODsCount(e.material),y=p.min_count!==1/0&&p.min_count>=0&&p.max_count>=0;if(!w&&!y){s.mesh_lod=0,s.texture_lod=0;return}w||(l=!0,o=0);const P=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let _=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const c=e;if(!c.boundingBox)c.computeBoundingBox();else if(this.skinnedMeshAutoUpdateBoundsInterval>0){if(!c[D.$skinnedMeshBoundsOffset]){const v=D.skinnedMeshBoundsFrameOffsetCounter++;c[D.$skinnedMeshBoundsOffset]=v}const x=c[D.$skinnedMeshBoundsOffset];if((r.frames+x)%this.skinnedMeshAutoUpdateBoundsInterval===0){const v=V(c),C=c.geometry;v&&(c.geometry=v),c.computeBoundingBox(),c.geometry=C}}_=c.boundingBox}if(_){const c=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 g=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(g)){s.mesh_lod=0,s.texture_lod=0;return}}if(this._tempBox.copy(_),this._tempBox.applyMatrix4(e.matrixWorld),c.isPerspectiveCamera&&D.isInside(this._tempBox,this.projectionScreenMatrix)){s.mesh_lod=0,s.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&c.isPerspectiveCamera&&c.fov>70){const g=this._tempBox.min,d=this._tempBox.max;let f=g.x,L=g.y,S=d.x,G=d.y;const J=2,oe=1.5,Z=(g.x+d.x)*.5,ee=(g.y+d.y)*.5;f=(f-Z)*J+Z,L=(L-ee)*J+ee,S=(S-Z)*J+Z,G=(G-ee)*J+ee;const Re=f<0&&S>0?0:Math.min(Math.abs(g.x),Math.abs(d.x)),$e=L<0&&G>0?0:Math.min(Math.abs(g.y),Math.abs(d.y)),ie=Math.max(Re,$e);r.lastCentrality=(oe-ie)*(oe-ie)*(oe-ie)}else r.lastCentrality=1;const x=this._tempBox.getSize(this._tempBoxSize);x.multiplyScalar(.5),screen.availHeight>0&&P>0&&x.multiplyScalar(P/screen.availHeight),t.isPerspectiveCamera?x.x*=t.aspect:t.isOrthographicCamera;const v=t.matrixWorldInverse,C=this._tempBox2;C.copy(_),C.applyMatrix4(e.matrixWorld),C.applyMatrix4(v);const b=C.getSize(this._tempBox2Size),R=Math.max(b.x,b.y);if(Math.max(x.x,x.y)!=0&&R!=0&&(x.z=b.z/Math.max(b.x,b.y)*Math.max(x.x,x.y)),r.lastScreenCoverage=Math.max(x.x,x.y,x.z),r.lastScreenspaceVolume.copy(x),r.lastScreenCoverage*=r.lastCentrality,E&&D.debugDrawLine){const g=this.tempMatrix.copy(this.projectionScreenMatrix);g.invert();const d=D.corner0,f=D.corner1,L=D.corner2,S=D.corner3;d.copy(this._tempBox.min),f.copy(this._tempBox.max),f.x=d.x,L.copy(this._tempBox.max),L.y=d.y,S.copy(this._tempBox.max);const G=(d.z+S.z)*.5;d.z=f.z=L.z=S.z=G,d.applyMatrix4(g),f.applyMatrix4(g),L.applyMatrix4(g),S.applyMatrix4(g),D.debugDrawLine(d,f,255),D.debugDrawLine(d,L,255),D.debugDrawLine(f,S,255),D.debugDrawLine(L,S,255)}let M=999;if(a&&r.lastScreenCoverage>0)for(let g=0;g<a.length;g++){const d=a[g],f=(d.densities?.[u]||d.density||1e-5)/r.lastScreenCoverage;if(u>0&&Te()&&!d.densities&&!globalThis["NEEDLE:MISSING_LOD_PRIMITIVE_DENSITIES"]&&(window["NEEDLE:MISSING_LOD_PRIMITIVE_DENSITIES"]=!0,console.warn("[Needle Progressive] Detected usage of mesh without primitive densities. This might cause incorrect LOD level selection: Consider re-optimizing your model by updating your Needle Integration, Needle glTF Pipeline or running optimization again on Needle Cloud.")),f<n){M=g;break}}M<o&&(o=M,l=!0)}if(l?s.mesh_lod=o:s.mesh_lod=r.lastLodLevel_Mesh,E&&s.mesh_lod!=r.lastLodLevel_Mesh){const c=a?.[s.mesh_lod];c&&console.log(`Mesh LOD changed: ${r.lastLodLevel_Mesh} \u2192 ${s.mesh_lod} (density: ${c.densities?.[u].toFixed(0)}) | ${e.name}`)}if(y){const c="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(r.lastLodLevel_Texture<0){if(s.texture_lod=p.max_count-1,E){const x=p.lods[p.max_count-1];E&&console.log(`First Texture LOD ${s.texture_lod} (${x.max_height}px) - ${e.name}`)}}else{const x=r.lastScreenspaceVolume.x+r.lastScreenspaceVolume.y+r.lastScreenspaceVolume.z;let v=r.lastScreenCoverage*4;this.context?.engine==="model-viewer"&&(v*=1.5);const C=P/window.devicePixelRatio*v;let b=!1;for(let R=p.lods.length-1;R>=0;R--){const M=p.lods[R];if(!(c&&M.max_height>=2048)&&!(Se()&&M.max_height>4096)&&(M.max_height>C||!b&&R===0)){if(b=!0,s.texture_lod=R,E&&s.texture_lod<r.lastLodLevel_Texture){const g=M.max_height;console.log(`Texture LOD changed: ${r.lastLodLevel_Texture} \u2192 ${s.texture_lod} = ${g}px
8
- Screensize: ${C.toFixed(0)}px, Coverage: ${(100*r.lastScreenCoverage).toFixed(2)}%, Volume ${x.toFixed(1)}
9
- ${e.name}`)}break}}}}else s.texture_lod=0}};class mt{frames=0;lastLodLevel_Mesh=-1;lastLodLevel_Texture=-1;lastScreenCoverage=0;lastScreenspaceVolume=new A;lastCentrality=0}const Ce=Symbol("NEEDLE_mesh_lod"),ne=Symbol("NEEDLE_texture_lod");let ye=null;function Ae(){const i=pt();i&&(i.mapURLs(function(t){return ke(),t}),ke(),ye?.disconnect(),ye=new MutationObserver(t=>{t.forEach(e=>{e.addedNodes.forEach(r=>{r instanceof HTMLElement&&r.tagName.toLowerCase()==="model-viewer"&&Ee(r)})})}),ye.observe(document,{childList:!0,subtree:!0}))}function pt(){return typeof customElements>"u"?null:customElements.get("model-viewer")||(customElements.whenDefined("model-viewer").then(()=>{console.debug("[gltf-progressive] model-viewer defined"),Ae()}),null)}function ke(){typeof document>"u"||document.querySelectorAll("model-viewer").forEach(i=>{Ee(i)})}const Ie=new WeakSet;let xt=0;function Ee(i){if(!i||Ie.has(i))return null;Ie.add(i),console.debug("[gltf-progressive] found new model-viewer..."+ ++xt+`
10
- `,i.getAttribute("src"));let t=null,e=null,r=null;for(let n=i;n!=null;n=Object.getPrototypeOf(n)){const s=Object.getOwnPropertySymbols(n),o=s.find(u=>u.toString()=="Symbol(renderer)"),l=s.find(u=>u.toString()=="Symbol(scene)"),a=s.find(u=>u.toString()=="Symbol(needsRender)");!t&&o!=null&&(t=i[o].threeRenderer),!e&&l!=null&&(e=i[l]),!r&&a!=null&&(r=i[a])}if(t&&e){let n=function(){if(r){let o=0,l=setInterval(()=>{if(o++>5){clearInterval(l);return}r?.call(i)},300)}};console.debug("[gltf-progressive] setup model-viewer");const s=Q.get(t,{engine:"model-viewer"});return Q.addPlugin(new wt),s.enable(),s.addEventListener("changed",()=>{r?.call(i)}),i.addEventListener("model-visibility",o=>{o.detail.visible&&r?.call(i)}),i.addEventListener("load",()=>{n()}),()=>{s.disable()}}return null}class wt{_didWarnAboutMissingUrl=!1;onBeforeUpdateLOD(t,e,r,n){this.tryParseMeshLOD(e,n),this.tryParseTextureLOD(e,n)}getUrl(t){if(!t)return null;let e=t.getAttribute("src");return e||(e=t.src),e||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",t),this._didWarnAboutMissingUrl=!0),e}tryGetCurrentGLTF(t){return t._currentGLTF}tryGetCurrentModelViewer(t){return t.element}tryParseTextureLOD(t,e){if(e[ne]==!0)return;e[ne]=!0;const r=this.tryGetCurrentGLTF(t),n=this.tryGetCurrentModelViewer(t),s=this.getUrl(n);if(s&&r&&e.material){let o=function(a){if(a[ne]==!0)return;a[ne]=!0,a.userData&&(a.userData.LOD=-1);const u=Object.keys(a);for(let w=0;w<u.length;w++){const p=u[w],y=a[p];if(y?.isTexture===!0){const P=y.userData?.associations?.textures;if(P==null)continue;const _=r.parser.json.textures[P];if(!_){console.warn("Texture data not found for texture index "+P);continue}if(_?.extensions?.[B]){const c=_.extensions[B];c&&s&&m.registerTexture(s,y,c.lods.length,P,c)}}}};const l=e.material;if(Array.isArray(l))for(const a of l)o(a);else o(l)}}tryParseMeshLOD(t,e){if(e[Ce]==!0)return;e[Ce]=!0;const r=this.tryGetCurrentModelViewer(t),n=this.getUrl(r);if(!n)return;const s=e.userData?.gltfExtensions?.[B];if(s&&n){const o=e.uuid;m.registerMesh(n,o,e,0,s.lods.length,s)}}}function yt(...i){let t,e,r,n;switch(i.length){case 2:[r,e]=i,n={};break;case 3:[r,e,n]=i;break;case 4:[t,e,r,n]=i;break;default:throw new Error("Invalid arguments")}te(e),ue(r),he(r,{progressive:!0,...n?.hints}),r.register(o=>new m(o));const s=Q.get(e);return n?.enableLODsManager!==!1&&s.enable(),s}if(Ae(),!nt){const i={gltfProgressive:{useNeedleProgressive:yt,LODsManager:Q,configureLoader:he,getRaycastMesh:V,useRaycastMeshes:it}};if(!globalThis.Needle)globalThis.Needle=i;else for(const t in i)globalThis.Needle[t]=i[t]}export{Q as LODsManager,m as NEEDLE_progressive,ue as addDracoAndKTX2Loaders,he as configureLoader,te as createLoaders,V as getRaycastMesh,Me as setDracoDecoderLocation,De as setKTX2TranscoderLocation};