@needle-tools/engine 5.1.0-next.1780579670.dramatic-pierogi.b8fa941 → 5.1.0

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 (122) hide show
  1. package/CHANGELOG.md +119 -0
  2. package/components.needle.json +1 -1
  3. package/dist/gltf-progressive-BGQ-cjly.umd.cjs +10 -0
  4. package/dist/gltf-progressive-BvQHrERj.min.js +10 -0
  5. package/dist/{gltf-progressive-CH7aqHHr.js → gltf-progressive-CtYnVfLc.js} +420 -351
  6. package/dist/{materialx-B85WjP7E.min.js → materialx-B5gKeM65.min.js} +1 -1
  7. package/dist/{materialx-B47Bz-xs.umd.cjs → materialx-CFRcCYWy.umd.cjs} +1 -1
  8. package/dist/{materialx-jkHmVPez.js → materialx-DqGmteNO.js} +1 -1
  9. package/dist/{needle-engine.bundle-WQeWxmZD.js → needle-engine.bundle-5oIL49YP.js} +6826 -6685
  10. package/dist/{needle-engine.bundle-BSPk6RkD.min.js → needle-engine.bundle-DAAfj8Cs.min.js} +161 -149
  11. package/dist/{needle-engine.bundle-DCPHDPAd.umd.cjs → needle-engine.bundle-DvOrfXws.umd.cjs} +159 -147
  12. package/dist/needle-engine.d.ts +106 -44
  13. package/dist/needle-engine.js +610 -608
  14. package/dist/needle-engine.min.js +1 -1
  15. package/dist/needle-engine.umd.cjs +1 -1
  16. package/dist/three.js +3 -0
  17. package/dist/three.min.js +22 -22
  18. package/dist/three.umd.cjs +24 -24
  19. package/dist/{vendor-BQ2Vuntm.min.js → vendor-2--bD1c9.min.js} +19 -19
  20. package/dist/{vendor-BslSKZPo.js → vendor-BNtcIZkv.js} +1141 -1138
  21. package/dist/{vendor-1UvpPPSB.umd.cjs → vendor-vbe9sv1t.umd.cjs} +20 -20
  22. package/lib/engine/api.d.ts +1 -1
  23. package/lib/engine/api.js +1 -1
  24. package/lib/engine/api.js.map +1 -1
  25. package/lib/engine/engine_context.js +16 -3
  26. package/lib/engine/engine_context.js.map +1 -1
  27. package/lib/engine/engine_init.js +2 -2
  28. package/lib/engine/engine_init.js.map +1 -1
  29. package/lib/engine/engine_license.d.ts +7 -7
  30. package/lib/engine/engine_license.js +72 -72
  31. package/lib/engine/engine_license.js.map +1 -1
  32. package/lib/engine/engine_networking_blob.js +3 -3
  33. package/lib/engine/engine_networking_blob.js.map +1 -1
  34. package/lib/engine/engine_utils_qrcode.js +2 -2
  35. package/lib/engine/engine_utils_qrcode.js.map +1 -1
  36. package/lib/engine/postprocessing/postprocessing.d.ts +2 -1
  37. package/lib/engine/postprocessing/postprocessing.js +3 -2
  38. package/lib/engine/postprocessing/postprocessing.js.map +1 -1
  39. package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js +2 -2
  40. package/lib/engine/webcomponents/needle menu/needle-menu.d.ts +2 -2
  41. package/lib/engine/webcomponents/needle menu/needle-menu.js +9 -9
  42. package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
  43. package/lib/engine/webcomponents/needle-engine.js +2 -2
  44. package/lib/engine/webcomponents/needle-engine.js.map +1 -1
  45. package/lib/engine/webcomponents/needle-engine.loading.js +2 -2
  46. package/lib/engine/webcomponents/needle-engine.loading.js.map +1 -1
  47. package/lib/engine/xr/NeedleXRSession.d.ts +24 -0
  48. package/lib/engine/xr/NeedleXRSession.js +52 -7
  49. package/lib/engine/xr/NeedleXRSession.js.map +1 -1
  50. package/lib/engine/xr/TempXRContext.js +2 -2
  51. package/lib/engine/xr/TempXRContext.js.map +1 -1
  52. package/lib/engine/xr/init.js +2 -3
  53. package/lib/engine/xr/init.js.map +1 -1
  54. package/lib/engine-components/Component.js +14 -1
  55. package/lib/engine-components/Component.js.map +1 -1
  56. package/lib/engine-components/ContactShadows.d.ts +7 -2
  57. package/lib/engine-components/ContactShadows.js +65 -45
  58. package/lib/engine-components/ContactShadows.js.map +1 -1
  59. package/lib/engine-components/GroundProjection.d.ts +6 -0
  60. package/lib/engine-components/GroundProjection.js +69 -7
  61. package/lib/engine-components/GroundProjection.js.map +1 -1
  62. package/lib/engine-components/NeedleMenu.d.ts +1 -1
  63. package/lib/engine-components/NeedleMenu.js +5 -2
  64. package/lib/engine-components/NeedleMenu.js.map +1 -1
  65. package/lib/engine-components/SceneSwitcher.d.ts +2 -0
  66. package/lib/engine-components/SceneSwitcher.js +26 -14
  67. package/lib/engine-components/SceneSwitcher.js.map +1 -1
  68. package/lib/engine-components/SeeThrough.d.ts +39 -0
  69. package/lib/engine-components/SeeThrough.js +69 -1
  70. package/lib/engine-components/SeeThrough.js.map +1 -1
  71. package/lib/engine-components/Skybox.js +9 -0
  72. package/lib/engine-components/Skybox.js.map +1 -1
  73. package/lib/engine-components/api.d.ts +1 -0
  74. package/lib/engine-components/api.js +1 -0
  75. package/lib/engine-components/api.js.map +1 -1
  76. package/lib/engine-components/export/usdz/USDZExporter.js +4 -4
  77. package/lib/engine-components/export/usdz/USDZExporter.js.map +1 -1
  78. package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.js +9 -5
  79. package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.js.map +1 -1
  80. package/lib/engine-components/particlesystem/ParticleSystem.js +4 -0
  81. package/lib/engine-components/particlesystem/ParticleSystem.js.map +1 -1
  82. package/lib/engine-components/postprocessing/Volume.d.ts +1 -9
  83. package/lib/engine-components/postprocessing/Volume.js +2 -14
  84. package/lib/engine-components/postprocessing/Volume.js.map +1 -1
  85. package/lib/engine-components/webxr/WebXRImageTracking.js +3 -0
  86. package/lib/engine-components/webxr/WebXRImageTracking.js.map +1 -1
  87. package/package.json +4 -4
  88. package/plugins/common/license.js +4 -4
  89. package/plugins/types/userconfig.d.ts +10 -0
  90. package/plugins/vite/build-pipeline.d.ts +19 -0
  91. package/plugins/vite/build-pipeline.js +67 -5
  92. package/plugins/vite/license.js +4 -4
  93. package/src/engine/api.ts +1 -1
  94. package/src/engine/engine_context.ts +15 -2
  95. package/src/engine/engine_gameobject.ts +1 -1
  96. package/src/engine/engine_init.ts +2 -2
  97. package/src/engine/engine_license.ts +69 -69
  98. package/src/engine/engine_networking_blob.ts +3 -3
  99. package/src/engine/engine_utils_qrcode.ts +2 -2
  100. package/src/engine/postprocessing/postprocessing.ts +3 -2
  101. package/src/engine/webcomponents/needle menu/needle-menu-spatial.ts +2 -2
  102. package/src/engine/webcomponents/needle menu/needle-menu.ts +10 -10
  103. package/src/engine/webcomponents/needle-engine.loading.ts +6 -6
  104. package/src/engine/webcomponents/needle-engine.ts +2 -2
  105. package/src/engine/xr/NeedleXRSession.ts +53 -7
  106. package/src/engine/xr/TempXRContext.ts +2 -2
  107. package/src/engine/xr/init.ts +2 -3
  108. package/src/engine-components/Component.ts +13 -1
  109. package/src/engine-components/ContactShadows.ts +75 -49
  110. package/src/engine-components/GroundProjection.ts +71 -7
  111. package/src/engine-components/NeedleMenu.ts +6 -3
  112. package/src/engine-components/SceneSwitcher.ts +23 -13
  113. package/src/engine-components/SeeThrough.ts +75 -1
  114. package/src/engine-components/Skybox.ts +8 -0
  115. package/src/engine-components/api.ts +1 -0
  116. package/src/engine-components/export/usdz/USDZExporter.ts +4 -4
  117. package/src/engine-components/export/usdz/extensions/behavior/BehaviourComponents.ts +12 -5
  118. package/src/engine-components/particlesystem/ParticleSystem.ts +4 -0
  119. package/src/engine-components/postprocessing/Volume.ts +2 -13
  120. package/src/engine-components/webxr/WebXRImageTracking.ts +1 -0
  121. package/dist/gltf-progressive-9tlS5iCx.umd.cjs +0 -10
  122. package/dist/gltf-progressive-CVg80COO.min.js +0 -10
@@ -3,7 +3,7 @@ import { Euler, Material, Matrix4, Mesh, Object3D, Quaternion, Vector3 } from "t
3
3
 
4
4
  import { isDevEnvironment, showBalloonMessage, showBalloonWarning } from "../../../engine/debug/index.js";
5
5
  import { findObjectOfType } from "../../../engine/engine_components.js";
6
- import { _$zFmYj } from "../../../engine/engine_license.js";
6
+ import { rXELCf } from "../../../engine/engine_license.js";
7
7
  import { serializable } from "../../../engine/engine_serialization.js";
8
8
  import { getFormattedDate, Progress } from "../../../engine/engine_time_utils.js";
9
9
  import { DeviceUtilities, getParam } from "../../../engine/engine_utils.js";
