@needle-tools/gltf-progressive 3.0.1 → 3.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.
@@ -1,8 +1,8 @@
1
- var Ye=Object.defineProperty,Je=(t,e,s)=>e in t?Ye(t,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):t[e]=s,u=(t,e,s)=>(Je(t,typeof e!="symbol"?e+"":e,s),s),Ee=(t,e,s)=>{if(!e.has(t))throw TypeError("Cannot "+s)},v=(t,e,s)=>(Ee(t,e,"read from private field"),s?s.call(t):e.get(t)),Y=(t,e,s)=>{if(e.has(t))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(t):e.set(t,s)},U=(t,e,s,o)=>(Ee(t,e,"write to private field"),o?o.call(t,s):e.set(t,s),s);import{BufferGeometry as ue,Mesh as J,Texture as se,TextureLoader as Qe,Matrix4 as Ce,Clock as Ze,MeshStandardMaterial as et,Sphere as tt,Box3 as Ie,Vector3 as z}from"three";import{GLTFLoader as ye}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as st}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as rt}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as ot}from"three/examples/jsm/loaders/KTX2Loader.js";const ke="";globalThis.GLTF_PROGRESSIVE_VERSION=ke,console.debug("[gltf-progressive] version -");let $="https://www.gstatic.com/draco/versioned/decoders/1.5.7/",Z="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";const it=$,nt=Z,Be=new URL($+"draco_decoder.js");Be.searchParams.append("range","true"),fetch(Be,{method:"GET",headers:{Range:"bytes=0-1"}}).catch(t=>{console.debug(`Failed to fetch remote Draco decoder from ${$} (offline: ${typeof navigator<"u"?navigator.onLine:"unknown"})`),$===it&&Ge("./include/draco/"),Z===nt&&Re("./include/ktx2/")}).finally(()=>{je()});function Ge(t){$=t,k&&k[Le]!=$?(console.debug("Updating Draco decoder path to "+t),k[Le]=$,k.setDecoderPath($),k.preload()):console.debug("Setting Draco decoder path to "+t)}function Re(t){Z=t,j&&j.transcoderPath!=Z?(console.debug("Updating KTX2 transcoder path to "+t),j.setTranscoderPath(Z),j.init()):console.debug("Setting KTX2 transcoder path to "+t)}const Le=Symbol("dracoDecoderPath");let k,de,j;function je(){k||(k=new rt,k[Le]=$,k.setDecoderPath($),k.setDecoderConfig({type:"js"}),k.preload()),j||(j=new ot,j.setTranscoderPath(Z),j.init()),de||(de=st)}function _e(t){return je(),t?j.detectSupport(t):t!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:k,ktx2Loader:j,meshoptDecoder:de}}function we(t){t.dracoLoader||t.setDRACOLoader(k),t.ktx2Loader||t.setKTX2Loader(j),t.meshoptDecoder||t.setMeshoptDecoder(de)}const Me=new WeakMap;function De(t,e){let s=Me.get(t);s?s=Object.assign(s,e):s=e,Me.set(t,s)}const Ne=ye.prototype.load;function at(...t){const e=Me.get(this);let s=t[0];const o=new URL(s,window.location.href);if(o.hostname.endsWith("needle.tools")){const r=e?.progressive!==void 0?e.progressive:!0,i=e!=null&&e.usecase?e.usecase:"default";r?this.requestHeader.Accept=`*/*;progressive=allowed;usecase=${i}`:this.requestHeader.Accept=`*/*;usecase=${i}`,s=o.toString()}return t[0]=s,Ne?.call(this,...t)}ye.prototype.load=at,re("debugprogressive");function re(t){if(typeof window>"u")return!1;const e=new URL(window.location.href).searchParams.get(t);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function lt(t,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||t===void 0)return e;const s=t.lastIndexOf("/");if(s>=0){const o=t.substring(0,s+1);for(;o.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return o+e}return e}let ce;function ut(){return ce!==void 0||(ce=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),re("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",ce)),ce}function dt(){if(typeof window>"u")return!1;const t=new URL(window.location.href),e=t.hostname==="localhost"||/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(t.hostname);return t.hostname==="127.0.0.1"||e}const ct=typeof window>"u"&&typeof document>"u",be=Symbol("needle:raycast-mesh");function ee(t){return t?.[be]instanceof ue?t[be]:null}function $e(t,e){if((t.type==="Mesh"||t.type==="SkinnedMesh")&&!ee(t)){const s=ht(e);s.userData={isRaycastMesh:!0},t[be]=s}}function We(t=!0){if(t){if(oe)return;const e=oe=J.prototype.raycast;J.prototype.raycast=function(s,o){const r=this,i=ee(r);let n;i&&r.isMesh&&(n=r.geometry,r.geometry=i),e.call(this,s,o),n&&(r.geometry=n)}}else{if(!oe)return;J.prototype.raycast=oe,oe=null}}let oe=null;function ht(t){const e=new ue;for(const s in t.attributes)e.setAttribute(s,t.getAttribute(s));return e.setIndex(t.getIndex()),e}const V=new Array,x=re("debugprogressive");let he,Q=-1;if(x){let t=function(){Q+=1,Q>=e&&(Q=-1),console.log(`Toggle LOD level [${Q}]`)},e=6;window.addEventListener("keyup",s=>{s.key==="p"&&t(),s.key==="w"&&(he=!he,console.log(`Toggle wireframe [${he}]`));const o=parseInt(s.key);!isNaN(o)&&o>=0&&(Q=o,console.log(`Set LOD level to [${Q}]`))})}function Fe(t){if(x)if(Array.isArray(t))for(const e of t)Fe(e);else t&&"wireframe"in t&&(t.wireframe=he===!0)}const W="NEEDLE_progressive",Oe=Symbol("needle-progressive-texture"),M=class{constructor(t,e){u(this,"parser"),u(this,"url"),u(this,"_isLoadingMesh"),u(this,"loadMesh",s=>{var o,r;if(this._isLoadingMesh)return null;const i=(r=(o=this.parser.json.meshes[s])==null?void 0:o.extensions)==null?void 0:r[W];return i?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",s).then(n=>{var l;return this._isLoadingMesh=!1,n&&M.registerMesh(this.url,i.guid,n,(l=i.lods)==null?void 0:l.length,0,i),n})):null}),x&&console.log("Progressive extension registered for",e),this.parser=t,this.url=e}get name(){return W}static getMeshLODExtension(t){const e=this.getAssignedLODInformation(t);return e!=null&&e.key?this.lodInfos.get(e.key):null}static getPrimitiveIndex(t){var e;return((e=this.getAssignedLODInformation(t))==null?void 0:e.index)??-1}static getMaterialMinMaxLODsCount(t,e){const s=this,o="LODS:minmax",r=t[o];if(r!=null)return r;if(e||(e={min_count:1/0,max_count:0,lods:[]}),Array.isArray(t)){for(const n of t)this.getMaterialMinMaxLODsCount(n,e);return t[o]=e,e}if(x==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const n=t;for(const l of Object.keys(n.uniforms)){const d=n.uniforms[l].value;d?.isTexture===!0&&i(d,e)}}else if(t.isMaterial)for(const n of Object.keys(t)){const l=t[n];l?.isTexture===!0&&i(l,e)}return t[o]=e,e;function i(n,l){const d=s.getAssignedLODInformation(n);if(d){const a=s.lodInfos.get(d.key);if(a&&a.lods){l.min_count=Math.min(l.min_count,a.lods.length),l.max_count=Math.max(l.max_count,a.lods.length);for(let h=0;h<a.lods.length;h++){const y=a.lods[h];y.width&&(l.lods[h]=l.lods[h]||{min_height:1/0,max_height:0},l.lods[h].min_height=Math.min(l.lods[h].min_height,y.height),l.lods[h].max_height=Math.max(l.lods[h].max_height,y.height))}}}}}static hasLODLevelAvailable(t,e){var s;if(Array.isArray(t)){for(const i of t)if(this.hasLODLevelAvailable(i,e))return!0;return!1}if(t.isMaterial===!0){for(const i of Object.keys(t)){const n=t[i];if(n&&n.isTexture&&this.hasLODLevelAvailable(n,e))return!0}return!1}else if(t.isGroup===!0){for(const i of t.children)if(i.isMesh===!0&&this.hasLODLevelAvailable(i,e))return!0}let o,r;if(t.isMesh?o=t.geometry:(t.isBufferGeometry||t.isTexture)&&(o=t),o&&(s=o?.userData)!=null&&s.LODS){const i=o.userData.LODS;if(r=this.lodInfos.get(i.key),e===void 0)return r!=null;if(r)return Array.isArray(r.lods)?e<r.lods.length:e===0}return!1}static assignMeshLOD(t,e){var s;if(!t)return Promise.resolve(null);if(t instanceof J||t.isMesh===!0){const o=t.geometry,r=this.getAssignedLODInformation(o);if(!r)return Promise.resolve(null);for(const i of V)(s=i.onBeforeGetLODMesh)==null||s.call(i,t,e);return t["LOD:requested level"]=e,M.getOrLoadLOD(o,e).then(i=>{if(Array.isArray(i)){const n=r.index||0;i=i[n]}return t["LOD:requested level"]===e&&(delete t["LOD:requested level"],i&&o!=i&&(i?.isBufferGeometry?t.geometry=i:x&&console.error("Invalid LOD geometry",i))),i}).catch(i=>(console.error("Error loading mesh LOD",t,i),null))}else x&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",t);return Promise.resolve(null)}static assignTextureLOD(t,e=0){if(!t)return Promise.resolve(null);if(t.isMesh===!0){const s=t;if(Array.isArray(s.material)){const o=new Array;for(const r of s.material){const i=this.assignTextureLOD(r,e);o.push(i)}return Promise.all(o).then(r=>{const i=new Array;for(const n of r)Array.isArray(n)&&i.push(...n);return i})}else return this.assignTextureLOD(s.material,e)}if(t.isMaterial===!0){const s=t,o=[],r=new Array;if(s.uniforms&&(s.isRawShaderMaterial||s.isShaderMaterial===!0)){const i=s;for(const n of Object.keys(i.uniforms)){const l=i.uniforms[n].value;if(l?.isTexture===!0){const d=this.assignTextureLODForSlot(l,e,s,n).then(a=>(a&&i.uniforms[n].value!=a&&(i.uniforms[n].value=a,i.uniformsNeedUpdate=!0),a));o.push(d),r.push(n)}}}else for(const i of Object.keys(s)){const n=s[i];if(n?.isTexture===!0){const l=this.assignTextureLODForSlot(n,e,s,i);o.push(l),r.push(i)}}return Promise.all(o).then(i=>{const n=new Array;for(let l=0;l<i.length;l++){const d=i[l],a=r[l];d&&d.isTexture===!0?n.push({material:s,slot:a,texture:d,level:e}):n.push({material:s,slot:a,texture:null,level:e})}return n})}if(t instanceof se||t.isTexture===!0){const s=t;return this.assignTextureLODForSlot(s,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,s,o){return t?.isTexture!==!0?Promise.resolve(null):o==="glyphMap"?Promise.resolve(t):M.getOrLoadLOD(t,e).then(r=>{if(Array.isArray(r))return null;if(r?.isTexture===!0){if(r!=t&&s&&o){const i=s[o];if(i&&!x){const n=this.getAssignedLODInformation(i);if(n&&n?.level<e)return x==="verbose"&&console.warn("Assigned texture level is already higher: ",n.level,e,s,i,r),null}s[o]=r}return r}else x=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(r=>(console.error("Error loading LOD",t,r),null))}afterRoot(t){var e,s;return x&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((o,r)=>{var i;if(o!=null&&o.extensions){const n=o?.extensions[W];if(n){if(!n.lods){x&&console.warn("Texture has no LODs",n);return}let l=!1;for(const d of this.parser.associations.keys())if(d.isTexture===!0){const a=this.parser.associations.get(d);a?.textures===r&&(l=!0,M.registerTexture(this.url,d,(i=n.lods)==null?void 0:i.length,r,n))}l||this.parser.getDependency("texture",r).then(d=>{var a;d&&M.registerTexture(this.url,d,(a=n.lods)==null?void 0:a.length,r,n)})}}}),(s=this.parser.json.meshes)==null||s.forEach((o,r)=>{if(o!=null&&o.extensions){const i=o?.extensions[W];if(i&&i.lods){for(const n of this.parser.associations.keys())if(n.isMesh){const l=this.parser.associations.get(n);l?.meshes===r&&M.registerMesh(this.url,i.guid,n,i.lods.length,l.primitives,i)}}}}),null}static async getOrLoadLOD(t,e){var s,o,r,i;const n=x=="verbose",l=t.userData.LODS;if(!l)return null;const d=l?.key;let a;if(t.isTexture===!0){const h=t;h.source&&h.source[Oe]&&(a=h.source[Oe])}if(a||(a=M.lodInfos.get(d)),a){if(e>0){let m=!1;const w=Array.isArray(a.lods);if(w&&e>=a.lods.length?m=!0:w||(m=!0),m)return this.lowresCache.get(d)}const h=Array.isArray(a.lods)?(s=a.lods[e])==null?void 0:s.path:a.lods;if(!h)return x&&!a["missing:uri"]&&(a["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,a)),null;const y=lt(l.url,h);if(y.endsWith(".glb")||y.endsWith(".gltf")){if(!a.guid)return console.warn("missing pointer for glb/gltf texture",a),null;const m=y+"_"+a.guid,w=this.previouslyLoaded.get(m);if(w!==void 0){n&&console.log(`LOD ${e} was already loading/loaded: ${m}`);let L=await w.catch(f=>(console.error(`Error loading LOD ${e} from ${y}
2
- `,f),null)),p=!1;if(L==null||(L instanceof se&&t instanceof se?(o=L.image)!=null&&o.data||(r=L.source)!=null&&r.data?L=this.copySettings(t,L):(p=!0,this.previouslyLoaded.delete(m)):L instanceof ue&&t instanceof ue&&((i=L.attributes.position)!=null&&i.array||(p=!0,this.previouslyLoaded.delete(m)))),!p)return L}const b=a,G=new Promise(async(L,p)=>{const f=new ye;we(f),x&&(await new Promise(_=>setTimeout(_,1e3)),n&&console.warn("Start loading (delayed) "+y,b.guid));let F=y;if(b&&Array.isArray(b.lods)){const _=b.lods[e];_.hash&&(F+="?v="+_.hash)}const D=await f.loadAsync(F).catch(_=>(console.error(`Error loading LOD ${e} from ${y}
3
- `,_),null));if(!D)return null;const R=D.parser;n&&console.log("Loading finished "+y,b.guid);let O=0;if(D.parser.json.textures){let _=!1;for(const c of D.parser.json.textures){if(c!=null&&c.extensions){const g=c?.extensions[W];if(g!=null&&g.guid&&g.guid===b.guid){_=!0;break}}O++}if(_){let c=await R.getDependency("texture",O);return c&&M.assignLODInformation(l.url,c,d,e,void 0),n&&console.log('change "'+t.name+'" \u2192 "'+c.name+'"',y,O,c,m),t instanceof se&&(c=this.copySettings(t,c)),c&&(c.guid=b.guid),L(c)}else x&&console.warn("Could not find texture with guid",b.guid,D.parser.json)}if(O=0,D.parser.json.meshes){let _=!1;for(const c of D.parser.json.meshes){if(c!=null&&c.extensions){const g=c?.extensions[W];if(g!=null&&g.guid&&g.guid===b.guid){_=!0;break}}O++}if(_){const c=await R.getDependency("mesh",O);if(n&&console.log(`Loaded Mesh "${c.name}"`,y,O,c,m),c.isMesh===!0){const g=c.geometry;return M.assignLODInformation(l.url,g,d,e,0),L(g)}else{const g=new Array;for(let S=0;S<c.children.length;S++){const C=c.children[S];if(C.isMesh===!0){const I=C.geometry;M.assignLODInformation(l.url,I,d,e,S),g.push(I)}}return L(g)}}else x&&console.warn("Could not find mesh with guid",b.guid,D.parser.json)}return L(null)});return this.previouslyLoaded.set(m,G),await G}else if(t instanceof se){n&&console.log("Load texture from uri: "+y);const m=await new Qe().loadAsync(y);return m?(m.guid=a.guid,m.flipY=!1,m.needsUpdate=!0,m.colorSpace=t.colorSpace,n&&console.log(a,m)):x&&console.warn("failed loading",y),m}}else x&&console.warn(`Can not load LOD ${e}: no LOD info found for "${d}" ${t.name}`,t.type);return null}static assignLODInformation(t,e,s,o,r){if(!e)return;e.userData||(e.userData={});const i=new gt(t,s,o,r);e.userData.LODS=i}static getAssignedLODInformation(t){var e;return((e=t?.userData)==null?void 0:e.LODS)||null}static copySettings(t,e){return e?(x&&console.warn(`Copy texture settings
1
+ var Qe=Object.defineProperty,Ye=(t,e,s)=>e in t?Qe(t,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):t[e]=s,u=(t,e,s)=>(Ye(t,typeof e!="symbol"?e+"":e,s),s),Ee=(t,e,s)=>{if(!e.has(t))throw TypeError("Cannot "+s)},y=(t,e,s)=>(Ee(t,e,"read from private field"),s?s.call(t):e.get(t)),Y=(t,e,s)=>{if(e.has(t))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(t):e.set(t,s)},U=(t,e,s,n)=>(Ee(t,e,"write to private field"),n?n.call(t,s):e.set(t,s),s);import{BufferGeometry as ue,Mesh as Z,Texture as se,TextureLoader as Ze,Matrix4 as Ce,Clock as Je,MeshStandardMaterial as et,Sphere as tt,Box3 as ke,Vector3 as W}from"three";import{GLTFLoader as xe}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as st}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as rt}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as nt}from"three/examples/jsm/loaders/KTX2Loader.js";const Be="";globalThis.GLTF_PROGRESSIVE_VERSION=Be,console.debug("[gltf-progressive] version -");let N="https://www.gstatic.com/draco/versioned/decoders/1.5.7/",ee="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";const ot=N,it=ee,Ie=new URL(N+"draco_decoder.js");Ie.searchParams.append("range","true"),fetch(Ie,{method:"GET",headers:{Range:"bytes=0-1"}}).catch(t=>{console.debug(`Failed to fetch remote Draco decoder from ${N} (offline: ${typeof navigator<"u"?navigator.onLine:"unknown"})`),N===ot&&Ge("./include/draco/"),ee===it&&Re("./include/ktx2/")}).finally(()=>{$e()});function Ge(t){N=t,I&&I[_e]!=N?(console.debug("Updating Draco decoder path to "+t),I[_e]=N,I.setDecoderPath(N),I.preload()):console.debug("Setting Draco decoder path to "+t)}function Re(t){ee=t,R&&R.transcoderPath!=ee?(console.debug("Updating KTX2 transcoder path to "+t),R.setTranscoderPath(ee),R.init()):console.debug("Setting KTX2 transcoder path to "+t)}const _e=Symbol("dracoDecoderPath");let I,de,R;function $e(){I||(I=new rt,I[_e]=N,I.setDecoderPath(N),I.setDecoderConfig({type:"js"}),I.preload()),R||(R=new nt,R.setTranscoderPath(ee),R.init()),de||(de=st)}function Le(t){return $e(),t?R.detectSupport(t):t!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:I,ktx2Loader:R,meshoptDecoder:de}}function we(t){t.dracoLoader||t.setDRACOLoader(I),t.ktx2Loader||t.setKTX2Loader(R),t.meshoptDecoder||t.setMeshoptDecoder(de)}const Me=new WeakMap;function be(t,e){let s=Me.get(t);s?s=Object.assign(s,e):s=e,Me.set(t,s)}const je=xe.prototype.load;function at(...t){const e=Me.get(this);let s=t[0];const n=new URL(s,window.location.href);if(n.hostname.endsWith("needle.tools")){const r=e?.progressive!==void 0?e.progressive:!0,o=e!=null&&e.usecase?e.usecase:"default";r?this.requestHeader.Accept=`*/*;progressive=allowed;usecase=${o}`:this.requestHeader.Accept=`*/*;usecase=${o}`,s=n.toString()}return t[0]=s,je?.call(this,...t)}xe.prototype.load=at,re("debugprogressive");function re(t){if(typeof window>"u")return!1;const e=new URL(window.location.href).searchParams.get(t);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function lt(t,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||t===void 0)return e;const s=t.lastIndexOf("/");if(s>=0){const n=t.substring(0,s+1);for(;n.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return n+e}return e}let ce;function ut(){return ce!==void 0||(ce=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),re("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",ce)),ce}function dt(){if(typeof window>"u")return!1;const t=new URL(window.location.href),e=t.hostname==="localhost"||/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(t.hostname);return t.hostname==="127.0.0.1"||e}class ct{constructor(e=100,s={}){u(this,"_running",new Map),u(this,"_queue",[]),u(this,"debug",!1),u(this,"tick",()=>{this.internalUpdate(),setTimeout(this.tick,10)}),this.maxConcurrent=e,this.debug=s.debug??!1,window.requestAnimationFrame(this.tick)}slot(e){return this.debug&&console.debug(`[PromiseQueue]: Requesting slot for key ${e}, running: ${this._running.size}, waiting: ${this._queue.length}`),new Promise(s=>{this._queue.push({key:e,resolve:s})})}add(e,s){this._running.has(e)||(this._running.set(e,s),s.finally(()=>{this._running.delete(e),this.debug&&console.debug(`[PromiseQueue]: Promise for key ${e} finished, running: ${this._running.size}, waiting: ${this._queue.length}`)}),this.debug&&console.debug(`[PromiseQueue]: Adding promise for key ${e}, running: ${this._running.size}, waiting: ${this._queue.length}`))}internalUpdate(){const e=this.maxConcurrent-this._running.size;for(let s=0;s<e&&this._queue.length>0;s++){this.debug&&console.debug(`[PromiseQueue]: Running ${this._running.size} promises, waiting for ${this._queue.length} more.`);const{key:n,resolve:r}=this._queue.shift();r({use:o=>this.add(n,o)})}}}const ht=typeof window>"u"&&typeof document>"u",De=Symbol("needle:raycast-mesh");function te(t){return t?.[De]instanceof ue?t[De]:null}function Ne(t,e){if((t.type==="Mesh"||t.type==="SkinnedMesh")&&!te(t)){const s=gt(e);s.userData={isRaycastMesh:!0},t[De]=s}}function Fe(t=!0){if(t){if(ne)return;const e=ne=Z.prototype.raycast;Z.prototype.raycast=function(s,n){const r=this,o=te(r);let i;o&&r.isMesh&&(i=r.geometry,r.geometry=o),e.call(this,s,n),i&&(r.geometry=i)}}else{if(!ne)return;Z.prototype.raycast=ne,ne=null}}let ne=null;function gt(t){const e=new ue;for(const s in t.attributes)e.setAttribute(s,t.getAttribute(s));return e.setIndex(t.getIndex()),e}const q=new Array,m=re("debugprogressive");let he,J=-1;if(m){let t=function(){J+=1,J>=e&&(J=-1),console.log(`Toggle LOD level [${J}]`)},e=6;window.addEventListener("keyup",s=>{s.key==="p"&&t(),s.key==="w"&&(he=!he,console.log(`Toggle wireframe [${he}]`));const n=parseInt(s.key);!isNaN(n)&&n>=0&&(J=n,console.log(`Set LOD level to [${J}]`))})}function Ue(t){if(m)if(Array.isArray(t))for(const e of t)Ue(e);else t&&"wireframe"in t&&(t.wireframe=he===!0)}const F="NEEDLE_progressive",Oe=Symbol("needle-progressive-texture"),M=class{constructor(t,e){u(this,"parser"),u(this,"url"),u(this,"_isLoadingMesh"),u(this,"loadMesh",s=>{var n,r;if(this._isLoadingMesh)return null;const o=(r=(n=this.parser.json.meshes[s])==null?void 0:n.extensions)==null?void 0:r[F];return o?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",s).then(i=>{var l;return this._isLoadingMesh=!1,i&&M.registerMesh(this.url,o.guid,i,(l=o.lods)==null?void 0:l.length,0,o),i})):null}),m&&console.log("Progressive extension registered for",e),this.parser=t,this.url=e}get name(){return F}static getMeshLODExtension(t){const e=this.getAssignedLODInformation(t);return e!=null&&e.key?this.lodInfos.get(e.key):null}static getPrimitiveIndex(t){var e;return((e=this.getAssignedLODInformation(t))==null?void 0:e.index)??-1}static getMaterialMinMaxLODsCount(t,e){const s=this,n="LODS:minmax",r=t[n];if(r!=null)return r;if(e||(e={min_count:1/0,max_count:0,lods:[]}),Array.isArray(t)){for(const i of t)this.getMaterialMinMaxLODsCount(i,e);return t[n]=e,e}if(m==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const i=t;for(const l of Object.keys(i.uniforms)){const d=i.uniforms[l].value;d?.isTexture===!0&&o(d,e)}}else if(t.isMaterial)for(const i of Object.keys(t)){const l=t[i];l?.isTexture===!0&&o(l,e)}return t[n]=e,e;function o(i,l){const d=s.getAssignedLODInformation(i);if(d){const a=s.lodInfos.get(d.key);if(a&&a.lods){l.min_count=Math.min(l.min_count,a.lods.length),l.max_count=Math.max(l.max_count,a.lods.length);for(let g=0;g<a.lods.length;g++){const x=a.lods[g];x.width&&(l.lods[g]=l.lods[g]||{min_height:1/0,max_height:0},l.lods[g].min_height=Math.min(l.lods[g].min_height,x.height),l.lods[g].max_height=Math.max(l.lods[g].max_height,x.height))}}}}}static hasLODLevelAvailable(t,e){var s;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 n,r;if(t.isMesh?n=t.geometry:(t.isBufferGeometry||t.isTexture)&&(n=t),n&&(s=n?.userData)!=null&&s.LODS){const o=n.userData.LODS;if(r=this.lodInfos.get(o.key),e===void 0)return r!=null;if(r)return Array.isArray(r.lods)?e<r.lods.length:e===0}return!1}static assignMeshLOD(t,e){var s;if(!t)return Promise.resolve(null);if(t instanceof Z||t.isMesh===!0){const n=t.geometry,r=this.getAssignedLODInformation(n);if(!r)return Promise.resolve(null);for(const o of q)(s=o.onBeforeGetLODMesh)==null||s.call(o,t,e);return t["LOD:requested level"]=e,M.getOrLoadLOD(n,e).then(o=>{if(Array.isArray(o)){const i=r.index||0;o=o[i]}return t["LOD:requested level"]===e&&(delete t["LOD:requested level"],o&&n!=o&&(o?.isBufferGeometry?t.geometry=o:m&&console.error("Invalid LOD geometry",o))),o}).catch(o=>(console.error("Error loading mesh LOD",t,o),null))}else m&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",t);return Promise.resolve(null)}static assignTextureLOD(t,e=0){if(!t)return Promise.resolve(null);if(t.isMesh===!0){const s=t;if(Array.isArray(s.material)){const n=new Array;for(const r of s.material){const o=this.assignTextureLOD(r,e);n.push(o)}return Promise.all(n).then(r=>{const o=new Array;for(const i of r)Array.isArray(i)&&o.push(...i);return o})}else return this.assignTextureLOD(s.material,e)}if(t.isMaterial===!0){const s=t,n=[],r=new Array;if(s.uniforms&&(s.isRawShaderMaterial||s.isShaderMaterial===!0)){const o=s;for(const i of Object.keys(o.uniforms)){const l=o.uniforms[i].value;if(l?.isTexture===!0){const d=this.assignTextureLODForSlot(l,e,s,i).then(a=>(a&&o.uniforms[i].value!=a&&(o.uniforms[i].value=a,o.uniformsNeedUpdate=!0),a));n.push(d),r.push(i)}}}else for(const o of Object.keys(s)){const i=s[o];if(i?.isTexture===!0){const l=this.assignTextureLODForSlot(i,e,s,o);n.push(l),r.push(o)}}return Promise.all(n).then(o=>{const i=new Array;for(let l=0;l<o.length;l++){const d=o[l],a=r[l];d&&d.isTexture===!0?i.push({material:s,slot:a,texture:d,level:e}):i.push({material:s,slot:a,texture:null,level:e})}return i})}if(t instanceof se||t.isTexture===!0){const s=t;return this.assignTextureLODForSlot(s,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,s,n){return t?.isTexture!==!0?Promise.resolve(null):n==="glyphMap"?Promise.resolve(t):M.getOrLoadLOD(t,e).then(r=>{if(Array.isArray(r))return null;if(r?.isTexture===!0){if(r!=t&&s&&n){const o=s[n];if(o&&!m){const i=this.getAssignedLODInformation(o);if(i&&i?.level<e)return m==="verbose"&&console.warn("Assigned texture level is already higher: ",i.level,e,s,o,r),null}s[n]=r}return r}else m=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(r=>(console.error("Error loading LOD",t,r),null))}afterRoot(t){var e,s;return m&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((n,r)=>{var o;if(n!=null&&n.extensions){const i=n?.extensions[F];if(i){if(!i.lods){m&&console.warn("Texture has no LODs",i);return}let l=!1;for(const d of this.parser.associations.keys())if(d.isTexture===!0){const a=this.parser.associations.get(d);a?.textures===r&&(l=!0,M.registerTexture(this.url,d,(o=i.lods)==null?void 0:o.length,r,i))}l||this.parser.getDependency("texture",r).then(d=>{var a;d&&M.registerTexture(this.url,d,(a=i.lods)==null?void 0:a.length,r,i)})}}}),(s=this.parser.json.meshes)==null||s.forEach((n,r)=>{if(n!=null&&n.extensions){const o=n?.extensions[F];if(o&&o.lods){for(const i of this.parser.associations.keys())if(i.isMesh){const l=this.parser.associations.get(i);l?.meshes===r&&M.registerMesh(this.url,o.guid,i,o.lods.length,l.primitives,o)}}}}),null}static async getOrLoadLOD(t,e){var s,n,r,o;const i=m=="verbose",l=t.userData.LODS;if(!l)return null;const d=l?.key;let a;if(t.isTexture===!0){const g=t;g.source&&g.source[Oe]&&(a=g.source[Oe])}if(a||(a=M.lodInfos.get(d)),a){if(e>0){let p=!1;const L=Array.isArray(a.lods);if(L&&e>=a.lods.length?p=!0:L||(p=!0),p)return this.lowresCache.get(d)}const g=Array.isArray(a.lods)?(s=a.lods[e])==null?void 0:s.path:a.lods;if(!g)return m&&!a["missing:uri"]&&(a["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,a)),null;const x=lt(l.url,g);if(x.endsWith(".glb")||x.endsWith(".gltf")){if(!a.guid)return console.warn("missing pointer for glb/gltf texture",a),null;const p=x+"_"+a.guid,L=this.previouslyLoaded.get(p);if(L!==void 0){i&&console.log(`LOD ${e} was already loading/loaded: ${p}`);let h=await L.catch(T=>(console.error(`Error loading LOD ${e} from ${x}
2
+ `,T),null)),v=!1;if(h==null||(h instanceof se&&t instanceof se?(n=h.image)!=null&&n.data||(r=h.source)!=null&&r.data?h=this.copySettings(t,h):(v=!0,this.previouslyLoaded.delete(p)):h instanceof ue&&t instanceof ue&&((o=h.attributes.position)!=null&&o.array||(v=!0,this.previouslyLoaded.delete(p)))),!v)return h}const Q=await this.queue.slot(x);if(!Q.use)return m&&console.log(`LOD ${e} was aborted: ${x}`),null;const w=a,k=new Promise(async(h,v)=>{const T=new xe;we(T),m&&(await new Promise(f=>setTimeout(f,1e3)),i&&console.warn("Start loading (delayed) "+x,w.guid));let G=x;if(w&&Array.isArray(w.lods)){const f=w.lods[e];f.hash&&(G+="?v="+f.hash)}const D=await T.loadAsync(G).catch(f=>(console.error(`Error loading LOD ${e} from ${x}
3
+ `,f),h(null)));if(!D)return h(null);const j=D.parser;i&&console.log("Loading finished "+x,w.guid);let O=0;if(D.parser.json.textures){let f=!1;for(const c of D.parser.json.textures){if(c!=null&&c.extensions){const _=c?.extensions[F];if(_!=null&&_.guid&&_.guid===w.guid){f=!0;break}}O++}if(f){let c=await j.getDependency("texture",O);return c&&M.assignLODInformation(l.url,c,d,e,void 0),i&&console.log('change "'+t.name+'" \u2192 "'+c.name+'"',x,O,c,p),t instanceof se&&(c=this.copySettings(t,c)),c&&(c.guid=w.guid),h(c)}else m&&console.warn("Could not find texture with guid",w.guid,D.parser.json)}if(O=0,D.parser.json.meshes){let f=!1;for(const c of D.parser.json.meshes){if(c!=null&&c.extensions){const _=c?.extensions[F];if(_!=null&&_.guid&&_.guid===w.guid){f=!0;break}}O++}if(f){const c=await j.getDependency("mesh",O);if(i&&console.log(`Loaded Mesh "${c.name}"`,x,O,c,p),c.isMesh===!0){const _=c.geometry;return M.assignLODInformation(l.url,_,d,e,0),h(_)}else{const _=new Array;for(let S=0;S<c.children.length;S++){const B=c.children[S];if(B.isMesh===!0){const z=B.geometry;M.assignLODInformation(l.url,z,d,e,S),_.push(z)}}return h(_)}}else m&&console.warn("Could not find mesh with guid",w.guid,D.parser.json)}return h(null)});return this.previouslyLoaded.set(p,k),Q.use(k),await k}else if(t instanceof se){i&&console.log("Load texture from uri: "+x);const p=await new Ze().loadAsync(x);return p?(p.guid=a.guid,p.flipY=!1,p.needsUpdate=!0,p.colorSpace=t.colorSpace,i&&console.log(a,p)):m&&console.warn("failed loading",x),p}}else m&&console.warn(`Can not load LOD ${e}: no LOD info found for "${d}" ${t.name}`,t.type);return null}static assignLODInformation(t,e,s,n,r){if(!e)return;e.userData||(e.userData={});const o=new ft(t,s,n,r);e.userData.LODS=o}static getAssignedLODInformation(t){var e;return((e=t?.userData)==null?void 0:e.LODS)||null}static copySettings(t,e){return e?(m&&console.warn(`Copy texture settings
4
4
  `,t.uuid,`
5
- `,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}};let P=M;u(P,"registerTexture",(t,e,s,o,r)=>{if(x&&console.log("> Progressive: register texture",o,e.name,e.uuid,e,r),!e){x&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[Oe]=r);const i=r.guid;M.assignLODInformation(t,e,i,s,o),M.lodInfos.set(i,r),M.lowresCache.set(i,e)}),u(P,"registerMesh",(t,e,s,o,r,i)=>{var n;const l=s.geometry;if(!l){x&&console.warn("gltf-progressive: Register mesh without geometry");return}l.userData||(l.userData={}),x&&console.log("> Progressive: register mesh "+s.name,{index:r,uuid:s.uuid},i,s),M.assignLODInformation(t,l,e,o,r),M.lodInfos.set(e,i);let d=M.lowresCache.get(e);d?d.push(s.geometry):d=[s.geometry],M.lowresCache.set(e,d),o>0&&!ee(s)&&$e(s,l);for(const a of V)(n=a.onRegisteredNewMesh)==null||n.call(a,s,i)}),u(P,"lodInfos",new Map),u(P,"previouslyLoaded",new Map),u(P,"lowresCache",new Map);class gt{constructor(e,s,o,r){u(this,"url"),u(this,"key"),u(this,"level"),u(this,"index"),this.url=e,this.key=s,this.level=o,r!=null&&(this.index=r)}}class ge{constructor(e,s){u(this,"frame_start"),u(this,"frame_capture_end"),u(this,"ready"),u(this,"_resolve"),u(this,"_signal"),u(this,"_resolved",!1),u(this,"_addedCount",0),u(this,"_resolvedCount",0),u(this,"_awaiting",[]),u(this,"_maxPromisesPerObject",1),u(this,"_currentFrame",0),u(this,"_seen",new WeakMap);var o;const r=Math.max(s.frames??2,2);this.frame_start=e,this.frame_capture_end=e+r,this.ready=new Promise(i=>{this._resolve=i}),this.ready.finally(()=>{this._resolved=!0,this._awaiting.length=0}),this._signal=s.signal,(o=this._signal)==null||o.addEventListener("abort",()=>{this.resolveNow()}),this._maxPromisesPerObject=Math.max(1,s.maxPromisesPerObject??1)}get awaitedCount(){return this._addedCount}get resolvedCount(){return this._resolvedCount}get currentlyAwaiting(){return this._awaiting.length}update(e){var s;this._currentFrame=e,((s=this._signal)!=null&&s.aborted||this._currentFrame>this.frame_capture_end&&this._awaiting.length===0)&&this.resolveNow()}add(e,s,o){if(this._resolved){x&&console.warn("PromiseGroup: Trying to add a promise to a resolved group, ignoring.");return}if(!(this._currentFrame>this.frame_capture_end)){if(this._maxPromisesPerObject>=1)if(this._seen.has(s)){let r=this._seen.get(s);if(r>=this._maxPromisesPerObject){x&&console.warn("PromiseGroup: Already awaiting object ignoring new promise for it.");return}this._seen.set(s,r+1)}else this._seen.set(s,1);this._awaiting.push(o),this._addedCount++,o.finally(()=>{this._resolvedCount++,this._awaiting.splice(this._awaiting.indexOf(o),1)})}}resolveNow(){var e,s;this._resolved||(s=this._resolve)==null||s.call(this,{awaited_count:this._addedCount,resolved_count:this._resolvedCount,cancelled:((e=this._signal)==null?void 0:e.aborted)??!1})}}u(ge,"addPromise",(t,e,s,o)=>{o.forEach(r=>{r.add(t,e,s)})});const N=re("debugprogressive"),ft=re("noprogressive"),Se=Symbol("Needle:LODSManager"),Pe=Symbol("Needle:LODState"),q=Symbol("Needle:CurrentLOD"),T={mesh_lod:-1,texture_lod:-1};var A,X,Te,K,ie,fe,H;const E=class{constructor(t,e){u(this,"renderer"),u(this,"context"),u(this,"projectionScreenMatrix",new Ce),u(this,"targetTriangleDensity",2e5),u(this,"skinnedMeshAutoUpdateBoundsInterval",30),u(this,"updateInterval","auto"),Y(this,A,1),u(this,"pause",!1),u(this,"manual",!1),u(this,"_newPromiseGroups",[]),u(this,"_promiseGroupIds",0),u(this,"_lodchangedlisteners",[]),Y(this,X,void 0),Y(this,Te,new Ze),Y(this,K,0),Y(this,ie,0),Y(this,fe,0),Y(this,H,0),u(this,"_fpsBuffer",[60,60,60,60,60]),u(this,"_sphere",new tt),u(this,"_tempBox",new Ie),u(this,"_tempBox2",new Ie),u(this,"tempMatrix",new Ce),u(this,"_tempWorldPosition",new z),u(this,"_tempBoxSize",new z),u(this,"_tempBox2Size",new z),this.renderer=t,this.context={...e}}static getObjectLODState(t){return t[Pe]}static addPlugin(t){V.push(t)}static removePlugin(t){const e=V.indexOf(t);e>=0&&V.splice(e,1)}static get(t,e){if(t[Se])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[Se];const s=new E(t,{engine:"unknown",...e});return t[Se]=s,s}get plugins(){return V}awaitLoading(t){const e=this._promiseGroupIds++,s=new ge(v(this,K),{...t});this._newPromiseGroups.push(s);const o=performance.now();return s.ready.finally(()=>{const r=this._newPromiseGroups.indexOf(s);r>=0&&(this._newPromiseGroups.splice(r,1),dt()&&performance.measure("LODsManager:awaitLoading",{start:o,detail:{id:e,name:t?.name,awaited:s.awaitedCount,resolved:s.resolvedCount}}))}),s.ready}_postprocessPromiseGroups(){if(this._newPromiseGroups.length!==0)for(let t=this._newPromiseGroups.length-1;t>=0;t--)this._newPromiseGroups[t].update(v(this,K))}addEventListener(t,e){t==="changed"&&this._lodchangedlisteners.push(e)}removeEventListener(t,e){if(t==="changed"){const s=this._lodchangedlisteners.indexOf(e);s>=0&&this._lodchangedlisteners.splice(s,1)}}enable(){if(v(this,X))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let t=0;U(this,X,this.renderer.render);const e=this;_e(this.renderer),this.renderer.render=function(s,o){const r=e.renderer.getRenderTarget();(r==null||"isXRRenderTarget"in r&&r.isXRRenderTarget)&&(t=0,U(e,K,v(e,K)+1),U(e,ie,v(e,Te).getDelta()),U(e,fe,v(e,fe)+v(e,ie)),e._fpsBuffer.shift(),e._fpsBuffer.push(1/v(e,ie)),U(e,H,e._fpsBuffer.reduce((n,l)=>n+l)/e._fpsBuffer.length),N&&v(e,K)%200===0&&console.log("FPS",Math.round(v(e,H)),"Interval:",v(e,A)));const i=t++;v(e,X).call(this,s,o),e.onAfterRender(s,o,i)}}disable(){v(this,X)&&(console.debug("[gltf-progressive] Disabling LODsManager for renderer"),this.renderer.render=v(this,X),U(this,X,void 0))}update(t,e){this.internalUpdate(t,e)}onAfterRender(t,e,s){if(this.pause)return;const o=this.renderer.renderLists.get(t,0).opaque;let r=!0;if(o.length===1){const i=o[0].material;(i.name==="EffectMaterial"||i.name==="CopyShader")&&(r=!1)}if((e.parent&&e.parent.type==="CubeCamera"||s>=1&&e.type==="OrthographicCamera")&&(r=!1),r){if(ft||(this.updateInterval==="auto"?v(this,H)<40&&v(this,A)<10?(U(this,A,v(this,A)+1),N&&console.warn("\u2193 Reducing LOD updates",v(this,A),v(this,H).toFixed(0))):v(this,H)>=60&&v(this,A)>1&&(U(this,A,v(this,A)-1),N&&console.warn("\u2191 Increasing LOD updates",v(this,A),v(this,H).toFixed(0))):U(this,A,this.updateInterval),v(this,A)>0&&v(this,K)%v(this,A)!=0))return;this.internalUpdate(t,e),this._postprocessPromiseGroups()}}internalUpdate(t,e){var s,o;const r=this.renderer.renderLists.get(t,0),i=r.opaque;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse);const n=this.targetTriangleDensity;for(const a of i){if(a.material&&(((s=a.geometry)==null?void 0:s.type)==="BoxGeometry"||((o=a.geometry)==null?void 0:o.type)==="BufferGeometry")&&(a.material.name==="SphericalGaussianBlur"||a.material.name=="BackgroundCubeMaterial"||a.material.name==="CubemapFromEquirect"||a.material.name==="EquirectangularToCubeUV")){N&&(a.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(a.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",a,a.material.name,a.material.type)));continue}switch(a.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}if(N==="color"&&a.material&&!a.object.progressive_debug_color){a.object.progressive_debug_color=!0;const y=Math.random()*16777215,m=new et({color:y});a.object.material=m}const h=a.object;(h instanceof J||h.isMesh)&&this.updateLODs(t,e,h,n)}const l=r.transparent;for(const a of l){const h=a.object;(h instanceof J||h.isMesh)&&this.updateLODs(t,e,h,n)}const d=r.transmissive;for(const a of d){const h=a.object;(h instanceof J||h.isMesh)&&this.updateLODs(t,e,h,n)}}updateLODs(t,e,s,o){var r,i;s.userData||(s.userData={});let n=s[Pe];if(n||(n=new mt,s[Pe]=n),n.frames++<2)return;for(const d of V)(r=d.onBeforeUpdateLOD)==null||r.call(d,this.renderer,t,e,s);const l=E.overrideGlobalLodLevel!==void 0?E.overrideGlobalLodLevel:Q;l>=0?(T.mesh_lod=l,T.texture_lod=l):(this.calculateLodLevel(e,s,n,o,T),T.mesh_lod=Math.round(T.mesh_lod),T.texture_lod=Math.round(T.texture_lod)),T.mesh_lod>=0&&this.loadProgressiveMeshes(s,T.mesh_lod),s.material&&T.texture_lod>=0&&this.loadProgressiveTextures(s.material,T.texture_lod),x&&s.material&&!s.isGizmo&&Fe(s.material);for(const d of V)(i=d.onAfterUpdatedLOD)==null||i.call(d,this.renderer,t,e,s,T);n.lastLodLevel_Mesh=T.mesh_lod,n.lastLodLevel_Texture=T.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const r of t)this.loadProgressiveTextures(r,e);return}let s=!1;(t[q]===void 0||e<t[q])&&(s=!0);const o=t["DEBUG:LOD"];if(o!=null&&(s=t[q]!=o,e=o),s){t[q]=e;const r=P.assignTextureLOD(t,e).then(i=>{this._lodchangedlisteners.forEach(n=>n({type:"texture",level:e,object:t}))});ge.addPromise("texture",t,r,this._newPromiseGroups)}}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);let s=t[q]!==e;const o=t["DEBUG:LOD"];if(o!=null&&(s=t[q]!=o,e=o),s){t[q]=e;const r=t.geometry,i=P.assignMeshLOD(t,e).then(n=>(n&&t[q]==e&&r!=t.geometry&&this._lodchangedlisteners.forEach(l=>l({type:"mesh",level:e,object:t})),n));return ge.addPromise("mesh",t,i,this._newPromiseGroups),i}return Promise.resolve(null)}static isInside(t,e){const s=t.min,o=t.max,r=(s.x+o.x)*.5,i=(s.y+o.y)*.5;return this._tempPtInside.set(r,i,s.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,s,o,r){var i,n,l;if(!e){r.mesh_lod=-1,r.texture_lod=-1;return}if(!t){r.mesh_lod=-1,r.texture_lod=-1;return}let d=10+1,a=!1;if(N&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const h=(i=P.getMeshLODExtension(e.geometry))==null?void 0:i.lods,y=P.getPrimitiveIndex(e.geometry),m=h&&h.length>0,w=P.getMaterialMinMaxLODsCount(e.material),b=w?.min_count!=1/0&&w.min_count>0&&w.max_count>0;if(!m&&!b){r.mesh_lod=0,r.texture_lod=0;return}m||(a=!0,d=0);const G=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let L=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const p=e;if(!p.boundingBox)p.computeBoundingBox();else if(this.skinnedMeshAutoUpdateBoundsInterval>0&&s.frames%this.skinnedMeshAutoUpdateBoundsInterval===0){const f=ee(p),F=p.geometry;f&&(p.geometry=f),p.computeBoundingBox(),p.geometry=F}L=p.boundingBox}if(L){const p=t;if(e.geometry.attributes.color&&e.geometry.attributes.color.count<100&&e.geometry.boundingSphere){this._sphere.copy(e.geometry.boundingSphere),this._sphere.applyMatrix4(e.matrixWorld);const c=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(c)){r.mesh_lod=0,r.texture_lod=0;return}}if(this._tempBox.copy(L),this._tempBox.applyMatrix4(e.matrixWorld),p.isPerspectiveCamera&&E.isInside(this._tempBox,this.projectionScreenMatrix)){r.mesh_lod=0,r.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&p.isPerspectiveCamera&&p.fov>70){const c=this._tempBox.min,g=this._tempBox.max;let S=c.x,C=c.y,I=g.x,te=g.y;const ne=2,ve=1.5,ae=(c.x+g.x)*.5,le=(c.y+g.y)*.5;S=(S-ae)*ne+ae,C=(C-le)*ne+le,I=(I-ae)*ne+ae,te=(te-le)*ne+le;const Ke=S<0&&I>0?0:Math.min(Math.abs(c.x),Math.abs(g.x)),He=C<0&&te>0?0:Math.min(Math.abs(c.y),Math.abs(g.y)),xe=Math.max(Ke,He);s.lastCentrality=(ve-xe)*(ve-xe)*(ve-xe)}else s.lastCentrality=1;const f=this._tempBox.getSize(this._tempBoxSize);f.multiplyScalar(.5),screen.availHeight>0&&G>0&&f.multiplyScalar(G/screen.availHeight),t.isPerspectiveCamera?f.x*=t.aspect:t.isOrthographicCamera;const F=t.matrixWorldInverse,D=this._tempBox2;D.copy(L),D.applyMatrix4(e.matrixWorld),D.applyMatrix4(F);const R=D.getSize(this._tempBox2Size),O=Math.max(R.x,R.y);if(Math.max(f.x,f.y)!=0&&O!=0&&(f.z=R.z/Math.max(R.x,R.y)*Math.max(f.x,f.y)),s.lastScreenCoverage=Math.max(f.x,f.y,f.z),s.lastScreenspaceVolume.copy(f),s.lastScreenCoverage*=s.lastCentrality,N&&E.debugDrawLine){const c=this.tempMatrix.copy(this.projectionScreenMatrix);c.invert();const g=E.corner0,S=E.corner1,C=E.corner2,I=E.corner3;g.copy(this._tempBox.min),S.copy(this._tempBox.max),S.x=g.x,C.copy(this._tempBox.max),C.y=g.y,I.copy(this._tempBox.max);const te=(g.z+I.z)*.5;g.z=S.z=C.z=I.z=te,g.applyMatrix4(c),S.applyMatrix4(c),C.applyMatrix4(c),I.applyMatrix4(c),E.debugDrawLine(g,S,255),E.debugDrawLine(g,C,255),E.debugDrawLine(S,I,255),E.debugDrawLine(C,I,255)}let _=999;if(h&&s.lastScreenCoverage>0)for(let c=0;c<h.length;c++){const g=h[c];if((((n=g.densities)==null?void 0:n[y])||g.density||1e-5)/s.lastScreenCoverage<o){_=c;break}}_<d&&(d=_,a=!0)}if(a?r.mesh_lod=d:r.mesh_lod=s.lastLodLevel_Mesh,N&&r.mesh_lod!=s.lastLodLevel_Mesh){const p=h?.[r.mesh_lod];p&&console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} \u2192 ${r.mesh_lod} (${p.density.toFixed(0)}) - ${e.name}`)}if(b){const p="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(s.lastLodLevel_Texture<0){if(r.texture_lod=w.max_count-1,N){const f=w.lods[w.max_count-1];N&&console.log(`First Texture LOD ${r.texture_lod} (${f.max_height}px) - ${e.name}`)}}else{const f=s.lastScreenspaceVolume.x+s.lastScreenspaceVolume.y+s.lastScreenspaceVolume.z;let F=s.lastScreenCoverage*4;((l=this.context)==null?void 0:l.engine)==="model-viewer"&&(F*=1.5);const D=G/window.devicePixelRatio*F;let R=!1;for(let O=w.lods.length-1;O>=0;O--){const _=w.lods[O];if(!(p&&_.max_height>=2048)&&!(ut()&&_.max_height>4096)&&(_.max_height>D||!R&&O===0)){if(R=!0,r.texture_lod=O,r.texture_lod<s.lastLodLevel_Texture){const c=_.max_height;N&&console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} \u2192 ${r.texture_lod} = ${c}px
6
- Screensize: ${D.toFixed(0)}px, Coverage: ${(100*s.lastScreenCoverage).toFixed(2)}%, Volume ${f.toFixed(1)}
7
- ${e.name}`)}break}}}}else r.texture_lod=0}};let B=E;A=new WeakMap,X=new WeakMap,Te=new WeakMap,K=new WeakMap,ie=new WeakMap,fe=new WeakMap,H=new WeakMap,u(B,"debugDrawLine"),u(B,"overrideGlobalLodLevel"),u(B,"corner0",new z),u(B,"corner1",new z),u(B,"corner2",new z),u(B,"corner3",new z),u(B,"_tempPtInside",new z);class mt{constructor(){u(this,"frames",0),u(this,"lastLodLevel_Mesh",-1),u(this,"lastLodLevel_Texture",-1),u(this,"lastScreenCoverage",0),u(this,"lastScreenspaceVolume",new z),u(this,"lastCentrality",0)}}const Ue=Symbol("NEEDLE_mesh_lod"),me=Symbol("NEEDLE_texture_lod");let pe=null;function Ae(){const t=pt();t&&(t.mapURLs(function(e){return ze(),e}),ze(),pe?.disconnect(),pe=new MutationObserver(e=>{e.forEach(s=>{s.addedNodes.forEach(o=>{o instanceof HTMLElement&&o.tagName.toLowerCase()==="model-viewer"&&qe(o)})})}),pe.observe(document,{childList:!0,subtree:!0}))}function pt(){return typeof customElements>"u"?null:customElements.get("model-viewer")||(customElements.whenDefined("model-viewer").then(()=>{console.debug("[gltf-progressive] model-viewer defined"),Ae()}),null)}function ze(){typeof document>"u"||document.querySelectorAll("model-viewer").forEach(t=>{qe(t)})}const Ve=new WeakSet;let vt=0;function qe(t){if(!t||Ve.has(t))return null;Ve.add(t),console.debug("[gltf-progressive] found new model-viewer..."+ ++vt+`
8
- `,t.getAttribute("src"));let e=null,s=null,o=null;for(let r=t;r!=null;r=Object.getPrototypeOf(r)){const i=Object.getOwnPropertySymbols(r),n=i.find(a=>a.toString()=="Symbol(renderer)"),l=i.find(a=>a.toString()=="Symbol(scene)"),d=i.find(a=>a.toString()=="Symbol(needsRender)");!e&&n!=null&&(e=t[n].threeRenderer),!s&&l!=null&&(s=t[l]),!o&&d!=null&&(o=t[d])}if(e&&s){let r=function(){if(o){let n=0,l=setInterval(()=>{if(n++>5){clearInterval(l);return}o?.call(t)},300)}};console.debug("[gltf-progressive] setup model-viewer");const i=B.get(e,{engine:"model-viewer"});return B.addPlugin(new xt),i.enable(),i.addEventListener("changed",()=>{o?.call(t)}),t.addEventListener("model-visibility",n=>{n.detail.visible&&o?.call(t)}),t.addEventListener("load",()=>{r()}),()=>{i.disable()}}return null}class xt{constructor(){u(this,"_didWarnAboutMissingUrl",!1)}onBeforeUpdateLOD(e,s,o,r){this.tryParseMeshLOD(s,r),this.tryParseTextureLOD(s,r)}getUrl(e){if(!e)return null;let s=e.getAttribute("src");return s||(s=e.src),s||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",e),this._didWarnAboutMissingUrl=!0),s}tryGetCurrentGLTF(e){return e._currentGLTF}tryGetCurrentModelViewer(e){return e.element}tryParseTextureLOD(e,s){if(s[me]==!0)return;s[me]=!0;const o=this.tryGetCurrentGLTF(e),r=this.tryGetCurrentModelViewer(e),i=this.getUrl(r);if(i&&o&&s.material){let n=function(d){var a,h,y;if(d[me]==!0)return;d[me]=!0,d.userData&&(d.userData.LOD=-1);const m=Object.keys(d);for(let w=0;w<m.length;w++){const b=m[w],G=d[b];if(G?.isTexture===!0){const L=(h=(a=G.userData)==null?void 0:a.associations)==null?void 0:h.textures;if(L==null)continue;const p=o.parser.json.textures[L];if(!p){console.warn("Texture data not found for texture index "+L);continue}if((y=p?.extensions)!=null&&y[W]){const f=p.extensions[W];f&&i&&P.registerTexture(i,G,f.lods.length,L,f)}}}};const l=s.material;if(Array.isArray(l))for(const d of l)n(d);else n(l)}}tryParseMeshLOD(e,s){var o,r;if(s[Ue]==!0)return;s[Ue]=!0;const i=this.tryGetCurrentModelViewer(e),n=this.getUrl(i);if(!n)return;const l=(r=(o=s.userData)==null?void 0:o.gltfExtensions)==null?void 0:r[W];if(l&&n){const d=s.uuid;P.registerMesh(n,d,s,0,l.lods.length,l)}}}function Xe(t,e,s,o){_e(e),we(s),De(s,{progressive:!0,...o?.hints}),s.register(i=>new P(i,t));const r=B.get(e);return o?.enableLODsManager!==!1&&r.enable(),r}if(Ae(),!ct){const t={gltfProgressive:{useNeedleProgressive:Xe,LODsManager:B,configureLoader:De,getRaycastMesh:ee,useRaycastMeshes:We}};if(!globalThis.Needle)globalThis.Needle=t;else for(const e in t)globalThis.Needle[e]=t[e]}export{W as EXTENSION_NAME,B as LODsManager,P as NEEDLE_progressive,ke as VERSION,we as addDracoAndKTX2Loaders,De as configureLoader,_e as createLoaders,ee as getRaycastMesh,Ae as patchModelViewer,$e as registerRaycastMesh,Ge as setDracoDecoderLocation,Re as setKTX2TranscoderLocation,Xe as useNeedleProgressive,We as useRaycastMeshes};
5
+ `,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}};let P=M;u(P,"registerTexture",(t,e,s,n,r)=>{if(m&&console.log("> Progressive: register texture",n,e.name,e.uuid,e,r),!e){m&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[Oe]=r);const o=r.guid;M.assignLODInformation(t,e,o,s,n),M.lodInfos.set(o,r),M.lowresCache.set(o,e)}),u(P,"registerMesh",(t,e,s,n,r,o)=>{var i;const l=s.geometry;if(!l){m&&console.warn("gltf-progressive: Register mesh without geometry");return}l.userData||(l.userData={}),m&&console.log("> Progressive: register mesh "+s.name,{index:r,uuid:s.uuid},o,s),M.assignLODInformation(t,l,e,n,r),M.lodInfos.set(e,o);let d=M.lowresCache.get(e);d?d.push(s.geometry):d=[s.geometry],M.lowresCache.set(e,d),n>0&&!te(s)&&Ne(s,l);for(const a of q)(i=a.onRegisteredNewMesh)==null||i.call(a,s,o)}),u(P,"lodInfos",new Map),u(P,"previouslyLoaded",new Map),u(P,"lowresCache",new Map),u(P,"queue",new ct(100,{debug:m!=!1}));class ft{constructor(e,s,n,r){u(this,"url"),u(this,"key"),u(this,"level"),u(this,"index"),this.url=e,this.key=s,this.level=n,r!=null&&(this.index=r)}}class ge{constructor(e,s){u(this,"frame_start"),u(this,"frame_capture_end"),u(this,"ready"),u(this,"_resolve"),u(this,"_signal"),u(this,"_resolved",!1),u(this,"_addedCount",0),u(this,"_resolvedCount",0),u(this,"_awaiting",[]),u(this,"_maxPromisesPerObject",1),u(this,"_currentFrame",0),u(this,"_seen",new WeakMap);var n;const r=Math.max(s.frames??2,2);this.frame_start=e,this.frame_capture_end=e+r,this.ready=new Promise(o=>{this._resolve=o}),this.ready.finally(()=>{this._resolved=!0,this._awaiting.length=0}),this._signal=s.signal,(n=this._signal)==null||n.addEventListener("abort",()=>{this.resolveNow()}),this._maxPromisesPerObject=Math.max(1,s.maxPromisesPerObject??1)}get awaitedCount(){return this._addedCount}get resolvedCount(){return this._resolvedCount}get currentlyAwaiting(){return this._awaiting.length}update(e){var s;this._currentFrame=e,((s=this._signal)!=null&&s.aborted||this._currentFrame>this.frame_capture_end&&this._awaiting.length===0)&&this.resolveNow()}add(e,s,n){if(this._resolved){m&&console.warn("PromiseGroup: Trying to add a promise to a resolved group, ignoring.");return}if(!(this._currentFrame>this.frame_capture_end)){if(this._maxPromisesPerObject>=1)if(this._seen.has(s)){let r=this._seen.get(s);if(r>=this._maxPromisesPerObject){m&&console.warn("PromiseGroup: Already awaiting object ignoring new promise for it.");return}this._seen.set(s,r+1)}else this._seen.set(s,1);this._awaiting.push(n),this._addedCount++,n.finally(()=>{this._resolvedCount++,this._awaiting.splice(this._awaiting.indexOf(n),1)})}}resolveNow(){var e,s;this._resolved||(s=this._resolve)==null||s.call(this,{awaited_count:this._addedCount,resolved_count:this._resolvedCount,cancelled:((e=this._signal)==null?void 0:e.aborted)??!1})}}u(ge,"addPromise",(t,e,s,n)=>{n.forEach(r=>{r.add(t,e,s)})});const $=re("debugprogressive"),mt=re("noprogressive"),Se=Symbol("Needle:LODSManager"),Pe=Symbol("Needle:LODState"),V=Symbol("Needle:CurrentLOD"),A={mesh_lod:-1,texture_lod:-1};var E,X,Te,K,oe,fe,H;const b=class{constructor(t,e){u(this,"renderer"),u(this,"context"),u(this,"projectionScreenMatrix",new Ce),u(this,"targetTriangleDensity",2e5),u(this,"skinnedMeshAutoUpdateBoundsInterval",30),u(this,"updateInterval","auto"),Y(this,E,1),u(this,"pause",!1),u(this,"manual",!1),u(this,"_newPromiseGroups",[]),u(this,"_promiseGroupIds",0),u(this,"_lodchangedlisteners",[]),Y(this,X,void 0),Y(this,Te,new Je),Y(this,K,0),Y(this,oe,0),Y(this,fe,0),Y(this,H,0),u(this,"_fpsBuffer",[60,60,60,60,60]),u(this,"_sphere",new tt),u(this,"_tempBox",new ke),u(this,"_tempBox2",new ke),u(this,"tempMatrix",new Ce),u(this,"_tempWorldPosition",new W),u(this,"_tempBoxSize",new W),u(this,"_tempBox2Size",new W),this.renderer=t,this.context={...e}}static getObjectLODState(t){return t[Pe]}static addPlugin(t){q.push(t)}static removePlugin(t){const e=q.indexOf(t);e>=0&&q.splice(e,1)}static get(t,e){if(t[Se])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[Se];const s=new b(t,{engine:"unknown",...e});return t[Se]=s,s}get plugins(){return q}awaitLoading(t){const e=this._promiseGroupIds++,s=new ge(y(this,K),{...t});this._newPromiseGroups.push(s);const n=performance.now();return s.ready.finally(()=>{const r=this._newPromiseGroups.indexOf(s);r>=0&&(this._newPromiseGroups.splice(r,1),dt()&&performance.measure("LODsManager:awaitLoading",{start:n,detail:{id:e,name:t?.name,awaited:s.awaitedCount,resolved:s.resolvedCount}}))}),s.ready}_postprocessPromiseGroups(){if(this._newPromiseGroups.length!==0)for(let t=this._newPromiseGroups.length-1;t>=0;t--)this._newPromiseGroups[t].update(y(this,K))}addEventListener(t,e){t==="changed"&&this._lodchangedlisteners.push(e)}removeEventListener(t,e){if(t==="changed"){const s=this._lodchangedlisteners.indexOf(e);s>=0&&this._lodchangedlisteners.splice(s,1)}}enable(){if(y(this,X))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let t=0;U(this,X,this.renderer.render);const e=this;Le(this.renderer),this.renderer.render=function(s,n){const r=e.renderer.getRenderTarget();(r==null||"isXRRenderTarget"in r&&r.isXRRenderTarget)&&(t=0,U(e,K,y(e,K)+1),U(e,oe,y(e,Te).getDelta()),U(e,fe,y(e,fe)+y(e,oe)),e._fpsBuffer.shift(),e._fpsBuffer.push(1/y(e,oe)),U(e,H,e._fpsBuffer.reduce((i,l)=>i+l)/e._fpsBuffer.length),$&&y(e,K)%200===0&&console.log("FPS",Math.round(y(e,H)),"Interval:",y(e,E)));const o=t++;y(e,X).call(this,s,n),e.onAfterRender(s,n,o)}}disable(){y(this,X)&&(console.debug("[gltf-progressive] Disabling LODsManager for renderer"),this.renderer.render=y(this,X),U(this,X,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 r=!0;if(n.length===1){const o=n[0].material;(o.name==="EffectMaterial"||o.name==="CopyShader")&&(r=!1)}if((e.parent&&e.parent.type==="CubeCamera"||s>=1&&e.type==="OrthographicCamera")&&(r=!1),r){if(mt||(this.updateInterval==="auto"?y(this,H)<40&&y(this,E)<10?(U(this,E,y(this,E)+1),$&&console.warn("\u2193 Reducing LOD updates",y(this,E),y(this,H).toFixed(0))):y(this,H)>=60&&y(this,E)>1&&(U(this,E,y(this,E)-1),$&&console.warn("\u2191 Increasing LOD updates",y(this,E),y(this,H).toFixed(0))):U(this,E,this.updateInterval),y(this,E)>0&&y(this,K)%y(this,E)!=0))return;this.internalUpdate(t,e),this._postprocessPromiseGroups()}}internalUpdate(t,e){var s,n;const r=this.renderer.renderLists.get(t,0),o=r.opaque;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse);const i=this.targetTriangleDensity;for(const a of o){if(a.material&&(((s=a.geometry)==null?void 0:s.type)==="BoxGeometry"||((n=a.geometry)==null?void 0:n.type)==="BufferGeometry")&&(a.material.name==="SphericalGaussianBlur"||a.material.name=="BackgroundCubeMaterial"||a.material.name==="CubemapFromEquirect"||a.material.name==="EquirectangularToCubeUV")){$&&(a.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(a.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",a,a.material.name,a.material.type)));continue}switch(a.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}if($==="color"&&a.material&&!a.object.progressive_debug_color){a.object.progressive_debug_color=!0;const x=Math.random()*16777215,p=new et({color:x});a.object.material=p}const g=a.object;(g instanceof Z||g.isMesh)&&this.updateLODs(t,e,g,i)}const l=r.transparent;for(const a of l){const g=a.object;(g instanceof Z||g.isMesh)&&this.updateLODs(t,e,g,i)}const d=r.transmissive;for(const a of d){const g=a.object;(g instanceof Z||g.isMesh)&&this.updateLODs(t,e,g,i)}}updateLODs(t,e,s,n){var r,o;s.userData||(s.userData={});let i=s[Pe];if(i||(i=new pt,s[Pe]=i),i.frames++<2)return;for(const d of q)(r=d.onBeforeUpdateLOD)==null||r.call(d,this.renderer,t,e,s);const l=b.overrideGlobalLodLevel!==void 0?b.overrideGlobalLodLevel:J;l>=0?(A.mesh_lod=l,A.texture_lod=l):(this.calculateLodLevel(e,s,i,n,A),A.mesh_lod=Math.round(A.mesh_lod),A.texture_lod=Math.round(A.texture_lod)),A.mesh_lod>=0&&this.loadProgressiveMeshes(s,A.mesh_lod),s.material&&A.texture_lod>=0&&this.loadProgressiveTextures(s.material,A.texture_lod),m&&s.material&&!s.isGizmo&&Ue(s.material);for(const d of q)(o=d.onAfterUpdatedLOD)==null||o.call(d,this.renderer,t,e,s,A);i.lastLodLevel_Mesh=A.mesh_lod,i.lastLodLevel_Texture=A.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const r of t)this.loadProgressiveTextures(r,e);return}let s=!1;(t[V]===void 0||e<t[V])&&(s=!0);const n=t["DEBUG:LOD"];if(n!=null&&(s=t[V]!=n,e=n),s){t[V]=e;const r=P.assignTextureLOD(t,e).then(o=>{this._lodchangedlisteners.forEach(i=>i({type:"texture",level:e,object:t}))});ge.addPromise("texture",t,r,this._newPromiseGroups)}}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);let s=t[V]!==e;const n=t["DEBUG:LOD"];if(n!=null&&(s=t[V]!=n,e=n),s){t[V]=e;const r=t.geometry,o=P.assignMeshLOD(t,e).then(i=>(i&&t[V]==e&&r!=t.geometry&&this._lodchangedlisteners.forEach(l=>l({type:"mesh",level:e,object:t})),i));return ge.addPromise("mesh",t,o,this._newPromiseGroups),o}return Promise.resolve(null)}static isInside(t,e){const s=t.min,n=t.max,r=(s.x+n.x)*.5,o=(s.y+n.y)*.5;return this._tempPtInside.set(r,o,s.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,s,n,r){var o,i,l;if(!e){r.mesh_lod=-1,r.texture_lod=-1;return}if(!t){r.mesh_lod=-1,r.texture_lod=-1;return}let d=10+1,a=!1;if($&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const g=(o=P.getMeshLODExtension(e.geometry))==null?void 0:o.lods,x=P.getPrimitiveIndex(e.geometry),p=g&&g.length>0,L=P.getMaterialMinMaxLODsCount(e.material),Q=L?.min_count!=1/0&&L.min_count>0&&L.max_count>0;if(!p&&!Q){r.mesh_lod=0,r.texture_lod=0;return}p||(a=!0,d=0);const w=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let k=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const h=e;if(!h.boundingBox)h.computeBoundingBox();else if(this.skinnedMeshAutoUpdateBoundsInterval>0){if(!h[b.$skinnedMeshBoundsOffset]){const T=b.skinnedMeshBoundsFrameOffsetCounter++;h[b.$skinnedMeshBoundsOffset]=T}const v=h[b.$skinnedMeshBoundsOffset];if((s.frames+v)%this.skinnedMeshAutoUpdateBoundsInterval===0){const T=te(h),G=h.geometry;T&&(h.geometry=T),h.computeBoundingBox(),h.geometry=G}}k=h.boundingBox}if(k){const h=t;if(e.geometry.attributes.color&&e.geometry.attributes.color.count<100&&e.geometry.boundingSphere){this._sphere.copy(e.geometry.boundingSphere),this._sphere.applyMatrix4(e.matrixWorld);const f=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(f)){r.mesh_lod=0,r.texture_lod=0;return}}if(this._tempBox.copy(k),this._tempBox.applyMatrix4(e.matrixWorld),h.isPerspectiveCamera&&b.isInside(this._tempBox,this.projectionScreenMatrix)){r.mesh_lod=0,r.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&h.isPerspectiveCamera&&h.fov>70){const f=this._tempBox.min,c=this._tempBox.max;let _=f.x,S=f.y,B=c.x,z=c.y;const ie=2,ve=1.5,ae=(f.x+c.x)*.5,le=(f.y+c.y)*.5;_=(_-ae)*ie+ae,S=(S-le)*ie+le,B=(B-ae)*ie+ae,z=(z-le)*ie+le;const Ke=_<0&&B>0?0:Math.min(Math.abs(f.x),Math.abs(c.x)),He=S<0&&z>0?0:Math.min(Math.abs(f.y),Math.abs(c.y)),ye=Math.max(Ke,He);s.lastCentrality=(ve-ye)*(ve-ye)*(ve-ye)}else s.lastCentrality=1;const v=this._tempBox.getSize(this._tempBoxSize);v.multiplyScalar(.5),screen.availHeight>0&&w>0&&v.multiplyScalar(w/screen.availHeight),t.isPerspectiveCamera?v.x*=t.aspect:t.isOrthographicCamera;const T=t.matrixWorldInverse,G=this._tempBox2;G.copy(k),G.applyMatrix4(e.matrixWorld),G.applyMatrix4(T);const D=G.getSize(this._tempBox2Size),j=Math.max(D.x,D.y);if(Math.max(v.x,v.y)!=0&&j!=0&&(v.z=D.z/Math.max(D.x,D.y)*Math.max(v.x,v.y)),s.lastScreenCoverage=Math.max(v.x,v.y,v.z),s.lastScreenspaceVolume.copy(v),s.lastScreenCoverage*=s.lastCentrality,$&&b.debugDrawLine){const f=this.tempMatrix.copy(this.projectionScreenMatrix);f.invert();const c=b.corner0,_=b.corner1,S=b.corner2,B=b.corner3;c.copy(this._tempBox.min),_.copy(this._tempBox.max),_.x=c.x,S.copy(this._tempBox.max),S.y=c.y,B.copy(this._tempBox.max);const z=(c.z+B.z)*.5;c.z=_.z=S.z=B.z=z,c.applyMatrix4(f),_.applyMatrix4(f),S.applyMatrix4(f),B.applyMatrix4(f),b.debugDrawLine(c,_,255),b.debugDrawLine(c,S,255),b.debugDrawLine(_,B,255),b.debugDrawLine(S,B,255)}let O=999;if(g&&s.lastScreenCoverage>0)for(let f=0;f<g.length;f++){const c=g[f];if((((i=c.densities)==null?void 0:i[x])||c.density||1e-5)/s.lastScreenCoverage<n){O=f;break}}O<d&&(d=O,a=!0)}if(a?r.mesh_lod=d:r.mesh_lod=s.lastLodLevel_Mesh,$&&r.mesh_lod!=s.lastLodLevel_Mesh){const h=g?.[r.mesh_lod];h&&console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} \u2192 ${r.mesh_lod} (${h.density.toFixed(0)}) - ${e.name}`)}if(Q){const h="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(s.lastLodLevel_Texture<0){if(r.texture_lod=L.max_count-1,$){const v=L.lods[L.max_count-1];$&&console.log(`First Texture LOD ${r.texture_lod} (${v.max_height}px) - ${e.name}`)}}else{const v=s.lastScreenspaceVolume.x+s.lastScreenspaceVolume.y+s.lastScreenspaceVolume.z;let T=s.lastScreenCoverage*4;((l=this.context)==null?void 0:l.engine)==="model-viewer"&&(T*=1.5);const G=w/window.devicePixelRatio*T;let D=!1;for(let j=L.lods.length-1;j>=0;j--){const O=L.lods[j];if(!(h&&O.max_height>=2048)&&!(ut()&&O.max_height>4096)&&(O.max_height>G||!D&&j===0)){if(D=!0,r.texture_lod=j,r.texture_lod<s.lastLodLevel_Texture){const f=O.max_height;$&&console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} \u2192 ${r.texture_lod} = ${f}px
6
+ Screensize: ${G.toFixed(0)}px, Coverage: ${(100*s.lastScreenCoverage).toFixed(2)}%, Volume ${v.toFixed(1)}
7
+ ${e.name}`)}break}}}}else r.texture_lod=0}};let C=b;E=new WeakMap,X=new WeakMap,Te=new WeakMap,K=new WeakMap,oe=new WeakMap,fe=new WeakMap,H=new WeakMap,u(C,"debugDrawLine"),u(C,"overrideGlobalLodLevel"),u(C,"corner0",new W),u(C,"corner1",new W),u(C,"corner2",new W),u(C,"corner3",new W),u(C,"_tempPtInside",new W),u(C,"skinnedMeshBoundsFrameOffsetCounter",0),u(C,"$skinnedMeshBoundsOffset",Symbol("gltf-progressive-skinnedMeshBoundsOffset"));class pt{constructor(){u(this,"frames",0),u(this,"lastLodLevel_Mesh",-1),u(this,"lastLodLevel_Texture",-1),u(this,"lastScreenCoverage",0),u(this,"lastScreenspaceVolume",new W),u(this,"lastCentrality",0)}}const We=Symbol("NEEDLE_mesh_lod"),me=Symbol("NEEDLE_texture_lod");let pe=null;function Ae(){const t=vt();t&&(t.mapURLs(function(e){return ze(),e}),ze(),pe?.disconnect(),pe=new MutationObserver(e=>{e.forEach(s=>{s.addedNodes.forEach(n=>{n instanceof HTMLElement&&n.tagName.toLowerCase()==="model-viewer"&&Ve(n)})})}),pe.observe(document,{childList:!0,subtree:!0}))}function vt(){return typeof customElements>"u"?null:customElements.get("model-viewer")||(customElements.whenDefined("model-viewer").then(()=>{console.debug("[gltf-progressive] model-viewer defined"),Ae()}),null)}function ze(){typeof document>"u"||document.querySelectorAll("model-viewer").forEach(t=>{Ve(t)})}const qe=new WeakSet;let yt=0;function Ve(t){if(!t||qe.has(t))return null;qe.add(t),console.debug("[gltf-progressive] found new model-viewer..."+ ++yt+`
8
+ `,t.getAttribute("src"));let e=null,s=null,n=null;for(let r=t;r!=null;r=Object.getPrototypeOf(r)){const o=Object.getOwnPropertySymbols(r),i=o.find(a=>a.toString()=="Symbol(renderer)"),l=o.find(a=>a.toString()=="Symbol(scene)"),d=o.find(a=>a.toString()=="Symbol(needsRender)");!e&&i!=null&&(e=t[i].threeRenderer),!s&&l!=null&&(s=t[l]),!n&&d!=null&&(n=t[d])}if(e&&s){let r=function(){if(n){let i=0,l=setInterval(()=>{if(i++>5){clearInterval(l);return}n?.call(t)},300)}};console.debug("[gltf-progressive] setup model-viewer");const o=C.get(e,{engine:"model-viewer"});return C.addPlugin(new xt),o.enable(),o.addEventListener("changed",()=>{n?.call(t)}),t.addEventListener("model-visibility",i=>{i.detail.visible&&n?.call(t)}),t.addEventListener("load",()=>{r()}),()=>{o.disable()}}return null}class xt{constructor(){u(this,"_didWarnAboutMissingUrl",!1)}onBeforeUpdateLOD(e,s,n,r){this.tryParseMeshLOD(s,r),this.tryParseTextureLOD(s,r)}getUrl(e){if(!e)return null;let s=e.getAttribute("src");return s||(s=e.src),s||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",e),this._didWarnAboutMissingUrl=!0),s}tryGetCurrentGLTF(e){return e._currentGLTF}tryGetCurrentModelViewer(e){return e.element}tryParseTextureLOD(e,s){if(s[me]==!0)return;s[me]=!0;const n=this.tryGetCurrentGLTF(e),r=this.tryGetCurrentModelViewer(e),o=this.getUrl(r);if(o&&n&&s.material){let i=function(d){var a,g,x;if(d[me]==!0)return;d[me]=!0,d.userData&&(d.userData.LOD=-1);const p=Object.keys(d);for(let L=0;L<p.length;L++){const Q=p[L],w=d[Q];if(w?.isTexture===!0){const k=(g=(a=w.userData)==null?void 0:a.associations)==null?void 0:g.textures;if(k==null)continue;const h=n.parser.json.textures[k];if(!h){console.warn("Texture data not found for texture index "+k);continue}if((x=h?.extensions)!=null&&x[F]){const v=h.extensions[F];v&&o&&P.registerTexture(o,w,v.lods.length,k,v)}}}};const l=s.material;if(Array.isArray(l))for(const d of l)i(d);else i(l)}}tryParseMeshLOD(e,s){var n,r;if(s[We]==!0)return;s[We]=!0;const o=this.tryGetCurrentModelViewer(e),i=this.getUrl(o);if(!i)return;const l=(r=(n=s.userData)==null?void 0:n.gltfExtensions)==null?void 0:r[F];if(l&&i){const d=s.uuid;P.registerMesh(i,d,s,0,l.lods.length,l)}}}function Xe(t,e,s,n){Le(e),we(s),be(s,{progressive:!0,...n?.hints}),s.register(o=>new P(o,t));const r=C.get(e);return n?.enableLODsManager!==!1&&r.enable(),r}if(Ae(),!ht){const t={gltfProgressive:{useNeedleProgressive:Xe,LODsManager:C,configureLoader:be,getRaycastMesh:te,useRaycastMeshes:Fe}};if(!globalThis.Needle)globalThis.Needle=t;else for(const e in t)globalThis.Needle[e]=t[e]}export{F as EXTENSION_NAME,C as LODsManager,P as NEEDLE_progressive,Be as VERSION,we as addDracoAndKTX2Loaders,be as configureLoader,Le as createLoaders,te as getRaycastMesh,Ae as patchModelViewer,Ne as registerRaycastMesh,Ge as setDracoDecoderLocation,Re as setKTX2TranscoderLocation,Xe as useNeedleProgressive,Fe as useRaycastMeshes};
@@ -1,8 +1,8 @@
1
- "use strict";var je=Object.defineProperty;var He=(n,t,e)=>t in n?je(n,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):n[t]=e;var c=(n,t,e)=>(He(n,typeof t!="symbol"?t+"":t,e),e),Ge=(n,t,e)=>{if(!t.has(n))throw TypeError("Cannot "+e)};var m=(n,t,e)=>(Ge(n,t,"read from private field"),e?e.call(n):t.get(n)),J=(n,t,e)=>{if(t.has(n))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(n):t.set(n,e)},W=(n,t,e,s)=>(Ge(n,t,"write to private field"),s?s.call(n,e):t.set(n,e),e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const p=require("three"),Te=require("three/examples/jsm/loaders/GLTFLoader.js"),Je=require("three/examples/jsm/libs/meshopt_decoder.module.js"),Qe=require("three/examples/jsm/loaders/DRACOLoader.js"),Ze=require("three/examples/jsm/loaders/KTX2Loader.js"),ke="";globalThis.GLTF_PROGRESSIVE_VERSION=ke;console.debug("[gltf-progressive] version -");let X="https://www.gstatic.com/draco/versioned/decoders/1.5.7/",se="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";const et=X,tt=se,Fe=new URL(X+"draco_decoder.js");Fe.searchParams.append("range","true");fetch(Fe,{method:"GET",headers:{Range:"bytes=0-1"}}).catch(n=>{console.debug(`Failed to fetch remote Draco decoder from ${X} (offline: ${typeof navigator<"u"?navigator.onLine:"unknown"})`),X===et&&$e("./include/draco/"),se===tt&&Ne("./include/ktx2/")}).finally(()=>{Ue()});function $e(n){X=n,I&&I[Oe]!=X?(console.debug("Updating Draco decoder path to "+n),I[Oe]=X,I.setDecoderPath(X),I.preload()):console.debug("Setting Draco decoder path to "+n)}function Ne(n){se=n,U&&U.transcoderPath!=se?(console.debug("Updating KTX2 transcoder path to "+n),U.setTranscoderPath(se),U.init()):console.debug("Setting KTX2 transcoder path to "+n)}const Oe=Symbol("dracoDecoderPath");let I,me,U;function Ue(){I||(I=new Qe.DRACOLoader,I[Oe]=X,I.setDecoderPath(X),I.setDecoderConfig({type:"js"}),I.preload()),U||(U=new Ze.KTX2Loader,U.setTranscoderPath(se),U.init()),me||(me=Je.MeshoptDecoder)}function Pe(n){return Ue(),n?U.detectSupport(n):n!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:I,ktx2Loader:U,meshoptDecoder:me}}function Ae(n){n.dracoLoader||n.setDRACOLoader(I),n.ktx2Loader||n.setKTX2Loader(U),n.meshoptDecoder||n.setMeshoptDecoder(me)}const be=new WeakMap;function Ce(n,t){let e=be.get(n);e?e=Object.assign(e,t):e=t,be.set(n,e)}const we=Te.GLTFLoader.prototype.load;function st(...n){const t=be.get(this);let e=n[0];const s=new URL(e,window.location.href);if(s.hostname.endsWith("needle.tools")){const r=(t==null?void 0:t.progressive)!==void 0?t.progressive:!0,o=t!=null&&t.usecase?t.usecase:"default";r?this.requestHeader.Accept=`*/*;progressive=allowed;usecase=${o}`:this.requestHeader.Accept=`*/*;usecase=${o}`,e=s.toString()}return n[0]=e,we==null?void 0:we.call(this,...n)}Te.GLTFLoader.prototype.load=st;ce("debugprogressive");function ce(n){if(typeof window>"u")return!1;const e=new URL(window.location.href).searchParams.get(n);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function rt(n,t){if(t===void 0||t.startsWith("./")||t.startsWith("http")||n===void 0)return t;const e=n.lastIndexOf("/");if(e>=0){const s=n.substring(0,e+1);for(;s.endsWith("/")&&t.startsWith("/");)t=t.substring(1);return s+t}return t}let ne;function ot(){return ne!==void 0||(ne=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),ce("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",ne)),ne}function it(){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}const nt=typeof window>"u"&&typeof document>"u",Se=Symbol("needle:raycast-mesh");function oe(n){return(n==null?void 0:n[Se])instanceof p.BufferGeometry?n[Se]:null}function Ve(n,t){if((n.type==="Mesh"||n.type==="SkinnedMesh")&&!oe(n)){const s=at(t);s.userData={isRaycastMesh:!0},n[Se]=s}}function ze(n=!0){if(n){if(ae)return;const t=ae=p.Mesh.prototype.raycast;p.Mesh.prototype.raycast=function(e,s){const i=this,r=oe(i);let o;r&&i.isMesh&&(o=i.geometry,i.geometry=r),t.call(this,e,s),o&&(i.geometry=o)}}else{if(!ae)return;p.Mesh.prototype.raycast=ae,ae=null}}let ae=null;function at(n){const t=new p.BufferGeometry;for(const e in n.attributes)t.setAttribute(e,n.getAttribute(e));return t.setIndex(n.getIndex()),t}const Z=new Array,L=ce("debugprogressive");let ge,te=-1;if(L){let n=function(){te+=1,te>=t&&(te=-1),console.log(`Toggle LOD level [${te}]`)},t=6;window.addEventListener("keyup",e=>{e.key==="p"&&n(),e.key==="w"&&(ge=!ge,console.log(`Toggle wireframe [${ge}]`));const s=parseInt(e.key);!isNaN(s)&&s>=0&&(te=s,console.log(`Set LOD level to [${te}]`))})}function We(n){if(L)if(Array.isArray(n))for(const t of n)We(t);else n&&"wireframe"in n&&(n.wireframe=ge===!0)}const q="NEEDLE_progressive",ve=Symbol("needle-progressive-texture"),S=class{constructor(t,e){c(this,"parser");c(this,"url");c(this,"_isLoadingMesh");c(this,"loadMesh",t=>{var s,i;if(this._isLoadingMesh)return null;const e=(i=(s=this.parser.json.meshes[t])==null?void 0:s.extensions)==null?void 0:i[q];return e?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",t).then(r=>{var o;return this._isLoadingMesh=!1,r&&S.registerMesh(this.url,e.guid,r,(o=e.lods)==null?void 0:o.length,0,e),r})):null});L&&console.log("Progressive extension registered for",e),this.parser=t,this.url=e}get name(){return q}static getMeshLODExtension(t){const e=this.getAssignedLODInformation(t);return e!=null&&e.key?this.lodInfos.get(e.key):null}static getPrimitiveIndex(t){var s;const e=(s=this.getAssignedLODInformation(t))==null?void 0:s.index;return e??-1}static getMaterialMinMaxLODsCount(t,e){const s=this,i="LODS:minmax",r=t[i];if(r!=null)return r;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[i]=e,e}if(L==="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==null?void 0:u.isTexture)===!0&&o(u,e)}}else if(t.isMaterial)for(const a of Object.keys(t)){const l=t[a];(l==null?void 0:l.isTexture)===!0&&o(l,e)}return t[i]=e,e;function o(a,l){const u=s.getAssignedLODInformation(a);if(u){const d=s.lodInfos.get(u.key);if(d&&d.lods){l.min_count=Math.min(l.min_count,d.lods.length),l.max_count=Math.max(l.max_count,d.lods.length);for(let h=0;h<d.lods.length;h++){const g=d.lods[h];g.width&&(l.lods[h]=l.lods[h]||{min_height:1/0,max_height:0},l.lods[h].min_height=Math.min(l.lods[h].min_height,g.height),l.lods[h].max_height=Math.max(l.lods[h].max_height,g.height))}}}}}static hasLODLevelAvailable(t,e){var r;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 a=t[o];if(a&&a.isTexture&&this.hasLODLevelAvailable(a,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 s,i;if(t.isMesh?s=t.geometry:(t.isBufferGeometry||t.isTexture)&&(s=t),s&&(r=s==null?void 0:s.userData)!=null&&r.LODS){const o=s.userData.LODS;if(i=this.lodInfos.get(o.key),e===void 0)return i!=null;if(i)return Array.isArray(i.lods)?e<i.lods.length:e===0}return!1}static assignMeshLOD(t,e){var s;if(!t)return Promise.resolve(null);if(t instanceof p.Mesh||t.isMesh===!0){const i=t.geometry,r=this.getAssignedLODInformation(i);if(!r)return Promise.resolve(null);for(const o of Z)(s=o.onBeforeGetLODMesh)==null||s.call(o,t,e);return t["LOD:requested level"]=e,S.getOrLoadLOD(i,e).then(o=>{if(Array.isArray(o)){const a=r.index||0;o=o[a]}return t["LOD:requested level"]===e&&(delete t["LOD:requested level"],o&&i!=o&&((o==null?void 0:o.isBufferGeometry)?t.geometry=o:L&&console.error("Invalid LOD geometry",o))),o}).catch(o=>(console.error("Error loading mesh LOD",t,o),null))}else L&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",t);return Promise.resolve(null)}static assignTextureLOD(t,e=0){if(!t)return Promise.resolve(null);if(t.isMesh===!0){const s=t;if(Array.isArray(s.material)){const i=new Array;for(const r of s.material){const o=this.assignTextureLOD(r,e);i.push(o)}return Promise.all(i).then(r=>{const o=new Array;for(const a of r)Array.isArray(a)&&o.push(...a);return o})}else return this.assignTextureLOD(s.material,e)}if(t.isMaterial===!0){const s=t,i=[],r=new Array;if(s.uniforms&&(s.isRawShaderMaterial||s.isShaderMaterial===!0)){const o=s;for(const a of Object.keys(o.uniforms)){const l=o.uniforms[a].value;if((l==null?void 0:l.isTexture)===!0){const u=this.assignTextureLODForSlot(l,e,s,a).then(d=>(d&&o.uniforms[a].value!=d&&(o.uniforms[a].value=d,o.uniformsNeedUpdate=!0),d));i.push(u),r.push(a)}}}else for(const o of Object.keys(s)){const a=s[o];if((a==null?void 0:a.isTexture)===!0){const l=this.assignTextureLODForSlot(a,e,s,o);i.push(l),r.push(o)}}return Promise.all(i).then(o=>{const a=new Array;for(let l=0;l<o.length;l++){const u=o[l],d=r[l];u&&u.isTexture===!0?a.push({material:s,slot:d,texture:u,level:e}):a.push({material:s,slot:d,texture:null,level:e})}return a})}if(t instanceof p.Texture||t.isTexture===!0){const s=t;return this.assignTextureLODForSlot(s,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,s,i){return(t==null?void 0:t.isTexture)!==!0?Promise.resolve(null):i==="glyphMap"?Promise.resolve(t):S.getOrLoadLOD(t,e).then(r=>{if(Array.isArray(r))return null;if((r==null?void 0:r.isTexture)===!0){if(r!=t&&s&&i){const o=s[i];if(o&&!L){const a=this.getAssignedLODInformation(o);if(a&&(a==null?void 0:a.level)<e)return L==="verbose"&&console.warn("Assigned texture level is already higher: ",a.level,e,s,o,r),null}s[i]=r}return r}else L=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(r=>(console.error("Error loading LOD",t,r),null))}afterRoot(t){var e,s;return L&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((i,r)=>{var o;if(i!=null&&i.extensions){const a=i==null?void 0:i.extensions[q];if(a){if(!a.lods){L&&console.warn("Texture has no LODs",a);return}let l=!1;for(const u of this.parser.associations.keys())if(u.isTexture===!0){const d=this.parser.associations.get(u);(d==null?void 0:d.textures)===r&&(l=!0,S.registerTexture(this.url,u,(o=a.lods)==null?void 0:o.length,r,a))}l||this.parser.getDependency("texture",r).then(u=>{var d;u&&S.registerTexture(this.url,u,(d=a.lods)==null?void 0:d.length,r,a)})}}}),(s=this.parser.json.meshes)==null||s.forEach((i,r)=>{if(i!=null&&i.extensions){const o=i==null?void 0:i.extensions[q];if(o&&o.lods){for(const a of this.parser.associations.keys())if(a.isMesh){const l=this.parser.associations.get(a);(l==null?void 0:l.meshes)===r&&S.registerMesh(this.url,o.guid,a,o.lods.length,l.primitives,o)}}}}),null}static async getOrLoadLOD(t,e){var a,l,u,d;const s=L=="verbose",i=t.userData.LODS;if(!i)return null;const r=i==null?void 0:i.key;let o;if(t.isTexture===!0){const h=t;h.source&&h.source[ve]&&(o=h.source[ve])}if(o||(o=S.lodInfos.get(r)),o){if(e>0){let w=!1;const O=Array.isArray(o.lods);if(O&&e>=o.lods.length?w=!0:O||(w=!0),w)return this.lowresCache.get(r)}const h=Array.isArray(o.lods)?(a=o.lods[e])==null?void 0:a.path:o.lods;if(!h)return L&&!o["missing:uri"]&&(o["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,o)),null;const g=rt(i.url,h);if(g.endsWith(".glb")||g.endsWith(".gltf")){if(!o.guid)return console.warn("missing pointer for glb/gltf texture",o),null;const w=g+"_"+o.guid,O=this.previouslyLoaded.get(w);if(O!==void 0){s&&console.log(`LOD ${e} was already loading/loaded: ${w}`);let v=await O.catch(y=>(console.error(`Error loading LOD ${e} from ${g}
2
- `,y),null)),D=!1;if(v==null||(v instanceof p.Texture&&t instanceof p.Texture?(l=v.image)!=null&&l.data||(u=v.source)!=null&&u.data?v=this.copySettings(t,v):(D=!0,this.previouslyLoaded.delete(w)):v instanceof p.BufferGeometry&&t instanceof p.BufferGeometry&&((d=v.attributes.position)!=null&&d.array||(D=!0,this.previouslyLoaded.delete(w)))),!D)return v}const _=o,V=new Promise(async(v,D)=>{const y=new Te.GLTFLoader;Ae(y),L&&(await new Promise(b=>setTimeout(b,1e3)),s&&console.warn("Start loading (delayed) "+g,_.guid));let Y=g;if(_&&Array.isArray(_.lods)){const b=_.lods[e];b.hash&&(Y+="?v="+b.hash)}const C=await y.loadAsync(Y).catch(b=>(console.error(`Error loading LOD ${e} from ${g}
3
- `,b),null));if(!C)return null;const F=C.parser;s&&console.log("Loading finished "+g,_.guid);let k=0;if(C.parser.json.textures){let b=!1;for(const f of C.parser.json.textures){if(f!=null&&f.extensions){const T=f==null?void 0:f.extensions[q];if(T!=null&&T.guid&&T.guid===_.guid){b=!0;break}}k++}if(b){let f=await F.getDependency("texture",k);return f&&S.assignLODInformation(i.url,f,r,e,void 0),s&&console.log('change "'+t.name+'" → "'+f.name+'"',g,k,f,w),t instanceof p.Texture&&(f=this.copySettings(t,f)),f&&(f.guid=_.guid),v(f)}else L&&console.warn("Could not find texture with guid",_.guid,C.parser.json)}if(k=0,C.parser.json.meshes){let b=!1;for(const f of C.parser.json.meshes){if(f!=null&&f.extensions){const T=f==null?void 0:f.extensions[q];if(T!=null&&T.guid&&T.guid===_.guid){b=!0;break}}k++}if(b){const f=await F.getDependency("mesh",k);if(s&&console.log(`Loaded Mesh "${f.name}"`,g,k,f,w),f.isMesh===!0){const T=f.geometry;return S.assignLODInformation(i.url,T,r,e,0),v(T)}else{const T=new Array;for(let x=0;x<f.children.length;x++){const M=f.children[x];if(M.isMesh===!0){const E=M.geometry;S.assignLODInformation(i.url,E,r,e,x),T.push(E)}}return v(T)}}else L&&console.warn("Could not find mesh with guid",_.guid,C.parser.json)}return v(null)});return this.previouslyLoaded.set(w,V),await V}else if(t instanceof p.Texture){s&&console.log("Load texture from uri: "+g);const O=await new p.TextureLoader().loadAsync(g);return O?(O.guid=o.guid,O.flipY=!1,O.needsUpdate=!0,O.colorSpace=t.colorSpace,s&&console.log(o,O)):L&&console.warn("failed loading",g),O}}else L&&console.warn(`Can not load LOD ${e}: no LOD info found for "${r}" ${t.name}`,t.type);return null}static assignLODInformation(t,e,s,i,r){if(!e)return;e.userData||(e.userData={});const o=new lt(t,s,i,r);e.userData.LODS=o}static getAssignedLODInformation(t){var e;return((e=t==null?void 0:t.userData)==null?void 0:e.LODS)||null}static copySettings(t,e){return e?(L&&console.warn(`Copy texture settings
1
+ "use strict";var je=Object.defineProperty;var He=(o,t,e)=>t in o?je(o,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):o[t]=e;var u=(o,t,e)=>(He(o,typeof t!="symbol"?t+"":t,e),e),Ee=(o,t,e)=>{if(!t.has(o))throw TypeError("Cannot "+e)};var L=(o,t,e)=>(Ee(o,t,"read from private field"),e?e.call(o):t.get(o)),j=(o,t,e)=>{if(t.has(o))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(o):t.set(o,e)},z=(o,t,e,s)=>(Ee(o,t,"write to private field"),s?s.call(o,e):t.set(o,e),e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const y=require("three"),Pe=require("three/examples/jsm/loaders/GLTFLoader.js"),Qe=require("three/examples/jsm/libs/meshopt_decoder.module.js"),Je=require("three/examples/jsm/loaders/DRACOLoader.js"),Ze=require("three/examples/jsm/loaders/KTX2Loader.js"),Re="";globalThis.GLTF_PROGRESSIVE_VERSION=Re;console.debug("[gltf-progressive] version -");let X="https://www.gstatic.com/draco/versioned/decoders/1.5.7/",se="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";const et=X,tt=se,Ie=new URL(X+"draco_decoder.js");Ie.searchParams.append("range","true");fetch(Ie,{method:"GET",headers:{Range:"bytes=0-1"}}).catch(o=>{console.debug(`Failed to fetch remote Draco decoder from ${X} (offline: ${typeof navigator<"u"?navigator.onLine:"unknown"})`),X===et&&Fe("./include/draco/"),se===tt&&Ne("./include/ktx2/")}).finally(()=>{Ue()});function Fe(o){X=o,I&&I[Oe]!=X?(console.debug("Updating Draco decoder path to "+o),I[Oe]=X,I.setDecoderPath(X),I.preload()):console.debug("Setting Draco decoder path to "+o)}function Ne(o){se=o,U&&U.transcoderPath!=se?(console.debug("Updating KTX2 transcoder path to "+o),U.setTranscoderPath(se),U.init()):console.debug("Setting KTX2 transcoder path to "+o)}const Oe=Symbol("dracoDecoderPath");let I,me,U;function Ue(){I||(I=new Je.DRACOLoader,I[Oe]=X,I.setDecoderPath(X),I.setDecoderConfig({type:"js"}),I.preload()),U||(U=new Ze.KTX2Loader,U.setTranscoderPath(se),U.init()),me||(me=Qe.MeshoptDecoder)}function Te(o){return Ue(),o?U.detectSupport(o):o!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:I,ktx2Loader:U,meshoptDecoder:me}}function Ae(o){o.dracoLoader||o.setDRACOLoader(I),o.ktx2Loader||o.setKTX2Loader(U),o.meshoptDecoder||o.setMeshoptDecoder(me)}const be=new WeakMap;function Ce(o,t){let e=be.get(o);e?e=Object.assign(e,t):e=t,be.set(o,e)}const we=Pe.GLTFLoader.prototype.load;function st(...o){const t=be.get(this);let e=o[0];const s=new URL(e,window.location.href);if(s.hostname.endsWith("needle.tools")){const r=(t==null?void 0:t.progressive)!==void 0?t.progressive:!0,i=t!=null&&t.usecase?t.usecase:"default";r?this.requestHeader.Accept=`*/*;progressive=allowed;usecase=${i}`:this.requestHeader.Accept=`*/*;usecase=${i}`,e=s.toString()}return o[0]=e,we==null?void 0:we.call(this,...o)}Pe.GLTFLoader.prototype.load=st;ue("debugprogressive");function ue(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 rt(o,t){if(t===void 0||t.startsWith("./")||t.startsWith("http")||o===void 0)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}let oe;function it(){return oe!==void 0||(oe=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),ue("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",oe)),oe}function nt(){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 ot{constructor(t=100,e={}){u(this,"_running",new Map);u(this,"_queue",[]);u(this,"debug",!1);u(this,"tick",()=>{this.internalUpdate(),setTimeout(this.tick,10)});this.maxConcurrent=t,this.debug=e.debug??!1,window.requestAnimationFrame(this.tick)}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 for key ${t} finished, running: ${this._running.size}, waiting: ${this._queue.length}`)}),this.debug&&console.debug(`[PromiseQueue]: Adding promise for key ${t}, running: ${this._running.size}, waiting: ${this._queue.length}`))}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:n}=this._queue.shift();n({use:r=>this.add(s,r)})}}}const at=typeof window>"u"&&typeof document>"u",Se=Symbol("needle:raycast-mesh");function ie(o){return(o==null?void 0:o[Se])instanceof y.BufferGeometry?o[Se]:null}function Ve(o,t){if((o.type==="Mesh"||o.type==="SkinnedMesh")&&!ie(o)){const s=lt(t);s.userData={isRaycastMesh:!0},o[Se]=s}}function qe(o=!0){if(o){if(ae)return;const t=ae=y.Mesh.prototype.raycast;y.Mesh.prototype.raycast=function(e,s){const n=this,r=ie(n);let i;r&&n.isMesh&&(i=n.geometry,n.geometry=r),t.call(this,e,s),i&&(n.geometry=i)}}else{if(!ae)return;y.Mesh.prototype.raycast=ae,ae=null}}let ae=null;function lt(o){const t=new y.BufferGeometry;for(const e in o.attributes)t.setAttribute(e,o.getAttribute(e));return t.setIndex(o.getIndex()),t}const Q=new Array,x=ue("debugprogressive");let ge,te=-1;if(x){let o=function(){te+=1,te>=t&&(te=-1),console.log(`Toggle LOD level [${te}]`)},t=6;window.addEventListener("keyup",e=>{e.key==="p"&&o(),e.key==="w"&&(ge=!ge,console.log(`Toggle wireframe [${ge}]`));const s=parseInt(e.key);!isNaN(s)&&s>=0&&(te=s,console.log(`Set LOD level to [${te}]`))})}function ze(o){if(x)if(Array.isArray(o))for(const t of o)ze(t);else o&&"wireframe"in o&&(o.wireframe=ge===!0)}const W="NEEDLE_progressive",Me=Symbol("needle-progressive-texture"),O=class{constructor(t,e){u(this,"parser");u(this,"url");u(this,"_isLoadingMesh");u(this,"loadMesh",t=>{var s,n;if(this._isLoadingMesh)return null;const e=(n=(s=this.parser.json.meshes[t])==null?void 0:s.extensions)==null?void 0:n[W];return e?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",t).then(r=>{var i;return this._isLoadingMesh=!1,r&&O.registerMesh(this.url,e.guid,r,(i=e.lods)==null?void 0:i.length,0,e),r})):null});x&&console.log("Progressive extension registered for",e),this.parser=t,this.url=e}get name(){return W}static getMeshLODExtension(t){const e=this.getAssignedLODInformation(t);return e!=null&&e.key?this.lodInfos.get(e.key):null}static getPrimitiveIndex(t){var s;const e=(s=this.getAssignedLODInformation(t))==null?void 0:s.index;return e??-1}static getMaterialMinMaxLODsCount(t,e){const s=this,n="LODS:minmax",r=t[n];if(r!=null)return r;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[n]=e,e}if(x==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const a=t;for(const l of Object.keys(a.uniforms)){const c=a.uniforms[l].value;(c==null?void 0:c.isTexture)===!0&&i(c,e)}}else if(t.isMaterial)for(const a of Object.keys(t)){const l=t[a];(l==null?void 0:l.isTexture)===!0&&i(l,e)}return t[n]=e,e;function i(a,l){const c=s.getAssignedLODInformation(a);if(c){const d=s.lodInfos.get(c.key);if(d&&d.lods){l.min_count=Math.min(l.min_count,d.lods.length),l.max_count=Math.max(l.max_count,d.lods.length);for(let p=0;p<d.lods.length;p++){const f=d.lods[p];f.width&&(l.lods[p]=l.lods[p]||{min_height:1/0,max_height:0},l.lods[p].min_height=Math.min(l.lods[p].min_height,f.height),l.lods[p].max_height=Math.max(l.lods[p].max_height,f.height))}}}}}static hasLODLevelAvailable(t,e){var r;if(Array.isArray(t)){for(const i of t)if(this.hasLODLevelAvailable(i,e))return!0;return!1}if(t.isMaterial===!0){for(const i of Object.keys(t)){const a=t[i];if(a&&a.isTexture&&this.hasLODLevelAvailable(a,e))return!0}return!1}else if(t.isGroup===!0){for(const i of t.children)if(i.isMesh===!0&&this.hasLODLevelAvailable(i,e))return!0}let s,n;if(t.isMesh?s=t.geometry:(t.isBufferGeometry||t.isTexture)&&(s=t),s&&(r=s==null?void 0:s.userData)!=null&&r.LODS){const i=s.userData.LODS;if(n=this.lodInfos.get(i.key),e===void 0)return n!=null;if(n)return Array.isArray(n.lods)?e<n.lods.length:e===0}return!1}static assignMeshLOD(t,e){var s;if(!t)return Promise.resolve(null);if(t instanceof y.Mesh||t.isMesh===!0){const n=t.geometry,r=this.getAssignedLODInformation(n);if(!r)return Promise.resolve(null);for(const i of Q)(s=i.onBeforeGetLODMesh)==null||s.call(i,t,e);return t["LOD:requested level"]=e,O.getOrLoadLOD(n,e).then(i=>{if(Array.isArray(i)){const a=r.index||0;i=i[a]}return t["LOD:requested level"]===e&&(delete t["LOD:requested level"],i&&n!=i&&((i==null?void 0:i.isBufferGeometry)?t.geometry=i:x&&console.error("Invalid LOD geometry",i))),i}).catch(i=>(console.error("Error loading mesh LOD",t,i),null))}else x&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",t);return Promise.resolve(null)}static assignTextureLOD(t,e=0){if(!t)return Promise.resolve(null);if(t.isMesh===!0){const s=t;if(Array.isArray(s.material)){const n=new Array;for(const r of s.material){const i=this.assignTextureLOD(r,e);n.push(i)}return Promise.all(n).then(r=>{const i=new Array;for(const a of r)Array.isArray(a)&&i.push(...a);return i})}else return this.assignTextureLOD(s.material,e)}if(t.isMaterial===!0){const s=t,n=[],r=new Array;if(s.uniforms&&(s.isRawShaderMaterial||s.isShaderMaterial===!0)){const i=s;for(const a of Object.keys(i.uniforms)){const l=i.uniforms[a].value;if((l==null?void 0:l.isTexture)===!0){const c=this.assignTextureLODForSlot(l,e,s,a).then(d=>(d&&i.uniforms[a].value!=d&&(i.uniforms[a].value=d,i.uniformsNeedUpdate=!0),d));n.push(c),r.push(a)}}}else for(const i of Object.keys(s)){const a=s[i];if((a==null?void 0:a.isTexture)===!0){const l=this.assignTextureLODForSlot(a,e,s,i);n.push(l),r.push(i)}}return Promise.all(n).then(i=>{const a=new Array;for(let l=0;l<i.length;l++){const c=i[l],d=r[l];c&&c.isTexture===!0?a.push({material:s,slot:d,texture:c,level:e}):a.push({material:s,slot:d,texture:null,level:e})}return a})}if(t instanceof y.Texture||t.isTexture===!0){const s=t;return this.assignTextureLODForSlot(s,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,s,n){return(t==null?void 0:t.isTexture)!==!0?Promise.resolve(null):n==="glyphMap"?Promise.resolve(t):O.getOrLoadLOD(t,e).then(r=>{if(Array.isArray(r))return null;if((r==null?void 0:r.isTexture)===!0){if(r!=t&&s&&n){const i=s[n];if(i&&!x){const a=this.getAssignedLODInformation(i);if(a&&(a==null?void 0:a.level)<e)return x==="verbose"&&console.warn("Assigned texture level is already higher: ",a.level,e,s,i,r),null}s[n]=r}return r}else x=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(r=>(console.error("Error loading LOD",t,r),null))}afterRoot(t){var e,s;return x&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((n,r)=>{var i;if(n!=null&&n.extensions){const a=n==null?void 0:n.extensions[W];if(a){if(!a.lods){x&&console.warn("Texture has no LODs",a);return}let l=!1;for(const c of this.parser.associations.keys())if(c.isTexture===!0){const d=this.parser.associations.get(c);(d==null?void 0:d.textures)===r&&(l=!0,O.registerTexture(this.url,c,(i=a.lods)==null?void 0:i.length,r,a))}l||this.parser.getDependency("texture",r).then(c=>{var d;c&&O.registerTexture(this.url,c,(d=a.lods)==null?void 0:d.length,r,a)})}}}),(s=this.parser.json.meshes)==null||s.forEach((n,r)=>{if(n!=null&&n.extensions){const i=n==null?void 0:n.extensions[W];if(i&&i.lods){for(const a of this.parser.associations.keys())if(a.isMesh){const l=this.parser.associations.get(a);(l==null?void 0:l.meshes)===r&&O.registerMesh(this.url,i.guid,a,i.lods.length,l.primitives,i)}}}}),null}static async getOrLoadLOD(t,e){var a,l,c,d;const s=x=="verbose",n=t.userData.LODS;if(!n)return null;const r=n==null?void 0:n.key;let i;if(t.isTexture===!0){const p=t;p.source&&p.source[Me]&&(i=p.source[Me])}if(i||(i=O.lodInfos.get(r)),i){if(e>0){let M=!1;const D=Array.isArray(i.lods);if(D&&e>=i.lods.length?M=!0:D||(M=!0),M)return this.lowresCache.get(r)}const p=Array.isArray(i.lods)?(a=i.lods[e])==null?void 0:a.path:i.lods;if(!p)return x&&!i["missing:uri"]&&(i["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,i)),null;const f=rt(n.url,p);if(f.endsWith(".glb")||f.endsWith(".gltf")){if(!i.guid)return console.warn("missing pointer for glb/gltf texture",i),null;const M=f+"_"+i.guid,D=this.previouslyLoaded.get(M);if(D!==void 0){s&&console.log(`LOD ${e} was already loading/loaded: ${M}`);let h=await D.catch(G=>(console.error(`Error loading LOD ${e} from ${f}
2
+ `,G),null)),_=!1;if(h==null||(h instanceof y.Texture&&t instanceof y.Texture?(l=h.image)!=null&&l.data||(c=h.source)!=null&&c.data?h=this.copySettings(t,h):(_=!0,this.previouslyLoaded.delete(M)):h instanceof y.BufferGeometry&&t instanceof y.BufferGeometry&&((d=h.attributes.position)!=null&&d.array||(_=!0,this.previouslyLoaded.delete(M)))),!_)return h}const C=await this.queue.slot(f);if(!C.use)return x&&console.log(`LOD ${e} was aborted: ${f}`),null;const S=i,F=new Promise(async(h,_)=>{const G=new Pe.GLTFLoader;Ae(G),x&&(await new Promise(v=>setTimeout(v,1e3)),s&&console.warn("Start loading (delayed) "+f,S.guid));let V=f;if(S&&Array.isArray(S.lods)){const v=S.lods[e];v.hash&&(V+="?v="+v.hash)}const P=await G.loadAsync(V).catch(v=>(console.error(`Error loading LOD ${e} from ${f}
3
+ `,v),h(null)));if(!P)return h(null);const ee=P.parser;s&&console.log("Loading finished "+f,S.guid);let E=0;if(P.parser.json.textures){let v=!1;for(const m of P.parser.json.textures){if(m!=null&&m.extensions){const g=m==null?void 0:m.extensions[W];if(g!=null&&g.guid&&g.guid===S.guid){v=!0;break}}E++}if(v){let m=await ee.getDependency("texture",E);return m&&O.assignLODInformation(n.url,m,r,e,void 0),s&&console.log('change "'+t.name+'" → "'+m.name+'"',f,E,m,M),t instanceof y.Texture&&(m=this.copySettings(t,m)),m&&(m.guid=S.guid),h(m)}else x&&console.warn("Could not find texture with guid",S.guid,P.parser.json)}if(E=0,P.parser.json.meshes){let v=!1;for(const m of P.parser.json.meshes){if(m!=null&&m.extensions){const g=m==null?void 0:m.extensions[W];if(g!=null&&g.guid&&g.guid===S.guid){v=!0;break}}E++}if(v){const m=await ee.getDependency("mesh",E);if(s&&console.log(`Loaded Mesh "${m.name}"`,f,E,m,M),m.isMesh===!0){const g=m.geometry;return O.assignLODInformation(n.url,g,r,e,0),h(g)}else{const g=new Array;for(let w=0;w<m.children.length;w++){const B=m.children[w];if(B.isMesh===!0){const $=B.geometry;O.assignLODInformation(n.url,$,r,e,w),g.push($)}}return h(g)}}else x&&console.warn("Could not find mesh with guid",S.guid,P.parser.json)}return h(null)});return this.previouslyLoaded.set(M,F),C.use(F),await F}else if(t instanceof y.Texture){s&&console.log("Load texture from uri: "+f);const D=await new y.TextureLoader().loadAsync(f);return D?(D.guid=i.guid,D.flipY=!1,D.needsUpdate=!0,D.colorSpace=t.colorSpace,s&&console.log(i,D)):x&&console.warn("failed loading",f),D}}else x&&console.warn(`Can not load LOD ${e}: no LOD info found for "${r}" ${t.name}`,t.type);return null}static assignLODInformation(t,e,s,n,r){if(!e)return;e.userData||(e.userData={});const i=new ut(t,s,n,r);e.userData.LODS=i}static getAssignedLODInformation(t){var e;return((e=t==null?void 0:t.userData)==null?void 0:e.LODS)||null}static copySettings(t,e){return e?(x&&console.warn(`Copy texture settings
4
4
  `,t.uuid,`
5
- `,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}};let P=S;c(P,"registerTexture",(t,e,s,i,r)=>{if(L&&console.log("> Progressive: register texture",i,e.name,e.uuid,e,r),!e){L&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[ve]=r);const o=r.guid;S.assignLODInformation(t,e,o,s,i),S.lodInfos.set(o,r),S.lowresCache.set(o,e)}),c(P,"registerMesh",(t,e,s,i,r,o)=>{var u;const a=s.geometry;if(!a){L&&console.warn("gltf-progressive: Register mesh without geometry");return}a.userData||(a.userData={}),L&&console.log("> Progressive: register mesh "+s.name,{index:r,uuid:s.uuid},o,s),S.assignLODInformation(t,a,e,i,r),S.lodInfos.set(e,o);let l=S.lowresCache.get(e);l?l.push(s.geometry):l=[s.geometry],S.lowresCache.set(e,l),i>0&&!oe(s)&&Ve(s,a);for(const d of Z)(u=d.onRegisteredNewMesh)==null||u.call(d,s,o)}),c(P,"lodInfos",new Map),c(P,"previouslyLoaded",new Map),c(P,"lowresCache",new Map);class lt{constructor(t,e,s,i){c(this,"url");c(this,"key");c(this,"level");c(this,"index");this.url=t,this.key=e,this.level=s,i!=null&&(this.index=i)}}class pe{constructor(t,e){c(this,"frame_start");c(this,"frame_capture_end");c(this,"ready");c(this,"_resolve");c(this,"_signal");c(this,"_resolved",!1);c(this,"_addedCount",0);c(this,"_resolvedCount",0);c(this,"_awaiting",[]);c(this,"_maxPromisesPerObject",1);c(this,"_currentFrame",0);c(this,"_seen",new WeakMap);var r;const i=Math.max(e.frames??2,2);this.frame_start=t,this.frame_capture_end=t+i,this.ready=new Promise(o=>{this._resolve=o}),this.ready.finally(()=>{this._resolved=!0,this._awaiting.length=0}),this._signal=e.signal,(r=this._signal)==null||r.addEventListener("abort",()=>{this.resolveNow()}),this._maxPromisesPerObject=Math.max(1,e.maxPromisesPerObject??1)}get awaitedCount(){return this._addedCount}get resolvedCount(){return this._resolvedCount}get currentlyAwaiting(){return this._awaiting.length}update(t){var e;this._currentFrame=t,((e=this._signal)!=null&&e.aborted||this._currentFrame>this.frame_capture_end&&this._awaiting.length===0)&&this.resolveNow()}add(t,e,s){if(this._resolved){L&&console.warn("PromiseGroup: Trying to add a promise to a resolved group, ignoring.");return}if(!(this._currentFrame>this.frame_capture_end)){if(this._maxPromisesPerObject>=1)if(this._seen.has(e)){let i=this._seen.get(e);if(i>=this._maxPromisesPerObject){L&&console.warn("PromiseGroup: Already awaiting object ignoring new promise for it.");return}this._seen.set(e,i+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(){var t,e;this._resolved||(e=this._resolve)==null||e.call(this,{awaited_count:this._addedCount,resolved_count:this._resolvedCount,cancelled:((t=this._signal)==null?void 0:t.aborted)??!1})}}c(pe,"addPromise",(t,e,s,i)=>{i.forEach(r=>{r.add(t,e,s)})});const N=ce("debugprogressive"),ct=ce("noprogressive"),Me=Symbol("Needle:LODSManager"),De=Symbol("Needle:LODState"),Q=Symbol("Needle:CurrentLOD"),G={mesh_lod:-1,texture_lod:-1};var R,j,ye,ee,re,Le,H;const A=class{constructor(t,e){c(this,"renderer");c(this,"context");c(this,"projectionScreenMatrix",new p.Matrix4);c(this,"targetTriangleDensity",2e5);c(this,"skinnedMeshAutoUpdateBoundsInterval",30);c(this,"updateInterval","auto");J(this,R,1);c(this,"pause",!1);c(this,"manual",!1);c(this,"_newPromiseGroups",[]);c(this,"_promiseGroupIds",0);c(this,"_lodchangedlisteners",[]);J(this,j,void 0);J(this,ye,new p.Clock);J(this,ee,0);J(this,re,0);J(this,Le,0);J(this,H,0);c(this,"_fpsBuffer",[60,60,60,60,60]);c(this,"_sphere",new p.Sphere);c(this,"_tempBox",new p.Box3);c(this,"_tempBox2",new p.Box3);c(this,"tempMatrix",new p.Matrix4);c(this,"_tempWorldPosition",new p.Vector3);c(this,"_tempBoxSize",new p.Vector3);c(this,"_tempBox2Size",new p.Vector3);this.renderer=t,this.context={...e}}static getObjectLODState(t){return t[De]}static addPlugin(t){Z.push(t)}static removePlugin(t){const e=Z.indexOf(t);e>=0&&Z.splice(e,1)}static get(t,e){if(t[Me])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[Me];const s=new A(t,{engine:"unknown",...e});return t[Me]=s,s}get plugins(){return Z}awaitLoading(t){const e=this._promiseGroupIds++,s=new pe(m(this,ee),{...t});this._newPromiseGroups.push(s);const i=performance.now();return s.ready.finally(()=>{const r=this._newPromiseGroups.indexOf(s);r>=0&&(this._newPromiseGroups.splice(r,1),it()&&performance.measure("LODsManager:awaitLoading",{start:i,detail:{id:e,name:t==null?void 0:t.name,awaited:s.awaitedCount,resolved:s.resolvedCount}}))}),s.ready}_postprocessPromiseGroups(){if(this._newPromiseGroups.length!==0)for(let t=this._newPromiseGroups.length-1;t>=0;t--)this._newPromiseGroups[t].update(m(this,ee))}addEventListener(t,e){t==="changed"&&this._lodchangedlisteners.push(e)}removeEventListener(t,e){if(t==="changed"){const s=this._lodchangedlisteners.indexOf(e);s>=0&&this._lodchangedlisteners.splice(s,1)}}enable(){if(m(this,j))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let t=0;W(this,j,this.renderer.render);const e=this;Pe(this.renderer),this.renderer.render=function(s,i){const r=e.renderer.getRenderTarget();(r==null||"isXRRenderTarget"in r&&r.isXRRenderTarget)&&(t=0,W(e,ee,m(e,ee)+1),W(e,re,m(e,ye).getDelta()),W(e,Le,m(e,Le)+m(e,re)),e._fpsBuffer.shift(),e._fpsBuffer.push(1/m(e,re)),W(e,H,e._fpsBuffer.reduce((a,l)=>a+l)/e._fpsBuffer.length),N&&m(e,ee)%200===0&&console.log("FPS",Math.round(m(e,H)),"Interval:",m(e,R)));const o=t++;m(e,j).call(this,s,i),e.onAfterRender(s,i,o)}}disable(){m(this,j)&&(console.debug("[gltf-progressive] Disabling LODsManager for renderer"),this.renderer.render=m(this,j),W(this,j,void 0))}update(t,e){this.internalUpdate(t,e)}onAfterRender(t,e,s){if(this.pause)return;const r=this.renderer.renderLists.get(t,0).opaque;let o=!0;if(r.length===1){const a=r[0].material;(a.name==="EffectMaterial"||a.name==="CopyShader")&&(o=!1)}if((e.parent&&e.parent.type==="CubeCamera"||s>=1&&e.type==="OrthographicCamera")&&(o=!1),o){if(ct||(this.updateInterval==="auto"?m(this,H)<40&&m(this,R)<10?(W(this,R,m(this,R)+1),N&&console.warn("↓ Reducing LOD updates",m(this,R),m(this,H).toFixed(0))):m(this,H)>=60&&m(this,R)>1&&(W(this,R,m(this,R)-1),N&&console.warn("↑ Increasing LOD updates",m(this,R),m(this,H).toFixed(0))):W(this,R,this.updateInterval),m(this,R)>0&&m(this,ee)%m(this,R)!=0))return;this.internalUpdate(t,e),this._postprocessPromiseGroups()}}internalUpdate(t,e){var l,u;const s=this.renderer.renderLists.get(t,0),i=s.opaque;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse);const r=this.targetTriangleDensity;for(const d of i){if(d.material&&(((l=d.geometry)==null?void 0:l.type)==="BoxGeometry"||((u=d.geometry)==null?void 0:u.type)==="BufferGeometry")&&(d.material.name==="SphericalGaussianBlur"||d.material.name=="BackgroundCubeMaterial"||d.material.name==="CubemapFromEquirect"||d.material.name==="EquirectangularToCubeUV")){N&&(d.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(d.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",d,d.material.name,d.material.type)));continue}switch(d.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}if(N==="color"&&d.material&&!d.object.progressive_debug_color){d.object.progressive_debug_color=!0;const g=Math.random()*16777215,w=new p.MeshStandardMaterial({color:g});d.object.material=w}const h=d.object;(h instanceof p.Mesh||h.isMesh)&&this.updateLODs(t,e,h,r)}const o=s.transparent;for(const d of o){const h=d.object;(h instanceof p.Mesh||h.isMesh)&&this.updateLODs(t,e,h,r)}const a=s.transmissive;for(const d of a){const h=d.object;(h instanceof p.Mesh||h.isMesh)&&this.updateLODs(t,e,h,r)}}updateLODs(t,e,s,i){var a,l;s.userData||(s.userData={});let r=s[De];if(r||(r=new dt,s[De]=r),r.frames++<2)return;for(const u of Z)(a=u.onBeforeUpdateLOD)==null||a.call(u,this.renderer,t,e,s);const o=A.overrideGlobalLodLevel!==void 0?A.overrideGlobalLodLevel:te;o>=0?(G.mesh_lod=o,G.texture_lod=o):(this.calculateLodLevel(e,s,r,i,G),G.mesh_lod=Math.round(G.mesh_lod),G.texture_lod=Math.round(G.texture_lod)),G.mesh_lod>=0&&this.loadProgressiveMeshes(s,G.mesh_lod),s.material&&G.texture_lod>=0&&this.loadProgressiveTextures(s.material,G.texture_lod),L&&s.material&&!s.isGizmo&&We(s.material);for(const u of Z)(l=u.onAfterUpdatedLOD)==null||l.call(u,this.renderer,t,e,s,G);r.lastLodLevel_Mesh=G.mesh_lod,r.lastLodLevel_Texture=G.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const r of t)this.loadProgressiveTextures(r,e);return}let s=!1;(t[Q]===void 0||e<t[Q])&&(s=!0);const i=t["DEBUG:LOD"];if(i!=null&&(s=t[Q]!=i,e=i),s){t[Q]=e;const r=P.assignTextureLOD(t,e).then(o=>{this._lodchangedlisteners.forEach(a=>a({type:"texture",level:e,object:t}))});pe.addPromise("texture",t,r,this._newPromiseGroups)}}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);let s=t[Q]!==e;const i=t["DEBUG:LOD"];if(i!=null&&(s=t[Q]!=i,e=i),s){t[Q]=e;const r=t.geometry,o=P.assignMeshLOD(t,e).then(a=>(a&&t[Q]==e&&r!=t.geometry&&this._lodchangedlisteners.forEach(l=>l({type:"mesh",level:e,object:t})),a));return pe.addPromise("mesh",t,o,this._newPromiseGroups),o}return Promise.resolve(null)}static isInside(t,e){const s=t.min,i=t.max,r=(s.x+i.x)*.5,o=(s.y+i.y)*.5;return this._tempPtInside.set(r,o,s.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,s,i,r){var V,K,v;if(!e){r.mesh_lod=-1,r.texture_lod=-1;return}if(!t){r.mesh_lod=-1,r.texture_lod=-1;return}let a=10+1,l=!1;if(N&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const u=(V=P.getMeshLODExtension(e.geometry))==null?void 0:V.lods,d=P.getPrimitiveIndex(e.geometry),h=u&&u.length>0,g=P.getMaterialMinMaxLODsCount(e.material),w=(g==null?void 0:g.min_count)!=1/0&&g.min_count>0&&g.max_count>0;if(!h&&!w){r.mesh_lod=0,r.texture_lod=0;return}h||(l=!0,a=0);const O=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let _=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const D=e;if(!D.boundingBox)D.computeBoundingBox();else if(this.skinnedMeshAutoUpdateBoundsInterval>0&&s.frames%this.skinnedMeshAutoUpdateBoundsInterval===0){const y=oe(D),Y=D.geometry;y&&(D.geometry=y),D.computeBoundingBox(),D.geometry=Y}_=D.boundingBox}if(_){const D=t;if(e.geometry.attributes.color&&e.geometry.attributes.color.count<100&&e.geometry.boundingSphere){this._sphere.copy(e.geometry.boundingSphere),this._sphere.applyMatrix4(e.matrixWorld);const x=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(x)){r.mesh_lod=0,r.texture_lod=0;return}}if(this._tempBox.copy(_),this._tempBox.applyMatrix4(e.matrixWorld),D.isPerspectiveCamera&&A.isInside(this._tempBox,this.projectionScreenMatrix)){r.mesh_lod=0,r.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&D.isPerspectiveCamera&&D.fov>70){const x=this._tempBox.min,M=this._tempBox.max;let E=x.x,$=x.y,z=M.x,ie=M.y;const de=2,xe=1.5,ue=(x.x+M.x)*.5,fe=(x.y+M.y)*.5;E=(E-ue)*de+ue,$=($-fe)*de+fe,z=(z-ue)*de+ue,ie=(ie-fe)*de+fe;const Ke=E<0&&z>0?0:Math.min(Math.abs(x.x),Math.abs(M.x)),Ye=$<0&&ie>0?0:Math.min(Math.abs(x.y),Math.abs(M.y)),_e=Math.max(Ke,Ye);s.lastCentrality=(xe-_e)*(xe-_e)*(xe-_e)}else s.lastCentrality=1;const y=this._tempBox.getSize(this._tempBoxSize);y.multiplyScalar(.5),screen.availHeight>0&&O>0&&y.multiplyScalar(O/screen.availHeight),t.isPerspectiveCamera?y.x*=t.aspect:t.isOrthographicCamera;const Y=t.matrixWorldInverse,C=this._tempBox2;C.copy(_),C.applyMatrix4(e.matrixWorld),C.applyMatrix4(Y);const F=C.getSize(this._tempBox2Size),k=Math.max(F.x,F.y);if(Math.max(y.x,y.y)!=0&&k!=0&&(y.z=F.z/Math.max(F.x,F.y)*Math.max(y.x,y.y)),s.lastScreenCoverage=Math.max(y.x,y.y,y.z),s.lastScreenspaceVolume.copy(y),s.lastScreenCoverage*=s.lastCentrality,N&&A.debugDrawLine){const x=this.tempMatrix.copy(this.projectionScreenMatrix);x.invert();const M=A.corner0,E=A.corner1,$=A.corner2,z=A.corner3;M.copy(this._tempBox.min),E.copy(this._tempBox.max),E.x=M.x,$.copy(this._tempBox.max),$.y=M.y,z.copy(this._tempBox.max);const ie=(M.z+z.z)*.5;M.z=E.z=$.z=z.z=ie,M.applyMatrix4(x),E.applyMatrix4(x),$.applyMatrix4(x),z.applyMatrix4(x),A.debugDrawLine(M,E,255),A.debugDrawLine(M,$,255),A.debugDrawLine(E,z,255),A.debugDrawLine($,z,255)}let f=999;if(u&&s.lastScreenCoverage>0)for(let x=0;x<u.length;x++){const M=u[x];if((((K=M.densities)==null?void 0:K[d])||M.density||1e-5)/s.lastScreenCoverage<i){f=x;break}}f<a&&(a=f,l=!0)}if(l?r.mesh_lod=a:r.mesh_lod=s.lastLodLevel_Mesh,N&&r.mesh_lod!=s.lastLodLevel_Mesh){const y=u==null?void 0:u[r.mesh_lod];y&&console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} → ${r.mesh_lod} (${y.density.toFixed(0)}) - ${e.name}`)}if(w){const D="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(s.lastLodLevel_Texture<0){if(r.texture_lod=g.max_count-1,N){const y=g.lods[g.max_count-1];N&&console.log(`First Texture LOD ${r.texture_lod} (${y.max_height}px) - ${e.name}`)}}else{const y=s.lastScreenspaceVolume.x+s.lastScreenspaceVolume.y+s.lastScreenspaceVolume.z;let Y=s.lastScreenCoverage*4;((v=this.context)==null?void 0:v.engine)==="model-viewer"&&(Y*=1.5);const F=O/window.devicePixelRatio*Y;let k=!1;for(let b=g.lods.length-1;b>=0;b--){const f=g.lods[b];if(!(D&&f.max_height>=2048)&&!(ot()&&f.max_height>4096)&&(f.max_height>F||!k&&b===0)){if(k=!0,r.texture_lod=b,r.texture_lod<s.lastLodLevel_Texture){const T=f.max_height;N&&console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${r.texture_lod} = ${T}px
6
- Screensize: ${F.toFixed(0)}px, Coverage: ${(100*s.lastScreenCoverage).toFixed(2)}%, Volume ${y.toFixed(1)}
7
- ${e.name}`)}break}}}}else r.texture_lod=0}};let B=A;R=new WeakMap,j=new WeakMap,ye=new WeakMap,ee=new WeakMap,re=new WeakMap,Le=new WeakMap,H=new WeakMap,c(B,"debugDrawLine"),c(B,"overrideGlobalLodLevel"),c(B,"corner0",new p.Vector3),c(B,"corner1",new p.Vector3),c(B,"corner2",new p.Vector3),c(B,"corner3",new p.Vector3),c(B,"_tempPtInside",new p.Vector3);class dt{constructor(){c(this,"frames",0);c(this,"lastLodLevel_Mesh",-1);c(this,"lastLodLevel_Texture",-1);c(this,"lastScreenCoverage",0);c(this,"lastScreenspaceVolume",new p.Vector3);c(this,"lastCentrality",0)}}const Be=Symbol("NEEDLE_mesh_lod"),he=Symbol("NEEDLE_texture_lod");let le=null;function Ee(){const n=ut();n&&(n.mapURLs(function(t){return Re(),t}),Re(),le==null||le.disconnect(),le=new MutationObserver(t=>{t.forEach(e=>{e.addedNodes.forEach(s=>{s instanceof HTMLElement&&s.tagName.toLowerCase()==="model-viewer"&&qe(s)})})}),le.observe(document,{childList:!0,subtree:!0}))}function ut(){if(typeof customElements>"u")return null;const n=customElements.get("model-viewer");return n||(customElements.whenDefined("model-viewer").then(()=>{console.debug("[gltf-progressive] model-viewer defined"),Ee()}),null)}function Re(){if(typeof document>"u")return;document.querySelectorAll("model-viewer").forEach(t=>{qe(t)})}const Ie=new WeakSet;let ft=0;function qe(n){if(!n||Ie.has(n))return null;Ie.add(n),console.debug("[gltf-progressive] found new model-viewer..."+ ++ft+`
8
- `,n.getAttribute("src"));let t=null,e=null,s=null;for(let i=n;i!=null;i=Object.getPrototypeOf(i)){const r=Object.getOwnPropertySymbols(i),o=r.find(u=>u.toString()=="Symbol(renderer)"),a=r.find(u=>u.toString()=="Symbol(scene)"),l=r.find(u=>u.toString()=="Symbol(needsRender)");!t&&o!=null&&(t=n[o].threeRenderer),!e&&a!=null&&(e=n[a]),!s&&l!=null&&(s=n[l])}if(t&&e){let i=function(){if(s){let o=0,a=setInterval(()=>{if(o++>5){clearInterval(a);return}s==null||s.call(n)},300)}};console.debug("[gltf-progressive] setup model-viewer");const r=B.get(t,{engine:"model-viewer"});return B.addPlugin(new ht),r.enable(),r.addEventListener("changed",()=>{s==null||s.call(n)}),n.addEventListener("model-visibility",o=>{o.detail.visible&&(s==null||s.call(n))}),n.addEventListener("load",()=>{i()}),()=>{r.disable()}}return null}class ht{constructor(){c(this,"_didWarnAboutMissingUrl",!1)}onBeforeUpdateLOD(t,e,s,i){this.tryParseMeshLOD(e,i),this.tryParseTextureLOD(e,i)}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[he]==!0)return;e[he]=!0;const s=this.tryGetCurrentGLTF(t),i=this.tryGetCurrentModelViewer(t),r=this.getUrl(i);if(r&&s&&e.material){let o=function(l){var d,h,g;if(l[he]==!0)return;l[he]=!0,l.userData&&(l.userData.LOD=-1);const u=Object.keys(l);for(let w=0;w<u.length;w++){const O=u[w],_=l[O];if((_==null?void 0:_.isTexture)===!0){const V=(h=(d=_.userData)==null?void 0:d.associations)==null?void 0:h.textures;if(V==null)continue;const K=s.parser.json.textures[V];if(!K){console.warn("Texture data not found for texture index "+V);continue}if((g=K==null?void 0:K.extensions)!=null&&g[q]){const v=K.extensions[q];v&&r&&P.registerTexture(r,_,v.lods.length,V,v)}}}};const a=e.material;if(Array.isArray(a))for(const l of a)o(l);else o(a)}}tryParseMeshLOD(t,e){var o,a;if(e[Be]==!0)return;e[Be]=!0;const s=this.tryGetCurrentModelViewer(t),i=this.getUrl(s);if(!i)return;const r=(a=(o=e.userData)==null?void 0:o.gltfExtensions)==null?void 0:a[q];if(r&&i){const l=e.uuid;P.registerMesh(i,l,e,0,r.lods.length,r)}}}function Xe(n,t,e,s){Pe(t),Ae(e),Ce(e,{progressive:!0,...s==null?void 0:s.hints}),e.register(r=>new P(r,n));const i=B.get(t);return(s==null?void 0:s.enableLODsManager)!==!1&&i.enable(),i}Ee();if(!nt){const n={gltfProgressive:{useNeedleProgressive:Xe,LODsManager:B,configureLoader:Ce,getRaycastMesh:oe,useRaycastMeshes:ze}};if(!globalThis.Needle)globalThis.Needle=n;else for(const t in n)globalThis.Needle[t]=n[t]}exports.EXTENSION_NAME=q;exports.LODsManager=B;exports.NEEDLE_progressive=P;exports.VERSION=ke;exports.addDracoAndKTX2Loaders=Ae;exports.configureLoader=Ce;exports.createLoaders=Pe;exports.getRaycastMesh=oe;exports.patchModelViewer=Ee;exports.registerRaycastMesh=Ve;exports.setDracoDecoderLocation=$e;exports.setKTX2TranscoderLocation=Ne;exports.useNeedleProgressive=Xe;exports.useRaycastMeshes=ze;
5
+ `,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}};let T=O;u(T,"registerTexture",(t,e,s,n,r)=>{if(x&&console.log("> Progressive: register texture",n,e.name,e.uuid,e,r),!e){x&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[Me]=r);const i=r.guid;O.assignLODInformation(t,e,i,s,n),O.lodInfos.set(i,r),O.lowresCache.set(i,e)}),u(T,"registerMesh",(t,e,s,n,r,i)=>{var c;const a=s.geometry;if(!a){x&&console.warn("gltf-progressive: Register mesh without geometry");return}a.userData||(a.userData={}),x&&console.log("> Progressive: register mesh "+s.name,{index:r,uuid:s.uuid},i,s),O.assignLODInformation(t,a,e,n,r),O.lodInfos.set(e,i);let l=O.lowresCache.get(e);l?l.push(s.geometry):l=[s.geometry],O.lowresCache.set(e,l),n>0&&!ie(s)&&Ve(s,a);for(const d of Q)(c=d.onRegisteredNewMesh)==null||c.call(d,s,i)}),u(T,"lodInfos",new Map),u(T,"previouslyLoaded",new Map),u(T,"lowresCache",new Map),u(T,"queue",new ot(100,{debug:x!=!1}));class ut{constructor(t,e,s,n){u(this,"url");u(this,"key");u(this,"level");u(this,"index");this.url=t,this.key=e,this.level=s,n!=null&&(this.index=n)}}class pe{constructor(t,e){u(this,"frame_start");u(this,"frame_capture_end");u(this,"ready");u(this,"_resolve");u(this,"_signal");u(this,"_resolved",!1);u(this,"_addedCount",0);u(this,"_resolvedCount",0);u(this,"_awaiting",[]);u(this,"_maxPromisesPerObject",1);u(this,"_currentFrame",0);u(this,"_seen",new WeakMap);var r;const n=Math.max(e.frames??2,2);this.frame_start=t,this.frame_capture_end=t+n,this.ready=new Promise(i=>{this._resolve=i}),this.ready.finally(()=>{this._resolved=!0,this._awaiting.length=0}),this._signal=e.signal,(r=this._signal)==null||r.addEventListener("abort",()=>{this.resolveNow()}),this._maxPromisesPerObject=Math.max(1,e.maxPromisesPerObject??1)}get awaitedCount(){return this._addedCount}get resolvedCount(){return this._resolvedCount}get currentlyAwaiting(){return this._awaiting.length}update(t){var e;this._currentFrame=t,((e=this._signal)!=null&&e.aborted||this._currentFrame>this.frame_capture_end&&this._awaiting.length===0)&&this.resolveNow()}add(t,e,s){if(this._resolved){x&&console.warn("PromiseGroup: Trying to add a promise to a resolved group, ignoring.");return}if(!(this._currentFrame>this.frame_capture_end)){if(this._maxPromisesPerObject>=1)if(this._seen.has(e)){let n=this._seen.get(e);if(n>=this._maxPromisesPerObject){x&&console.warn("PromiseGroup: Already awaiting object ignoring new promise for it.");return}this._seen.set(e,n+1)}else this._seen.set(e,1);this._awaiting.push(s),this._addedCount++,s.finally(()=>{this._resolvedCount++,this._awaiting.splice(this._awaiting.indexOf(s),1)})}}resolveNow(){var t,e;this._resolved||(e=this._resolve)==null||e.call(this,{awaited_count:this._addedCount,resolved_count:this._resolvedCount,cancelled:((t=this._signal)==null?void 0:t.aborted)??!1})}}u(pe,"addPromise",(t,e,s,n)=>{n.forEach(r=>{r.add(t,e,s)})});const N=ue("debugprogressive"),dt=ue("noprogressive"),ve=Symbol("Needle:LODSManager"),De=Symbol("Needle:LODState"),H=Symbol("Needle:CurrentLOD"),k={mesh_lod:-1,texture_lod:-1};var R,K,ye,J,re,Le,Y;const b=class{constructor(t,e){u(this,"renderer");u(this,"context");u(this,"projectionScreenMatrix",new y.Matrix4);u(this,"targetTriangleDensity",2e5);u(this,"skinnedMeshAutoUpdateBoundsInterval",30);u(this,"updateInterval","auto");j(this,R,1);u(this,"pause",!1);u(this,"manual",!1);u(this,"_newPromiseGroups",[]);u(this,"_promiseGroupIds",0);u(this,"_lodchangedlisteners",[]);j(this,K,void 0);j(this,ye,new y.Clock);j(this,J,0);j(this,re,0);j(this,Le,0);j(this,Y,0);u(this,"_fpsBuffer",[60,60,60,60,60]);u(this,"_sphere",new y.Sphere);u(this,"_tempBox",new y.Box3);u(this,"_tempBox2",new y.Box3);u(this,"tempMatrix",new y.Matrix4);u(this,"_tempWorldPosition",new y.Vector3);u(this,"_tempBoxSize",new y.Vector3);u(this,"_tempBox2Size",new y.Vector3);this.renderer=t,this.context={...e}}static getObjectLODState(t){return t[De]}static addPlugin(t){Q.push(t)}static removePlugin(t){const e=Q.indexOf(t);e>=0&&Q.splice(e,1)}static get(t,e){if(t[ve])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[ve];const s=new b(t,{engine:"unknown",...e});return t[ve]=s,s}get plugins(){return Q}awaitLoading(t){const e=this._promiseGroupIds++,s=new pe(L(this,J),{...t});this._newPromiseGroups.push(s);const n=performance.now();return s.ready.finally(()=>{const r=this._newPromiseGroups.indexOf(s);r>=0&&(this._newPromiseGroups.splice(r,1),nt()&&performance.measure("LODsManager:awaitLoading",{start:n,detail:{id:e,name:t==null?void 0:t.name,awaited:s.awaitedCount,resolved:s.resolvedCount}}))}),s.ready}_postprocessPromiseGroups(){if(this._newPromiseGroups.length!==0)for(let t=this._newPromiseGroups.length-1;t>=0;t--)this._newPromiseGroups[t].update(L(this,J))}addEventListener(t,e){t==="changed"&&this._lodchangedlisteners.push(e)}removeEventListener(t,e){if(t==="changed"){const s=this._lodchangedlisteners.indexOf(e);s>=0&&this._lodchangedlisteners.splice(s,1)}}enable(){if(L(this,K))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let t=0;z(this,K,this.renderer.render);const e=this;Te(this.renderer),this.renderer.render=function(s,n){const r=e.renderer.getRenderTarget();(r==null||"isXRRenderTarget"in r&&r.isXRRenderTarget)&&(t=0,z(e,J,L(e,J)+1),z(e,re,L(e,ye).getDelta()),z(e,Le,L(e,Le)+L(e,re)),e._fpsBuffer.shift(),e._fpsBuffer.push(1/L(e,re)),z(e,Y,e._fpsBuffer.reduce((a,l)=>a+l)/e._fpsBuffer.length),N&&L(e,J)%200===0&&console.log("FPS",Math.round(L(e,Y)),"Interval:",L(e,R)));const i=t++;L(e,K).call(this,s,n),e.onAfterRender(s,n,i)}}disable(){L(this,K)&&(console.debug("[gltf-progressive] Disabling LODsManager for renderer"),this.renderer.render=L(this,K),z(this,K,void 0))}update(t,e){this.internalUpdate(t,e)}onAfterRender(t,e,s){if(this.pause)return;const r=this.renderer.renderLists.get(t,0).opaque;let i=!0;if(r.length===1){const a=r[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(dt||(this.updateInterval==="auto"?L(this,Y)<40&&L(this,R)<10?(z(this,R,L(this,R)+1),N&&console.warn("↓ Reducing LOD updates",L(this,R),L(this,Y).toFixed(0))):L(this,Y)>=60&&L(this,R)>1&&(z(this,R,L(this,R)-1),N&&console.warn("↑ Increasing LOD updates",L(this,R),L(this,Y).toFixed(0))):z(this,R,this.updateInterval),L(this,R)>0&&L(this,J)%L(this,R)!=0))return;this.internalUpdate(t,e),this._postprocessPromiseGroups()}}internalUpdate(t,e){var l,c;const s=this.renderer.renderLists.get(t,0),n=s.opaque;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse);const r=this.targetTriangleDensity;for(const d of n){if(d.material&&(((l=d.geometry)==null?void 0:l.type)==="BoxGeometry"||((c=d.geometry)==null?void 0:c.type)==="BufferGeometry")&&(d.material.name==="SphericalGaussianBlur"||d.material.name=="BackgroundCubeMaterial"||d.material.name==="CubemapFromEquirect"||d.material.name==="EquirectangularToCubeUV")){N&&(d.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(d.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",d,d.material.name,d.material.type)));continue}switch(d.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}if(N==="color"&&d.material&&!d.object.progressive_debug_color){d.object.progressive_debug_color=!0;const f=Math.random()*16777215,M=new y.MeshStandardMaterial({color:f});d.object.material=M}const p=d.object;(p instanceof y.Mesh||p.isMesh)&&this.updateLODs(t,e,p,r)}const i=s.transparent;for(const d of i){const p=d.object;(p instanceof y.Mesh||p.isMesh)&&this.updateLODs(t,e,p,r)}const a=s.transmissive;for(const d of a){const p=d.object;(p instanceof y.Mesh||p.isMesh)&&this.updateLODs(t,e,p,r)}}updateLODs(t,e,s,n){var a,l;s.userData||(s.userData={});let r=s[De];if(r||(r=new ct,s[De]=r),r.frames++<2)return;for(const c of Q)(a=c.onBeforeUpdateLOD)==null||a.call(c,this.renderer,t,e,s);const i=b.overrideGlobalLodLevel!==void 0?b.overrideGlobalLodLevel:te;i>=0?(k.mesh_lod=i,k.texture_lod=i):(this.calculateLodLevel(e,s,r,n,k),k.mesh_lod=Math.round(k.mesh_lod),k.texture_lod=Math.round(k.texture_lod)),k.mesh_lod>=0&&this.loadProgressiveMeshes(s,k.mesh_lod),s.material&&k.texture_lod>=0&&this.loadProgressiveTextures(s.material,k.texture_lod),x&&s.material&&!s.isGizmo&&ze(s.material);for(const c of Q)(l=c.onAfterUpdatedLOD)==null||l.call(c,this.renderer,t,e,s,k);r.lastLodLevel_Mesh=k.mesh_lod,r.lastLodLevel_Texture=k.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const r of t)this.loadProgressiveTextures(r,e);return}let s=!1;(t[H]===void 0||e<t[H])&&(s=!0);const n=t["DEBUG:LOD"];if(n!=null&&(s=t[H]!=n,e=n),s){t[H]=e;const r=T.assignTextureLOD(t,e).then(i=>{this._lodchangedlisteners.forEach(a=>a({type:"texture",level:e,object:t}))});pe.addPromise("texture",t,r,this._newPromiseGroups)}}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);let s=t[H]!==e;const n=t["DEBUG:LOD"];if(n!=null&&(s=t[H]!=n,e=n),s){t[H]=e;const r=t.geometry,i=T.assignMeshLOD(t,e).then(a=>(a&&t[H]==e&&r!=t.geometry&&this._lodchangedlisteners.forEach(l=>l({type:"mesh",level:e,object:t})),a));return pe.addPromise("mesh",t,i,this._newPromiseGroups),i}return Promise.resolve(null)}static isInside(t,e){const s=t.min,n=t.max,r=(s.x+n.x)*.5,i=(s.y+n.y)*.5;return this._tempPtInside.set(r,i,s.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,s,n,r){var S,F,Z;if(!e){r.mesh_lod=-1,r.texture_lod=-1;return}if(!t){r.mesh_lod=-1,r.texture_lod=-1;return}let a=10+1,l=!1;if(N&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const c=(S=T.getMeshLODExtension(e.geometry))==null?void 0:S.lods,d=T.getPrimitiveIndex(e.geometry),p=c&&c.length>0,f=T.getMaterialMinMaxLODsCount(e.material),M=(f==null?void 0:f.min_count)!=1/0&&f.min_count>0&&f.max_count>0;if(!p&&!M){r.mesh_lod=0,r.texture_lod=0;return}p||(l=!0,a=0);const D=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let C=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const h=e;if(!h.boundingBox)h.computeBoundingBox();else if(this.skinnedMeshAutoUpdateBoundsInterval>0){if(!h[b.$skinnedMeshBoundsOffset]){const G=b.skinnedMeshBoundsFrameOffsetCounter++;h[b.$skinnedMeshBoundsOffset]=G}const _=h[b.$skinnedMeshBoundsOffset];if((s.frames+_)%this.skinnedMeshAutoUpdateBoundsInterval===0){const G=ie(h),V=h.geometry;G&&(h.geometry=G),h.computeBoundingBox(),h.geometry=V}}C=h.boundingBox}if(C){const h=t;if(e.geometry.attributes.color&&e.geometry.attributes.color.count<100&&e.geometry.boundingSphere){this._sphere.copy(e.geometry.boundingSphere),this._sphere.applyMatrix4(e.matrixWorld);const g=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(g)){r.mesh_lod=0,r.texture_lod=0;return}}if(this._tempBox.copy(C),this._tempBox.applyMatrix4(e.matrixWorld),h.isPerspectiveCamera&&b.isInside(this._tempBox,this.projectionScreenMatrix)){r.mesh_lod=0,r.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&h.isPerspectiveCamera&&h.fov>70){const g=this._tempBox.min,w=this._tempBox.max;let B=g.x,$=g.y,q=w.x,ne=w.y;const de=2,xe=1.5,ce=(g.x+w.x)*.5,fe=(g.y+w.y)*.5;B=(B-ce)*de+ce,$=($-fe)*de+fe,q=(q-ce)*de+ce,ne=(ne-fe)*de+fe;const Ke=B<0&&q>0?0:Math.min(Math.abs(g.x),Math.abs(w.x)),Ye=$<0&&ne>0?0:Math.min(Math.abs(g.y),Math.abs(w.y)),_e=Math.max(Ke,Ye);s.lastCentrality=(xe-_e)*(xe-_e)*(xe-_e)}else s.lastCentrality=1;const _=this._tempBox.getSize(this._tempBoxSize);_.multiplyScalar(.5),screen.availHeight>0&&D>0&&_.multiplyScalar(D/screen.availHeight),t.isPerspectiveCamera?_.x*=t.aspect:t.isOrthographicCamera;const G=t.matrixWorldInverse,V=this._tempBox2;V.copy(C),V.applyMatrix4(e.matrixWorld),V.applyMatrix4(G);const P=V.getSize(this._tempBox2Size),ee=Math.max(P.x,P.y);if(Math.max(_.x,_.y)!=0&&ee!=0&&(_.z=P.z/Math.max(P.x,P.y)*Math.max(_.x,_.y)),s.lastScreenCoverage=Math.max(_.x,_.y,_.z),s.lastScreenspaceVolume.copy(_),s.lastScreenCoverage*=s.lastCentrality,N&&b.debugDrawLine){const g=this.tempMatrix.copy(this.projectionScreenMatrix);g.invert();const w=b.corner0,B=b.corner1,$=b.corner2,q=b.corner3;w.copy(this._tempBox.min),B.copy(this._tempBox.max),B.x=w.x,$.copy(this._tempBox.max),$.y=w.y,q.copy(this._tempBox.max);const ne=(w.z+q.z)*.5;w.z=B.z=$.z=q.z=ne,w.applyMatrix4(g),B.applyMatrix4(g),$.applyMatrix4(g),q.applyMatrix4(g),b.debugDrawLine(w,B,255),b.debugDrawLine(w,$,255),b.debugDrawLine(B,q,255),b.debugDrawLine($,q,255)}let v=999;if(c&&s.lastScreenCoverage>0)for(let g=0;g<c.length;g++){const w=c[g];if((((F=w.densities)==null?void 0:F[d])||w.density||1e-5)/s.lastScreenCoverage<n){v=g;break}}v<a&&(a=v,l=!0)}if(l?r.mesh_lod=a:r.mesh_lod=s.lastLodLevel_Mesh,N&&r.mesh_lod!=s.lastLodLevel_Mesh){const _=c==null?void 0:c[r.mesh_lod];_&&console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} → ${r.mesh_lod} (${_.density.toFixed(0)}) - ${e.name}`)}if(M){const h="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(s.lastLodLevel_Texture<0){if(r.texture_lod=f.max_count-1,N){const _=f.lods[f.max_count-1];N&&console.log(`First Texture LOD ${r.texture_lod} (${_.max_height}px) - ${e.name}`)}}else{const _=s.lastScreenspaceVolume.x+s.lastScreenspaceVolume.y+s.lastScreenspaceVolume.z;let G=s.lastScreenCoverage*4;((Z=this.context)==null?void 0:Z.engine)==="model-viewer"&&(G*=1.5);const P=D/window.devicePixelRatio*G;let ee=!1;for(let E=f.lods.length-1;E>=0;E--){const v=f.lods[E];if(!(h&&v.max_height>=2048)&&!(it()&&v.max_height>4096)&&(v.max_height>P||!ee&&E===0)){if(ee=!0,r.texture_lod=E,r.texture_lod<s.lastLodLevel_Texture){const m=v.max_height;N&&console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${r.texture_lod} = ${m}px
6
+ Screensize: ${P.toFixed(0)}px, Coverage: ${(100*s.lastScreenCoverage).toFixed(2)}%, Volume ${_.toFixed(1)}
7
+ ${e.name}`)}break}}}}else r.texture_lod=0}};let A=b;R=new WeakMap,K=new WeakMap,ye=new WeakMap,J=new WeakMap,re=new WeakMap,Le=new WeakMap,Y=new WeakMap,u(A,"debugDrawLine"),u(A,"overrideGlobalLodLevel"),u(A,"corner0",new y.Vector3),u(A,"corner1",new y.Vector3),u(A,"corner2",new y.Vector3),u(A,"corner3",new y.Vector3),u(A,"_tempPtInside",new y.Vector3),u(A,"skinnedMeshBoundsFrameOffsetCounter",0),u(A,"$skinnedMeshBoundsOffset",Symbol("gltf-progressive-skinnedMeshBoundsOffset"));class ct{constructor(){u(this,"frames",0);u(this,"lastLodLevel_Mesh",-1);u(this,"lastLodLevel_Texture",-1);u(this,"lastScreenCoverage",0);u(this,"lastScreenspaceVolume",new y.Vector3);u(this,"lastCentrality",0)}}const Be=Symbol("NEEDLE_mesh_lod"),he=Symbol("NEEDLE_texture_lod");let le=null;function Ge(){const o=ft();o&&(o.mapURLs(function(t){return $e(),t}),$e(),le==null||le.disconnect(),le=new MutationObserver(t=>{t.forEach(e=>{e.addedNodes.forEach(s=>{s instanceof HTMLElement&&s.tagName.toLowerCase()==="model-viewer"&&We(s)})})}),le.observe(document,{childList:!0,subtree:!0}))}function ft(){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"),Ge()}),null)}function $e(){if(typeof document>"u")return;document.querySelectorAll("model-viewer").forEach(t=>{We(t)})}const ke=new WeakSet;let ht=0;function We(o){if(!o||ke.has(o))return null;ke.add(o),console.debug("[gltf-progressive] found new model-viewer..."+ ++ht+`
8
+ `,o.getAttribute("src"));let t=null,e=null,s=null;for(let n=o;n!=null;n=Object.getPrototypeOf(n)){const r=Object.getOwnPropertySymbols(n),i=r.find(c=>c.toString()=="Symbol(renderer)"),a=r.find(c=>c.toString()=="Symbol(scene)"),l=r.find(c=>c.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 n=function(){if(s){let i=0,a=setInterval(()=>{if(i++>5){clearInterval(a);return}s==null||s.call(o)},300)}};console.debug("[gltf-progressive] setup model-viewer");const r=A.get(t,{engine:"model-viewer"});return A.addPlugin(new gt),r.enable(),r.addEventListener("changed",()=>{s==null||s.call(o)}),o.addEventListener("model-visibility",i=>{i.detail.visible&&(s==null||s.call(o))}),o.addEventListener("load",()=>{n()}),()=>{r.disable()}}return null}class gt{constructor(){u(this,"_didWarnAboutMissingUrl",!1)}onBeforeUpdateLOD(t,e,s,n){this.tryParseMeshLOD(e,n),this.tryParseTextureLOD(e,n)}getUrl(t){if(!t)return null;let e=t.getAttribute("src");return e||(e=t.src),e||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",t),this._didWarnAboutMissingUrl=!0),e}tryGetCurrentGLTF(t){return t._currentGLTF}tryGetCurrentModelViewer(t){return t.element}tryParseTextureLOD(t,e){if(e[he]==!0)return;e[he]=!0;const s=this.tryGetCurrentGLTF(t),n=this.tryGetCurrentModelViewer(t),r=this.getUrl(n);if(r&&s&&e.material){let i=function(l){var d,p,f;if(l[he]==!0)return;l[he]=!0,l.userData&&(l.userData.LOD=-1);const c=Object.keys(l);for(let M=0;M<c.length;M++){const D=c[M],C=l[D];if((C==null?void 0:C.isTexture)===!0){const S=(p=(d=C.userData)==null?void 0:d.associations)==null?void 0:p.textures;if(S==null)continue;const F=s.parser.json.textures[S];if(!F){console.warn("Texture data not found for texture index "+S);continue}if((f=F==null?void 0:F.extensions)!=null&&f[W]){const Z=F.extensions[W];Z&&r&&T.registerTexture(r,C,Z.lods.length,S,Z)}}}};const a=e.material;if(Array.isArray(a))for(const l of a)i(l);else i(a)}}tryParseMeshLOD(t,e){var i,a;if(e[Be]==!0)return;e[Be]=!0;const s=this.tryGetCurrentModelViewer(t),n=this.getUrl(s);if(!n)return;const r=(a=(i=e.userData)==null?void 0:i.gltfExtensions)==null?void 0:a[W];if(r&&n){const l=e.uuid;T.registerMesh(n,l,e,0,r.lods.length,r)}}}function Xe(o,t,e,s){Te(t),Ae(e),Ce(e,{progressive:!0,...s==null?void 0:s.hints}),e.register(r=>new T(r,o));const n=A.get(t);return(s==null?void 0:s.enableLODsManager)!==!1&&n.enable(),n}Ge();if(!at){const o={gltfProgressive:{useNeedleProgressive:Xe,LODsManager:A,configureLoader:Ce,getRaycastMesh:ie,useRaycastMeshes:qe}};if(!globalThis.Needle)globalThis.Needle=o;else for(const t in o)globalThis.Needle[t]=o[t]}exports.EXTENSION_NAME=W;exports.LODsManager=A;exports.NEEDLE_progressive=T;exports.VERSION=Re;exports.addDracoAndKTX2Loaders=Ae;exports.configureLoader=Ce;exports.createLoaders=Te;exports.getRaycastMesh=ie;exports.patchModelViewer=Ge;exports.registerRaycastMesh=Ve;exports.setDracoDecoderLocation=Fe;exports.setKTX2TranscoderLocation=Ne;exports.useNeedleProgressive=Xe;exports.useRaycastMeshes=qe;
@@ -123,6 +123,7 @@ export declare class NEEDLE_progressive implements GLTFLoaderPlugin {
123
123
  /** this contains the geometry/textures that were originally loaded */
124
124
  private static readonly lowresCache;
125
125
  private static getOrLoadLOD;
126
+ private static queue;
126
127
  private static assignLODInformation;
127
128
  private static getAssignedLODInformation;
128
129
  private static copySettings;
package/lib/extension.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { BufferGeometry, Mesh, Texture, TextureLoader } from "three";
2
2
  import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
3
3
  import { addDracoAndKTX2Loaders } from "./loaders.js";
4
- import { resolveUrl } from "./utils.internal.js";
4
+ import { PromiseQueue, resolveUrl } from "./utils.internal.js";
5
5
  import { getRaycastMesh, registerRaycastMesh } from "./utils.js";
6
6
  // All of this has to be removed
7
7
  // import { getRaycastMesh, setRaycastMesh } from "../../engine_physics.js";
@@ -499,20 +499,20 @@ export class NEEDLE_progressive {
499
499
  return null;
500
500
  }
501
501
  const LODKEY = LOD?.key;
502
- let progressiveInfo;
502
+ let lodInfo;
503
503
  // See https://github.com/needle-tools/needle-engine-support/issues/133
504
504
  if (current.isTexture === true) {
505
505
  const tex = current;
506
506
  if (tex.source && tex.source[$progressiveTextureExtension])
507
- progressiveInfo = tex.source[$progressiveTextureExtension];
507
+ lodInfo = tex.source[$progressiveTextureExtension];
508
508
  }
509
- if (!progressiveInfo)
510
- progressiveInfo = NEEDLE_progressive.lodInfos.get(LODKEY);
511
- if (progressiveInfo) {
509
+ if (!lodInfo)
510
+ lodInfo = NEEDLE_progressive.lodInfos.get(LODKEY);
511
+ if (lodInfo) {
512
512
  if (level > 0) {
513
513
  let useLowRes = false;
514
- const hasMultipleLevels = Array.isArray(progressiveInfo.lods);
515
- if (hasMultipleLevels && level >= progressiveInfo.lods.length) {
514
+ const hasMultipleLevels = Array.isArray(lodInfo.lods);
515
+ if (hasMultipleLevels && level >= lodInfo.lods.length) {
516
516
  useLowRes = true;
517
517
  }
518
518
  else if (!hasMultipleLevels) {
@@ -524,12 +524,12 @@ export class NEEDLE_progressive {
524
524
  }
525
525
  }
526
526
  /** the unresolved LOD url */
527
- const unresolved_lod_url = Array.isArray(progressiveInfo.lods) ? progressiveInfo.lods[level]?.path : progressiveInfo.lods;
527
+ const unresolved_lod_url = Array.isArray(lodInfo.lods) ? lodInfo.lods[level]?.path : lodInfo.lods;
528
528
  // check if we have a uri
529
529
  if (!unresolved_lod_url) {
530
- if (debug && !progressiveInfo["missing:uri"]) {
531
- progressiveInfo["missing:uri"] = true;
532
- console.warn("Missing uri for progressive asset for LOD " + level, progressiveInfo);
530
+ if (debug && !lodInfo["missing:uri"]) {
531
+ lodInfo["missing:uri"] = true;
532
+ console.warn("Missing uri for progressive asset for LOD " + level, lodInfo);
533
533
  }
534
534
  return null;
535
535
  }
@@ -537,12 +537,12 @@ export class NEEDLE_progressive {
537
537
  const lod_url = resolveUrl(LOD.url, unresolved_lod_url);
538
538
  // check if the requested file needs to be loaded via a GLTFLoader
539
539
  if (lod_url.endsWith(".glb") || lod_url.endsWith(".gltf")) {
540
- if (!progressiveInfo.guid) {
541
- console.warn("missing pointer for glb/gltf texture", progressiveInfo);
540
+ if (!lodInfo.guid) {
541
+ console.warn("missing pointer for glb/gltf texture", lodInfo);
542
542
  return null;
543
543
  }
544
544
  // check if the requested file has already been loaded
545
- const KEY = lod_url + "_" + progressiveInfo.guid;
545
+ const KEY = lod_url + "_" + lodInfo.guid;
546
546
  // check if the requested file is currently being loaded
547
547
  const existing = this.previouslyLoaded.get(KEY);
548
548
  if (existing !== undefined) {
@@ -581,7 +581,13 @@ export class NEEDLE_progressive {
581
581
  return res;
582
582
  }
583
583
  }
584
- const ext = progressiveInfo;
584
+ const slot = await this.queue.slot(lod_url);
585
+ if (!slot.use) {
586
+ if (debug)
587
+ console.log(`LOD ${level} was aborted: ${lod_url}`);
588
+ return null; // the request was aborted, we don't load it again
589
+ }
590
+ const ext = lodInfo;
585
591
  const request = new Promise(async (resolve, _) => {
586
592
  const loader = new GLTFLoader();
587
593
  addDracoAndKTX2Loaders(loader);
@@ -599,10 +605,11 @@ export class NEEDLE_progressive {
599
605
  }
600
606
  const gltf = await loader.loadAsync(url).catch(err => {
601
607
  console.error(`Error loading LOD ${level} from ${lod_url}\n`, err);
602
- return null;
608
+ return resolve(null);
603
609
  });
604
- if (!gltf)
605
- return null;
610
+ if (!gltf) {
611
+ return resolve(null);
612
+ }
606
613
  const parser = gltf.parser;
607
614
  if (debugverbose)
608
615
  console.log("Loading finished " + lod_url, ext.guid);
@@ -687,6 +694,7 @@ export class NEEDLE_progressive {
687
694
  return resolve(null);
688
695
  });
689
696
  this.previouslyLoaded.set(KEY, request);
697
+ slot.use(request);
690
698
  const res = await request;
691
699
  return res;
692
700
  }
@@ -697,12 +705,12 @@ export class NEEDLE_progressive {
697
705
  const loader = new TextureLoader();
698
706
  const tex = await loader.loadAsync(lod_url);
699
707
  if (tex) {
700
- tex.guid = progressiveInfo.guid;
708
+ tex.guid = lodInfo.guid;
701
709
  tex.flipY = false;
702
710
  tex.needsUpdate = true;
703
711
  tex.colorSpace = current.colorSpace;
704
712
  if (debugverbose)
705
- console.log(progressiveInfo, tex);
713
+ console.log(lodInfo, tex);
706
714
  }
707
715
  else if (debug)
708
716
  console.warn("failed loading", lod_url);
@@ -716,6 +724,7 @@ export class NEEDLE_progressive {
716
724
  }
717
725
  return null;
718
726
  }
727
+ static queue = new PromiseQueue(100, { debug: debug != false });
719
728
  static assignLODInformation(url, res, key, level, index) {
720
729
  if (!res)
721
730
  return;
@@ -149,6 +149,8 @@ export declare class LODsManager {
149
149
  private static corner3;
150
150
  private static readonly _tempPtInside;
151
151
  private static isInside;
152
+ private static skinnedMeshBoundsFrameOffsetCounter;
153
+ private static $skinnedMeshBoundsOffset;
152
154
  private calculateLodLevel;
153
155
  }
154
156
  declare class LOD_state {
@@ -457,6 +457,8 @@ export class LODsManager {
457
457
  const pt1 = this._tempPtInside.set(centerx, centery, min.z).applyMatrix4(matrix);
458
458
  return pt1.z < 0;
459
459
  }
460
+ static skinnedMeshBoundsFrameOffsetCounter = 0;
461
+ static $skinnedMeshBoundsOffset = Symbol("gltf-progressive-skinnedMeshBoundsOffset");
460
462
  calculateLodLevel(camera, mesh, state, desiredDensity, result) {
461
463
  if (!mesh) {
462
464
  result.mesh_lod = -1;
@@ -502,16 +504,25 @@ export class LODsManager {
502
504
  skinnedMesh.computeBoundingBox();
503
505
  }
504
506
  // Fix: https://linear.app/needle/issue/NE-5264
505
- else if (this.skinnedMeshAutoUpdateBoundsInterval > 0
506
- && state.frames % this.skinnedMeshAutoUpdateBoundsInterval === 0) {
507
- // use lowres geometry for bounding box calculation
508
- const raycastmesh = getRaycastMesh(skinnedMesh);
509
- const originalGeometry = skinnedMesh.geometry;
510
- if (raycastmesh) {
511
- skinnedMesh.geometry = raycastmesh;
507
+ else if (this.skinnedMeshAutoUpdateBoundsInterval > 0) {
508
+ // Save a frame offset per object to stagger updates of skinned meshes across multiple frames
509
+ // This isn't a perfect solution to improve perf impact of skinned mesh updates (e.g. large skinned meshes would still be costly)
510
+ // But for many smaller meshes it helps to avoid spikes in performance
511
+ if (!skinnedMesh[LODsManager.$skinnedMeshBoundsOffset]) {
512
+ const offset = LODsManager.skinnedMeshBoundsFrameOffsetCounter++;
513
+ skinnedMesh[LODsManager.$skinnedMeshBoundsOffset] = offset;
514
+ }
515
+ const frameOffset = skinnedMesh[LODsManager.$skinnedMeshBoundsOffset];
516
+ if ((state.frames + frameOffset) % this.skinnedMeshAutoUpdateBoundsInterval === 0) {
517
+ // use lowres geometry for bounding box calculation
518
+ const raycastmesh = getRaycastMesh(skinnedMesh);
519
+ const originalGeometry = skinnedMesh.geometry;
520
+ if (raycastmesh) {
521
+ skinnedMesh.geometry = raycastmesh;
522
+ }
523
+ skinnedMesh.computeBoundingBox();
524
+ skinnedMesh.geometry = originalGeometry;
512
525
  }
513
- skinnedMesh.computeBoundingBox();
514
- skinnedMesh.geometry = originalGeometry;
515
526
  }
516
527
  boundingBox = skinnedMesh.boundingBox;
517
528
  }