@@ -277,7 +277,7 @@ export class USDZExporter extends Behaviour {
277
277
  let name = this.exportFileName ?? this.objectToExport?.name ?? this.name;
278
278
  name += "-" + getFormattedDate(); // seems iOS caches the file in some cases, this ensures we always have a fresh file
279
279
 
280
- if (!_$zFmYj()) {
280
+ if (!rXELCf()) {
281
281
  if (name !== "") name += "-";
282
282
  name += "MadeWithNeedle";
283
283
  }
@@ -682,7 +682,7 @@ export class USDZExporter extends Behaviour {
682
682
  if (debug)
683
683
  showBalloonMessage("Quicklook url: " + callToActionURL);
684
684
  if (callToActionURL) {
685
- if (!_$zFmYj()) {
685
+ if (!rXELCf()) {
686
686
  console.warn("Quicklook closed: custom redirects require a Needle Engine Pro license: https://needle.tools/pricing", callToActionURL)
687
687
  }
688
688
  else {
@@ -697,7 +697,7 @@ export class USDZExporter extends Behaviour {
697
697
  private buildQuicklookOverlay(): CustomBranding {
698
698
  const obj: CustomBranding = {};
699
699
  if (this.customBranding) Object.assign(obj, this.customBranding);
700
- if (!_$zFmYj()) {
700
+ if (!rXELCf()) {
701
701
  console.log("Custom Quicklook banner text requires pro license: https://needle.tools/pricing");
702
702
  obj.callToAction = "Close";
703
703
  obj.checkoutTitle = "🌵 Made with Needle";
@@ -11,6 +11,7 @@ import { Animation } from "../../../../Animation.js";
11
11
  import { Animator } from "../../../../Animator.js";
12
12
  import { AudioSource } from "../../../../AudioSource.js";
13
13
  import { Behaviour, GameObject } from "../../../../Component.js";
14
+ import type { ComponentInit } from "../../../../../engine/engine_types.js";
14
15
  import { Rigidbody } from "../../../../RigidBody.js";
15
16
  import type { IPointerClickHandler, PointerEventData } from "../../../../ui/PointerEvents.js";
16
17
  import { makeNameSafeForUSD, USDDocument, USDObject, USDZExporterContext } from "../../ThreeUSDZExporter.js";
@@ -811,13 +812,16 @@ export class PlayAudioOnClick extends Behaviour implements IPointerClickHandler,
811
812
 
812
813
  ensureAudioSource() {
813
814
  if (!this.target) {
814
- const newAudioSource = this.gameObject.addComponent(AudioSource);
815
+ const initializeAudioSource: ComponentInit<AudioSource> = {
816
+ spatialBlend: 1,
817
+ volume: 1,
818
+ loop: false,
819
+ clip: this.clip,
820
+ preload: true,
821
+ };
822
+ const newAudioSource = this.gameObject.addComponent(AudioSource, initializeAudioSource);
815
823
  if (newAudioSource) {
816
824
  this.target = newAudioSource;
817
- newAudioSource.spatialBlend = 1;
818
- newAudioSource.volume = 1;
819
- newAudioSource.loop = false;
820
- newAudioSource.preload = true;
821
825
  }
822
826
  }
823
827
  }
@@ -828,6 +832,9 @@ export class PlayAudioOnClick extends Behaviour implements IPointerClickHandler,
828
832
  label: "Play audio: " + (this.clip || this.target?.clip || "unknown clip"),
829
833
  hidden: false,
830
834
  })
835
+
836
+ this.ensureAudioSource();
837
+
831
838
  }
832
839
  onDisable(): void {
833
840
  this.context.accessibility.updateElement(this, {
@@ -593,6 +593,10 @@ class ColorBehaviour extends ParticleSystemBaseBehaviour {
593
593
  col.copy(this.system.main.startColor.evaluate(Math.random()));
594
594
  if (materialColor?.color) {
595
595
  tempColor.copy(materialColor.color);
596
+ // THREE.Color has no alpha — the material's color alpha is stored in
597
+ // material.opacity. Without this, a particle material's alpha/opacity
598
+ // was ignored (reported externally). multiply() propagates alpha.
599
+ tempColor.alpha = materialColor.opacity ?? 1;
596
600
  col.multiply(tempColor)
597
601
  }
598
602
  col.convertLinearToSRGB();
@@ -79,16 +79,6 @@ export class Volume extends Behaviour implements IEditorModificationReceiver, IP
79
79
  @serializeable()
80
80
  multisampling: "auto" | number = "auto";
81
81
 
82
- /** When enabled, the device pixel ratio will be gradually reduced when FPS is low
83
- * and restored when performance recovers. This helps maintain smooth frame rates
84
- * on devices where full retina resolution is too expensive for postprocessing.
85
- * Pushed to `context.postprocessing.adaptiveResolution` when this Volume is active.
86
- * Disable this if you need a fixed resolution and prefer consistent quality over frame rate.
87
- * @default true
88
- */
89
- @serializeable()
90
- adaptiveResolution: boolean = true;
91
-
92
82
  /**
93
83
  * Add a post processing effect to this Volume and push it to the core postprocessing stack.
94
84
  */
@@ -195,7 +185,7 @@ export class Volume extends Behaviour implements IEditorModificationReceiver, IP
195
185
  this.pushEffectsToCore();
196
186
  this._isDirty = false;
197
187
  }
198
- // Push config changes (user may change multisampling/adaptiveResolution at runtime)
188
+ // Push config changes (user may change multisampling at runtime)
199
189
  this.syncConfigToCore();
200
190
 
201
191
  // Process queued editor modifications after the handler is ready
@@ -242,11 +232,10 @@ export class Volume extends Behaviour implements IEditorModificationReceiver, IP
242
232
  this._activeEffects.length = 0;
243
233
  }
244
234
 
245
- /** Push multisampling and adaptiveResolution config to the core stack */
235
+ /** Push multisampling config to the core stack */
246
236
  private syncConfigToCore() {
247
237
  const pp = this.context.postprocessing;
248
238
  pp.multisampling = this.multisampling;
249
- pp.adaptiveResolution = this.adaptiveResolution;
250
239
  }
251
240
 
252
241
  private _applyPostQueue() {
@@ -567,6 +567,7 @@ export class WebXRImageTracking extends Behaviour {
567
567
  * });
568
568
  * ```
569
569
  */
570
+ @serializable(EventList)
570
571
  imageTracked: EventList<WebXRImageTrackingEvent> = new EventList();
571
572
 
572
573
  /** @inheritdoc */
@@ -1,10 +0,0 @@
1
- "use strict";const f=require("./three.umd.cjs"),Y=require("./three-examples.umd.cjs");var ce=typeof document<"u"?document.currentScript:null;const Fe="";globalThis.GLTF_PROGRESSIVE_VERSION=Fe;console.debug("[gltf-progressive] version -");let I="https://www.gstatic.com/draco/versioned/decoders/1.5.7/",X="https://cdn.needle.tools/static/three/0.179.1/basis2/";const ze=I,Ve=X,Ce=new URL(I+"draco_decoder.js");Ce.searchParams.append("range","true");fetch(Ce,{method:"GET",headers:{Range:"bytes=0-1"}}).catch(o=>{console.debug(`Failed to fetch remote Draco decoder from ${I} (offline: ${typeof navigator<"u"?navigator.onLine:"unknown"})`),I===ze&&Pe("./include/draco/"),X===Ve&&ke("./include/ktx2/")}).finally(()=>{Re()});const Ee=()=>({dracoDecoderPath:I,ktx2TranscoderPath:X});function Pe(o){I=o,k&&k[ye]!=I?(console.debug("Updating Draco decoder path to "+o),k[ye]=I,k.setDecoderPath(I),k.preload()):console.debug("Setting Draco decoder path to "+o)}function ke(o){X=o,$&&$.transcoderPath!=X?(console.debug("Updating KTX2 transcoder path to "+o),$.setTranscoderPath(X),$.init()):console.debug("Setting KTX2 transcoder path to "+o)}function le(o){return Re(),o?$.detectSupport(o):o!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:k,ktx2Loader:$,meshoptDecoder:ae}}function Le(o){o.dracoLoader||o.setDRACOLoader(k),o.ktx2Loader||o.setKTX2Loader($),o.meshoptDecoder||o.setMeshoptDecoder(ae)}const ye=Symbol("dracoDecoderPath");let k,ae,$;function Re(){k||(k=new Y.DRACOLoader,k[ye]=I,k.setDecoderPath(I),k.setDecoderConfig({type:"js"}),k.preload()),$||($=new Y.KTX2Loader,$.setTranscoderPath(X),$.init()),ae||(ae=Y.MeshoptDecoder)}const xe=new WeakMap;function Me(o,t){let e=xe.get(o);e?e=Object.assign(e,t):e=t,xe.set(o,e)}const Ne=Y.GLTFLoader.prototype.load;function Xe(...o){const t=xe.get(this);let e=o[0];const s=new URL(e,window.location.href);if(s.hostname.endsWith("needle.tools")){const n=t?.progressive!==void 0?t.progressive:!0,i=t?.usecase?t.usecase:"default";n?this.requestHeader.Accept=`*/*;progressive=allowed;usecase=${i}`:this.requestHeader.Accept=`*/*;usecase=${i}`,e=s.toString()}return o[0]=e,Ne?.call(this,...o)}Y.GLTFLoader.prototype.load=Xe;z("debugprogressive");function z(o){if(typeof window>"u")return!1;const e=new URL(window.location.href).searchParams.get(o);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function Ke(o,t){if(t===void 0||o===void 0||t.startsWith("./")||t.startsWith("http")||t.startsWith("data:")||t.startsWith("blob:"))return t;const e=o.lastIndexOf("/");if(e>=0){const s=o.substring(0,e+1);for(;s.endsWith("/")&&t.startsWith("/");)t=t.substring(1);return s+t}return t}function ve(){return J!==void 0||(J=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),z("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",J)),J}let J;function Ae(){if(typeof window>"u")return!1;const o=new URL(window.location.href),t=o.hostname==="localhost"||/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(o.hostname);return o.hostname==="127.0.0.1"||t}class je{constructor(t,e={}){this.maxConcurrent=t,this.debug=e.debug??!1,typeof window<"u"&&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:s,resolve:r}=this._queue.shift();r({use:n=>this.add(s,n)})}}}function He(o){const t=o.image?.width??0,e=o.image?.height??0,s=o.image?.depth??1,r=Math.floor(Math.log2(Math.max(t,e,s)))+1,n=Ye(o);return t*e*s*n*(1-Math.pow(.25,r))/(1-.25)}function Ye(o){let t=4;const e=o.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 s=1;const r=o.type;return r===1009||r===1010?s=1:r===1011||r===1012?s=2:r===1013||r===1014||r===1015?s=4:r===1016&&(s=2),t*s}const Qe=typeof window>"u"&&typeof document>"u",we=Symbol("needle:raycast-mesh");function Q(o){return o?.[we]instanceof f.BufferGeometry?o[we]:null}function Je(o,t){if((o.type==="Mesh"||o.type==="SkinnedMesh")&&!Q(o)){const s=et(t);s.userData={isRaycastMesh:!0},o[we]=s}}function Ze(o=!0){if(o){if(Z)return;const t=Z=f.Mesh.prototype.raycast;f.Mesh.prototype.raycast=function(e,s){const r=this,n=Q(r);let i;n&&r.isMesh&&(i=r.geometry,r.geometry=n),t.call(this,e,s),i&&(r.geometry=i)}}else{if(!Z)return;f.Mesh.prototype.raycast=Z,Z=null}}let Z=null;function et(o){const t=new f.BufferGeometry;for(const e in o.attributes)t.setAttribute(e,o.getAttribute(e));return t.setIndex(o.getIndex()),t}const q=new Array,g=z("debugprogressive");let se,E=-1;if(g){let o=function(){E+=1,E>=t&&(E=-1),console.log(`Toggle LOD level [${E}]`)};const t=6;window.addEventListener("keyup",e=>{e.key==="p"&&o(),e.key==="w"&&(se=!se,console.log(`Toggle wireframe [${se}]`));const s=parseInt(e.key);!isNaN(s)&&s>=0&&(E=s,console.log(`Set LOD level to [${E}]`))})}function Ie(o){if(g&&se!==void 0)if(Array.isArray(o))for(const t of o)Ie(t);else o&&"wireframe"in o&&(o.wireframe=se===!0)}const ee=new Array;let tt=0;const st=ve()?2:10;function rt(o){if(ee.length<st){const s=ee.length;g&&console.warn(`[Worker] Creating new worker #${s}`);const r=De.createWorker(o||{});return ee.push(r),r}const t=tt++%ee.length;return ee[t]}class De{constructor(t,e){this.worker=t,this._debug=e.debug??!1,t.onmessage=s=>{const r=s.data;switch(this._debug&&console.log("[Worker] EVENT",r),r.type){case"loaded-gltf":for(const n of this._running)if(n.url===r.result.url){nt(r.result),n.resolve(r.result);const i=n.url;i.startsWith("blob:")&&URL.revokeObjectURL(i)}}},t.onerror=s=>{console.error("[Worker] Error in gltf-progressive worker:",s)},t.postMessage({type:"init"})}static async createWorker(t){const e=new Worker(new URL("/gltf-progressive.worker-BqODMeeW.js",typeof document>"u"?require("url").pathToFileURL(__filename).href:ce&&ce.tagName.toUpperCase()==="SCRIPT"&&ce.src||new URL("gltf-progressive-9tlS5iCx.umd.cjs",document.baseURI).href),{type:"module"});return new De(e,t)}_running=[];_webglRenderer=null;async load(t,e){const s=Ee();let r=e?.renderer;r||(this._webglRenderer??=(async()=>{const{WebGLRenderer:u}=await Promise.resolve().then(()=>require("./three.umd.cjs")).then(c=>c.THREE);return new u})(),r=await this._webglRenderer);const a=le(r).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 l={type:"load",url:t,dracoDecoderPath:s.dracoDecoderPath,ktx2TranscoderPath:s.ktx2TranscoderPath,ktx2LoaderConfig:a};return this._debug&&console.debug("[Worker] Sending load request",l),this.worker.postMessage(l),new Promise(u=>{this._running.push({url:t.toString(),resolve:u})})}_debug=!1}function nt(o){for(const t of o.geometries){const e=t.geometry,s=new f.BufferGeometry;if(s.name=e.name||"",e.index){const r=e.index;s.setIndex(de(r))}for(const r in e.attributes){const n=e.attributes[r],i=de(n);s.setAttribute(r,i)}if(e.morphAttributes)for(const r in e.morphAttributes){const i=e.morphAttributes[r].map(a=>de(a));s.morphAttributes[r]=i}if(s.morphTargetsRelative=e.morphTargetsRelative??!1,s.boundingBox=new f.Box3,s.boundingBox.min=new f.Vector3(e.boundingBox?.min.x,e.boundingBox?.min.y,e.boundingBox?.min.z),s.boundingBox.max=new f.Vector3(e.boundingBox?.max.x,e.boundingBox?.max.y,e.boundingBox?.max.z),s.boundingSphere=new f.Sphere(new f.Vector3(e.boundingSphere?.center.x,e.boundingSphere?.center.y,e.boundingSphere?.center.z),e.boundingSphere?.radius),e.groups)for(const r of e.groups)s.addGroup(r.start,r.count,r.materialIndex);e.userData&&(s.userData=e.userData),t.geometry=s}for(const t of o.textures){const e=t.texture;let s=null;if(e.isCompressedTexture){const r=e.mipmaps,n=e.image?.width||e.source?.data?.width||-1,i=e.image?.height||e.source?.data?.height||-1;s=new f.CompressedTexture(r,n,i,e.format,e.type,e.mapping,e.wrapS,e.wrapT,e.magFilter,e.minFilter,e.anisotropy,e.colorSpace)}else s=new f.Texture(e.image,e.mapping,e.wrapS,e.wrapT,e.magFilter,e.minFilter,e.format,e.type,e.anisotropy,e.colorSpace),s.mipmaps=e.mipmaps,s.channel=e.channel,s.source.data=e.source.data,s.flipY=e.flipY,s.premultiplyAlpha=e.premultiplyAlpha,s.unpackAlignment=e.unpackAlignment,s.matrix=new f.Matrix3(...e.matrix.elements);if(!s){console.error("[Worker] Failed to create new texture from received data. Texture is not a CompressedTexture or Texture.");continue}t.texture=s}return o}function de(o){let t=o;if("isInterleavedBufferAttribute"in o&&o.isInterleavedBufferAttribute){const e=o.data,s=e.array,r=new f.InterleavedBuffer(s,e.stride);t=new f.InterleavedBufferAttribute(r,o.itemSize,s.byteOffset,o.normalized),t.offset=o.offset}else"isBufferAttribute"in o&&o.isBufferAttribute&&(t=new f.BufferAttribute(o.array,o.itemSize,o.normalized),t.usage=o.usage,t.gpuType=o.gpuType,t.updateRanges=o.updateRanges);return t}const ot=z("gltf-progressive-worker");z("gltf-progressive-reduce-mipmaps");const te=z("gltf-progressive-gc"),fe=Symbol("needle-progressive-texture"),W="NEEDLE_progressive";class p{get name(){return W}static getMeshLODExtension(t){const e=this.getAssignedLODInformation(t);return e?.key?this.lodInfos.get(e.key):null}static getPrimitiveIndex(t){const e=this.getAssignedLODInformation(t)?.index;return e??-1}static getMaterialMinMaxLODsCount(t,e){const s=this,r="LODS:minmax",n=t[r];if(n!=null)return n;if(e||(e={min_count:1/0,max_count:0,lods:[]}),Array.isArray(t)){for(const a of t)this.getMaterialMinMaxLODsCount(a,e);return t[r]=e,e}if(g==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const a=t;for(const l of Object.keys(a.uniforms)){const u=a.uniforms[l].value;u?.isTexture===!0&&i(u,e)}}else if(t.isMaterial)for(const a of Object.keys(t)){const l=t[a];l?.isTexture===!0&&i(l,e)}else g&&console.warn(`[getMaterialMinMaxLODsCount] Unsupported material type: ${t.type}`);return t[r]=e,e;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 d=0;d<c.lods.length;d++){const h=c.lods[d];h.width&&(l.lods[d]=l.lods[d]||{min_height:1/0,max_height:0},l.lods[d].min_height=Math.min(l.lods[d].min_height,h.height),l.lods[d].max_height=Math.max(l.lods[d].max_height,h.height))}}}}}static hasLODLevelAvailable(t,e){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 s,r;if(t.isMesh?s=t.geometry:(t.isBufferGeometry||t.isTexture)&&(s=t),s&&s?.userData?.LODS){const n=s.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,s){if(!t)return Promise.resolve(null);if(t instanceof f.Mesh||t.isMesh===!0){const r=t.geometry,n=this.getAssignedLODInformation(r);if(!n)return Promise.resolve(null);for(const a of q)a.onBeforeGetLODMesh?.(t,e);t["LOD:requested level"]=e;const i=()=>t["LOD:requested level"]===e||this.shouldApplyStaleMeshLOD(t,e);return p.getOrLoadLOD(r,e,{isCurrent:i}).then(a=>{if(Array.isArray(a)){const u=n.index||0;a=a[u]}const l=t["LOD:requested level"]===e;return(l||this.shouldApplyStaleMeshLOD(t,e))&&(l&&delete t["LOD:requested level"],a&&r!=a&&(a?.isBufferGeometry?typeof s?.apply=="function"?s.apply(a,e,t):s?.apply!==!1&&(t.geometry=a):g&&console.error("Invalid LOD geometry",a))),a}).catch(a=>(console.error("Error loading mesh LOD",t,a),null))}else g&&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,s){if(!t)return Promise.resolve(null);const r=s?.force===!0;if(t.isMesh===!0){const n=t;if(Array.isArray(n.material)){const i=new Array;for(const a of n.material){const l=this.assignTextureLOD(a,e,s);i.push(l)}return Promise.all(i).then(a=>{const l=new Array;for(const u of a)Array.isArray(u)&&l.push(...u);return l})}else return this.assignTextureLOD(n.material,e,s)}if(t.isMaterial===!0){const n=t,i=[],a=new Array;if(this.trackCurrentMaterialTextureSlots(n),n.uniforms&&(n.isRawShaderMaterial||n.isShaderMaterial===!0)){const l=n;for(const u of Object.keys(l.uniforms)){const c=l.uniforms[u].value;if(c?.isTexture===!0){const d=this.assignTextureLODForSlot(c,e,n,u,r).then(h=>(h&&l.uniforms[u].value!=h&&(l.uniforms[u].value=h,l.uniformsNeedUpdate=!0),h));i.push(d),a.push(u)}}}else for(const l of Object.keys(n)){const u=n[l];if(u?.isTexture===!0){const c=this.assignTextureLODForSlot(u,e,n,l,r);i.push(c),a.push(l)}}return Promise.all(i).then(l=>{const u=new Array;for(let c=0;c<l.length;c++){const d=l[c],h=a[c];d&&d.isTexture===!0?u.push({material:n,slot:h,texture:d,level:e}):u.push({material:n,slot:h,texture:null,level:e})}return u})}if(t instanceof f.Texture||t.isTexture===!0){const n=t;return this.assignTextureLODForSlot(n,e,null,null,r)}return Promise.resolve(null)}static set maxConcurrentLoadingTasks(t){p.queue.maxConcurrent=t}static get maxConcurrentLoadingTasks(){return p.queue.maxConcurrent}static assignTextureLODForSlot(t,e,s,r,n){if(t?.isTexture!==!0)return Promise.resolve(null);if(r==="glyphMap")return Promise.resolve(t);const i=this.getAssignedLODInformation(t);if(i&&(i.level===e||!n&&i.level<e))return Promise.resolve(t);if(s&&r){const d=this.getPendingTextureSlotRequest(s,r);if(d&&d.level===e&&d.force===n)return d.promise}const a=s&&r?this.nextTextureSlotRequestId(s,r,e,n):0,l=()=>!s||!r||this.getLatestTextureSlotRequest(s,r)?.id===a,u=()=>l()||this.shouldApplyStaleTextureSlotLOD(s,r,e,n),c=p.getOrLoadLOD(t,e,{isCurrent:u}).then(d=>{if(!l()&&!this.shouldApplyStaleTextureSlotLOD(s,r,e,n))return null;if(Array.isArray(d))return console.warn("Progressive: Got an array of textures for a texture slot, this should not happen..."),null;if(d?.isTexture===!0){if(d!=t&&s&&r){const h=this.getMaterialTextureSlot(s,r)??t;if(h&&!n){const m=this.getAssignedLODInformation(h);if(m&&m?.level<e)return g==="verbose"&&console.warn("Assigned texture level is already higher: ",m.level,e,s,h,d),null}this.assignTrackedTextureSlot(s,r,d)}return d}else g=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(d=>(console.error("Error loading LOD",t,d),null));return s&&r&&this.setPendingTextureSlotRequest(s,r,e,n,a,c),c}static trackedTextureSlots=new WeakMap;static pendingTextureSlotRequests=new WeakMap;static latestTextureSlotRequests=new WeakMap;static textureSlotRequestId=0;static trackCurrentMaterialTextureSlots(t){if(t.uniforms&&(t.isRawShaderMaterial||t.isShaderMaterial===!0)){const e=t;for(const s of Object.keys(e.uniforms)){const r=e.uniforms[s].value;r?.isTexture===!0&&this.ensureTrackedTextureSlot(t,s,r)}return}for(const e of Object.keys(t)){const s=t[e];s?.isTexture===!0&&this.ensureTrackedTextureSlot(t,e,s)}}static getPendingTextureSlotRequest(t,e){return this.pendingTextureSlotRequests.get(t)?.get(e)}static nextTextureSlotRequestId(t,e,s,r){let n=this.latestTextureSlotRequests.get(t);n||(n=new Map,this.latestTextureSlotRequests.set(t,n));const i=++this.textureSlotRequestId;return n.set(e,{id:i,level:s,force:r}),i}static getLatestTextureSlotRequest(t,e){return this.latestTextureSlotRequests.get(t)?.get(e)}static shouldApplyStaleTextureSlotLOD(t,e,s,r){if(!t||!e)return!1;const n=this.getLatestTextureSlotRequest(t,e),i=this.getMaterialTextureSlot(t,e),a=this.getAssignedLODInformation(i)?.level??1/0;return s>=a?!1:r?n?s>=n.level:!1:!0}static shouldApplyStaleMeshLOD(t,e){const s=t["LOD:requested level"];if(typeof s!="number")return!1;const r=this.getAssignedLODInformation(t.geometry)?.level??1/0;return e<r&&e>=s}static setPendingTextureSlotRequest(t,e,s,r,n,i){let a=this.pendingTextureSlotRequests.get(t);a||(a=new Map,this.pendingTextureSlotRequests.set(t,a));const l={level:s,force:r,id:n,promise:i};a.set(e,l),i.finally(()=>{a.get(e)?.id===n&&a.delete(e)})}static getMaterialTextureSlot(t,e){const r=t.uniforms?.[e];if(r?.value?.isTexture===!0)return r.value;const n=t[e];return n?.isTexture===!0?n:null}static setMaterialTextureSlot(t,e,s){const n=t.uniforms?.[e];if(n?.value?.isTexture===!0){n.value=s,t.uniformsNeedUpdate=!0;return}t[e]=s}static assignTrackedTextureSlot(t,e,s){let r=this.trackedTextureSlots.get(t);r||(r=new Map,this.trackedTextureSlots.set(t,r));const n=this.getMaterialTextureSlot(t,e);let i=r.get(e);!i&&n?i=this.ensureTrackedTextureSlot(t,e,n):i&&n&&i!==n&&(this.releaseTrackedTextureSlot(t,e,i),i=this.ensureTrackedTextureSlot(t,e,n)),!(i===s&&n===s)&&(i&&i!==s&&this.releaseTrackedTextureSlot(t,e,i),i!==s&&(this.trackTextureUsage(s),r.set(e,s)),n!==s&&this.setMaterialTextureSlot(t,e,s))}static ensureTrackedTextureSlot(t,e,s){let r=this.trackedTextureSlots.get(t);r||(r=new Map,this.trackedTextureSlots.set(t,r));const n=r.get(e);return n===s?n:(n&&this.releaseTrackedTextureSlot(t,e,n),this.trackTextureUsage(s),r.set(e,s),s)}static releaseTrackedTextureSlot(t,e,s){const r=this.trackedTextureSlots.get(t);if(r?.get(e)===s&&r.delete(e),this.untrackTextureUsage(s)&&(g||te)){const i=this.getAssignedLODInformation(s);console.log(`[gltf-progressive] Disposed old texture LOD ${i?.level??"?"} for ${t.name||t.type}.${e}`,s.uuid)}}parser;url;constructor(t){const e=t.options.path;g&&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?.[W];return e?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",t).then(s=>(this._isLoadingMesh=!1,s&&p.registerMesh(this.url,e.guid,s,e.lods?.length,0,e),s))):null};afterRoot(t){return g&&console.log("AFTER",this.url,t),this.parser.json.textures?.forEach((e,s)=>{if(e?.extensions){const r=e?.extensions[W];if(r){if(!r.lods){g&&console.warn("Texture has no LODs",r);return}let n=!1;for(const i of this.parser.associations.keys())i.isTexture===!0&&this.parser.associations.get(i)?.textures===s&&(n=!0,p.registerTexture(this.url,i,r.lods?.length,s,r));n||this.parser.getDependency("texture",s).then(i=>{i&&p.registerTexture(this.url,i,r.lods?.length,s,r)})}}}),this.parser.json.meshes?.forEach((e,s)=>{if(e?.extensions){const r=e?.extensions[W];if(r&&r.lods){for(const n of this.parser.associations.keys())if(n.isMesh){const i=this.parser.associations.get(n);i?.meshes===s&&p.registerMesh(this.url,r.guid,n,r.lods.length,i.primitives,r)}}}}),null}static registerTexture=(t,e,s,r,n)=>{if(!e){g&&console.error("!! gltf-progressive: Called register texture without texture");return}if(g){const a=e.image?.width||e.source?.data?.width||0,l=e.image?.height||e.source?.data?.height||0;console.log(`> gltf-progressive: register texture[${r}] "${e.name||e.uuid}", Current: ${a}x${l}, Max: ${n.lods[0]?.width}x${n.lods[0]?.height}, uuid: ${e.uuid}`,n,e)}e.source&&(e.source[fe]=n);const i=n.guid;p.assignLODInformation(t,e,i,s,r),p.lodInfos.set(i,n),p.lowresCache.set(i,new WeakRef(e))};static registerMesh=(t,e,s,r,n,i)=>{const a=s.geometry;if(!a){g&&console.warn("gltf-progressive: Register mesh without geometry");return}a.userData||(a.userData={}),g&&console.log("> Progressive: register mesh "+s.name,{index:n,uuid:s.uuid},i,s),p.assignLODInformation(t,a,e,r,n),p.lodInfos.set(e,i);let u=p.lowresCache.get(e)?.deref();u?u.push(s.geometry):u=[s.geometry],p.lowresCache.set(e,new WeakRef(u)),r>0&&!Q(s)&&Je(s,a);for(const c of q)c.onRegisteredNewMesh?.(s,i)};static dispose(t){if(t){this.lodInfos.delete(t);const e=this.lowresCache.get(t);if(e){const s=e.deref();if(s){if(s.isTexture){const r=s;this.textureRefCounts.delete(r.uuid),r.dispose()}else if(Array.isArray(s))for(const r of s)r.dispose()}this.lowresCache.delete(t)}for(const[s,r]of this.cache)s.includes(t)&&(this._disposeCacheEntry(r),this.cache.delete(s))}else{this.lodInfos.clear();for(const[,e]of this.lowresCache){const s=e.deref();if(s){if(s.isTexture){const r=s;this.textureRefCounts.delete(r.uuid),r.dispose()}else if(Array.isArray(s))for(const r of s)r.dispose()}}this.lowresCache.clear();for(const[,e]of this.cache)this._disposeCacheEntry(e);this.cache.clear(),this.textureRefCounts.clear(),this.trackedTextureSlots=new WeakMap,this.pendingTextureSlotRequests=new WeakMap,this.latestTextureSlotRequests=new WeakMap,this.textureSlotRequestId=0}}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 s of e)s.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=p.cache.get(t);(g||te)&&console.debug(`[gltf-progressive] Memory: Resource GC'd
2
- ${t}`),e instanceof WeakRef&&(e.deref()||(p.cache.delete(t),(g||te)&&console.log("[gltf-progressive] ↪ Cache entry deleted (GC)")))});static trackTextureUsage(t){const e=t.uuid,s=this.textureRefCounts.get(e)||0;this.textureRefCounts.set(e,s+1),g==="verbose"&&console.log(`[gltf-progressive] Track texture ${e}, refCount: ${s} → ${s+1}`)}static untrackTextureUsage(t){const e=t.uuid,s=this.textureRefCounts.get(e);if(!s)return(g==="verbose"||te)&&n("[gltf-progressive] Memory: Untrack untracked texture (dispose immediately)",0),t.dispose(),!0;const r=s-1;if(r<=0)return this.textureRefCounts.delete(e),(g||te)&&n("[gltf-progressive] Memory: Dispose texture",r),t.dispose(),!0;return this.textureRefCounts.set(e,r),g==="verbose"&&n("[gltf-progressive] Memory: Untrack texture",r),!1;function n(i,a){const l=t.image?.width||t.source?.data?.width||0,u=t.image?.height||t.source?.data?.height||0,c=l&&u?`${l}x${u}`:"N/A";let d="N/A";l&&u&&(d=`~${(He(t)/(1024*1024)).toFixed(2)} MB`),console.log(`${i} — ${t.name} ${c} (${d}), refCount: ${s} → ${a}
3
- ${e}`)}}static workers=[];static _workersIndex=0;static async getOrLoadLOD(t,e,s){const r=g=="verbose",n=this.getAssignedLODInformation(t);if(!n)return g&&console.warn(`[gltf-progressive] No LOD information found: ${t.name}, uuid: ${t.uuid}, type: ${t.type}`,t),null;const i=n?.key;let a;if(t.isTexture===!0){const u=t;u.source&&u.source[fe]&&(a=u.source[fe])}if(a||(a=p.lodInfos.get(i)),!a)g&&console.warn(`Can not load LOD ${e}: no LOD info found for "${i}" ${t.name}`,t.type,p.lodInfos);else{if(e>0){let d=!1;const h=Array.isArray(a.lods);if(h&&e>=a.lods.length?d=!0:h||(d=!0),d){const m=this.lowresCache.get(i);if(m){const T=m.deref();if(T)return T;this.lowresCache.delete(i),g&&console.log(`[gltf-progressive] Lowres cache entry was GC'd: ${i}`)}return null}}const u=Array.isArray(a.lods)?a.lods[e]?.path:a.lods;if(!u)return g&&!a["missing:uri"]&&(a["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,a)),null;const c=Ke(n.url,u);if(c.endsWith(".glb")||c.endsWith(".gltf")){if(!a.guid)return console.warn("missing pointer for glb/gltf texture",a),null;const d=c+"_"+a.guid,h=await this.tryResolveLODCacheEntry(this.cache.get(d),d,c,t,e,r);if(h.found)return h.value;if(s?.isCurrent?.()===!1)return r&&console.log(`Skipping stale LOD ${e} request before queue: ${c}`),null;const m=await this.queue.slot(c);if(s?.isCurrent?.()===!1)return r&&console.log(`Skipping stale LOD ${e} request after queue: ${c}`),null;const T=await this.tryResolveLODCacheEntry(this.cache.get(d),d,c,t,e,r);if(T.found)return T.value;if(!m.use)return g&&console.log(`LOD ${e} was aborted: ${c}`),null;const x=a,w=new Promise(async(M,V)=>{if(ot){const y=await(await rt({})).load(c);if(y.textures.length>0)for(const _ of y.textures){let O=_.texture;return p.assignLODInformation(n.url,O,i,e,void 0),t instanceof f.Texture&&(O=this.copySettings(t,O)),O&&(O.guid=x.guid),M(O)}if(y.geometries.length>0){const _=new Array;for(const O of y.geometries){const B=O.geometry;p.assignLODInformation(n.url,B,i,e,O.primitiveIndex),_.push(B)}return M(_)}return M(null)}const L=new Y.GLTFLoader;Le(L),g&&(await new Promise(b=>setTimeout(b,1e3)),r&&console.warn("Start loading (delayed) "+c,x.guid));let S=c;if(x&&Array.isArray(x.lods)){const b=x.lods[e];b.hash&&(S+="?v="+b.hash)}const D=await L.loadAsync(S).catch(b=>(console.error(`Error loading LOD ${e} from ${c}
4
- `,b),M(null)));if(!D)return M(null);const R=D.parser;r&&console.log("Loading finished "+c,x.guid);let P=0;if(D.parser.json.textures){let b=!1;for(const y of D.parser.json.textures){if(y?.extensions){const _=y?.extensions[W];if(_?.guid&&_.guid===x.guid){b=!0;break}}P++}if(b){let y=await R.getDependency("texture",P);return y&&p.assignLODInformation(n.url,y,i,e,void 0),r&&console.log('change "'+t.name+'" → "'+y.name+'"',c,P,y,d),t instanceof f.Texture&&(y=this.copySettings(t,y)),y&&(y.guid=x.guid),M(y)}else g&&console.warn("Could not find texture with guid",x.guid,D.parser.json)}if(P=0,D.parser.json.meshes){let b=!1;for(const y of D.parser.json.meshes){if(y?.extensions){const _=y?.extensions[W];if(_?.guid&&_.guid===x.guid){b=!0;break}}P++}if(b){const y=await R.getDependency("mesh",P);if(r&&console.log(`Loaded Mesh "${y.name}"`,c,P,y,d),y.isMesh===!0){const _=y.geometry;return p.assignLODInformation(n.url,_,i,e,0),M(_)}else{const _=new Array;for(let O=0;O<y.children.length;O++){const B=y.children[O];if(B.isMesh===!0){const ne=B.geometry;p.assignLODInformation(n.url,ne,i,e,O),_.push(ne)}}return M(_)}}else g&&console.warn("Could not find mesh with guid",x.guid,D.parser.json)}return M(null)});this.cache.set(d,w),m.use(w);const v=await w;return v!=null?v instanceof f.Texture?(this.cache.set(d,new WeakRef(v)),p._resourceRegistry.register(v,d)):Array.isArray(v)?this.cache.set(d,Promise.resolve(v)):this.cache.set(d,Promise.resolve(v)):this.cache.set(d,Promise.resolve(null)),v}else if(t instanceof f.Texture){if(s?.isCurrent?.()===!1)return r&&console.log(`Skipping stale texture LOD ${e} request: ${c}`),null;r&&console.log("Load texture from uri: "+c);const h=await new f.TextureLoader().loadAsync(c);return s?.isCurrent?.()===!1?(h?.dispose(),null):(h?(h.guid=a.guid,h.flipY=!1,h.needsUpdate=!0,h.colorSpace=t.colorSpace,r&&console.log(a,h)):g&&console.warn("failed loading",c),h)}}return null}static async tryResolveLODCacheEntry(t,e,s,r,n,i){if(t===void 0)return{found:!1};if(i&&console.log(`LOD ${n} was already loading/loaded: ${e}`),t instanceof WeakRef){const u=t.deref();if(u){let c=u,d=!1;if(c instanceof f.Texture&&r instanceof f.Texture?c.image?.data||c.source?.data?c=this.copySettings(r,c):d=!0:c instanceof f.BufferGeometry&&r instanceof f.BufferGeometry&&(c.attributes.position?.array||(d=!0)),!d)return{found:!0,value:c}}return this.cache.delete(e),g&&console.log(`[gltf-progressive] Re-loading GC'd/disposed resource: ${e}`),{found:!1}}let a=await t.catch(u=>(console.error(`Error loading LOD ${n} from ${s}
5
- `,u),null)),l=!1;return a==null||(a instanceof f.Texture&&r instanceof f.Texture?a.image?.data||a.source?.data?a=this.copySettings(r,a):(l=!0,this.cache.delete(e)):a instanceof f.BufferGeometry&&r instanceof f.BufferGeometry&&(a.attributes.position?.array||(l=!0,this.cache.delete(e)))),l?{found:!1}:{found:!0,value:a}}static _queue;static get queue(){return this._queue??=new je(ve()?20:50,{debug:g!=!1})}static assignLODInformation(t,e,s,r,n){if(!e)return;e.userData||(e.userData={});const i=new it(t,s,r,n);e.userData.LODS=i,"source"in e&&typeof e.source=="object"&&(e.source.LODS=i)}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?(g==="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 it{url;key;level;index;constructor(t,e,s,r){this.url=t,this.key=e,this.level=s,r!=null&&(this.index=r)}}class oe{static addPromise=(t,e,s,r)=>{r.forEach(n=>{n.add(t,e,s)})};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,s){if(this._resolved){g&&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)){const r=this._seen.get(e);if(r>=this._maxPromisesPerObject){g&&console.warn("PromiseGroup: Already awaiting object ignoring new promise for it.");return}this._seen.set(e,r+1)}else this._seen.set(e,1);this._awaiting.push(s),this._addedCount++,s.finally(()=>{this._resolvedCount++,this._awaiting.splice(this._awaiting.indexOf(s),1)})}}resolveNow(){this._resolved||this._resolve?.({awaited_count:this._addedCount,resolved_count:this._resolvedCount,cancelled:this._signal?.aborted??!1})}}const A=z("debugprogressive"),at=A==="colors",lt=z("noprogressive"),he=Symbol("Needle:LODSManager"),ge=Symbol("Needle:LODState"),U=Symbol("Needle:CurrentLOD"),C={mesh_lod:-1,texture_lod:-1},ut=new f.Color,_e=[3526751,11065402,15978811,15897394,15749691,11032304,4827122,3332036,16739229,7306743,14053330,3516499,12035359,14703919,3963096,42662,14100029,8344319,4633680,16229681,3120096,12076434,9083434,2060171,15751837,10182117,48121,62932,16704576,15817653,5083278,5592405],pe=new f.Box3,F=new f.Box3,Oe=new f.Box3,ct=new f.Vector3,dt=new f.Vector3,ft=new f.Matrix4,G=new f.Vector3,K=new f.Vector3,j=new f.Vector3,H=new f.Vector3;function ht(o,t){const e=o.min,s=o.max,r=(e.x+s.x)*.5,n=(e.y+s.y)*.5;return G.set(r,n,e.z).applyMatrix4(t).z<0}function $e(o){const{geometry:t,matrixWorld:e,camera:s,projectionScreenMatrix:r,desiredDensity:n,canvasHeight:i=0,currentLevel:a=-1,xrEnabled:l=!1,debugDrawLine:u,warnMissingPrimitiveDensities:c=!1}=o,d=p.getMeshLODExtension(t)?.lods,h=p.getPrimitiveIndex(t),m=o.target??{level:a,primitiveIndex:h,screenCoverage:0,screenspaceVolume:new f.Vector3,centrality:1};if(m.level=a,m.primitiveIndex=h,m.screenCoverage=0,m.screenspaceVolume.set(0,0,0),m.centrality=1,!d?.length)return m;let T=o.boundingBox??t.boundingBox;if(T||(t.computeBoundingBox(),T=t.boundingBox),!T)return m;if(pe.copy(T).applyMatrix4(e),s.isPerspectiveCamera&&ht(pe,r))return m.level=0,m.screenCoverage=1/0,m.screenspaceVolume.set(1/0,1/0,1/0),m;if(F.copy(pe).applyMatrix4(r),l&&s.isPerspectiveCamera&&s.fov>70){const L=F.min,S=F.max;let D=L.x,R=L.y,P=S.x,b=S.y;const y=2,_=1.5,O=(L.x+S.x)*.5,B=(L.y+S.y)*.5;D=(D-O)*y+O,R=(R-B)*y+B,P=(P-O)*y+O,b=(b-B)*y+B;const ne=D<0&&P>0?0:Math.min(Math.abs(L.x),Math.abs(S.x)),Ue=R<0&&b>0?0:Math.min(Math.abs(L.y),Math.abs(S.y)),ue=Math.max(ne,Ue);m.centrality=(_-ue)*(_-ue)*(_-ue)}const x=F.getSize(ct);x.multiplyScalar(.5),globalThis.screen?.availHeight>0&&i>0&&x.multiplyScalar(i/globalThis.screen.availHeight),s.isPerspectiveCamera&&(x.x*=s.aspect),Oe.copy(T).applyMatrix4(e).applyMatrix4(s.matrixWorldInverse);const w=Oe.getSize(dt),v=Math.max(x.x,x.y),M=Math.max(w.x,w.y);v!==0&&M!==0&&(x.z=w.z/M*v);const V=Math.max(x.x,x.y,x.z)*m.centrality;if(m.screenCoverage=V,m.screenspaceVolume.copy(x),V<=0)return m;if(u){const L=ft.copy(r);L.invert(),G.copy(F.min),K.copy(F.max),K.x=G.x,j.copy(F.max),j.y=G.y,H.copy(F.max);const S=(G.z+H.z)*.5;G.z=K.z=j.z=H.z=S,G.applyMatrix4(L),K.applyMatrix4(L),j.applyMatrix4(L),H.applyMatrix4(L),u(G,K,255),u(G,j,255),u(K,H,255),u(j,H,255)}for(let L=0;L<d.length;L++){const S=d[L],D=S.densities?.[h]||S.density||1e-5;if(h>0&&c&&Ae()&&!S.densities&&!globalThis["NEEDLE:MISSING_LOD_PRIMITIVE_DENSITIES"]&&(globalThis["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.")),D/V<n){m.level=L;break}}return m}let re=class N{static debugDrawLine;static getObjectLODState(t){return t[ge]}static addPlugin(t){q.push(t)}static removePlugin(t){const e=q.indexOf(t);e>=0&&q.splice(e,1)}static getPlugins(){return q}static get(t,e){if(t[he])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[he];const s=new N(t,{engine:"unknown",...e});return t[he]=s,s}renderer;context;projectionScreenMatrix=new f.Matrix4;get plugins(){return q}overrideLodLevel=void 0;targetTriangleDensity=2e5;skinnedMeshAutoUpdateBoundsInterval=30;updateInterval="auto";#e=1;pause=!1;manual=!1;_newPromiseGroups=[];_promiseGroupIds=0;awaitLoading(t){const e=this._promiseGroupIds++,s=new oe(this.#r,{...t});this._newPromiseGroups.push(s);const r=performance.now();return s.ready.finally(()=>{const n=this._newPromiseGroups.indexOf(s);n>=0&&(this._newPromiseGroups.splice(n,1),Ae()&&performance.measure("LODsManager:awaitLoading",{start:r,detail:{id:e,name:t?.name,awaited:s.awaitedCount,resolved:s.resolvedCount}}))}),s.ready}trackLoadingPromise(t,e,s){return oe.addPromise(t,e,s,this._newPromiseGroups),s}_postprocessPromiseGroups(){if(this._newPromiseGroups.length!==0)for(let t=this._newPromiseGroups.length-1;t>=0;t--)this._newPromiseGroups[t].update(this.#r)}_lodchangedlisteners=[];addEventListener(t,e){return t==="changed"?(this._lodchangedlisteners.push(e),()=>{this.removeEventListener(t,e)}):()=>{}}removeEventListener(t,e){let s=!1;if(t==="changed"){const r=this._lodchangedlisteners.indexOf(e);r>=0&&(this._lodchangedlisteners.splice(r,1),s=!0)}return s}constructor(t,e){this.renderer=t,this.context={...e}}#t;#o=new f.Clock;#r=0;#n=0;#i=0;#s=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;le(this.renderer),this.renderer.render=function(s,r){const n=e.renderer.getRenderTarget();(n==null||"isXRRenderTarget"in n&&n.isXRRenderTarget)&&(t=0,e.#r+=1,e.#n=e.#o.getDelta(),e.#i+=e.#n,e._fpsBuffer.shift(),e._fpsBuffer.push(1/e.#n),e.#s=e._fpsBuffer.reduce((a,l)=>a+l)/e._fpsBuffer.length,A&&e.#r%200===0&&console.log("FPS",Math.round(e.#s),"Interval:",e.#e));const i=t++;e.#t.call(this,s,r),e.onAfterRender(s,r,i)}}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,s){if(this.pause)return;const n=this.renderer.renderLists.get(t,0).opaque;let i=!0;if(n.length===1){const a=n[0].material;(a.name==="EffectMaterial"||a.name==="CopyShader")&&(i=!1)}if((e.parent&&e.parent.type==="CubeCamera"||s>=1&&e.type==="OrthographicCamera")&&(i=!1),i){if(lt||(this.updateInterval==="auto"?this.#s<40&&this.#e<10?(this.#e+=1,A&&console.warn("↓ Reducing LOD updates",this.#e,this.#s.toFixed(0))):this.#s>=60&&this.#e>1&&(this.#e-=1,A&&console.warn("↑ Increasing LOD updates",this.#e,this.#s.toFixed(0))):this.#e=this.updateInterval,this.#e>0&&this.#r%this.#e!=0))return;this.internalUpdate(t,e),this._postprocessPromiseGroups()}}internalUpdate(t,e){const s=this.renderer.renderLists.get(t,0),r=s.opaque;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse);const n=this.targetTriangleDensity;for(const l of r){if(l.material&&(l.geometry?.type==="BoxGeometry"||l.geometry?.type==="BufferGeometry")&&(l.material.name==="SphericalGaussianBlur"||l.material.name=="BackgroundCubeMaterial"||l.material.name==="CubemapFromEquirect"||l.material.name==="EquirectangularToCubeUV")){A&&(l.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(l.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",l,l.material.name,l.material.type)));continue}switch(l.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}const u=l.object;(u instanceof f.Mesh||u.isMesh)&&this.updateLODs(t,e,u,n)}const i=s.transparent;for(const l of i){const u=l.object;(u instanceof f.Mesh||u.isMesh)&&this.updateLODs(t,e,u,n)}const a=s.transmissive;for(const l of a){const u=l.object;(u instanceof f.Mesh||u.isMesh)&&this.updateLODs(t,e,u,n)}}updateLODs(t,e,s,r){s.userData||(s.userData={});let n=s[ge];if(n||(n=new gt,s[ge]=n),n.frames++<2)return;for(const a of q)a.onBeforeUpdateLOD?.(this.renderer,t,e,s);const i=this.overrideLodLevel!==void 0?this.overrideLodLevel:E;i>=0?(C.mesh_lod=i,C.texture_lod=i):(this.calculateLodLevel(e,s,n,r,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),s.material&&C.texture_lod>=0&&this.loadProgressiveTextures(s.material,C.texture_lod,i),g&&s.material&&!s.isGizmo&&Ie(s.material),at&&s.material&&!s.isGizmo&&!s.isBatchedMesh&&Be(s.material,C.mesh_lod);for(const a of q)a.onAfterUpdatedLOD?.(this.renderer,t,e,s,C);n.lastLodLevel_Mesh=C.mesh_lod,n.lastLodLevel_Texture=C.texture_lod}loadProgressiveTextures(t,e,s){if(!t)return;if(Array.isArray(t)){for(const i of t)this.loadProgressiveTextures(i,e,s);return}let r=!1;(t[U]===void 0||e<t[U])&&(r=!0);const n=s!==void 0&&s>=0;if(n&&(r=t[U]!=s,e=s),r){t[U]=e;const i=n?{force:!0}:void 0,a=p.assignTextureLOD(t,e,i).then(l=>{this._lodchangedlisteners.forEach(u=>u({type:"texture",level:e,object:t}))});oe.addPromise("texture",t,a,this._newPromiseGroups)}}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);let s=t[U]!==e;const r=t["DEBUG:LOD"];if(r!=null&&(s=t[U]!=r,e=r),s){t[U]=e;const n=t.geometry,i=p.assignMeshLOD(t,e).then(a=>(a&&t[U]==e&&n!=t.geometry&&this._lodchangedlisteners.forEach(l=>l({type:"mesh",level:e,object:t})),a));return oe.addPromise("mesh",t,i,this._newPromiseGroups),i}return Promise.resolve(null)}_sphere=new f.Sphere;_tempWorldPosition=new f.Vector3;static skinnedMeshBoundsFrameOffsetCounter=0;static $skinnedMeshBoundsOffset=Symbol("gltf-progressive-skinnedMeshBoundsOffset");calculateLodLevel(t,e,s,r,n){if(!e){n.mesh_lod=-1,n.texture_lod=-1;return}if(!t){n.mesh_lod=-1,n.texture_lod=-1;return}let a=10+1,l=!1;if(A&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const u=p.getMeshLODExtension(e.geometry)?.lods,c=p.getPrimitiveIndex(e.geometry),d=u&&u.length>0,h=p.getMaterialMinMaxLODsCount(e.material),m=h.min_count!==1/0&&h.min_count>=0&&h.max_count>=0;if(!d&&!m){n.mesh_lod=0,n.texture_lod=0;return}d||(l=!0,a=0);const T=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let x=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const w=e;if(!w.boundingBox)w.computeBoundingBox();else if(this.skinnedMeshAutoUpdateBoundsInterval>0){if(!w[N.$skinnedMeshBoundsOffset]){const M=N.skinnedMeshBoundsFrameOffsetCounter++;w[N.$skinnedMeshBoundsOffset]=M}const v=w[N.$skinnedMeshBoundsOffset];if((s.frames+v)%this.skinnedMeshAutoUpdateBoundsInterval===0){const M=Q(w),V=w.geometry;M&&(w.geometry=M),w.computeBoundingBox(),w.geometry=V}}x=w.boundingBox}if(x){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)){n.mesh_lod=0,n.texture_lod=0;return}}const w=$e({geometry:e.geometry,matrixWorld:e.matrixWorld,camera:t,projectionScreenMatrix:this.projectionScreenMatrix,desiredDensity:r,canvasHeight:T,currentLevel:s.lastLodLevel_Mesh,boundingBox:x,xrEnabled:this.renderer.xr.enabled,debugDrawLine:A?N.debugDrawLine:void 0,warnMissingPrimitiveDensities:!0});if(s.lastCentrality=w.centrality,s.lastScreenCoverage=w.screenCoverage,s.lastScreenspaceVolume.copy(w.screenspaceVolume),w.screenCoverage===1/0){n.mesh_lod=0,n.texture_lod=0;return}w.level>=0&&w.level<a&&(a=w.level,l=!0)}if(l?n.mesh_lod=a:n.mesh_lod=s.lastLodLevel_Mesh,A&&n.mesh_lod!=s.lastLodLevel_Mesh){const v=u?.[n.mesh_lod];v&&console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} → ${n.mesh_lod} (density: ${v.densities?.[c].toFixed(0)}) | ${e.name}`)}if(m){const w="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(s.lastLodLevel_Texture<0){if(n.texture_lod=h.max_count-1,A){const v=h.lods[h.max_count-1];A&&console.log(`First Texture LOD ${n.texture_lod} (${v.max_height}px) - ${e.name}`)}}else{const v=s.lastScreenspaceVolume.x+s.lastScreenspaceVolume.y+s.lastScreenspaceVolume.z;let M=s.lastScreenCoverage*4;this.context?.engine==="model-viewer"&&(M*=1.5);const L=T/window.devicePixelRatio*M;let S=!1;for(let D=h.lods.length-1;D>=0;D--){const R=h.lods[D];if(!(w&&R.max_height>=2048)&&!(ve()&&R.max_height>4096)&&(R.max_height>L||!S&&D===0)){if(S=!0,n.texture_lod=D,A&&n.texture_lod<s.lastLodLevel_Texture){const P=R.max_height;console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${n.texture_lod} = ${P}px
8
- Screensize: ${L.toFixed(0)}px, Coverage: ${(100*s.lastScreenCoverage).toFixed(2)}%, Volume ${v.toFixed(1)}
9
- ${e.name}`)}break}}}}else n.texture_lod=0}};class gt{frames=0;lastLodLevel_Mesh=-1;lastLodLevel_Texture=-1;lastScreenCoverage=0;lastScreenspaceVolume=new f.Vector3;lastCentrality=0}function Be(o,t){if(!(t<0)){if(Array.isArray(o)){for(const e of o)Be(e,t);return}"color"in o&&o.color instanceof f.Color&&(o.color.copy(Ge(t,ut)),o.needsUpdate=!0)}}function Ge(o,t){const e=Math.max(0,Math.min(_e.length-1,Math.floor(o)));return t.setHex(_e[e])}const Te=Symbol("NEEDLE_mesh_lod"),ie=Symbol("NEEDLE_texture_lod");let me=null;function qe(){const o=pt();o&&(o.mapURLs(function(t){return Se(),t}),Se(),me?.disconnect(),me=new MutationObserver(t=>{t.forEach(e=>{e.addedNodes.forEach(s=>{s instanceof HTMLElement&&s.tagName.toLowerCase()==="model-viewer"&&We(s)})})}),me.observe(document,{childList:!0,subtree:!0}))}function pt(){if(typeof customElements>"u")return null;const o=customElements.get("model-viewer");return o||(customElements.whenDefined("model-viewer").then(()=>{console.debug("[gltf-progressive] model-viewer defined"),qe()}),null)}function Se(){if(typeof document>"u")return;document.querySelectorAll("model-viewer").forEach(t=>{We(t)})}const be=new WeakSet;let mt=0;function We(o){if(!o||be.has(o))return null;be.add(o),console.debug("[gltf-progressive] found new model-viewer..."+ ++mt+`
10
- `,o.getAttribute("src"));let t=null,e=null,s=null;for(let r=o;r!=null;r=Object.getPrototypeOf(r)){const n=Object.getOwnPropertySymbols(r),i=n.find(u=>u.toString()=="Symbol(renderer)"),a=n.find(u=>u.toString()=="Symbol(scene)"),l=n.find(u=>u.toString()=="Symbol(needsRender)");!t&&i!=null&&(t=o[i].threeRenderer),!e&&a!=null&&(e=o[a]),!s&&l!=null&&(s=o[l])}if(t&&e){let r=function(){if(s){let i=0;const a=setInterval(()=>{if(i++>5){clearInterval(a);return}s?.call(o)},300)}};console.debug("[gltf-progressive] setup model-viewer");const n=re.get(t,{engine:"model-viewer"});return re.addPlugin(new yt),n.enable(),n.addEventListener("changed",()=>{s?.call(o)}),o.addEventListener("model-visibility",i=>{i.detail.visible&&s?.call(o)}),o.addEventListener("load",()=>{r()}),()=>{n.disable()}}return null}class yt{_didWarnAboutMissingUrl=!1;onBeforeUpdateLOD(t,e,s,r){this.tryParseMeshLOD(e,r),this.tryParseTextureLOD(e,r)}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[ie]==!0)return;e[ie]=!0;const s=this.tryGetCurrentGLTF(t),r=this.tryGetCurrentModelViewer(t),n=this.getUrl(r);if(n&&s&&e.material){let i=function(l){if(l[ie]==!0)return;l[ie]=!0,l.userData&&(l.userData.LOD=-1);const u=Object.keys(l);for(let c=0;c<u.length;c++){const d=u[c],h=l[d];if(h?.isTexture===!0){const m=h.userData?.associations?.textures;if(m==null)continue;const T=s.parser.json.textures[m];if(!T){console.warn("Texture data not found for texture index "+m);continue}if(T?.extensions?.[W]){const x=T.extensions[W];x&&n&&p.registerTexture(n,h,x.lods.length,m,x)}}}};const a=e.material;if(Array.isArray(a))for(const l of a)i(l);else i(a)}}tryParseMeshLOD(t,e){if(e[Te]==!0)return;e[Te]=!0;const s=this.tryGetCurrentModelViewer(t),r=this.getUrl(s);if(!r)return;const n=e.userData?.gltfExtensions?.[W];if(n&&r){const i=e.uuid;p.registerMesh(r,i,e,0,n.lods.length,n)}}}function xt(...o){let t,e,s,r;switch(o.length){case 2:[s,e]=o,r={};break;case 3:[s,e,r]=o;break;case 4:[t,e,s,r]=o;break;default:throw new Error("Invalid arguments")}le(e),Le(s),Me(s,{progressive:!0,...r?.hints}),s.register(i=>new p(i));const n=re.get(e);return r?.enableLODsManager!==!1&&n.enable(),n}qe();if(!Qe){const o={gltfProgressive:{useNeedleProgressive:xt,LODsManager:re,configureLoader:Me,getRaycastMesh:Q,useRaycastMeshes:Ze}};if(!globalThis.Needle)globalThis.Needle=o;else for(const t in o)globalThis.Needle[t]=o[t]}exports.LODsManager=re;exports.NEEDLE_progressive=p;exports.addDracoAndKTX2Loaders=Le;exports.calculateMeshLODLevel=$e;exports.configureLoader=Me;exports.createLoaders=le;exports.getLODColor=Ge;exports.getRaycastMesh=Q;exports.setDracoDecoderLocation=Pe;exports.setKTX2TranscoderLocation=ke;
@@ -1,10 +0,0 @@
1
- import{BufferGeometry as z,Mesh as V,Box3 as ne,Vector3 as S,Sphere as Te,CompressedTexture as He,Texture as I,Matrix3 as Xe,InterleavedBuffer as Ke,InterleavedBufferAttribute as Ye,BufferAttribute as Qe,TextureLoader as Je,Matrix4 as Se,Clock as Ze,Color as Oe}from"./three.min.js";import{DRACOLoader as et,KTX2Loader as tt,MeshoptDecoder as rt,GLTFLoader as he}from"./three-examples.min.js";const st="";globalThis.GLTF_PROGRESSIVE_VERSION=st,console.debug("[gltf-progressive] version -");let C="https://www.gstatic.com/draco/versioned/decoders/1.5.7/",H="https://cdn.needle.tools/static/three/0.179.1/basis2/";const ot=C,nt=H,ke=new URL(C+"draco_decoder.js");ke.searchParams.append("range","true"),fetch(ke,{method:"GET",headers:{Range:"bytes=0-1"}}).catch(n=>{console.debug(`Failed to fetch remote Draco decoder from ${C} (offline: ${typeof navigator<"u"?navigator.onLine:"unknown"})`),C===ot&&Ce("./include/draco/"),H===nt&&Pe("./include/ktx2/")}).finally(()=>{Ae()});const it=()=>({dracoDecoderPath:C,ktx2TranscoderPath:H});function Ce(n){C=n,T&&T[fe]!=C?(console.debug("Updating Draco decoder path to "+n),T[fe]=C,T.setDecoderPath(C),T.preload()):console.debug("Setting Draco decoder path to "+n)}function Pe(n){H=n,P&&P.transcoderPath!=H?(console.debug("Updating KTX2 transcoder path to "+n),P.setTranscoderPath(H),P.init()):console.debug("Setting KTX2 transcoder path to "+n)}function ie(n){return Ae(),n?P.detectSupport(n):n!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:T,ktx2Loader:P,meshoptDecoder:ae}}function ge(n){n.dracoLoader||n.setDRACOLoader(T),n.ktx2Loader||n.setKTX2Loader(P),n.meshoptDecoder||n.setMeshoptDecoder(ae)}const fe=Symbol("dracoDecoderPath");let T,ae,P;function Ae(){T||(T=new et,T[fe]=C,T.setDecoderPath(C),T.setDecoderConfig({type:"js"}),T.preload()),P||(P=new tt,P.setTranscoderPath(H),P.init()),ae||(ae=rt)}const me=new WeakMap;function pe(n,t){let e=me.get(n);e?e=Object.assign(e,t):e=t,me.set(n,e)}const at=he.prototype.load;function lt(...n){const t=me.get(this);let e=n[0];const r=new URL(e,window.location.href);if(r.hostname.endsWith("needle.tools")){const s=t?.progressive!==void 0?t.progressive:!0,o=t?.usecase?t.usecase:"default";s?this.requestHeader.Accept=`*/*;progressive=allowed;usecase=${o}`:this.requestHeader.Accept=`*/*;usecase=${o}`,e=r.toString()}return n[0]=e,at?.call(this,...n)}he.prototype.load=lt,W("debugprogressive");function W(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 ut(n,t){if(t===void 0||n===void 0||t.startsWith("./")||t.startsWith("http")||t.startsWith("data:")||t.startsWith("blob:"))return t;const e=n.lastIndexOf("/");if(e>=0){const r=n.substring(0,e+1);for(;r.endsWith("/")&&t.startsWith("/");)t=t.substring(1);return r+t}return t}function xe(){return le!==void 0||(le=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),W("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",le)),le}let le;function Re(){if(typeof window>"u")return!1;const n=new URL(window.location.href),t=n.hostname==="localhost"||/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(n.hostname);return n.hostname==="127.0.0.1"||t}class ct{constructor(t,e={}){this.maxConcurrent=t,this.debug=e.debug??!1,typeof window<"u"&&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:s}=this._queue.shift();s({use:o=>this.add(r,o)})}}}function dt(n){const t=n.image?.width??0,e=n.image?.height??0,r=n.image?.depth??1,s=Math.floor(Math.log2(Math.max(t,e,r)))+1,o=ht(n);return t*e*r*o*(1-Math.pow(.25,s))/(1-.25)}function ht(n){let t=4;const e=n.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 s=n.type;return s===1009||s===1010?r=1:s===1011||s===1012?r=2:s===1013||s===1014||s===1015?r=4:s===1016&&(r=2),t*r}const gt=typeof window>"u"&&typeof document>"u",ye=Symbol("needle:raycast-mesh");function Y(n){return n?.[ye]instanceof z?n[ye]:null}function ft(n,t){if((n.type==="Mesh"||n.type==="SkinnedMesh")&&!Y(n)){const e=pt(t);e.userData={isRaycastMesh:!0},n[ye]=e}}function mt(n=!0){if(n){if(ee)return;const t=ee=V.prototype.raycast;V.prototype.raycast=function(e,r){const s=this,o=Y(s);let i;o&&s.isMesh&&(i=s.geometry,s.geometry=o),t.call(this,e,r),i&&(s.geometry=i)}}else{if(!ee)return;V.prototype.raycast=ee,ee=null}}let ee=null;function pt(n){const t=new z;for(const e in n.attributes)t.setAttribute(e,n.getAttribute(e));return t.setIndex(n.getIndex()),t}const $=new Array,g=W("debugprogressive");let te,X=-1;if(g){let n=function(){X+=1,X>=t&&(X=-1),console.log(`Toggle LOD level [${X}]`)};window.addEventListener("keyup",e=>{e.key==="p"&&n(),e.key==="w"&&(te=!te,console.log(`Toggle wireframe [${te}]`));const r=parseInt(e.key);!isNaN(r)&&r>=0&&(X=r,console.log(`Set LOD level to [${X}]`))})}function Ie(n){if(g&&te!==void 0)if(Array.isArray(n))for(const t of n)Ie(t);else n&&"wireframe"in n&&(n.wireframe=te===!0)}const re=new Array;let xt=0;const yt=xe()?2:10;function vt(n){if(re.length<yt){const e=re.length;g&&console.warn(`[Worker] Creating new worker #${e}`);const r=_e.createWorker(n||{});return re.push(r),r}const t=xt++%re.length;return re[t]}class _e{constructor(t,e){this.worker=t,this._debug=e.debug??!1,t.onmessage=r=>{const s=r.data;switch(this._debug&&console.log("[Worker] EVENT",s),s.type){case"loaded-gltf":for(const o of this._running)if(o.url===s.result.url){wt(s.result),o.resolve(s.result);const i=o.url;i.startsWith("blob:")&&URL.revokeObjectURL(i)}}},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("./gltf-progressive.worker-BqODMeeW.js",import.meta.url).toString()}';`],{type:"text/javascript"})),{type:"module"});return new _e(e,t)}_running=[];_webglRenderer=null;async load(t,e){const r=it();let s=e?.renderer;s||(this._webglRenderer??=(async()=>{const{WebGLRenderer:a}=await import("./three.min.js").then(l=>l.THREE);return new a})(),s=await this._webglRenderer);const o=ie(s).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 i={type:"load",url:t,dracoDecoderPath:r.dracoDecoderPath,ktx2TranscoderPath:r.ktx2TranscoderPath,ktx2LoaderConfig:o};return this._debug&&console.debug("[Worker] Sending load request",i),this.worker.postMessage(i),new Promise(a=>{this._running.push({url:t.toString(),resolve:a})})}_debug=!1}function wt(n){for(const t of n.geometries){const e=t.geometry,r=new z;if(r.name=e.name||"",e.index){const s=e.index;r.setIndex(ve(s))}for(const s in e.attributes){const o=e.attributes[s],i=ve(o);r.setAttribute(s,i)}if(e.morphAttributes)for(const s in e.morphAttributes){const o=e.morphAttributes[s].map(i=>ve(i));r.morphAttributes[s]=o}if(r.morphTargetsRelative=e.morphTargetsRelative??!1,r.boundingBox=new ne,r.boundingBox.min=new S(e.boundingBox?.min.x,e.boundingBox?.min.y,e.boundingBox?.min.z),r.boundingBox.max=new S(e.boundingBox?.max.x,e.boundingBox?.max.y,e.boundingBox?.max.z),r.boundingSphere=new Te(new S(e.boundingSphere?.center.x,e.boundingSphere?.center.y,e.boundingSphere?.center.z),e.boundingSphere?.radius),e.groups)for(const s of e.groups)r.addGroup(s.start,s.count,s.materialIndex);e.userData&&(r.userData=e.userData),t.geometry=r}for(const t of n.textures){const e=t.texture;let r=null;if(e.isCompressedTexture){const s=e.mipmaps,o=e.image?.width||e.source?.data?.width||-1,i=e.image?.height||e.source?.data?.height||-1;r=new He(s,o,i,e.format,e.type,e.mapping,e.wrapS,e.wrapT,e.magFilter,e.minFilter,e.anisotropy,e.colorSpace)}else r=new I(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 Xe(...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 n}function ve(n){let t=n;if("isInterleavedBufferAttribute"in n&&n.isInterleavedBufferAttribute){const e=n.data,r=e.array,s=new Ke(r,e.stride);t=new Ye(s,n.itemSize,r.byteOffset,n.normalized),t.offset=n.offset}else"isBufferAttribute"in n&&n.isBufferAttribute&&(t=new Qe(n.array,n.itemSize,n.normalized),t.usage=n.usage,t.gpuType=n.gpuType,t.updateRanges=n.updateRanges);return t}const Lt=W("gltf-progressive-worker");W("gltf-progressive-reduce-mipmaps");const se=W("gltf-progressive-gc"),we=Symbol("needle-progressive-texture"),B="NEEDLE_progressive";class f{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,s="LODS:minmax",o=t[s];if(o!=null)return o;if(e||(e={min_count:1/0,max_count:0,lods:[]}),Array.isArray(t)){for(const a of t)this.getMaterialMinMaxLODsCount(a,e);return t[s]=e,e}if(g==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const a=t;for(const l of Object.keys(a.uniforms)){const u=a.uniforms[l].value;u?.isTexture===!0&&i(u,e)}}else if(t.isMaterial)for(const a of Object.keys(t)){const l=t[a];l?.isTexture===!0&&i(l,e)}else g&&console.warn(`[getMaterialMinMaxLODsCount] Unsupported material type: ${t.type}`);return t[s]=e,e;function i(a,l){const u=r.getAssignedLODInformation(a);if(u){const c=r.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 d=0;d<c.lods.length;d++){const p=c.lods[d];p.width&&(l.lods[d]=l.lods[d]||{min_height:1/0,max_height:0},l.lods[d].min_height=Math.min(l.lods[d].min_height,p.height),l.lods[d].max_height=Math.max(l.lods[d].max_height,p.height))}}}}}static hasLODLevelAvailable(t,e){if(Array.isArray(t)){for(const o of t)if(this.hasLODLevelAvailable(o,e))return!0;return!1}if(t.isMaterial===!0){for(const o of Object.keys(t)){const i=t[o];if(i&&i.isTexture&&this.hasLODLevelAvailable(i,e))return!0}return!1}else if(t.isGroup===!0){for(const o of t.children)if(o.isMesh===!0&&this.hasLODLevelAvailable(o,e))return!0}let r,s;if(t.isMesh?r=t.geometry:(t.isBufferGeometry||t.isTexture)&&(r=t),r&&r?.userData?.LODS){const o=r.userData.LODS;if(s=this.lodInfos.get(o.key),e===void 0)return s!=null;if(s)return Array.isArray(s.lods)?e<s.lods.length:e===0}return!1}static assignMeshLOD(t,e,r){if(!t)return Promise.resolve(null);if(t instanceof V||t.isMesh===!0){const s=t.geometry,o=this.getAssignedLODInformation(s);if(!o)return Promise.resolve(null);for(const a of $)a.onBeforeGetLODMesh?.(t,e);t["LOD:requested level"]=e;const i=()=>t["LOD:requested level"]===e||this.shouldApplyStaleMeshLOD(t,e);return f.getOrLoadLOD(s,e,{isCurrent:i}).then(a=>{if(Array.isArray(a)){const u=o.index||0;a=a[u]}const l=t["LOD:requested level"]===e;return(l||this.shouldApplyStaleMeshLOD(t,e))&&(l&&delete t["LOD:requested level"],a&&s!=a&&(a?.isBufferGeometry?typeof r?.apply=="function"?r.apply(a,e,t):r?.apply!==!1&&(t.geometry=a):g&&console.error("Invalid LOD geometry",a))),a}).catch(a=>(console.error("Error loading mesh LOD",t,a),null))}else g&&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,r){if(!t)return Promise.resolve(null);const s=r?.force===!0;if(t.isMesh===!0){const o=t;if(Array.isArray(o.material)){const i=new Array;for(const a of o.material){const l=this.assignTextureLOD(a,e,r);i.push(l)}return Promise.all(i).then(a=>{const l=new Array;for(const u of a)Array.isArray(u)&&l.push(...u);return l})}else return this.assignTextureLOD(o.material,e,r)}if(t.isMaterial===!0){const o=t,i=[],a=new Array;if(this.trackCurrentMaterialTextureSlots(o),o.uniforms&&(o.isRawShaderMaterial||o.isShaderMaterial===!0)){const l=o;for(const u of Object.keys(l.uniforms)){const c=l.uniforms[u].value;if(c?.isTexture===!0){const d=this.assignTextureLODForSlot(c,e,o,u,s).then(p=>(p&&l.uniforms[u].value!=p&&(l.uniforms[u].value=p,l.uniformsNeedUpdate=!0),p));i.push(d),a.push(u)}}}else for(const l of Object.keys(o)){const u=o[l];if(u?.isTexture===!0){const c=this.assignTextureLODForSlot(u,e,o,l,s);i.push(c),a.push(l)}}return Promise.all(i).then(l=>{const u=new Array;for(let c=0;c<l.length;c++){const d=l[c],p=a[c];d&&d.isTexture===!0?u.push({material:o,slot:p,texture:d,level:e}):u.push({material:o,slot:p,texture:null,level:e})}return u})}if(t instanceof I||t.isTexture===!0){const o=t;return this.assignTextureLODForSlot(o,e,null,null,s)}return Promise.resolve(null)}static set maxConcurrentLoadingTasks(t){f.queue.maxConcurrent=t}static get maxConcurrentLoadingTasks(){return f.queue.maxConcurrent}static assignTextureLODForSlot(t,e,r,s,o){if(t?.isTexture!==!0)return Promise.resolve(null);if(s==="glyphMap")return Promise.resolve(t);const i=this.getAssignedLODInformation(t);if(i&&(i.level===e||!o&&i.level<e))return Promise.resolve(t);if(r&&s){const d=this.getPendingTextureSlotRequest(r,s);if(d&&d.level===e&&d.force===o)return d.promise}const a=r&&s?this.nextTextureSlotRequestId(r,s,e,o):0,l=()=>!r||!s||this.getLatestTextureSlotRequest(r,s)?.id===a,u=()=>l()||this.shouldApplyStaleTextureSlotLOD(r,s,e,o),c=f.getOrLoadLOD(t,e,{isCurrent:u}).then(d=>{if(!l()&&!this.shouldApplyStaleTextureSlotLOD(r,s,e,o))return null;if(Array.isArray(d))return console.warn("Progressive: Got an array of textures for a texture slot, this should not happen..."),null;if(d?.isTexture===!0){if(d!=t&&r&&s){const p=this.getMaterialTextureSlot(r,s)??t;if(p&&!o){const m=this.getAssignedLODInformation(p);if(m&&m?.level<e)return g==="verbose"&&console.warn("Assigned texture level is already higher: ",m.level,e,r,p,d),null}this.assignTrackedTextureSlot(r,s,d)}return d}else g=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(d=>(console.error("Error loading LOD",t,d),null));return r&&s&&this.setPendingTextureSlotRequest(r,s,e,o,a,c),c}static trackedTextureSlots=new WeakMap;static pendingTextureSlotRequests=new WeakMap;static latestTextureSlotRequests=new WeakMap;static textureSlotRequestId=0;static trackCurrentMaterialTextureSlots(t){if(t.uniforms&&(t.isRawShaderMaterial||t.isShaderMaterial===!0)){const e=t;for(const r of Object.keys(e.uniforms)){const s=e.uniforms[r].value;s?.isTexture===!0&&this.ensureTrackedTextureSlot(t,r,s)}return}for(const e of Object.keys(t)){const r=t[e];r?.isTexture===!0&&this.ensureTrackedTextureSlot(t,e,r)}}static getPendingTextureSlotRequest(t,e){return this.pendingTextureSlotRequests.get(t)?.get(e)}static nextTextureSlotRequestId(t,e,r,s){let o=this.latestTextureSlotRequests.get(t);o||(o=new Map,this.latestTextureSlotRequests.set(t,o));const i=++this.textureSlotRequestId;return o.set(e,{id:i,level:r,force:s}),i}static getLatestTextureSlotRequest(t,e){return this.latestTextureSlotRequests.get(t)?.get(e)}static shouldApplyStaleTextureSlotLOD(t,e,r,s){if(!t||!e)return!1;const o=this.getLatestTextureSlotRequest(t,e),i=this.getMaterialTextureSlot(t,e),a=this.getAssignedLODInformation(i)?.level??1/0;return r>=a?!1:s?o?r>=o.level:!1:!0}static shouldApplyStaleMeshLOD(t,e){const r=t["LOD:requested level"];if(typeof r!="number")return!1;const s=this.getAssignedLODInformation(t.geometry)?.level??1/0;return e<s&&e>=r}static setPendingTextureSlotRequest(t,e,r,s,o,i){let a=this.pendingTextureSlotRequests.get(t);a||(a=new Map,this.pendingTextureSlotRequests.set(t,a));const l={level:r,force:s,id:o,promise:i};a.set(e,l),i.finally(()=>{a.get(e)?.id===o&&a.delete(e)})}static getMaterialTextureSlot(t,e){const r=t.uniforms?.[e];if(r?.value?.isTexture===!0)return r.value;const s=t[e];return s?.isTexture===!0?s:null}static setMaterialTextureSlot(t,e,r){const s=t.uniforms?.[e];if(s?.value?.isTexture===!0){s.value=r,t.uniformsNeedUpdate=!0;return}t[e]=r}static assignTrackedTextureSlot(t,e,r){let s=this.trackedTextureSlots.get(t);s||(s=new Map,this.trackedTextureSlots.set(t,s));const o=this.getMaterialTextureSlot(t,e);let i=s.get(e);!i&&o?i=this.ensureTrackedTextureSlot(t,e,o):i&&o&&i!==o&&(this.releaseTrackedTextureSlot(t,e,i),i=this.ensureTrackedTextureSlot(t,e,o)),!(i===r&&o===r)&&(i&&i!==r&&this.releaseTrackedTextureSlot(t,e,i),i!==r&&(this.trackTextureUsage(r),s.set(e,r)),o!==r&&this.setMaterialTextureSlot(t,e,r))}static ensureTrackedTextureSlot(t,e,r){let s=this.trackedTextureSlots.get(t);s||(s=new Map,this.trackedTextureSlots.set(t,s));const o=s.get(e);return o===r?o:(o&&this.releaseTrackedTextureSlot(t,e,o),this.trackTextureUsage(r),s.set(e,r),r)}static releaseTrackedTextureSlot(t,e,r){const s=this.trackedTextureSlots.get(t);if(s?.get(e)===r&&s.delete(e),this.untrackTextureUsage(r)&&(g||se)){const o=this.getAssignedLODInformation(r);console.log(`[gltf-progressive] Disposed old texture LOD ${o?.level??"?"} for ${t.name||t.type}.${e}`,r.uuid)}}parser;url;constructor(t){const e=t.options.path;g&&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&&f.registerMesh(this.url,e.guid,r,e.lods?.length,0,e),r))):null};afterRoot(t){return g&&console.log("AFTER",this.url,t),this.parser.json.textures?.forEach((e,r)=>{if(e?.extensions){const s=e?.extensions[B];if(s){if(!s.lods){g&&console.warn("Texture has no LODs",s);return}let o=!1;for(const i of this.parser.associations.keys())i.isTexture===!0&&this.parser.associations.get(i)?.textures===r&&(o=!0,f.registerTexture(this.url,i,s.lods?.length,r,s));o||this.parser.getDependency("texture",r).then(i=>{i&&f.registerTexture(this.url,i,s.lods?.length,r,s)})}}}),this.parser.json.meshes?.forEach((e,r)=>{if(e?.extensions){const s=e?.extensions[B];if(s&&s.lods){for(const o of this.parser.associations.keys())if(o.isMesh){const i=this.parser.associations.get(o);i?.meshes===r&&f.registerMesh(this.url,s.guid,o,s.lods.length,i.primitives,s)}}}}),null}static registerTexture=(t,e,r,s,o)=>{if(!e){g&&console.error("!! gltf-progressive: Called register texture without texture");return}if(g){const a=e.image?.width||e.source?.data?.width||0,l=e.image?.height||e.source?.data?.height||0;console.log(`> gltf-progressive: register texture[${s}] "${e.name||e.uuid}", Current: ${a}x${l}, Max: ${o.lods[0]?.width}x${o.lods[0]?.height}, uuid: ${e.uuid}`,o,e)}e.source&&(e.source[we]=o);const i=o.guid;f.assignLODInformation(t,e,i,r,s),f.lodInfos.set(i,o),f.lowresCache.set(i,new WeakRef(e))};static registerMesh=(t,e,r,s,o,i)=>{const a=r.geometry;if(!a){g&&console.warn("gltf-progressive: Register mesh without geometry");return}a.userData||(a.userData={}),g&&console.log("> Progressive: register mesh "+r.name,{index:o,uuid:r.uuid},i,r),f.assignLODInformation(t,a,e,s,o),f.lodInfos.set(e,i);let l=f.lowresCache.get(e)?.deref();l?l.push(r.geometry):l=[r.geometry],f.lowresCache.set(e,new WeakRef(l)),s>0&&!Y(r)&&ft(r,a);for(const u of $)u.onRegisteredNewMesh?.(r,i)};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 s=r;this.textureRefCounts.delete(s.uuid),s.dispose()}else if(Array.isArray(r))for(const s of r)s.dispose()}this.lowresCache.delete(t)}for(const[r,s]of this.cache)r.includes(t)&&(this._disposeCacheEntry(s),this.cache.delete(r))}else{this.lodInfos.clear();for(const[,e]of this.lowresCache){const r=e.deref();if(r){if(r.isTexture){const s=r;this.textureRefCounts.delete(s.uuid),s.dispose()}else if(Array.isArray(r))for(const s of r)s.dispose()}}this.lowresCache.clear();for(const[,e]of this.cache)this._disposeCacheEntry(e);this.cache.clear(),this.textureRefCounts.clear(),this.trackedTextureSlots=new WeakMap,this.pendingTextureSlotRequests=new WeakMap,this.latestTextureSlotRequests=new WeakMap,this.textureSlotRequestId=0}}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=f.cache.get(t);(g||se)&&console.debug(`[gltf-progressive] Memory: Resource GC'd
2
- ${t}`),e instanceof WeakRef&&(e.deref()||(f.cache.delete(t),(g||se)&&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),g==="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(g==="verbose"||se)&&o("[gltf-progressive] Memory: Untrack untracked texture (dispose immediately)",0),t.dispose(),!0;const s=r-1;if(s<=0)return this.textureRefCounts.delete(e),(g||se)&&o("[gltf-progressive] Memory: Dispose texture",s),t.dispose(),!0;return this.textureRefCounts.set(e,s),g==="verbose"&&o("[gltf-progressive] Memory: Untrack texture",s),!1;function o(i,a){const l=t.image?.width||t.source?.data?.width||0,u=t.image?.height||t.source?.data?.height||0,c=l&&u?`${l}x${u}`:"N/A";let d="N/A";l&&u&&(d=`~${(dt(t)/(1024*1024)).toFixed(2)} MB`),console.log(`${i} \u2014 ${t.name} ${c} (${d}), refCount: ${r} \u2192 ${a}
3
- ${e}`)}}static workers=[];static _workersIndex=0;static async getOrLoadLOD(t,e,r){const s=g=="verbose",o=this.getAssignedLODInformation(t);if(!o)return g&&console.warn(`[gltf-progressive] No LOD information found: ${t.name}, uuid: ${t.uuid}, type: ${t.type}`,t),null;const i=o?.key;let a;if(t.isTexture===!0){const l=t;l.source&&l.source[we]&&(a=l.source[we])}if(a||(a=f.lodInfos.get(i)),!a)g&&console.warn(`Can not load LOD ${e}: no LOD info found for "${i}" ${t.name}`,t.type,f.lodInfos);else{if(e>0){let c=!1;const d=Array.isArray(a.lods);if(d&&e>=a.lods.length?c=!0:d||(c=!0),c){const p=this.lowresCache.get(i);if(p){const m=p.deref();if(m)return m;this.lowresCache.delete(i),g&&console.log(`[gltf-progressive] Lowres cache entry was GC'd: ${i}`)}return null}}const l=Array.isArray(a.lods)?a.lods[e]?.path:a.lods;if(!l)return g&&!a["missing:uri"]&&(a["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,a)),null;const u=ut(o.url,l);if(u.endsWith(".glb")||u.endsWith(".gltf")){if(!a.guid)return console.warn("missing pointer for glb/gltf texture",a),null;const c=u+"_"+a.guid,d=await this.tryResolveLODCacheEntry(this.cache.get(c),c,u,t,e,s);if(d.found)return d.value;if(r?.isCurrent?.()===!1)return s&&console.log(`Skipping stale LOD ${e} request before queue: ${u}`),null;const p=await this.queue.slot(u);if(r?.isCurrent?.()===!1)return s&&console.log(`Skipping stale LOD ${e} request after queue: ${u}`),null;const m=await this.tryResolveLODCacheEntry(this.cache.get(c),c,u,t,e,s);if(m.found)return m.value;if(!p.use)return g&&console.log(`LOD ${e} was aborted: ${u}`),null;const L=a,h=new Promise(async(D,G)=>{if(Lt){const b=await(await vt({})).load(u);if(b.textures.length>0)for(const x of b.textures){let w=x.texture;return f.assignLODInformation(o.url,w,i,e,void 0),t instanceof I&&(w=this.copySettings(t,w)),w&&(w.guid=L.guid),D(w)}if(b.geometries.length>0){const x=new Array;for(const w of b.geometries){const k=w.geometry;f.assignLODInformation(o.url,k,i,e,w.primitiveIndex),x.push(k)}return D(x)}return D(null)}const E=new he;ge(E),g&&(await new Promise(b=>setTimeout(b,1e3)),s&&console.warn("Start loading (delayed) "+u,L.guid));let y=u;if(L&&Array.isArray(L.lods)){const b=L.lods[e];b.hash&&(y+="?v="+b.hash)}const v=await E.loadAsync(y).catch(b=>(console.error(`Error loading LOD ${e} from ${u}
4
- `,b),D(null)));if(!v)return D(null);const R=v.parser;s&&console.log("Loading finished "+u,L.guid);let O=0;if(v.parser.json.textures){let b=!1;for(const x of v.parser.json.textures){if(x?.extensions){const w=x?.extensions[B];if(w?.guid&&w.guid===L.guid){b=!0;break}}O++}if(b){let x=await R.getDependency("texture",O);return x&&f.assignLODInformation(o.url,x,i,e,void 0),s&&console.log('change "'+t.name+'" \u2192 "'+x.name+'"',u,O,x,c),t instanceof I&&(x=this.copySettings(t,x)),x&&(x.guid=L.guid),D(x)}else g&&console.warn("Could not find texture with guid",L.guid,v.parser.json)}if(O=0,v.parser.json.meshes){let b=!1;for(const x of v.parser.json.meshes){if(x?.extensions){const w=x?.extensions[B];if(w?.guid&&w.guid===L.guid){b=!0;break}}O++}if(b){const x=await R.getDependency("mesh",O);if(s&&console.log(`Loaded Mesh "${x.name}"`,u,O,x,c),x.isMesh===!0){const w=x.geometry;return f.assignLODInformation(o.url,w,i,e,0),D(w)}else{const w=new Array;for(let k=0;k<x.children.length;k++){const U=x.children[k];if(U.isMesh===!0){const F=U.geometry;f.assignLODInformation(o.url,F,i,e,k),w.push(F)}}return D(w)}}else g&&console.warn("Could not find mesh with guid",L.guid,v.parser.json)}return D(null)});this.cache.set(c,h),p.use(h);const M=await h;return M!=null?M instanceof I?(this.cache.set(c,new WeakRef(M)),f._resourceRegistry.register(M,c)):Array.isArray(M)?this.cache.set(c,Promise.resolve(M)):this.cache.set(c,Promise.resolve(M)):this.cache.set(c,Promise.resolve(null)),M}else if(t instanceof I){if(r?.isCurrent?.()===!1)return s&&console.log(`Skipping stale texture LOD ${e} request: ${u}`),null;s&&console.log("Load texture from uri: "+u);const c=await new Je().loadAsync(u);return r?.isCurrent?.()===!1?(c?.dispose(),null):(c?(c.guid=a.guid,c.flipY=!1,c.needsUpdate=!0,c.colorSpace=t.colorSpace,s&&console.log(a,c)):g&&console.warn("failed loading",u),c)}}return null}static async tryResolveLODCacheEntry(t,e,r,s,o,i){if(t===void 0)return{found:!1};if(i&&console.log(`LOD ${o} was already loading/loaded: ${e}`),t instanceof WeakRef){const u=t.deref();if(u){let c=u,d=!1;if(c instanceof I&&s instanceof I?c.image?.data||c.source?.data?c=this.copySettings(s,c):d=!0:c instanceof z&&s instanceof z&&(c.attributes.position?.array||(d=!0)),!d)return{found:!0,value:c}}return this.cache.delete(e),g&&console.log(`[gltf-progressive] Re-loading GC'd/disposed resource: ${e}`),{found:!1}}let a=await t.catch(u=>(console.error(`Error loading LOD ${o} from ${r}
5
- `,u),null)),l=!1;return a==null||(a instanceof I&&s instanceof I?a.image?.data||a.source?.data?a=this.copySettings(s,a):(l=!0,this.cache.delete(e)):a instanceof z&&s instanceof z&&(a.attributes.position?.array||(l=!0,this.cache.delete(e)))),l?{found:!1}:{found:!0,value:a}}static _queue;static get queue(){return this._queue??=new ct(xe()?20:50,{debug:g!=!1})}static assignLODInformation(t,e,r,s,o){if(!e)return;e.userData||(e.userData={});const i=new bt(t,r,s,o);e.userData.LODS=i,"source"in e&&typeof e.source=="object"&&(e.source.LODS=i)}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?(g==="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 bt{url;key;level;index;constructor(t,e,r,s){this.url=t,this.key=e,this.level=r,s!=null&&(this.index=s)}}class ue{static addPromise=(t,e,r,s)=>{s.forEach(o=>{o.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(s=>{this._resolve=s}),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){g&&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)){const s=this._seen.get(e);if(s>=this._maxPromisesPerObject){g&&console.warn("PromiseGroup: Already awaiting object ignoring new promise for it.");return}this._seen.set(e,s+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 A=W("debugprogressive"),Mt=A==="colors",Dt=W("noprogressive"),Le=Symbol("Needle:LODSManager"),be=Symbol("Needle:LODState"),j=Symbol("Needle:CurrentLOD"),_={mesh_lod:-1,texture_lod:-1},_t=new Oe,Ee=[3526751,11065402,15978811,15897394,15749691,11032304,4827122,3332036,16739229,7306743,14053330,3516499,12035359,14703919,3963096,42662,14100029,8344319,4633680,16229681,3120096,12076434,9083434,2060171,15751837,10182117,48121,62932,16704576,15817653,5083278,5592405],Me=new ne,N=new ne,$e=new ne,Tt=new S,St=new S,Ot=new Se,q=new S,Q=new S,J=new S,Z=new S;function kt(n,t){const e=n.min,r=n.max,s=(e.x+r.x)*.5,o=(e.y+r.y)*.5;return q.set(s,o,e.z).applyMatrix4(t).z<0}function Be(n){const{geometry:t,matrixWorld:e,camera:r,projectionScreenMatrix:s,desiredDensity:o,canvasHeight:i=0,currentLevel:a=-1,xrEnabled:l=!1,debugDrawLine:u,warnMissingPrimitiveDensities:c=!1}=n,d=f.getMeshLODExtension(t)?.lods,p=f.getPrimitiveIndex(t),m=n.target??{level:a,primitiveIndex:p,screenCoverage:0,screenspaceVolume:new S,centrality:1};if(m.level=a,m.primitiveIndex=p,m.screenCoverage=0,m.screenspaceVolume.set(0,0,0),m.centrality=1,!d?.length)return m;let L=n.boundingBox??t.boundingBox;if(L||(t.computeBoundingBox(),L=t.boundingBox),!L)return m;if(Me.copy(L).applyMatrix4(e),r.isPerspectiveCamera&&kt(Me,s))return m.level=0,m.screenCoverage=1/0,m.screenspaceVolume.set(1/0,1/0,1/0),m;if(N.copy(Me).applyMatrix4(s),l&&r.isPerspectiveCamera&&r.fov>70){const y=N.min,v=N.max;let R=y.x,O=y.y,b=v.x,x=v.y;const w=2,k=1.5,U=(y.x+v.x)*.5,F=(y.y+v.y)*.5;R=(R-U)*w+U,O=(O-F)*w+F,b=(b-U)*w+U,x=(x-F)*w+F;const ze=R<0&&b>0?0:Math.min(Math.abs(y.x),Math.abs(v.x)),Ve=O<0&&x>0?0:Math.min(Math.abs(y.y),Math.abs(v.y)),de=Math.max(ze,Ve);m.centrality=(k-de)*(k-de)*(k-de)}const h=N.getSize(Tt);h.multiplyScalar(.5),globalThis.screen?.availHeight>0&&i>0&&h.multiplyScalar(i/globalThis.screen.availHeight),r.isPerspectiveCamera&&(h.x*=r.aspect),$e.copy(L).applyMatrix4(e).applyMatrix4(r.matrixWorldInverse);const M=$e.getSize(St),D=Math.max(h.x,h.y),G=Math.max(M.x,M.y);D!==0&&G!==0&&(h.z=M.z/G*D);const E=Math.max(h.x,h.y,h.z)*m.centrality;if(m.screenCoverage=E,m.screenspaceVolume.copy(h),E<=0)return m;if(u){const y=Ot.copy(s);y.invert(),q.copy(N.min),Q.copy(N.max),Q.x=q.x,J.copy(N.max),J.y=q.y,Z.copy(N.max);const v=(q.z+Z.z)*.5;q.z=Q.z=J.z=Z.z=v,q.applyMatrix4(y),Q.applyMatrix4(y),J.applyMatrix4(y),Z.applyMatrix4(y),u(q,Q,255),u(q,J,255),u(Q,Z,255),u(J,Z,255)}for(let y=0;y<d.length;y++){const v=d[y],R=v.densities?.[p]||v.density||1e-5;if(p>0&&c&&Re()&&!v.densities&&!globalThis["NEEDLE:MISSING_LOD_PRIMITIVE_DENSITIES"]&&(globalThis["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.")),R/E<o){m.level=y;break}}return m}let oe=class K{static debugDrawLine;static getObjectLODState(t){return t[be]}static addPlugin(t){$.push(t)}static removePlugin(t){const e=$.indexOf(t);e>=0&&$.splice(e,1)}static getPlugins(){return $}static get(t,e){if(t[Le])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[Le];const r=new K(t,{engine:"unknown",...e});return t[Le]=r,r}renderer;context;projectionScreenMatrix=new Se;get plugins(){return $}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 ue(this.#s,{...t});this._newPromiseGroups.push(r);const s=performance.now();return r.ready.finally(()=>{const o=this._newPromiseGroups.indexOf(r);o>=0&&(this._newPromiseGroups.splice(o,1),Re()&&performance.measure("LODsManager:awaitLoading",{start:s,detail:{id:e,name:t?.name,awaited:r.awaitedCount,resolved:r.resolvedCount}}))}),r.ready}trackLoadingPromise(t,e,r){return ue.addPromise(t,e,r,this._newPromiseGroups),r}_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){return t==="changed"?(this._lodchangedlisteners.push(e),()=>{this.removeEventListener(t,e)}):()=>{}}removeEventListener(t,e){let r=!1;if(t==="changed"){const s=this._lodchangedlisteners.indexOf(e);s>=0&&(this._lodchangedlisteners.splice(s,1),r=!0)}return r}constructor(t,e){this.renderer=t,this.context={...e}}#t;#n=new Ze;#s=0;#o=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;ie(this.renderer),this.renderer.render=function(r,s){const o=e.renderer.getRenderTarget();(o==null||"isXRRenderTarget"in o&&o.isXRRenderTarget)&&(t=0,e.#s+=1,e.#o=e.#n.getDelta(),e.#i+=e.#o,e._fpsBuffer.shift(),e._fpsBuffer.push(1/e.#o),e.#r=e._fpsBuffer.reduce((a,l)=>a+l)/e._fpsBuffer.length,A&&e.#s%200===0&&console.log("FPS",Math.round(e.#r),"Interval:",e.#e));const i=t++;e.#t.call(this,r,s),e.onAfterRender(r,s,i)}}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 s=this.renderer.renderLists.get(t,0).opaque;let o=!0;if(s.length===1){const i=s[0].material;(i.name==="EffectMaterial"||i.name==="CopyShader")&&(o=!1)}if((e.parent&&e.parent.type==="CubeCamera"||r>=1&&e.type==="OrthographicCamera")&&(o=!1),o){if(Dt||(this.updateInterval==="auto"?this.#r<40&&this.#e<10?(this.#e+=1,A&&console.warn("\u2193 Reducing LOD updates",this.#e,this.#r.toFixed(0))):this.#r>=60&&this.#e>1&&(this.#e-=1,A&&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),s=r.opaque;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse);const o=this.targetTriangleDensity;for(const l of s){if(l.material&&(l.geometry?.type==="BoxGeometry"||l.geometry?.type==="BufferGeometry")&&(l.material.name==="SphericalGaussianBlur"||l.material.name=="BackgroundCubeMaterial"||l.material.name==="CubemapFromEquirect"||l.material.name==="EquirectangularToCubeUV")){A&&(l.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(l.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",l,l.material.name,l.material.type)));continue}switch(l.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}const u=l.object;(u instanceof V||u.isMesh)&&this.updateLODs(t,e,u,o)}const i=r.transparent;for(const l of i){const u=l.object;(u instanceof V||u.isMesh)&&this.updateLODs(t,e,u,o)}const a=r.transmissive;for(const l of a){const u=l.object;(u instanceof V||u.isMesh)&&this.updateLODs(t,e,u,o)}}updateLODs(t,e,r,s){r.userData||(r.userData={});let o=r[be];if(o||(o=new Ct,r[be]=o),o.frames++<2)return;for(const a of $)a.onBeforeUpdateLOD?.(this.renderer,t,e,r);const i=this.overrideLodLevel!==void 0?this.overrideLodLevel:X;i>=0?(_.mesh_lod=i,_.texture_lod=i):(this.calculateLodLevel(e,r,o,s,_),_.mesh_lod=Math.round(_.mesh_lod),_.texture_lod=Math.round(_.texture_lod)),_.mesh_lod>=0&&this.loadProgressiveMeshes(r,_.mesh_lod),r.material&&_.texture_lod>=0&&this.loadProgressiveTextures(r.material,_.texture_lod,i),g&&r.material&&!r.isGizmo&&Ie(r.material),Mt&&r.material&&!r.isGizmo&&!r.isBatchedMesh&&qe(r.material,_.mesh_lod);for(const a of $)a.onAfterUpdatedLOD?.(this.renderer,t,e,r,_);o.lastLodLevel_Mesh=_.mesh_lod,o.lastLodLevel_Texture=_.texture_lod}loadProgressiveTextures(t,e,r){if(!t)return;if(Array.isArray(t)){for(const i of t)this.loadProgressiveTextures(i,e,r);return}let s=!1;(t[j]===void 0||e<t[j])&&(s=!0);const o=r!==void 0&&r>=0;if(o&&(s=t[j]!=r,e=r),s){t[j]=e;const i=o?{force:!0}:void 0,a=f.assignTextureLOD(t,e,i).then(l=>{this._lodchangedlisteners.forEach(u=>u({type:"texture",level:e,object:t}))});ue.addPromise("texture",t,a,this._newPromiseGroups)}}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);let r=t[j]!==e;const s=t["DEBUG:LOD"];if(s!=null&&(r=t[j]!=s,e=s),r){t[j]=e;const o=t.geometry,i=f.assignMeshLOD(t,e).then(a=>(a&&t[j]==e&&o!=t.geometry&&this._lodchangedlisteners.forEach(l=>l({type:"mesh",level:e,object:t})),a));return ue.addPromise("mesh",t,i,this._newPromiseGroups),i}return Promise.resolve(null)}_sphere=new Te;_tempWorldPosition=new S;static skinnedMeshBoundsFrameOffsetCounter=0;static $skinnedMeshBoundsOffset=Symbol("gltf-progressive-skinnedMeshBoundsOffset");calculateLodLevel(t,e,r,s,o){if(!e){o.mesh_lod=-1,o.texture_lod=-1;return}if(!t){o.mesh_lod=-1,o.texture_lod=-1;return}let i=10+1,a=!1;if(A&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const l=f.getMeshLODExtension(e.geometry)?.lods,u=f.getPrimitiveIndex(e.geometry),c=l&&l.length>0,d=f.getMaterialMinMaxLODsCount(e.material),p=d.min_count!==1/0&&d.min_count>=0&&d.max_count>=0;if(!c&&!p){o.mesh_lod=0,o.texture_lod=0;return}c||(a=!0,i=0);const m=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let L=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const h=e;if(!h.boundingBox)h.computeBoundingBox();else if(this.skinnedMeshAutoUpdateBoundsInterval>0){if(!h[K.$skinnedMeshBoundsOffset]){const D=K.skinnedMeshBoundsFrameOffsetCounter++;h[K.$skinnedMeshBoundsOffset]=D}const M=h[K.$skinnedMeshBoundsOffset];if((r.frames+M)%this.skinnedMeshAutoUpdateBoundsInterval===0){const D=Y(h),G=h.geometry;D&&(h.geometry=D),h.computeBoundingBox(),h.geometry=G}}L=h.boundingBox}if(L){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)){o.mesh_lod=0,o.texture_lod=0;return}}const h=Be({geometry:e.geometry,matrixWorld:e.matrixWorld,camera:t,projectionScreenMatrix:this.projectionScreenMatrix,desiredDensity:s,canvasHeight:m,currentLevel:r.lastLodLevel_Mesh,boundingBox:L,xrEnabled:this.renderer.xr.enabled,debugDrawLine:A?K.debugDrawLine:void 0,warnMissingPrimitiveDensities:!0});if(r.lastCentrality=h.centrality,r.lastScreenCoverage=h.screenCoverage,r.lastScreenspaceVolume.copy(h.screenspaceVolume),h.screenCoverage===1/0){o.mesh_lod=0,o.texture_lod=0;return}h.level>=0&&h.level<i&&(i=h.level,a=!0)}if(a?o.mesh_lod=i:o.mesh_lod=r.lastLodLevel_Mesh,A&&o.mesh_lod!=r.lastLodLevel_Mesh){const h=l?.[o.mesh_lod];h&&console.log(`Mesh LOD changed: ${r.lastLodLevel_Mesh} \u2192 ${o.mesh_lod} (density: ${h.densities?.[u].toFixed(0)}) | ${e.name}`)}if(p){const h="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(r.lastLodLevel_Texture<0){if(o.texture_lod=d.max_count-1,A){const M=d.lods[d.max_count-1];A&&console.log(`First Texture LOD ${o.texture_lod} (${M.max_height}px) - ${e.name}`)}}else{const M=r.lastScreenspaceVolume.x+r.lastScreenspaceVolume.y+r.lastScreenspaceVolume.z;let D=r.lastScreenCoverage*4;this.context?.engine==="model-viewer"&&(D*=1.5);const G=m/window.devicePixelRatio*D;let E=!1;for(let y=d.lods.length-1;y>=0;y--){const v=d.lods[y];if(!(h&&v.max_height>=2048)&&!(xe()&&v.max_height>4096)&&(v.max_height>G||!E&&y===0)){if(E=!0,o.texture_lod=y,A&&o.texture_lod<r.lastLodLevel_Texture){const R=v.max_height;console.log(`Texture LOD changed: ${r.lastLodLevel_Texture} \u2192 ${o.texture_lod} = ${R}px
8
- Screensize: ${G.toFixed(0)}px, Coverage: ${(100*r.lastScreenCoverage).toFixed(2)}%, Volume ${M.toFixed(1)}
9
- ${e.name}`)}break}}}}else o.texture_lod=0}};class Ct{frames=0;lastLodLevel_Mesh=-1;lastLodLevel_Texture=-1;lastScreenCoverage=0;lastScreenspaceVolume=new S;lastCentrality=0}function qe(n,t){if(!(t<0)){if(Array.isArray(n)){for(const e of n)qe(e,t);return}"color"in n&&n.color instanceof Oe&&(n.color.copy(Ge(t,_t)),n.needsUpdate=!0)}}function Ge(n,t){const e=Math.max(0,Math.min(Ee.length-1,Math.floor(n)));return t.setHex(Ee[e])}const We=Symbol("NEEDLE_mesh_lod"),ce=Symbol("NEEDLE_texture_lod");let De=null;function je(){const n=Pt();n&&(n.mapURLs(function(t){return Ne(),t}),Ne(),De?.disconnect(),De=new MutationObserver(t=>{t.forEach(e=>{e.addedNodes.forEach(r=>{r instanceof HTMLElement&&r.tagName.toLowerCase()==="model-viewer"&&Fe(r)})})}),De.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"),je()}),null)}function Ne(){typeof document>"u"||document.querySelectorAll("model-viewer").forEach(n=>{Fe(n)})}const Ue=new WeakSet;let At=0;function Fe(n){if(!n||Ue.has(n))return null;Ue.add(n),console.debug("[gltf-progressive] found new model-viewer..."+ ++At+`
10
- `,n.getAttribute("src"));let t=null,e=null,r=null;for(let s=n;s!=null;s=Object.getPrototypeOf(s)){const o=Object.getOwnPropertySymbols(s),i=o.find(u=>u.toString()=="Symbol(renderer)"),a=o.find(u=>u.toString()=="Symbol(scene)"),l=o.find(u=>u.toString()=="Symbol(needsRender)");!t&&i!=null&&(t=n[i].threeRenderer),!e&&a!=null&&(e=n[a]),!r&&l!=null&&(r=n[l])}if(t&&e){let s=function(){if(r){let i=0;const a=setInterval(()=>{if(i++>5){clearInterval(a);return}r?.call(n)},300)}};console.debug("[gltf-progressive] setup model-viewer");const o=oe.get(t,{engine:"model-viewer"});return oe.addPlugin(new Rt),o.enable(),o.addEventListener("changed",()=>{r?.call(n)}),n.addEventListener("model-visibility",i=>{i.detail.visible&&r?.call(n)}),n.addEventListener("load",()=>{s()}),()=>{o.disable()}}return null}class Rt{_didWarnAboutMissingUrl=!1;onBeforeUpdateLOD(t,e,r,s){this.tryParseMeshLOD(e,s),this.tryParseTextureLOD(e,s)}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[ce]==!0)return;e[ce]=!0;const r=this.tryGetCurrentGLTF(t),s=this.tryGetCurrentModelViewer(t),o=this.getUrl(s);if(o&&r&&e.material){let i=function(l){if(l[ce]==!0)return;l[ce]=!0,l.userData&&(l.userData.LOD=-1);const u=Object.keys(l);for(let c=0;c<u.length;c++){const d=u[c],p=l[d];if(p?.isTexture===!0){const m=p.userData?.associations?.textures;if(m==null)continue;const L=r.parser.json.textures[m];if(!L){console.warn("Texture data not found for texture index "+m);continue}if(L?.extensions?.[B]){const h=L.extensions[B];h&&o&&f.registerTexture(o,p,h.lods.length,m,h)}}}};const a=e.material;if(Array.isArray(a))for(const l of a)i(l);else i(a)}}tryParseMeshLOD(t,e){if(e[We]==!0)return;e[We]=!0;const r=this.tryGetCurrentModelViewer(t),s=this.getUrl(r);if(!s)return;const o=e.userData?.gltfExtensions?.[B];if(o&&s){const i=e.uuid;f.registerMesh(s,i,e,0,o.lods.length,o)}}}function It(...n){let t,e,r,s;switch(n.length){case 2:[r,e]=n,s={};break;case 3:[r,e,s]=n;break;case 4:[t,e,r,s]=n;break;default:throw new Error("Invalid arguments")}ie(e),ge(r),pe(r,{progressive:!0,...s?.hints}),r.register(i=>new f(i));const o=oe.get(e);return s?.enableLODsManager!==!1&&o.enable(),o}if(je(),!gt){const n={gltfProgressive:{useNeedleProgressive:It,LODsManager:oe,configureLoader:pe,getRaycastMesh:Y,useRaycastMeshes:mt}};if(!globalThis.Needle)globalThis.Needle=n;else for(const t in n)globalThis.Needle[t]=n[t]}export{oe as LODsManager,f as NEEDLE_progressive,ge as addDracoAndKTX2Loaders,Be as calculateMeshLODLevel,pe as configureLoader,ie as createLoaders,Ge as getLODColor,Y as getRaycastMesh,Ce as setDracoDecoderLocation,Pe as setKTX2TranscoderLocation};