@needle-tools/gltf-progressive 2.1.0-experimental.3 → 2.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 Ue=Object.defineProperty,ze=(t,e,s)=>e in t?Ue(t,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):t[e]=s,c=(t,e,s)=>(ze(t,typeof e!="symbol"?e+"":e,s),s),Te=(t,e,s)=>{if(!e.has(t))throw TypeError("Cannot "+s)},v=(t,e,s)=>(Te(t,e,"read from private field"),s?s.call(t):e.get(t)),V=(t,e,s)=>{if(e.has(t))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(t):e.set(t,s)},G=(t,e,s,o)=>(Te(t,e,"write to private field"),o?o.call(t,s):e.set(t,s),s);import{BufferGeometry as le,Mesh as q,Material as Ve,Texture as ee,TextureLoader as qe,Matrix4 as Ee,Clock as Xe,MeshStandardMaterial as He,Sphere as Ke,Box3 as Ae,Vector3 as N}from"three";import{GLTFLoader as me}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as Ye}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as Je}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as Qe}from"three/examples/jsm/loaders/KTX2Loader.js";const pe="";globalThis.GLTF_PROGRESSIVE_VERSION=pe,console.debug(`[gltf-progressive] version ${pe}`);let Y="https://www.gstatic.com/draco/versioned/decoders/1.5.7/",te="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";const Ze=Y,et=te,tt=new URL(Y+"draco_decoder.js");fetch(tt,{method:"GET",headers:{Range:"bytes=0-1"}}).catch(t=>{Y===Ze&&(Y="./include/draco/"),te===et&&(te="./include/ktx2/")}).finally(()=>{Ie()});function st(t){Y=t}function rt(t){te=t}let X,ue,H;function Ie(){X||(X=new Je,X.setDecoderPath(Y),X.setDecoderConfig({type:"js"}),X.preload()),H||(H=new Qe,H.setTranscoderPath(te),H.init()),ue||(ue=Ye)}function ye(t){return Ie(),t?H.detectSupport(t):t!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:X,ktx2Loader:H,meshoptDecoder:ue}}function ve(t){t.dracoLoader||t.setDRACOLoader(X),t.ktx2Loader||t.setKTX2Loader(H),t.meshoptDecoder||t.setMeshoptDecoder(ue)}const xe=new WeakMap;function Le(t,e){let s=xe.get(t);s?s=Object.assign(s,e):s=e,xe.set(t,s)}const Pe=me.prototype.load;function nt(...t){const e=xe.get(this);let s=t[0];const o=new URL(s,window.location.href);if(o.hostname.endsWith("needle.tools")){const r=e?.progressive!==void 0?e.progressive:!0,n=e!=null&&e.usecase?e.usecase:"default";r?this.requestHeader.Accept=`*/*;progressive=allowed;usecase=${n}`:this.requestHeader.Accept=`*/*;usecase=${n}`,s=o.toString()}return t[0]=s,Pe?.call(this,...t)}me.prototype.load=nt,se("debugprogressive");function se(t){if(typeof window>"u")return!1;const e=new URL(window.location.href).searchParams.get(t);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function ot(t,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||t===void 0)return e;const s=t.lastIndexOf("/");if(s>=0){const o=t.substring(0,s+1);for(;o.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return o+e}return e}let ce;function it(){return ce!==void 0||(ce=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),se("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",ce)),ce}const at=typeof window>"u"&&typeof document>"u",Me=Symbol("needle:raycast-mesh");function J(t){return t?.[Me]instanceof le?t[Me]:null}function ke(t,e){if((t.type==="Mesh"||t.type==="SkinnedMesh")&&!J(t)){const s=lt(e);s.userData={isRaycastMesh:!0},t[Me]=s}}function Be(t=!0){if(t){if(re)return;const e=re=q.prototype.raycast;q.prototype.raycast=function(s,o){const r=this,n=J(r);let i;n&&r.isMesh&&(i=r.geometry,r.geometry=n),e.call(this,s,o),i&&(r.geometry=i)}}else{if(!re)return;q.prototype.raycast=re,re=null}}let re=null;function lt(t){const e=new le;for(const s in t.attributes)e.setAttribute(s,t.getAttribute(s));return e.setIndex(t.getIndex()),e}const $=new Array,j="NEEDLE_progressive",x=se("debugprogressive"),De=Symbol("needle-progressive-texture"),ne=new Map,we=new Set;if(x){let t=function(){e+=1,console.log("Toggle LOD level",e,ne),ne.forEach((r,n)=>{for(const i of r.keys){const l=n[i];if(l!=null){if(l.isBufferGeometry===!0){const u=S.getMeshLODInformation(l),a=u?Math.min(e,u.lods.length):0;n["DEBUG:LOD"]=e,S.assignMeshLOD(n,a),u&&(s=Math.max(s,u.lods.length-1))}else if(n.isMaterial===!0){n["DEBUG:LOD"]=e,S.assignTextureLOD(n,e);break}}}}),e>=s&&(e=-1)},e=-1,s=2,o=!1;window.addEventListener("keyup",r=>{r.key==="p"&&t(),r.key==="w"&&(o=!o,we&&we.forEach(n=>{n.name!="BackgroundCubeMaterial"&&n.glyphMap==null&&"wireframe"in n&&(n.wireframe=o)}))})}function Re(t,e,s){var o;if(!x)return;ne.has(t)||ne.set(t,{keys:[],sourceId:s});const r=ne.get(t);((o=r?.keys)==null?void 0:o.includes(e))==!1&&r.keys.push(e)}const w=class{constructor(t,e){c(this,"parser"),c(this,"url"),c(this,"_isLoadingMesh"),c(this,"loadMesh",s=>{var o,r;if(this._isLoadingMesh)return null;const n=(r=(o=this.parser.json.meshes[s])==null?void 0:o.extensions)==null?void 0:r[j];return n?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",s).then(i=>{var l;return this._isLoadingMesh=!1,i&&w.registerMesh(this.url,n.guid,i,(l=n.lods)==null?void 0:l.length,void 0,n),i})):null}),x&&console.log("Progressive extension registered for",e),this.parser=t,this.url=e}get name(){return j}static getMeshLODInformation(t){const e=this.getAssignedLODInformation(t);return e!=null&&e.key?this.lodInfos.get(e.key):null}static getMaterialMinMaxLODsCount(t,e){const s=this,o="LODS:minmax",r=t[o];if(r!=null)return r;if(e||(e={min_count:1/0,max_count:0,lods:[]}),Array.isArray(t)){for(const i of t)this.getMaterialMinMaxLODsCount(i,e);return t[o]=e,e}if(x==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const i=t;for(const l of Object.keys(i.uniforms)){const u=i.uniforms[l].value;u?.isTexture===!0&&n(u,e)}}else if(t.isMaterial)for(const i of Object.keys(t)){const l=t[i];l?.isTexture===!0&&n(l,e)}return t[o]=e,e;function n(i,l){const u=s.getAssignedLODInformation(i);if(u){const a=s.lodInfos.get(u.key);if(a&&a.lods){l.min_count=Math.min(l.min_count,a.lods.length),l.max_count=Math.max(l.max_count,a.lods.length);for(let f=0;f<a.lods.length;f++){const g=a.lods[f];g.width&&(l.lods[f]=l.lods[f]||{min_height:1/0,max_height:0},l.lods[f].min_height=Math.min(l.lods[f].min_height,g.height),l.lods[f].max_height=Math.max(l.lods[f].max_height,g.height))}}}}}static hasLODLevelAvailable(t,e){var s;if(Array.isArray(t)){for(const n of t)if(this.hasLODLevelAvailable(n,e))return!0;return!1}if(t.isMaterial===!0){for(const n of Object.keys(t)){const i=t[n];if(i&&i.isTexture&&this.hasLODLevelAvailable(i,e))return!0}return!1}else if(t.isGroup===!0){for(const n of t.children)if(n.isMesh===!0&&this.hasLODLevelAvailable(n,e))return!0}let o,r;if(t.isMesh?o=t.geometry:(t.isBufferGeometry||t.isTexture)&&(o=t),o&&(s=o?.userData)!=null&&s.LODS){const n=o.userData.LODS;if(r=this.lodInfos.get(n.key),e===void 0)return r!=null;if(r)return Array.isArray(r.lods)?e<r.lods.length:e===0}return!1}static assignMeshLOD(t,e){var s;if(!t)return Promise.resolve(null);if(t instanceof q||t.isMesh===!0){const o=t.geometry,r=this.getAssignedLODInformation(o);if(!r)return Promise.resolve(null);for(const n of $)(s=n.onBeforeGetLODMesh)==null||s.call(n,t,e);return t["LOD:requested level"]=e,w.getOrLoadLOD(o,e).then(n=>{if(Array.isArray(n)){const i=r.index||0;n=n[i]}return t["LOD:requested level"]===e&&(delete t["LOD:requested level"],n&&o!=n&&(n?.isBufferGeometry?(t.geometry=n,x&&Re(t,"geometry",r.url)):x&&console.error("Invalid LOD geometry",n))),n}).catch(n=>(console.error("Error loading mesh LOD",t,n),null))}else x&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",t);return Promise.resolve(null)}static assignTextureLOD(t,e=0){if(!t)return Promise.resolve(null);if(t.isMesh===!0){const s=t;if(Array.isArray(s.material)){const o=new Array;for(const r of s.material){const n=this.assignTextureLOD(r,e);o.push(n)}return Promise.all(o).then(r=>{const n=new Array;for(const i of r)Array.isArray(i)&&n.push(...i);return n})}else return this.assignTextureLOD(s.material,e)}if(t instanceof Ve||t.isMaterial===!0){const s=t,o=[],r=new Array;if(x&&we.add(s),s.uniforms&&(s.isRawShaderMaterial||s.isShaderMaterial===!0)){const n=s;for(const i of Object.keys(n.uniforms)){const l=n.uniforms[i].value;if(l?.isTexture===!0){const u=this.assignTextureLODForSlot(l,e,s,i).then(a=>(a&&n.uniforms[i].value!=a&&(n.uniforms[i].value=a,n.uniformsNeedUpdate=!0),a));o.push(u),r.push(i)}}}else for(const n of Object.keys(s)){const i=s[n];if(i?.isTexture===!0){const l=this.assignTextureLODForSlot(i,e,s,n);o.push(l),r.push(n)}}return Promise.all(o).then(n=>{const i=new Array;for(let l=0;l<n.length;l++){const u=n[l],a=r[l];u&&u.isTexture===!0?i.push({material:s,slot:a,texture:u,level:e}):i.push({material:s,slot:a,texture:null,level:e})}return i})}if(t instanceof ee||t.isTexture===!0){const s=t;return this.assignTextureLODForSlot(s,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,s,o){return t?.isTexture!==!0?Promise.resolve(null):o==="glyphMap"?Promise.resolve(t):w.getOrLoadLOD(t,e).then(r=>{if(Array.isArray(r))return null;if(r?.isTexture===!0){if(r!=t){if(s&&o){const n=s[o];if(n){const i=this.getAssignedLODInformation(n);if(i&&i?.level<e)return x==="verbose"&&console.warn("Assigned texture level is already higher: ",i.level,e,s,n,r),null}s[o]=r}if(x&&o&&s){const n=this.getAssignedLODInformation(t);n&&Re(s,o,n.url)}}return r}else x=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(r=>(console.error("Error loading LOD",t,r),null))}afterRoot(t){var e,s;return x&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((o,r)=>{var n;if(o!=null&&o.extensions){const i=o?.extensions[j];if(i){if(!i.lods){x&&console.warn("Texture has no LODs",i);return}let l=!1;for(const u of this.parser.associations.keys())if(u.isTexture===!0){const a=this.parser.associations.get(u);a?.textures===r&&(l=!0,w.registerTexture(this.url,u,(n=i.lods)==null?void 0:n.length,r,i))}l||this.parser.getDependency("texture",r).then(u=>{var a;u&&w.registerTexture(this.url,u,(a=i.lods)==null?void 0:a.length,r,i)})}}}),(s=this.parser.json.meshes)==null||s.forEach((o,r)=>{if(o!=null&&o.extensions){const n=o?.extensions[j];if(n&&n.lods){for(const i of this.parser.associations.keys())if(i.isMesh){const l=this.parser.associations.get(i);l?.meshes===r&&w.registerMesh(this.url,n.guid,i,n.lods.length,l.primitives,n)}}}}),null}static async getOrLoadLOD(t,e){var s,o,r,n;const i=x=="verbose",l=t.userData.LODS;if(!l)return null;const u=l?.key;let a;if(t.isTexture===!0){const f=t;f.source&&f.source[De]&&(a=f.source[De])}if(a||(a=w.lodInfos.get(u)),a){if(e>0){let p=!1;const A=Array.isArray(a.lods);if(A&&e>=a.lods.length?p=!0:A||(p=!0),p)return this.lowresCache.get(u)}const f=Array.isArray(a.lods)?(s=a.lods[e])==null?void 0:s.path:a.lods;if(!f)return x&&!a["missing:uri"]&&(a["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,a)),null;const g=ot(l.url,f);if(g.endsWith(".glb")||g.endsWith(".gltf")){if(!a.guid)return console.warn("missing pointer for glb/gltf texture",a),null;const p=g+"_"+a.guid,A=this.previouslyLoaded.get(p);if(A!==void 0){i&&console.log(`LOD ${e} was already loading/loaded: ${p}`);let d=await A.catch(b=>(console.error(`Error loading LOD ${e} from ${g}
2
- `,b),null)),O=!1;if(d==null||(d instanceof ee&&t instanceof ee?(o=d.image)!=null&&o.data||(r=d.source)!=null&&r.data?d=this.copySettings(t,d):(O=!0,this.previouslyLoaded.delete(p)):d instanceof le&&t instanceof le&&((n=d.attributes.position)!=null&&n.array||(O=!0,this.previouslyLoaded.delete(p)))),!O)return d}const D=a,L=new Promise(async(d,O)=>{const b=new me;ve(b),x&&(await new Promise(m=>setTimeout(m,1e3)),i&&console.warn("Start loading (delayed) "+g,D.guid));let I=g;if(D&&Array.isArray(D.lods)){const m=D.lods[e];m.hash&&(I+="?v="+m.hash)}const T=await b.loadAsync(I).catch(m=>(console.error(`Error loading LOD ${e} from ${g}
3
- `,m),null));if(!T)return null;const W=T.parser;i&&console.log("Loading finished "+g,D.guid);let y=0;if(T.parser.json.textures){let m=!1;for(const h of T.parser.json.textures){if(h!=null&&h.extensions){const M=h?.extensions[j];if(M!=null&&M.guid&&M.guid===D.guid){m=!0;break}}y++}if(m){let h=await W.getDependency("texture",y);return h&&w.assignLODInformation(l.url,h,u,e,void 0,void 0),i&&console.log('change "'+t.name+'" \u2192 "'+h.name+'"',g,y,h,p),t instanceof ee&&(h=this.copySettings(t,h)),h&&(h.guid=D.guid),d(h)}else x&&console.warn("Could not find texture with guid",D.guid,T.parser.json)}if(y=0,T.parser.json.meshes){let m=!1;for(const h of T.parser.json.meshes){if(h!=null&&h.extensions){const M=h?.extensions[j];if(M!=null&&M.guid&&M.guid===D.guid){m=!0;break}}y++}if(m){const h=await W.getDependency("mesh",y),M=D;if(i&&console.log(`Loaded Mesh "${h.name}"`,g,y,h,p),h.isMesh===!0){const _=h.geometry;return w.assignLODInformation(l.url,_,u,e,void 0,M.density),d(_)}else{const _=new Array;for(let C=0;C<h.children.length;C++){const z=h.children[C];if(z.isMesh===!0){const K=z.geometry;w.assignLODInformation(l.url,K,u,e,C,M.density),_.push(K)}}return d(_)}}else x&&console.warn("Could not find mesh with guid",D.guid,T.parser.json)}return d(null)});return this.previouslyLoaded.set(p,L),await L}else if(t instanceof ee){i&&console.log("Load texture from uri: "+g);const p=await new qe().loadAsync(g);return p?(p.guid=a.guid,p.flipY=!1,p.needsUpdate=!0,p.colorSpace=t.colorSpace,i&&console.log(a,p)):x&&console.warn("failed loading",g),p}}else x&&console.warn(`Can not load LOD ${e}: no LOD info found for "${u}" ${t.name}`,t.type);return null}static assignLODInformation(t,e,s,o,r,n){if(!e)return;e.userData||(e.userData={});const i=new ut(t,s,o,r,n);e.userData.LODS=i}static getAssignedLODInformation(t){var e;return((e=t?.userData)==null?void 0:e.LODS)||null}static copySettings(t,e){return e=e.clone(),x&&console.warn(`Copying texture settings
1
+ var Ue=Object.defineProperty,ze=(t,e,r)=>e in t?Ue(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,c=(t,e,r)=>(ze(t,typeof e!="symbol"?e+"":e,r),r),Te=(t,e,r)=>{if(!e.has(t))throw TypeError("Cannot "+r)},L=(t,e,r)=>(Te(t,e,"read from private field"),r?r.call(t):e.get(t)),q=(t,e,r)=>{if(e.has(t))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(t):e.set(t,r)},G=(t,e,r,n)=>(Te(t,e,"write to private field"),n?n.call(t,r):e.set(t,r),r);import{BufferGeometry as le,Mesh as X,Texture as ee,TextureLoader as Ve,Matrix4 as Ee,Clock as qe,MeshStandardMaterial as Xe,Sphere as He,Box3 as Ae,Vector3 as W}from"three";import{GLTFLoader as me}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as Ke}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as Ye}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as Je}from"three/examples/jsm/loaders/KTX2Loader.js";const pe="";globalThis.GLTF_PROGRESSIVE_VERSION=pe,console.debug(`[gltf-progressive] version ${pe}`);let J="https://www.gstatic.com/draco/versioned/decoders/1.5.7/",te="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";const Qe=J,Ze=te,et=new URL(J+"draco_decoder.js");fetch(et,{method:"GET",headers:{Range:"bytes=0-1"}}).catch(t=>{J===Qe&&(J="./include/draco/"),te===Ze&&(te="./include/ktx2/")}).finally(()=>{Pe()});function tt(t){J=t}function rt(t){te=t}let H,ue,K;function Pe(){H||(H=new Ye,H.setDecoderPath(J),H.setDecoderConfig({type:"js"}),H.preload()),K||(K=new Je,K.setTranscoderPath(te),K.init()),ue||(ue=Ke)}function ve(t){return Pe(),t?K.detectSupport(t):t!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:H,ktx2Loader:K,meshoptDecoder:ue}}function ye(t){t.dracoLoader||t.setDRACOLoader(H),t.ktx2Loader||t.setKTX2Loader(K),t.meshoptDecoder||t.setMeshoptDecoder(ue)}const xe=new WeakMap;function Le(t,e){let r=xe.get(t);r?r=Object.assign(r,e):r=e,xe.set(t,r)}const Ie=me.prototype.load;function st(...t){const e=xe.get(this);let r=t[0];const n=new URL(r,window.location.href);if(n.hostname.endsWith("needle.tools")){const s=e?.progressive!==void 0?e.progressive:!0,o=e!=null&&e.usecase?e.usecase:"default";s?this.requestHeader.Accept=`*/*;progressive=allowed;usecase=${o}`:this.requestHeader.Accept=`*/*;usecase=${o}`,r=n.toString()}return t[0]=r,Ie?.call(this,...t)}me.prototype.load=st,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 ot(t,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||t===void 0)return e;const r=t.lastIndexOf("/");if(r>=0){const n=t.substring(0,r+1);for(;n.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return n+e}return e}let ce;function nt(){return ce!==void 0||(ce=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),re("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",ce)),ce}const it=typeof window>"u"&&typeof document>"u",Me=Symbol("needle:raycast-mesh");function Q(t){return t?.[Me]instanceof le?t[Me]:null}function Be(t,e){if((t.type==="Mesh"||t.type==="SkinnedMesh")&&!Q(t)){const r=at(e);r.userData={isRaycastMesh:!0},t[Me]=r}}function Ce(t=!0){if(t){if(se)return;const e=se=X.prototype.raycast;X.prototype.raycast=function(r,n){const s=this,o=Q(s);let i;o&&s.isMesh&&(i=s.geometry,s.geometry=o),e.call(this,r,n),i&&(s.geometry=i)}}else{if(!se)return;X.prototype.raycast=se,se=null}}let se=null;function at(t){const e=new le;for(const r in t.attributes)e.setAttribute(r,t.getAttribute(r));return e.setIndex(t.getIndex()),e}const $=new Array,N="NEEDLE_progressive",y=re("debugprogressive"),De=Symbol("needle-progressive-texture"),oe=new Map,we=new Set;if(y){let t=function(){e+=1,console.log("Toggle LOD level",e,oe),oe.forEach((s,o)=>{for(const i of s.keys){const l=o[i];if(l!=null)if(l.isBufferGeometry===!0){const u=T.getMeshLODInformation(l),a=u?Math.min(e,u.lods.length):0;o["DEBUG:LOD"]=a,u&&(r=Math.max(r,u.lods.length-1))}else o.isMaterial===!0&&(o["DEBUG:LOD"]=e)}}),e>=r&&(e=-1)},e=-1,r=2,n=!1;window.addEventListener("keyup",s=>{s.key==="p"&&t(),s.key==="w"&&(n=!n,we&&we.forEach(o=>{o.name!="BackgroundCubeMaterial"&&o.glyphMap==null&&"wireframe"in o&&(o.wireframe=n)}))})}function ke(t,e,r){var n;if(!y)return;oe.has(t)||oe.set(t,{keys:[],sourceId:r});const s=oe.get(t);((n=s?.keys)==null?void 0:n.includes(e))==!1&&s.keys.push(e)}const w=class{constructor(t,e){c(this,"parser"),c(this,"url"),c(this,"_isLoadingMesh"),c(this,"loadMesh",r=>{var n,s;if(this._isLoadingMesh)return null;const o=(s=(n=this.parser.json.meshes[r])==null?void 0:n.extensions)==null?void 0:s[N];return o?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",r).then(i=>{var l;return this._isLoadingMesh=!1,i&&w.registerMesh(this.url,o.guid,i,(l=o.lods)==null?void 0:l.length,void 0,o),i})):null}),y&&console.log("Progressive extension registered for",e),this.parser=t,this.url=e}get name(){return N}static getMeshLODInformation(t){const e=this.getAssignedLODInformation(t);return e!=null&&e.key?this.lodInfos.get(e.key):null}static getMaterialMinMaxLODsCount(t,e){const r=this,n="LODS:minmax",s=t[n];if(s!=null)return s;if(e||(e={min_count:1/0,max_count:0,lods:[]}),Array.isArray(t)){for(const i of t)this.getMaterialMinMaxLODsCount(i,e);return t[n]=e,e}if(y==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const i=t;for(const l of Object.keys(i.uniforms)){const u=i.uniforms[l].value;u?.isTexture===!0&&o(u,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 u=r.getAssignedLODInformation(i);if(u){const a=r.lodInfos.get(u.key);if(a&&a.lods){l.min_count=Math.min(l.min_count,a.lods.length),l.max_count=Math.max(l.max_count,a.lods.length);for(let f=0;f<a.lods.length;f++){const g=a.lods[f];g.width&&(l.lods[f]=l.lods[f]||{min_height:1/0,max_height:0},l.lods[f].min_height=Math.min(l.lods[f].min_height,g.height),l.lods[f].max_height=Math.max(l.lods[f].max_height,g.height))}}}}}static hasLODLevelAvailable(t,e){var 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 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,s;if(t.isMesh?n=t.geometry:(t.isBufferGeometry||t.isTexture)&&(n=t),n&&(r=n?.userData)!=null&&r.LODS){const o=n.userData.LODS;if(s=this.lodInfos.get(o.key),e===void 0)return s!=null;if(s)return Array.isArray(s.lods)?e<s.lods.length:e===0}return!1}static assignMeshLOD(t,e){var r;if(!t)return Promise.resolve(null);if(t instanceof X||t.isMesh===!0){const n=t.geometry,s=this.getAssignedLODInformation(n);if(!s)return Promise.resolve(null);for(const o of $)(r=o.onBeforeGetLODMesh)==null||r.call(o,t,e);return t["LOD:requested level"]=e,w.getOrLoadLOD(n,e).then(o=>{if(Array.isArray(o)){const i=s.index||0;o=o[i]}return t["LOD:requested level"]===e&&(delete t["LOD:requested level"],o&&n!=o&&(o?.isBufferGeometry?(t.geometry=o,y&&ke(t,"geometry",s.url)):y&&console.error("Invalid LOD geometry",o))),o}).catch(o=>(console.error("Error loading mesh LOD",t,o),null))}else y&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",t);return Promise.resolve(null)}static assignTextureLOD(t,e=0){if(!t)return Promise.resolve(null);if(t.isMesh===!0){const r=t;if(Array.isArray(r.material)){const n=new Array;for(const s of r.material){const o=this.assignTextureLOD(s,e);n.push(o)}return Promise.all(n).then(s=>{const o=new Array;for(const i of s)Array.isArray(i)&&o.push(...i);return o})}else return this.assignTextureLOD(r.material,e)}if(t.isMaterial===!0){const r=t,n=[],s=new Array;if(y&&we.add(r),r.uniforms&&(r.isRawShaderMaterial||r.isShaderMaterial===!0)){const o=r;for(const i of Object.keys(o.uniforms)){const l=o.uniforms[i].value;if(l?.isTexture===!0){const u=this.assignTextureLODForSlot(l,e,r,i).then(a=>(a&&o.uniforms[i].value!=a&&(o.uniforms[i].value=a,o.uniformsNeedUpdate=!0),a));n.push(u),s.push(i)}}}else for(const o of Object.keys(r)){const i=r[o];if(i?.isTexture===!0){const l=this.assignTextureLODForSlot(i,e,r,o);n.push(l),s.push(o)}}return Promise.all(n).then(o=>{const i=new Array;for(let l=0;l<o.length;l++){const u=o[l],a=s[l];u&&u.isTexture===!0?i.push({material:r,slot:a,texture:u,level:e}):i.push({material:r,slot:a,texture:null,level:e})}return i})}if(t instanceof ee||t.isTexture===!0){const r=t;return this.assignTextureLODForSlot(r,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,r,n){return t?.isTexture!==!0?Promise.resolve(null):n==="glyphMap"?Promise.resolve(t):w.getOrLoadLOD(t,e).then(s=>{if(Array.isArray(s))return null;if(s?.isTexture===!0){if(s!=t){if(r&&n){const o=r[n];if(o&&!y){const i=this.getAssignedLODInformation(o);if(i&&i?.level<e)return y==="verbose"&&console.warn("Assigned texture level is already higher: ",i.level,e,r,o,s),null}r[n]=s}if(y&&n&&r){const o=this.getAssignedLODInformation(t);o?ke(r,n,o.url):console.warn("No LOD info for texture",t)}}return s}else y=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(s=>(console.error("Error loading LOD",t,s),null))}afterRoot(t){var e,r;return y&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((n,s)=>{var o;if(n!=null&&n.extensions){const i=n?.extensions[N];if(i){if(!i.lods){y&&console.warn("Texture has no LODs",i);return}let l=!1;for(const u of this.parser.associations.keys())if(u.isTexture===!0){const a=this.parser.associations.get(u);a?.textures===s&&(l=!0,w.registerTexture(this.url,u,(o=i.lods)==null?void 0:o.length,s,i))}l||this.parser.getDependency("texture",s).then(u=>{var a;u&&w.registerTexture(this.url,u,(a=i.lods)==null?void 0:a.length,s,i)})}}}),(r=this.parser.json.meshes)==null||r.forEach((n,s)=>{if(n!=null&&n.extensions){const o=n?.extensions[N];if(o&&o.lods){for(const i of this.parser.associations.keys())if(i.isMesh){const l=this.parser.associations.get(i);l?.meshes===s&&w.registerMesh(this.url,o.guid,i,o.lods.length,l.primitives,o)}}}}),null}static async getOrLoadLOD(t,e){var r,n,s,o;const i=y=="verbose",l=t.userData.LODS;if(!l)return null;const u=l?.key;let a;if(t.isTexture===!0){const f=t;f.source&&f.source[De]&&(a=f.source[De])}if(a||(a=w.lodInfos.get(u)),a){if(e>0){let v=!1;const A=Array.isArray(a.lods);if(A&&e>=a.lods.length?v=!0:A||(v=!0),v)return this.lowresCache.get(u)}const f=Array.isArray(a.lods)?(r=a.lods[e])==null?void 0:r.path:a.lods;if(!f)return y&&!a["missing:uri"]&&(a["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,a)),null;const g=ot(l.url,f);if(g.endsWith(".glb")||g.endsWith(".gltf")){if(!a.guid)return console.warn("missing pointer for glb/gltf texture",a),null;const v=g+"_"+a.guid,A=this.previouslyLoaded.get(v);if(A!==void 0){i&&console.log(`LOD ${e} was already loading/loaded: ${v}`);let d=await A.catch(_=>(console.error(`Error loading LOD ${e} from ${g}
2
+ `,_),null)),O=!1;if(d==null||(d instanceof ee&&t instanceof ee?(n=d.image)!=null&&n.data||(s=d.source)!=null&&s.data?d=this.copySettings(t,d):(O=!0,this.previouslyLoaded.delete(v)):d instanceof le&&t instanceof le&&((o=d.attributes.position)!=null&&o.array||(O=!0,this.previouslyLoaded.delete(v)))),!O)return d}const D=a,x=new Promise(async(d,O)=>{const _=new me;ye(_),y&&(await new Promise(p=>setTimeout(p,1e3)),i&&console.warn("Start loading (delayed) "+g,D.guid));let I=g;if(D&&Array.isArray(D.lods)){const p=D.lods[e];p.hash&&(I+="?v="+p.hash)}const b=await _.loadAsync(I).catch(p=>(console.error(`Error loading LOD ${e} from ${g}
3
+ `,p),null));if(!b)return null;const B=b.parser;i&&console.log("Loading finished "+g,D.guid);let m=0;if(b.parser.json.textures){let p=!1;for(const h of b.parser.json.textures){if(h!=null&&h.extensions){const M=h?.extensions[N];if(M!=null&&M.guid&&M.guid===D.guid){p=!0;break}}m++}if(p){let h=await B.getDependency("texture",m);return h&&w.assignLODInformation(l.url,h,u,e,void 0,void 0),i&&console.log('change "'+t.name+'" \u2192 "'+h.name+'"',g,m,h,v),t instanceof ee&&(h=this.copySettings(t,h)),h&&(h.guid=D.guid),d(h)}else y&&console.warn("Could not find texture with guid",D.guid,b.parser.json)}if(m=0,b.parser.json.meshes){let p=!1;for(const h of b.parser.json.meshes){if(h!=null&&h.extensions){const M=h?.extensions[N];if(M!=null&&M.guid&&M.guid===D.guid){p=!0;break}}m++}if(p){const h=await B.getDependency("mesh",m),M=D;if(i&&console.log(`Loaded Mesh "${h.name}"`,g,m,h,v),h.isMesh===!0){const S=h.geometry;return w.assignLODInformation(l.url,S,u,e,void 0,M.density),d(S)}else{const S=new Array;for(let j=0;j<h.children.length;j++){const V=h.children[j];if(V.isMesh===!0){const Y=V.geometry;w.assignLODInformation(l.url,Y,u,e,j,M.density),S.push(Y)}}return d(S)}}else y&&console.warn("Could not find mesh with guid",D.guid,b.parser.json)}return d(null)});return this.previouslyLoaded.set(v,x),await x}else if(t instanceof ee){i&&console.log("Load texture from uri: "+g);const v=await new Ve().loadAsync(g);return v?(v.guid=a.guid,v.flipY=!1,v.needsUpdate=!0,v.colorSpace=t.colorSpace,i&&console.log(a,v)):y&&console.warn("failed loading",g),v}}else y&&console.warn(`Can not load LOD ${e}: no LOD info found for "${u}" ${t.name}`,t.type);return null}static assignLODInformation(t,e,r,n,s,o){if(!e)return;e.userData||(e.userData={});const i=new lt(t,r,n,s,o);e.userData.LODS=i}static getAssignedLODInformation(t){var e;return((e=t?.userData)==null?void 0:e.LODS)||null}static copySettings(t,e){return y&&console.warn(`Copy texture settings
4
4
  `,t.uuid,`
5
- `,e.uuid),e.offset=t.offset,e.repeat=t.repeat,e.colorSpace=t.colorSpace,e.magFilter=t.magFilter,e.minFilter=t.minFilter,e.wrapS=t.wrapS,e.wrapT=t.wrapT,e.flipY=t.flipY,e.anisotropy=t.anisotropy,e.mipmaps||(e.generateMipmaps=t.generateMipmaps),e}};let S=w;c(S,"registerTexture",(t,e,s,o,r)=>{if(x&&console.log("> Progressive: register texture",o,e.name,e.uuid,e,r),!e){x&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[De]=r);const n=r.guid;w.assignLODInformation(t,e,n,s,o,void 0),w.lodInfos.set(n,r),w.lowresCache.set(n,e)}),c(S,"registerMesh",(t,e,s,o,r,n)=>{var i;x&&console.log("> Progressive: register mesh",r,s.name,n,s.uuid,s);const l=s.geometry;if(!l){x&&console.warn("gltf-progressive: Register mesh without geometry");return}l.userData||(l.userData={}),w.assignLODInformation(t,l,e,o,r,n.density),w.lodInfos.set(e,n);let u=w.lowresCache.get(e);u?u.push(s.geometry):u=[s.geometry],w.lowresCache.set(e,u),o>0&&!J(s)&&ke(s,l);for(const a of $)(i=a.onRegisteredNewMesh)==null||i.call(a,s,n)}),c(S,"lodInfos",new Map),c(S,"previouslyLoaded",new Map),c(S,"lowresCache",new Map);class ut{constructor(e,s,o,r,n){c(this,"url"),c(this,"key"),c(this,"level"),c(this,"index"),c(this,"density"),this.url=e,this.key=s,this.level=o,r!=null&&(this.index=r),n!=null&&(this.density=n)}}const k=se("debugprogressive"),ct=se("noprogressive"),Oe=Symbol("Needle:LODSManager"),be=Symbol("Needle:LODState"),Q=Symbol("Needle:CurrentLOD"),B={mesh_lod:-1,texture_lod:-1};var E,F,_e,Z,oe,de,U;const P=class{constructor(t,e){c(this,"context"),c(this,"renderer"),c(this,"projectionScreenMatrix",new Ee),c(this,"targetTriangleDensity",2e5),c(this,"updateInterval","auto"),V(this,E,1),c(this,"pause",!1),c(this,"manual",!1),c(this,"_lodchangedlisteners",[]),V(this,F,void 0),V(this,_e,new Xe),V(this,Z,0),V(this,oe,0),V(this,de,0),V(this,U,0),c(this,"_fpsBuffer",[60,60,60,60,60]),c(this,"_sphere",new Ke),c(this,"_tempBox",new Ae),c(this,"_tempBox2",new Ae),c(this,"tempMatrix",new Ee),c(this,"_tempWorldPosition",new N),c(this,"_tempBoxSize",new N),c(this,"_tempBox2Size",new N),this.renderer=t,this.context={...e}}static getObjectLODState(t){return t[be]}static addPlugin(t){$.push(t)}static removePlugin(t){const e=$.indexOf(t);e>=0&&$.splice(e,1)}static get(t,e){if(t[Oe])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[Oe];const s=new P(t,{engine:"unknown",...e});return t[Oe]=s,s}get plugins(){return $}addEventListener(t,e){t==="changed"&&this._lodchangedlisteners.push(e)}removeEventListener(t,e){if(t==="changed"){const s=this._lodchangedlisteners.indexOf(e);s>=0&&this._lodchangedlisteners.splice(s,1)}}enable(){if(v(this,F))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let t=0;G(this,F,this.renderer.render);const e=this;ye(this.renderer),this.renderer.render=function(s,o){const r=e.renderer.getRenderTarget();(r==null||"isXRRenderTarget"in r&&r.isXRRenderTarget)&&(t=0,G(e,Z,v(e,Z)+1),G(e,oe,v(e,_e).getDelta()),G(e,de,v(e,de)+v(e,oe)),e._fpsBuffer.shift(),e._fpsBuffer.push(1/v(e,oe)),G(e,U,e._fpsBuffer.reduce((i,l)=>i+l)/e._fpsBuffer.length),k&&v(e,Z)%200===0&&console.log("FPS",Math.round(v(e,U)),"Interval:",v(e,E)));const n=t++;v(e,F).call(this,s,o),e.onAfterRender(s,o,n)}}disable(){v(this,F)&&(console.debug("[gltf-progressive] Disabling LODsManager for renderer"),this.renderer.render=v(this,F),G(this,F,void 0))}update(t,e){this.internalUpdate(t,e)}onAfterRender(t,e,s){if(this.pause)return;const o=this.renderer.renderLists.get(t,0).opaque;let r=!0;if(o.length===1){const n=o[0].material;(n.name==="EffectMaterial"||n.name==="CopyShader")&&(r=!1)}if((e.parent&&e.parent.type==="CubeCamera"||s>=1&&e.type==="OrthographicCamera")&&(r=!1),r){if(ct||(this.updateInterval==="auto"?v(this,U)<40&&v(this,E)<10?(G(this,E,v(this,E)+1),k&&console.warn("\u2193 Reducing LOD updates",v(this,E),v(this,U).toFixed(0))):v(this,U)>=60&&v(this,E)>1&&(G(this,E,v(this,E)-1),k&&console.warn("\u2191 Increasing LOD updates",v(this,E),v(this,U).toFixed(0))):G(this,E,this.updateInterval),v(this,E)>0&&v(this,Z)%v(this,E)!=0))return;this.internalUpdate(t,e)}}internalUpdate(t,e){var s,o;const r=this.renderer.renderLists.get(t,0),n=r.opaque;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse);const i=this.targetTriangleDensity;for(const a of n){if(a.material&&(((s=a.geometry)==null?void 0:s.type)==="BoxGeometry"||((o=a.geometry)==null?void 0:o.type)==="BufferGeometry")&&(a.material.name==="SphericalGaussianBlur"||a.material.name=="BackgroundCubeMaterial"||a.material.name==="CubemapFromEquirect"||a.material.name==="EquirectangularToCubeUV")){k&&(a.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(a.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",a,a.material.name,a.material.type)));continue}switch(a.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}if(k==="color"&&a.material&&!a.object.progressive_debug_color){a.object.progressive_debug_color=!0;const g=Math.random()*16777215,p=new He({color:g});a.object.material=p}const f=a.object;(f instanceof q||f.isMesh)&&this.updateLODs(t,e,f,i)}const l=r.transparent;for(const a of l){const f=a.object;(f instanceof q||f.isMesh)&&this.updateLODs(t,e,f,i)}const u=r.transmissive;for(const a of u){const f=a.object;(f instanceof q||f.isMesh)&&this.updateLODs(t,e,f,i)}}updateLODs(t,e,s,o){var r,n;s.userData||(s.userData={});let i=s[be];if(i||(i=new dt,s[be]=i),i.frames++<2)return;for(const u of $)(r=u.onBeforeUpdateLOD)==null||r.call(u,this.renderer,t,e,s);this.calculateLodLevel(e,s,i,o,B),B.mesh_lod=Math.round(B.mesh_lod),B.texture_lod=Math.round(B.texture_lod),B.mesh_lod>=0&&this.loadProgressiveMeshes(s,B.mesh_lod);let l=B.texture_lod;if(s.material&&l>=0){const u=s["DEBUG:LOD"];u!=null&&(l=u),this.loadProgressiveTextures(s.material,l)}for(const u of $)(n=u.onAfterUpdatedLOD)==null||n.call(u,this.renderer,t,e,s,B);i.lastLodLevel_Mesh=B.mesh_lod,i.lastLodLevel_Texture=B.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const o of t)this.loadProgressiveTextures(o,e);return}let s=!1;(t[Q]===void 0||e<t[Q])&&(s=!0),s&&(t[Q]=e,S.assignTextureLOD(t,e).then(o=>{this._lodchangedlisteners.forEach(r=>r({type:"texture",level:e,object:t}))}))}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);if(t[Q]!==e){t[Q]=e;const s=t.geometry;return S.assignMeshLOD(t,e).then(o=>(o&&t[Q]==e&&s!=t.geometry&&this._lodchangedlisteners.forEach(r=>r({type:"mesh",level:e,object:t})),o))}return Promise.resolve(null)}static isInside(t,e){const s=t.min,o=t.max,r=(s.x+o.x)*.5,n=(s.y+o.y)*.5;return this._tempPtInside.set(r,n,s.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,s,o,r){var n;if(!e){r.mesh_lod=-1,r.texture_lod=-1;return}if(!t){r.mesh_lod=-1,r.texture_lod=-1;return}let i=10+1,l=!1;if(k&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const u=S.getMeshLODInformation(e.geometry),a=u?.lods,f=a&&a.length>0,g=S.getMaterialMinMaxLODsCount(e.material),p=g?.min_count!=1/0&&g.min_count>0&&g.max_count>0;if(!f&&!p){r.mesh_lod=0,r.texture_lod=0;return}f||(l=!0,i=0);const A=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let D=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const L=e;if(!L.boundingBox)L.computeBoundingBox();else if(s.frames%30===0){const d=J(L),O=L.geometry;d&&(L.geometry=d),L.computeBoundingBox(),L.geometry=O}D=L.boundingBox}if(D&&t.isPerspectiveCamera){const L=t;if(e.geometry.attributes.color&&e.geometry.attributes.color.count<100&&e.geometry.boundingSphere){this._sphere.copy(e.geometry.boundingSphere),this._sphere.applyMatrix4(e.matrixWorld);const y=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(y)){r.mesh_lod=0,r.texture_lod=0;return}}if(this._tempBox.copy(D),this._tempBox.applyMatrix4(e.matrixWorld),P.isInside(this._tempBox,this.projectionScreenMatrix)){r.mesh_lod=0,r.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&L.fov>70){const y=this._tempBox.min,m=this._tempBox.max;let h=y.x,M=y.y,_=m.x,C=m.y;const z=2,K=1.5,ie=(y.x+m.x)*.5,ae=(y.y+m.y)*.5;h=(h-ie)*z+ie,M=(M-ae)*z+ae,_=(_-ie)*z+ie,C=(C-ae)*z+ae;const $e=h<0&&_>0?0:Math.min(Math.abs(y.x),Math.abs(m.x)),Fe=M<0&&C>0?0:Math.min(Math.abs(y.y),Math.abs(m.y)),ge=Math.max($e,Fe);s.lastCentrality=(K-ge)*(K-ge)*(K-ge)}else s.lastCentrality=1;const d=this._tempBox.getSize(this._tempBoxSize);d.multiplyScalar(.5),screen.availHeight>0&&A>0&&d.multiplyScalar(A/screen.availHeight),d.x*=L.aspect;const O=t.matrixWorldInverse,b=this._tempBox2;b.copy(D),b.applyMatrix4(e.matrixWorld),b.applyMatrix4(O);const I=b.getSize(this._tempBox2Size),T=Math.max(I.x,I.y);if(Math.max(d.x,d.y)!=0&&T!=0&&(d.z=I.z/Math.max(I.x,I.y)*Math.max(d.x,d.y)),s.lastScreenCoverage=Math.max(d.x,d.y,d.z),s.lastScreenspaceVolume.copy(d),s.lastScreenCoverage*=s.lastCentrality,k&&P.debugDrawLine){const y=this.tempMatrix.copy(this.projectionScreenMatrix);y.invert();const m=P.corner0,h=P.corner1,M=P.corner2,_=P.corner3;m.copy(this._tempBox.min),h.copy(this._tempBox.max),h.x=m.x,M.copy(this._tempBox.max),M.y=m.y,_.copy(this._tempBox.max);const C=(m.z+_.z)*.5;m.z=h.z=M.z=_.z=C,m.applyMatrix4(y),h.applyMatrix4(y),M.applyMatrix4(y),_.applyMatrix4(y),P.debugDrawLine(m,h,255),P.debugDrawLine(m,M,255),P.debugDrawLine(h,_,255),P.debugDrawLine(M,_,255)}let W=999;if(a&&s.lastScreenCoverage>0){for(let y=0;y<a.length;y++)if(a[y].density/s.lastScreenCoverage<o){W=y;break}}W<i&&(i=W,l=!0)}if(l?r.mesh_lod=i:r.mesh_lod=s.lastLodLevel_Mesh,k&&r.mesh_lod!=s.lastLodLevel_Mesh){const L=a?.[r.mesh_lod];L&&console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} \u2192 ${r.mesh_lod} (${L.density.toFixed(0)}) - ${e.name}`)}if(p){const L="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(s.lastLodLevel_Texture<0){if(r.texture_lod=g.max_count-1,k){const d=g.lods[g.max_count-1];k&&console.log(`First Texture LOD ${r.texture_lod} (${d.max_height}px) - ${e.name}`)}}else{const d=s.lastScreenspaceVolume.x+s.lastScreenspaceVolume.y+s.lastScreenspaceVolume.z;let O=s.lastScreenCoverage*4;((n=this.context)==null?void 0:n.engine)==="model-viewer"&&(O*=1.5);const b=A/window.devicePixelRatio*O;for(let I=g.lods.length-1;I>=0;I--){let T=g.lods[I];if(!(L&&T.max_height>=2048)&&!(it()&&T.max_height>4096)&&T.max_height>b){if(r.texture_lod=I,r.texture_lod<s.lastLodLevel_Texture){const W=T.max_height;k&&console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} \u2192 ${r.texture_lod} = ${W}px
6
- Screensize: ${b.toFixed(0)}px, Coverage: ${(100*s.lastScreenCoverage).toFixed(2)}%, Volume ${d.toFixed(1)}
7
- ${e.name}`)}break}}}}else r.texture_lod=0}};let R=P;E=new WeakMap,F=new WeakMap,_e=new WeakMap,Z=new WeakMap,oe=new WeakMap,de=new WeakMap,U=new WeakMap,c(R,"debugDrawLine"),c(R,"corner0",new N),c(R,"corner1",new N),c(R,"corner2",new N),c(R,"corner3",new N),c(R,"_tempPtInside",new N);class dt{constructor(){c(this,"frames",0),c(this,"lastLodLevel_Mesh",-1),c(this,"lastLodLevel_Texture",-1),c(this,"lastScreenCoverage",0),c(this,"lastScreenspaceVolume",new N),c(this,"lastCentrality",0)}}const Ce=Symbol("NEEDLE_mesh_lod"),he=Symbol("NEEDLE_texture_lod");let fe=null;function Se(){const t=ht();t&&(t.mapURLs(function(e){return je(),e}),je(),fe?.disconnect(),fe=new MutationObserver(e=>{e.forEach(s=>{s.addedNodes.forEach(o=>{o instanceof HTMLElement&&o.tagName.toLowerCase()==="model-viewer"&&Ne(o)})})}),fe.observe(document,{childList:!0,subtree:!0}))}function ht(){return typeof customElements>"u"?null:customElements.get("model-viewer")||(customElements.whenDefined("model-viewer").then(()=>{console.debug("[gltf-progressive] model-viewer defined"),Se()}),null)}function je(){typeof document>"u"||document.querySelectorAll("model-viewer").forEach(t=>{Ne(t)})}const Ge=new WeakSet;let ft=0;function Ne(t){if(!t||Ge.has(t))return null;Ge.add(t),console.debug("[gltf-progressive] found new model-viewer..."+ ++ft+`
8
- `,t.getAttribute("src"));let e=null,s=null,o=null;for(let r=t;r!=null;r=Object.getPrototypeOf(r)){const n=Object.getOwnPropertySymbols(r),i=n.find(a=>a.toString()=="Symbol(renderer)"),l=n.find(a=>a.toString()=="Symbol(scene)"),u=n.find(a=>a.toString()=="Symbol(needsRender)");!e&&i!=null&&(e=t[i].threeRenderer),!s&&l!=null&&(s=t[l]),!o&&u!=null&&(o=t[u])}if(e&&s){let r=function(){if(o){let i=0,l=setInterval(()=>{if(i++>5){clearInterval(l);return}o?.call(t)},300)}};console.debug("[gltf-progressive] setup model-viewer");const n=R.get(e,{engine:"model-viewer"});return R.addPlugin(new gt),n.enable(),n.addEventListener("changed",()=>{o?.call(t)}),t.addEventListener("model-visibility",i=>{i.detail.visible&&o?.call(t)}),t.addEventListener("load",()=>{r()}),()=>{n.disable()}}return null}class gt{constructor(){c(this,"_didWarnAboutMissingUrl",!1)}onBeforeUpdateLOD(e,s,o,r){this.tryParseMeshLOD(s,r),this.tryParseTextureLOD(s,r)}getUrl(e){if(!e)return null;let s=e.getAttribute("src");return s||(s=e.src),s||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",e),this._didWarnAboutMissingUrl=!0),s}tryGetCurrentGLTF(e){return e._currentGLTF}tryGetCurrentModelViewer(e){return e.element}tryParseTextureLOD(e,s){if(s[he]==!0)return;s[he]=!0;const o=this.tryGetCurrentGLTF(e),r=this.tryGetCurrentModelViewer(e),n=this.getUrl(r);if(n&&o&&s.material){let i=function(u){var a,f,g;if(u[he]==!0)return;u[he]=!0,u.userData&&(u.userData.LOD=-1);const p=Object.keys(u);for(let A=0;A<p.length;A++){const D=p[A],L=u[D];if(L?.isTexture===!0){const d=(f=(a=L.userData)==null?void 0:a.associations)==null?void 0:f.textures;if(d==null)continue;const O=o.parser.json.textures[d];if(!O){console.warn("Texture data not found for texture index "+d);continue}if((g=O?.extensions)!=null&&g[j]){const b=O.extensions[j];b&&n&&S.registerTexture(n,L,b.lods.length,d,b)}}}};const l=s.material;if(Array.isArray(l))for(const u of l)i(u);else i(l)}}tryParseMeshLOD(e,s){var o,r;if(s[Ce]==!0)return;s[Ce]=!0;const n=this.tryGetCurrentModelViewer(e),i=this.getUrl(n);if(!i)return;const l=(r=(o=s.userData)==null?void 0:o.gltfExtensions)==null?void 0:r[j];if(l&&i){const u=s.uuid;S.registerMesh(i,u,s,0,l.lods.length,l)}}}function We(t,e,s,o){ye(e),ve(s),Le(s,{progressive:!0,...o?.hints}),s.register(n=>new S(n,t));const r=R.get(e);return o?.enableLODsManager!==!1&&r.enable(),r}if(Se(),!at){const t={gltfProgressive:{useNeedleProgressive:We,LODsManager:R,configureLoader:Le,getRaycastMesh:J,useRaycastMeshes:Be}};if(!globalThis.Needle)globalThis.Needle=t;else for(const e in t)globalThis.Needle[e]=t[e]}export{j as EXTENSION_NAME,R as LODsManager,S as NEEDLE_progressive,pe as VERSION,ve as addDracoAndKTX2Loaders,Le as configureLoader,ye as createLoaders,J as getRaycastMesh,Se as patchModelViewer,ke as registerRaycastMesh,st as setDracoDecoderLocation,rt as setKTX2TranscoderLocation,We as useNeedleProgressive,Be as useRaycastMeshes};
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}};let T=w;c(T,"registerTexture",(t,e,r,n,s)=>{if(y&&console.log("> Progressive: register texture",n,e.name,e.uuid,e,s),!e){y&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[De]=s);const o=s.guid;w.assignLODInformation(t,e,o,r,n,void 0),w.lodInfos.set(o,s),w.lowresCache.set(o,e)}),c(T,"registerMesh",(t,e,r,n,s,o)=>{var i;y&&console.log("> Progressive: register mesh",s,r.name,o,r.uuid,r);const l=r.geometry;if(!l){y&&console.warn("gltf-progressive: Register mesh without geometry");return}l.userData||(l.userData={}),w.assignLODInformation(t,l,e,n,s,o.density),w.lodInfos.set(e,o);let u=w.lowresCache.get(e);u?u.push(r.geometry):u=[r.geometry],w.lowresCache.set(e,u),n>0&&!Q(r)&&Be(r,l);for(const a of $)(i=a.onRegisteredNewMesh)==null||i.call(a,r,o)}),c(T,"lodInfos",new Map),c(T,"previouslyLoaded",new Map),c(T,"lowresCache",new Map);class lt{constructor(e,r,n,s,o){c(this,"url"),c(this,"key"),c(this,"level"),c(this,"index"),c(this,"density"),this.url=e,this.key=r,this.level=n,s!=null&&(this.index=s),o!=null&&(this.density=o)}}const C=re("debugprogressive"),ut=re("noprogressive"),Oe=Symbol("Needle:LODSManager"),_e=Symbol("Needle:LODState"),F=Symbol("Needle:CurrentLOD"),k={mesh_lod:-1,texture_lod:-1};var E,U,be,Z,ne,de,z;const P=class{constructor(t,e){c(this,"context"),c(this,"renderer"),c(this,"projectionScreenMatrix",new Ee),c(this,"targetTriangleDensity",2e5),c(this,"updateInterval","auto"),q(this,E,1),c(this,"pause",!1),c(this,"manual",!1),c(this,"_lodchangedlisteners",[]),q(this,U,void 0),q(this,be,new qe),q(this,Z,0),q(this,ne,0),q(this,de,0),q(this,z,0),c(this,"_fpsBuffer",[60,60,60,60,60]),c(this,"_sphere",new He),c(this,"_tempBox",new Ae),c(this,"_tempBox2",new Ae),c(this,"tempMatrix",new Ee),c(this,"_tempWorldPosition",new W),c(this,"_tempBoxSize",new W),c(this,"_tempBox2Size",new W),this.renderer=t,this.context={...e}}static getObjectLODState(t){return t[_e]}static addPlugin(t){$.push(t)}static removePlugin(t){const e=$.indexOf(t);e>=0&&$.splice(e,1)}static get(t,e){if(t[Oe])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[Oe];const r=new P(t,{engine:"unknown",...e});return t[Oe]=r,r}get plugins(){return $}addEventListener(t,e){t==="changed"&&this._lodchangedlisteners.push(e)}removeEventListener(t,e){if(t==="changed"){const r=this._lodchangedlisteners.indexOf(e);r>=0&&this._lodchangedlisteners.splice(r,1)}}enable(){if(L(this,U))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let t=0;G(this,U,this.renderer.render);const e=this;ve(this.renderer),this.renderer.render=function(r,n){const s=e.renderer.getRenderTarget();(s==null||"isXRRenderTarget"in s&&s.isXRRenderTarget)&&(t=0,G(e,Z,L(e,Z)+1),G(e,ne,L(e,be).getDelta()),G(e,de,L(e,de)+L(e,ne)),e._fpsBuffer.shift(),e._fpsBuffer.push(1/L(e,ne)),G(e,z,e._fpsBuffer.reduce((i,l)=>i+l)/e._fpsBuffer.length),C&&L(e,Z)%200===0&&console.log("FPS",Math.round(L(e,z)),"Interval:",L(e,E)));const o=t++;L(e,U).call(this,r,n),e.onAfterRender(r,n,o)}}disable(){L(this,U)&&(console.debug("[gltf-progressive] Disabling LODsManager for renderer"),this.renderer.render=L(this,U),G(this,U,void 0))}update(t,e){this.internalUpdate(t,e)}onAfterRender(t,e,r){if(this.pause)return;const n=this.renderer.renderLists.get(t,0).opaque;let s=!0;if(n.length===1){const o=n[0].material;(o.name==="EffectMaterial"||o.name==="CopyShader")&&(s=!1)}if((e.parent&&e.parent.type==="CubeCamera"||r>=1&&e.type==="OrthographicCamera")&&(s=!1),s){if(ut||(this.updateInterval==="auto"?L(this,z)<40&&L(this,E)<10?(G(this,E,L(this,E)+1),C&&console.warn("\u2193 Reducing LOD updates",L(this,E),L(this,z).toFixed(0))):L(this,z)>=60&&L(this,E)>1&&(G(this,E,L(this,E)-1),C&&console.warn("\u2191 Increasing LOD updates",L(this,E),L(this,z).toFixed(0))):G(this,E,this.updateInterval),L(this,E)>0&&L(this,Z)%L(this,E)!=0))return;this.internalUpdate(t,e)}}internalUpdate(t,e){var r,n;const s=this.renderer.renderLists.get(t,0),o=s.opaque;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse);const i=this.targetTriangleDensity;for(const a of o){if(a.material&&(((r=a.geometry)==null?void 0:r.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")){C&&(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(C==="color"&&a.material&&!a.object.progressive_debug_color){a.object.progressive_debug_color=!0;const g=Math.random()*16777215,v=new Xe({color:g});a.object.material=v}const f=a.object;(f instanceof X||f.isMesh)&&this.updateLODs(t,e,f,i)}const l=s.transparent;for(const a of l){const f=a.object;(f instanceof X||f.isMesh)&&this.updateLODs(t,e,f,i)}const u=s.transmissive;for(const a of u){const f=a.object;(f instanceof X||f.isMesh)&&this.updateLODs(t,e,f,i)}}updateLODs(t,e,r,n){var s,o;r.userData||(r.userData={});let i=r[_e];if(i||(i=new ct,r[_e]=i),i.frames++<2)return;for(const u of $)(s=u.onBeforeUpdateLOD)==null||s.call(u,this.renderer,t,e,r);this.calculateLodLevel(e,r,i,n,k),k.mesh_lod=Math.round(k.mesh_lod),k.texture_lod=Math.round(k.texture_lod),k.mesh_lod>=0&&this.loadProgressiveMeshes(r,k.mesh_lod);let l=k.texture_lod;r.material&&l>=0&&this.loadProgressiveTextures(r.material,l);for(const u of $)(o=u.onAfterUpdatedLOD)==null||o.call(u,this.renderer,t,e,r,k);i.lastLodLevel_Mesh=k.mesh_lod,i.lastLodLevel_Texture=k.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const s of t)this.loadProgressiveTextures(s,e);return}let r=!1;(t[F]===void 0||e<t[F])&&(r=!0);const n=t["DEBUG:LOD"];n!=null&&(r=t[F]!=n,e=n),r&&(t[F]=e,T.assignTextureLOD(t,e).then(s=>{this._lodchangedlisteners.forEach(o=>o({type:"texture",level:e,object:t}))}))}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);let r=t[F]!==e;const n=t["DEBUG:LOD"];if(n!=null&&(r=t[F]!=n,e=n),r){t[F]=e;const s=t.geometry;return T.assignMeshLOD(t,e).then(o=>(o&&t[F]==e&&s!=t.geometry&&this._lodchangedlisteners.forEach(i=>i({type:"mesh",level:e,object:t})),o))}return Promise.resolve(null)}static isInside(t,e){const r=t.min,n=t.max,s=(r.x+n.x)*.5,o=(r.y+n.y)*.5;return this._tempPtInside.set(s,o,r.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,r,n,s){var o;if(!e){s.mesh_lod=-1,s.texture_lod=-1;return}if(!t){s.mesh_lod=-1,s.texture_lod=-1;return}let i=10+1,l=!1;if(C&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const u=T.getMeshLODInformation(e.geometry),a=u?.lods,f=a&&a.length>0,g=T.getMaterialMinMaxLODsCount(e.material),v=g?.min_count!=1/0&&g.min_count>0&&g.max_count>0;if(!f&&!v){s.mesh_lod=0,s.texture_lod=0;return}f||(l=!0,i=0);const A=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let D=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const x=e;if(!x.boundingBox)x.computeBoundingBox();else if(r.frames%30===0){const d=Q(x),O=x.geometry;d&&(x.geometry=d),x.computeBoundingBox(),x.geometry=O}D=x.boundingBox}if(D){const x=t;if(e.geometry.attributes.color&&e.geometry.attributes.color.count<100&&e.geometry.boundingSphere){this._sphere.copy(e.geometry.boundingSphere),this._sphere.applyMatrix4(e.matrixWorld);const m=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(m)){s.mesh_lod=0,s.texture_lod=0;return}}if(this._tempBox.copy(D),this._tempBox.applyMatrix4(e.matrixWorld),x.isPerspectiveCamera&&P.isInside(this._tempBox,this.projectionScreenMatrix)){s.mesh_lod=0,s.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&x.isPerspectiveCamera&&x.fov>70){const m=this._tempBox.min,p=this._tempBox.max;let h=m.x,M=m.y,S=p.x,j=p.y;const V=2,Y=1.5,ie=(m.x+p.x)*.5,ae=(m.y+p.y)*.5;h=(h-ie)*V+ie,M=(M-ae)*V+ae,S=(S-ie)*V+ie,j=(j-ae)*V+ae;const $e=h<0&&S>0?0:Math.min(Math.abs(m.x),Math.abs(p.x)),Fe=M<0&&j>0?0:Math.min(Math.abs(m.y),Math.abs(p.y)),ge=Math.max($e,Fe);r.lastCentrality=(Y-ge)*(Y-ge)*(Y-ge)}else r.lastCentrality=1;const d=this._tempBox.getSize(this._tempBoxSize);d.multiplyScalar(.5),screen.availHeight>0&&A>0&&d.multiplyScalar(A/screen.availHeight),t.isPerspectiveCamera?d.x*=t.aspect:t.isOrthographicCamera;const O=t.matrixWorldInverse,_=this._tempBox2;_.copy(D),_.applyMatrix4(e.matrixWorld),_.applyMatrix4(O);const I=_.getSize(this._tempBox2Size),b=Math.max(I.x,I.y);if(Math.max(d.x,d.y)!=0&&b!=0&&(d.z=I.z/Math.max(I.x,I.y)*Math.max(d.x,d.y)),r.lastScreenCoverage=Math.max(d.x,d.y,d.z),r.lastScreenspaceVolume.copy(d),r.lastScreenCoverage*=r.lastCentrality,C&&P.debugDrawLine){const m=this.tempMatrix.copy(this.projectionScreenMatrix);m.invert();const p=P.corner0,h=P.corner1,M=P.corner2,S=P.corner3;p.copy(this._tempBox.min),h.copy(this._tempBox.max),h.x=p.x,M.copy(this._tempBox.max),M.y=p.y,S.copy(this._tempBox.max);const j=(p.z+S.z)*.5;p.z=h.z=M.z=S.z=j,p.applyMatrix4(m),h.applyMatrix4(m),M.applyMatrix4(m),S.applyMatrix4(m),P.debugDrawLine(p,h,255),P.debugDrawLine(p,M,255),P.debugDrawLine(h,S,255),P.debugDrawLine(M,S,255)}let B=999;if(a&&r.lastScreenCoverage>0){for(let m=0;m<a.length;m++)if(a[m].density/r.lastScreenCoverage<n){B=m;break}}B<i&&(i=B,l=!0)}if(l?s.mesh_lod=i:s.mesh_lod=r.lastLodLevel_Mesh,C&&s.mesh_lod!=r.lastLodLevel_Mesh){const x=a?.[s.mesh_lod];x&&console.log(`Mesh LOD changed: ${r.lastLodLevel_Mesh} \u2192 ${s.mesh_lod} (${x.density.toFixed(0)}) - ${e.name}`)}if(v){const x="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(r.lastLodLevel_Texture<0){if(s.texture_lod=g.max_count-1,C){const d=g.lods[g.max_count-1];C&&console.log(`First Texture LOD ${s.texture_lod} (${d.max_height}px) - ${e.name}`)}}else{const d=r.lastScreenspaceVolume.x+r.lastScreenspaceVolume.y+r.lastScreenspaceVolume.z;let O=r.lastScreenCoverage*4;((o=this.context)==null?void 0:o.engine)==="model-viewer"&&(O*=1.5);const _=A/window.devicePixelRatio*O;let I=!1;for(let b=g.lods.length-1;b>=0;b--){let B=g.lods[b];if(!(x&&B.max_height>=2048)&&!(nt()&&B.max_height>4096)&&(B.max_height>_||!I&&b===0)){if(I=!0,s.texture_lod=b,s.texture_lod<r.lastLodLevel_Texture){const m=B.max_height;C&&console.log(`Texture LOD changed: ${r.lastLodLevel_Texture} \u2192 ${s.texture_lod} = ${m}px
6
+ Screensize: ${_.toFixed(0)}px, Coverage: ${(100*r.lastScreenCoverage).toFixed(2)}%, Volume ${d.toFixed(1)}
7
+ ${e.name}`)}break}}}}else s.texture_lod=0}};let R=P;E=new WeakMap,U=new WeakMap,be=new WeakMap,Z=new WeakMap,ne=new WeakMap,de=new WeakMap,z=new WeakMap,c(R,"debugDrawLine"),c(R,"corner0",new W),c(R,"corner1",new W),c(R,"corner2",new W),c(R,"corner3",new W),c(R,"_tempPtInside",new W);class ct{constructor(){c(this,"frames",0),c(this,"lastLodLevel_Mesh",-1),c(this,"lastLodLevel_Texture",-1),c(this,"lastScreenCoverage",0),c(this,"lastScreenspaceVolume",new W),c(this,"lastCentrality",0)}}const Re=Symbol("NEEDLE_mesh_lod"),he=Symbol("NEEDLE_texture_lod");let fe=null;function Se(){const t=dt();t&&(t.mapURLs(function(e){return je(),e}),je(),fe?.disconnect(),fe=new MutationObserver(e=>{e.forEach(r=>{r.addedNodes.forEach(n=>{n instanceof HTMLElement&&n.tagName.toLowerCase()==="model-viewer"&&Ge(n)})})}),fe.observe(document,{childList:!0,subtree:!0}))}function dt(){return typeof customElements>"u"?null:customElements.get("model-viewer")||(customElements.whenDefined("model-viewer").then(()=>{console.debug("[gltf-progressive] model-viewer defined"),Se()}),null)}function je(){typeof document>"u"||document.querySelectorAll("model-viewer").forEach(t=>{Ge(t)})}const Ne=new WeakSet;let ht=0;function Ge(t){if(!t||Ne.has(t))return null;Ne.add(t),console.debug("[gltf-progressive] found new model-viewer..."+ ++ht+`
8
+ `,t.getAttribute("src"));let e=null,r=null,n=null;for(let s=t;s!=null;s=Object.getPrototypeOf(s)){const o=Object.getOwnPropertySymbols(s),i=o.find(a=>a.toString()=="Symbol(renderer)"),l=o.find(a=>a.toString()=="Symbol(scene)"),u=o.find(a=>a.toString()=="Symbol(needsRender)");!e&&i!=null&&(e=t[i].threeRenderer),!r&&l!=null&&(r=t[l]),!n&&u!=null&&(n=t[u])}if(e&&r){let s=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=R.get(e,{engine:"model-viewer"});return R.addPlugin(new ft),o.enable(),o.addEventListener("changed",()=>{n?.call(t)}),t.addEventListener("model-visibility",i=>{i.detail.visible&&n?.call(t)}),t.addEventListener("load",()=>{s()}),()=>{o.disable()}}return null}class ft{constructor(){c(this,"_didWarnAboutMissingUrl",!1)}onBeforeUpdateLOD(e,r,n,s){this.tryParseMeshLOD(r,s),this.tryParseTextureLOD(r,s)}getUrl(e){if(!e)return null;let r=e.getAttribute("src");return r||(r=e.src),r||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",e),this._didWarnAboutMissingUrl=!0),r}tryGetCurrentGLTF(e){return e._currentGLTF}tryGetCurrentModelViewer(e){return e.element}tryParseTextureLOD(e,r){if(r[he]==!0)return;r[he]=!0;const n=this.tryGetCurrentGLTF(e),s=this.tryGetCurrentModelViewer(e),o=this.getUrl(s);if(o&&n&&r.material){let i=function(u){var a,f,g;if(u[he]==!0)return;u[he]=!0,u.userData&&(u.userData.LOD=-1);const v=Object.keys(u);for(let A=0;A<v.length;A++){const D=v[A],x=u[D];if(x?.isTexture===!0){const d=(f=(a=x.userData)==null?void 0:a.associations)==null?void 0:f.textures;if(d==null)continue;const O=n.parser.json.textures[d];if(!O){console.warn("Texture data not found for texture index "+d);continue}if((g=O?.extensions)!=null&&g[N]){const _=O.extensions[N];_&&o&&T.registerTexture(o,x,_.lods.length,d,_)}}}};const l=r.material;if(Array.isArray(l))for(const u of l)i(u);else i(l)}}tryParseMeshLOD(e,r){var n,s;if(r[Re]==!0)return;r[Re]=!0;const o=this.tryGetCurrentModelViewer(e),i=this.getUrl(o);if(!i)return;const l=(s=(n=r.userData)==null?void 0:n.gltfExtensions)==null?void 0:s[N];if(l&&i){const u=r.uuid;T.registerMesh(i,u,r,0,l.lods.length,l)}}}function We(t,e,r,n){ve(e),ye(r),Le(r,{progressive:!0,...n?.hints}),r.register(o=>new T(o,t));const s=R.get(e);return n?.enableLODsManager!==!1&&s.enable(),s}if(Se(),!it){const t={gltfProgressive:{useNeedleProgressive:We,LODsManager:R,configureLoader:Le,getRaycastMesh:Q,useRaycastMeshes:Ce}};if(!globalThis.Needle)globalThis.Needle=t;else for(const e in t)globalThis.Needle[e]=t[e]}export{N as EXTENSION_NAME,R as LODsManager,T as NEEDLE_progressive,pe as VERSION,ye as addDracoAndKTX2Loaders,Le as configureLoader,ve as createLoaders,Q as getRaycastMesh,Se as patchModelViewer,Be as registerRaycastMesh,tt as setDracoDecoderLocation,rt as setKTX2TranscoderLocation,We as useNeedleProgressive,Ce as useRaycastMeshes};
@@ -1,8 +1,8 @@
1
- "use strict";var Ue=Object.defineProperty;var ze=(n,e,t)=>e in n?Ue(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var d=(n,e,t)=>(ze(n,typeof e!="symbol"?e+"":e,t),t),Ee=(n,e,t)=>{if(!e.has(n))throw TypeError("Cannot "+t)};var L=(n,e,t)=>(Ee(n,e,"read from private field"),t?t.call(n):e.get(n)),K=(n,e,t)=>{if(e.has(n))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(n):e.set(n,t)},N=(n,e,t,s)=>(Ee(n,e,"write to private field"),s?s.call(n,t):e.set(n,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const p=require("three"),_e=require("three/examples/jsm/loaders/GLTFLoader.js"),We=require("three/examples/jsm/libs/meshopt_decoder.module.js"),qe=require("three/examples/jsm/loaders/DRACOLoader.js"),Xe=require("three/examples/jsm/loaders/KTX2Loader.js"),Oe="";globalThis.GLTF_PROGRESSIVE_VERSION=Oe;console.debug(`[gltf-progressive] version ${Oe}`);let ee="https://www.gstatic.com/draco/versioned/decoders/1.5.7/",ne="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";const Ke=ee,Ye=ne,He=new URL(ee+"draco_decoder.js");fetch(He,{method:"GET",headers:{Range:"bytes=0-1"}}).catch(n=>{ee===Ke&&(ee="./include/draco/"),ne===Ye&&(ne="./include/ktx2/")}).finally(()=>{ke()});function je(n){ee=n}function Je(n){ne=n}let H,de,j;function ke(){H||(H=new qe.DRACOLoader,H.setDecoderPath(ee),H.setDecoderConfig({type:"js"}),H.preload()),j||(j=new Xe.KTX2Loader,j.setTranscoderPath(ne),j.init()),de||(de=We.MeshoptDecoder)}function Se(n){return ke(),n?j.detectSupport(n):n!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:H,ktx2Loader:j,meshoptDecoder:de}}function be(n){n.dracoLoader||n.setDRACOLoader(H),n.ktx2Loader||n.setKTX2Loader(j),n.meshoptDecoder||n.setMeshoptDecoder(de)}const De=new WeakMap;function Te(n,e){let t=De.get(n);t?t=Object.assign(t,e):t=e,De.set(n,t)}const me=_e.GLTFLoader.prototype.load;function Qe(...n){const e=De.get(this);let t=n[0];const s=new URL(t,window.location.href);if(s.hostname.endsWith("needle.tools")){const r=(e==null?void 0:e.progressive)!==void 0?e.progressive:!0,i=e!=null&&e.usecase?e.usecase:"default";r?this.requestHeader.Accept=`*/*;progressive=allowed;usecase=${i}`:this.requestHeader.Accept=`*/*;usecase=${i}`,t=s.toString()}return n[0]=t,me==null?void 0:me.call(this,...n)}_e.GLTFLoader.prototype.load=Qe;ae("debugprogressive");function ae(n){if(typeof window>"u")return!1;const t=new URL(window.location.href).searchParams.get(n);return t==null||t==="0"||t==="false"?!1:t===""?!0:t}function Ze(n,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||n===void 0)return e;const t=n.lastIndexOf("/");if(t>=0){const s=n.substring(0,t+1);for(;s.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return s+e}return e}let se;function et(){return se!==void 0||(se=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),ae("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",se)),se}const tt=typeof window>"u"&&typeof document>"u",we=Symbol("needle:raycast-mesh");function te(n){return(n==null?void 0:n[we])instanceof p.BufferGeometry?n[we]:null}function Ie(n,e){if((n.type==="Mesh"||n.type==="SkinnedMesh")&&!te(n)){const s=st(e);s.userData={isRaycastMesh:!0},n[we]=s}}function Ge(n=!0){if(n){if(re)return;const e=re=p.Mesh.prototype.raycast;p.Mesh.prototype.raycast=function(t,s){const o=this,r=te(o);let i;r&&o.isMesh&&(i=o.geometry,o.geometry=r),e.call(this,t,s),i&&(o.geometry=i)}}else{if(!re)return;p.Mesh.prototype.raycast=re,re=null}}let re=null;function st(n){const e=new p.BufferGeometry;for(const t in n.attributes)e.setAttribute(t,n.getAttribute(t));return e.setIndex(n.getIndex()),e}const Y=new Array,U="NEEDLE_progressive",x=ae("debugprogressive"),Le=Symbol("needle-progressive-texture"),oe=new Map,ve=new Set;if(x){let n=function(){e+=1,console.log("Toggle LOD level",e,oe),oe.forEach((o,r)=>{for(const i of o.keys){const a=r[i];if(a!=null){if(a.isBufferGeometry===!0){const l=O.getMeshLODInformation(a),u=l?Math.min(e,l.lods.length):0;r["DEBUG:LOD"]=e,O.assignMeshLOD(r,u),l&&(t=Math.max(t,l.lods.length-1))}else if(r.isMaterial===!0){r["DEBUG:LOD"]=e,O.assignTextureLOD(r,e);break}}}}),e>=t&&(e=-1)},e=-1,t=2,s=!1;window.addEventListener("keyup",o=>{o.key==="p"&&n(),o.key==="w"&&(s=!s,ve&&ve.forEach(r=>{r.name!="BackgroundCubeMaterial"&&r.glyphMap==null&&"wireframe"in r&&(r.wireframe=s)}))})}function Pe(n,e,t){var o;if(!x)return;oe.has(n)||oe.set(n,{keys:[],sourceId:t});const s=oe.get(n);((o=s==null?void 0:s.keys)==null?void 0:o.includes(e))==!1&&s.keys.push(e)}const _=class{constructor(e,t){d(this,"parser");d(this,"url");d(this,"_isLoadingMesh");d(this,"loadMesh",e=>{var s,o;if(this._isLoadingMesh)return null;const t=(o=(s=this.parser.json.meshes[e])==null?void 0:s.extensions)==null?void 0:o[U];return t?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",e).then(r=>{var i;return this._isLoadingMesh=!1,r&&_.registerMesh(this.url,t.guid,r,(i=t.lods)==null?void 0:i.length,void 0,t),r})):null});x&&console.log("Progressive extension registered for",t),this.parser=e,this.url=t}get name(){return U}static getMeshLODInformation(e){const t=this.getAssignedLODInformation(e);return t!=null&&t.key?this.lodInfos.get(t.key):null}static getMaterialMinMaxLODsCount(e,t){const s=this,o="LODS:minmax",r=e[o];if(r!=null)return r;if(t||(t={min_count:1/0,max_count:0,lods:[]}),Array.isArray(e)){for(const a of e)this.getMaterialMinMaxLODsCount(a,t);return e[o]=t,t}if(x==="verbose"&&console.log("getMaterialMinMaxLODsCount",e),e.type==="ShaderMaterial"||e.type==="RawShaderMaterial"){const a=e;for(const l of Object.keys(a.uniforms)){const u=a.uniforms[l].value;(u==null?void 0:u.isTexture)===!0&&i(u,t)}}else if(e.isMaterial)for(const a of Object.keys(e)){const l=e[a];(l==null?void 0:l.isTexture)===!0&&i(l,t)}return e[o]=t,t;function i(a,l){const u=s.getAssignedLODInformation(a);if(u){const c=s.lodInfos.get(u.key);if(c&&c.lods){l.min_count=Math.min(l.min_count,c.lods.length),l.max_count=Math.max(l.max_count,c.lods.length);for(let g=0;g<c.lods.length;g++){const y=c.lods[g];y.width&&(l.lods[g]=l.lods[g]||{min_height:1/0,max_height:0},l.lods[g].min_height=Math.min(l.lods[g].min_height,y.height),l.lods[g].max_height=Math.max(l.lods[g].max_height,y.height))}}}}}static hasLODLevelAvailable(e,t){var r;if(Array.isArray(e)){for(const i of e)if(this.hasLODLevelAvailable(i,t))return!0;return!1}if(e.isMaterial===!0){for(const i of Object.keys(e)){const a=e[i];if(a&&a.isTexture&&this.hasLODLevelAvailable(a,t))return!0}return!1}else if(e.isGroup===!0){for(const i of e.children)if(i.isMesh===!0&&this.hasLODLevelAvailable(i,t))return!0}let s,o;if(e.isMesh?s=e.geometry:(e.isBufferGeometry||e.isTexture)&&(s=e),s&&(r=s==null?void 0:s.userData)!=null&&r.LODS){const i=s.userData.LODS;if(o=this.lodInfos.get(i.key),t===void 0)return o!=null;if(o)return Array.isArray(o.lods)?t<o.lods.length:t===0}return!1}static assignMeshLOD(e,t){var s;if(!e)return Promise.resolve(null);if(e instanceof p.Mesh||e.isMesh===!0){const o=e.geometry,r=this.getAssignedLODInformation(o);if(!r)return Promise.resolve(null);for(const i of Y)(s=i.onBeforeGetLODMesh)==null||s.call(i,e,t);return e["LOD:requested level"]=t,_.getOrLoadLOD(o,t).then(i=>{if(Array.isArray(i)){const a=r.index||0;i=i[a]}return e["LOD:requested level"]===t&&(delete e["LOD:requested level"],i&&o!=i&&((i==null?void 0:i.isBufferGeometry)?(e.geometry=i,x&&Pe(e,"geometry",r.url)):x&&console.error("Invalid LOD geometry",i))),i}).catch(i=>(console.error("Error loading mesh LOD",e,i),null))}else x&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",e);return Promise.resolve(null)}static assignTextureLOD(e,t=0){if(!e)return Promise.resolve(null);if(e.isMesh===!0){const s=e;if(Array.isArray(s.material)){const o=new Array;for(const r of s.material){const i=this.assignTextureLOD(r,t);o.push(i)}return Promise.all(o).then(r=>{const i=new Array;for(const a of r)Array.isArray(a)&&i.push(...a);return i})}else return this.assignTextureLOD(s.material,t)}if(e instanceof p.Material||e.isMaterial===!0){const s=e,o=[],r=new Array;if(x&&ve.add(s),s.uniforms&&(s.isRawShaderMaterial||s.isShaderMaterial===!0)){const i=s;for(const a of Object.keys(i.uniforms)){const l=i.uniforms[a].value;if((l==null?void 0:l.isTexture)===!0){const u=this.assignTextureLODForSlot(l,t,s,a).then(c=>(c&&i.uniforms[a].value!=c&&(i.uniforms[a].value=c,i.uniformsNeedUpdate=!0),c));o.push(u),r.push(a)}}}else for(const i of Object.keys(s)){const a=s[i];if((a==null?void 0:a.isTexture)===!0){const l=this.assignTextureLODForSlot(a,t,s,i);o.push(l),r.push(i)}}return Promise.all(o).then(i=>{const a=new Array;for(let l=0;l<i.length;l++){const u=i[l],c=r[l];u&&u.isTexture===!0?a.push({material:s,slot:c,texture:u,level:t}):a.push({material:s,slot:c,texture:null,level:t})}return a})}if(e instanceof p.Texture||e.isTexture===!0){const s=e;return this.assignTextureLODForSlot(s,t,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(e,t,s,o){return(e==null?void 0:e.isTexture)!==!0?Promise.resolve(null):o==="glyphMap"?Promise.resolve(e):_.getOrLoadLOD(e,t).then(r=>{if(Array.isArray(r))return null;if((r==null?void 0:r.isTexture)===!0){if(r!=e){if(s&&o){const i=s[o];if(i){const a=this.getAssignedLODInformation(i);if(a&&(a==null?void 0:a.level)<t)return x==="verbose"&&console.warn("Assigned texture level is already higher: ",a.level,t,s,i,r),null}s[o]=r}if(x&&o&&s){const i=this.getAssignedLODInformation(e);i&&Pe(s,o,i.url)}}return r}else x=="verbose"&&console.warn("No LOD found for",e,t);return null}).catch(r=>(console.error("Error loading LOD",e,r),null))}afterRoot(e){var t,s;return x&&console.log("AFTER",this.url,e),(t=this.parser.json.textures)==null||t.forEach((o,r)=>{var i;if(o!=null&&o.extensions){const a=o==null?void 0:o.extensions[U];if(a){if(!a.lods){x&&console.warn("Texture has no LODs",a);return}let l=!1;for(const u of this.parser.associations.keys())if(u.isTexture===!0){const c=this.parser.associations.get(u);(c==null?void 0:c.textures)===r&&(l=!0,_.registerTexture(this.url,u,(i=a.lods)==null?void 0:i.length,r,a))}l||this.parser.getDependency("texture",r).then(u=>{var c;u&&_.registerTexture(this.url,u,(c=a.lods)==null?void 0:c.length,r,a)})}}}),(s=this.parser.json.meshes)==null||s.forEach((o,r)=>{if(o!=null&&o.extensions){const i=o==null?void 0:o.extensions[U];if(i&&i.lods){for(const a of this.parser.associations.keys())if(a.isMesh){const l=this.parser.associations.get(a);(l==null?void 0:l.meshes)===r&&_.registerMesh(this.url,i.guid,a,i.lods.length,l.primitives,i)}}}}),null}static async getOrLoadLOD(e,t){var a,l,u,c;const s=x=="verbose",o=e.userData.LODS;if(!o)return null;const r=o==null?void 0:o.key;let i;if(e.isTexture===!0){const g=e;g.source&&g.source[Le]&&(i=g.source[Le])}if(i||(i=_.lodInfos.get(r)),i){if(t>0){let D=!1;const v=Array.isArray(i.lods);if(v&&t>=i.lods.length?D=!0:v||(D=!0),D)return this.lowresCache.get(r)}const g=Array.isArray(i.lods)?(a=i.lods[t])==null?void 0:a.path:i.lods;if(!g)return x&&!i["missing:uri"]&&(i["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+t,i)),null;const y=Ze(o.url,g);if(y.endsWith(".glb")||y.endsWith(".gltf")){if(!i.guid)return console.warn("missing pointer for glb/gltf texture",i),null;const D=y+"_"+i.guid,v=this.previouslyLoaded.get(D);if(v!==void 0){s&&console.log(`LOD ${t} was already loading/loaded: ${D}`);let h=await v.catch($=>(console.error(`Error loading LOD ${t} from ${y}
2
- `,$),null)),k=!1;if(h==null||(h instanceof p.Texture&&e instanceof p.Texture?(l=h.image)!=null&&l.data||(u=h.source)!=null&&u.data?h=this.copySettings(e,h):(k=!0,this.previouslyLoaded.delete(D)):h instanceof p.BufferGeometry&&e instanceof p.BufferGeometry&&((c=h.attributes.position)!=null&&c.array||(k=!0,this.previouslyLoaded.delete(D)))),!k)return h}const M=i,V=new Promise(async(h,k)=>{const $=new _e.GLTFLoader;be($),x&&(await new Promise(E=>setTimeout(E,1e3)),s&&console.warn("Start loading (delayed) "+y,M.guid));let I=y;if(M&&Array.isArray(M.lods)){const E=M.lods[t];E.hash&&(I+="?v="+E.hash)}const b=await $.loadAsync(I).catch(E=>(console.error(`Error loading LOD ${t} from ${y}
3
- `,E),null));if(!b)return null;const q=b.parser;s&&console.log("Loading finished "+y,M.guid);let A=0;if(b.parser.json.textures){let E=!1;for(const f of b.parser.json.textures){if(f!=null&&f.extensions){const m=f==null?void 0:f.extensions[U];if(m!=null&&m.guid&&m.guid===M.guid){E=!0;break}}A++}if(E){let f=await q.getDependency("texture",A);return f&&_.assignLODInformation(o.url,f,r,t,void 0,void 0),s&&console.log('change "'+e.name+'" → "'+f.name+'"',y,A,f,D),e instanceof p.Texture&&(f=this.copySettings(e,f)),f&&(f.guid=M.guid),h(f)}else x&&console.warn("Could not find texture with guid",M.guid,b.parser.json)}if(A=0,b.parser.json.meshes){let E=!1;for(const f of b.parser.json.meshes){if(f!=null&&f.extensions){const m=f==null?void 0:f.extensions[U];if(m!=null&&m.guid&&m.guid===M.guid){E=!0;break}}A++}if(E){const f=await q.getDependency("mesh",A),m=M;if(s&&console.log(`Loaded Mesh "${f.name}"`,y,A,f,D),f.isMesh===!0){const S=f.geometry;return _.assignLODInformation(o.url,S,r,t,void 0,m.density),h(S)}else{const S=new Array;for(let T=0;T<f.children.length;T++){const P=f.children[T];if(P.isMesh===!0){const X=P.geometry;_.assignLODInformation(o.url,X,r,t,T,m.density),S.push(X)}}return h(S)}}else x&&console.warn("Could not find mesh with guid",M.guid,b.parser.json)}return h(null)});return this.previouslyLoaded.set(D,V),await V}else if(e instanceof p.Texture){s&&console.log("Load texture from uri: "+y);const v=await new p.TextureLoader().loadAsync(y);return v?(v.guid=i.guid,v.flipY=!1,v.needsUpdate=!0,v.colorSpace=e.colorSpace,s&&console.log(i,v)):x&&console.warn("failed loading",y),v}}else x&&console.warn(`Can not load LOD ${t}: no LOD info found for "${r}" ${e.name}`,e.type);return null}static assignLODInformation(e,t,s,o,r,i){if(!t)return;t.userData||(t.userData={});const a=new rt(e,s,o,r,i);t.userData.LODS=a}static getAssignedLODInformation(e){var t;return((t=e==null?void 0:e.userData)==null?void 0:t.LODS)||null}static copySettings(e,t){return t=t.clone(),x&&console.warn(`Copying texture settings
1
+ "use strict";var Ue=Object.defineProperty;var ze=(n,e,t)=>e in n?Ue(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var d=(n,e,t)=>(ze(n,typeof e!="symbol"?e+"":e,t),t),Ee=(n,e,t)=>{if(!e.has(n))throw TypeError("Cannot "+t)};var m=(n,e,t)=>(Ee(n,e,"read from private field"),t?t.call(n):e.get(n)),K=(n,e,t)=>{if(e.has(n))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(n):e.set(n,t)},N=(n,e,t,s)=>(Ee(n,e,"write to private field"),s?s.call(n,t):e.set(n,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const y=require("three"),Oe=require("three/examples/jsm/loaders/GLTFLoader.js"),We=require("three/examples/jsm/libs/meshopt_decoder.module.js"),qe=require("three/examples/jsm/loaders/DRACOLoader.js"),Xe=require("three/examples/jsm/loaders/KTX2Loader.js"),_e="";globalThis.GLTF_PROGRESSIVE_VERSION=_e;console.debug(`[gltf-progressive] version ${_e}`);let ee="https://www.gstatic.com/draco/versioned/decoders/1.5.7/",ne="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";const Ke=ee,Ye=ne,He=new URL(ee+"draco_decoder.js");fetch(He,{method:"GET",headers:{Range:"bytes=0-1"}}).catch(n=>{ee===Ke&&(ee="./include/draco/"),ne===Ye&&(ne="./include/ktx2/")}).finally(()=>{Ge()});function je(n){ee=n}function Je(n){ne=n}let j,de,J;function Ge(){j||(j=new qe.DRACOLoader,j.setDecoderPath(ee),j.setDecoderConfig({type:"js"}),j.preload()),J||(J=new Xe.KTX2Loader,J.setTranscoderPath(ne),J.init()),de||(de=We.MeshoptDecoder)}function Se(n){return Ge(),n?J.detectSupport(n):n!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:j,ktx2Loader:J,meshoptDecoder:de}}function be(n){n.dracoLoader||n.setDRACOLoader(j),n.ktx2Loader||n.setKTX2Loader(J),n.meshoptDecoder||n.setMeshoptDecoder(de)}const De=new WeakMap;function Te(n,e){let t=De.get(n);t?t=Object.assign(t,e):t=e,De.set(n,t)}const Le=Oe.GLTFLoader.prototype.load;function Qe(...n){const e=De.get(this);let t=n[0];const s=new URL(t,window.location.href);if(s.hostname.endsWith("needle.tools")){const r=(e==null?void 0:e.progressive)!==void 0?e.progressive:!0,o=e!=null&&e.usecase?e.usecase:"default";r?this.requestHeader.Accept=`*/*;progressive=allowed;usecase=${o}`:this.requestHeader.Accept=`*/*;usecase=${o}`,t=s.toString()}return n[0]=t,Le==null?void 0:Le.call(this,...n)}Oe.GLTFLoader.prototype.load=Qe;ae("debugprogressive");function ae(n){if(typeof window>"u")return!1;const t=new URL(window.location.href).searchParams.get(n);return t==null||t==="0"||t==="false"?!1:t===""?!0:t}function Ze(n,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||n===void 0)return e;const t=n.lastIndexOf("/");if(t>=0){const s=n.substring(0,t+1);for(;s.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return s+e}return e}let se;function et(){return se!==void 0||(se=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),ae("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",se)),se}const tt=typeof window>"u"&&typeof document>"u",we=Symbol("needle:raycast-mesh");function te(n){return(n==null?void 0:n[we])instanceof y.BufferGeometry?n[we]:null}function Ie(n,e){if((n.type==="Mesh"||n.type==="SkinnedMesh")&&!te(n)){const s=st(e);s.userData={isRaycastMesh:!0},n[we]=s}}function ke(n=!0){if(n){if(re)return;const e=re=y.Mesh.prototype.raycast;y.Mesh.prototype.raycast=function(t,s){const i=this,r=te(i);let o;r&&i.isMesh&&(o=i.geometry,i.geometry=r),e.call(this,t,s),o&&(i.geometry=o)}}else{if(!re)return;y.Mesh.prototype.raycast=re,re=null}}let re=null;function st(n){const e=new y.BufferGeometry;for(const t in n.attributes)e.setAttribute(t,n.getAttribute(t));return e.setIndex(n.getIndex()),e}const H=new Array,U="NEEDLE_progressive",x=ae("debugprogressive"),me=Symbol("needle-progressive-texture"),ie=new Map,ve=new Set;if(x){let n=function(){e+=1,console.log("Toggle LOD level",e,ie),ie.forEach((i,r)=>{for(const o of i.keys){const a=r[o];if(a!=null)if(a.isBufferGeometry===!0){const l=b.getMeshLODInformation(a),u=l?Math.min(e,l.lods.length):0;r["DEBUG:LOD"]=u,l&&(t=Math.max(t,l.lods.length-1))}else r.isMaterial===!0&&(r["DEBUG:LOD"]=e)}}),e>=t&&(e=-1)},e=-1,t=2,s=!1;window.addEventListener("keyup",i=>{i.key==="p"&&n(),i.key==="w"&&(s=!s,ve&&ve.forEach(r=>{r.name!="BackgroundCubeMaterial"&&r.glyphMap==null&&"wireframe"in r&&(r.wireframe=s)}))})}function Pe(n,e,t){var i;if(!x)return;ie.has(n)||ie.set(n,{keys:[],sourceId:t});const s=ie.get(n);((i=s==null?void 0:s.keys)==null?void 0:i.includes(e))==!1&&s.keys.push(e)}const O=class{constructor(e,t){d(this,"parser");d(this,"url");d(this,"_isLoadingMesh");d(this,"loadMesh",e=>{var s,i;if(this._isLoadingMesh)return null;const t=(i=(s=this.parser.json.meshes[e])==null?void 0:s.extensions)==null?void 0:i[U];return t?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",e).then(r=>{var o;return this._isLoadingMesh=!1,r&&O.registerMesh(this.url,t.guid,r,(o=t.lods)==null?void 0:o.length,void 0,t),r})):null});x&&console.log("Progressive extension registered for",t),this.parser=e,this.url=t}get name(){return U}static getMeshLODInformation(e){const t=this.getAssignedLODInformation(e);return t!=null&&t.key?this.lodInfos.get(t.key):null}static getMaterialMinMaxLODsCount(e,t){const s=this,i="LODS:minmax",r=e[i];if(r!=null)return r;if(t||(t={min_count:1/0,max_count:0,lods:[]}),Array.isArray(e)){for(const a of e)this.getMaterialMinMaxLODsCount(a,t);return e[i]=t,t}if(x==="verbose"&&console.log("getMaterialMinMaxLODsCount",e),e.type==="ShaderMaterial"||e.type==="RawShaderMaterial"){const a=e;for(const l of Object.keys(a.uniforms)){const u=a.uniforms[l].value;(u==null?void 0:u.isTexture)===!0&&o(u,t)}}else if(e.isMaterial)for(const a of Object.keys(e)){const l=e[a];(l==null?void 0:l.isTexture)===!0&&o(l,t)}return e[i]=t,t;function o(a,l){const u=s.getAssignedLODInformation(a);if(u){const c=s.lodInfos.get(u.key);if(c&&c.lods){l.min_count=Math.min(l.min_count,c.lods.length),l.max_count=Math.max(l.max_count,c.lods.length);for(let g=0;g<c.lods.length;g++){const p=c.lods[g];p.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,p.height),l.lods[g].max_height=Math.max(l.lods[g].max_height,p.height))}}}}}static hasLODLevelAvailable(e,t){var r;if(Array.isArray(e)){for(const o of e)if(this.hasLODLevelAvailable(o,t))return!0;return!1}if(e.isMaterial===!0){for(const o of Object.keys(e)){const a=e[o];if(a&&a.isTexture&&this.hasLODLevelAvailable(a,t))return!0}return!1}else if(e.isGroup===!0){for(const o of e.children)if(o.isMesh===!0&&this.hasLODLevelAvailable(o,t))return!0}let s,i;if(e.isMesh?s=e.geometry:(e.isBufferGeometry||e.isTexture)&&(s=e),s&&(r=s==null?void 0:s.userData)!=null&&r.LODS){const o=s.userData.LODS;if(i=this.lodInfos.get(o.key),t===void 0)return i!=null;if(i)return Array.isArray(i.lods)?t<i.lods.length:t===0}return!1}static assignMeshLOD(e,t){var s;if(!e)return Promise.resolve(null);if(e instanceof y.Mesh||e.isMesh===!0){const i=e.geometry,r=this.getAssignedLODInformation(i);if(!r)return Promise.resolve(null);for(const o of H)(s=o.onBeforeGetLODMesh)==null||s.call(o,e,t);return e["LOD:requested level"]=t,O.getOrLoadLOD(i,t).then(o=>{if(Array.isArray(o)){const a=r.index||0;o=o[a]}return e["LOD:requested level"]===t&&(delete e["LOD:requested level"],o&&i!=o&&((o==null?void 0:o.isBufferGeometry)?(e.geometry=o,x&&Pe(e,"geometry",r.url)):x&&console.error("Invalid LOD geometry",o))),o}).catch(o=>(console.error("Error loading mesh LOD",e,o),null))}else x&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",e);return Promise.resolve(null)}static assignTextureLOD(e,t=0){if(!e)return Promise.resolve(null);if(e.isMesh===!0){const s=e;if(Array.isArray(s.material)){const i=new Array;for(const r of s.material){const o=this.assignTextureLOD(r,t);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,t)}if(e.isMaterial===!0){const s=e,i=[],r=new Array;if(x&&ve.add(s),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,t,s,a).then(c=>(c&&o.uniforms[a].value!=c&&(o.uniforms[a].value=c,o.uniformsNeedUpdate=!0),c));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,t,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],c=r[l];u&&u.isTexture===!0?a.push({material:s,slot:c,texture:u,level:t}):a.push({material:s,slot:c,texture:null,level:t})}return a})}if(e instanceof y.Texture||e.isTexture===!0){const s=e;return this.assignTextureLODForSlot(s,t,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(e,t,s,i){return(e==null?void 0:e.isTexture)!==!0?Promise.resolve(null):i==="glyphMap"?Promise.resolve(e):O.getOrLoadLOD(e,t).then(r=>{if(Array.isArray(r))return null;if((r==null?void 0:r.isTexture)===!0){if(r!=e){if(s&&i){const o=s[i];if(o&&!x){const a=this.getAssignedLODInformation(o);if(a&&(a==null?void 0:a.level)<t)return x==="verbose"&&console.warn("Assigned texture level is already higher: ",a.level,t,s,o,r),null}s[i]=r}if(x&&i&&s){const o=this.getAssignedLODInformation(e);o?Pe(s,i,o.url):console.warn("No LOD info for texture",e)}}return r}else x=="verbose"&&console.warn("No LOD found for",e,t);return null}).catch(r=>(console.error("Error loading LOD",e,r),null))}afterRoot(e){var t,s;return x&&console.log("AFTER",this.url,e),(t=this.parser.json.textures)==null||t.forEach((i,r)=>{var o;if(i!=null&&i.extensions){const a=i==null?void 0:i.extensions[U];if(a){if(!a.lods){x&&console.warn("Texture has no LODs",a);return}let l=!1;for(const u of this.parser.associations.keys())if(u.isTexture===!0){const c=this.parser.associations.get(u);(c==null?void 0:c.textures)===r&&(l=!0,O.registerTexture(this.url,u,(o=a.lods)==null?void 0:o.length,r,a))}l||this.parser.getDependency("texture",r).then(u=>{var c;u&&O.registerTexture(this.url,u,(c=a.lods)==null?void 0:c.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[U];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&&O.registerMesh(this.url,o.guid,a,o.lods.length,l.primitives,o)}}}}),null}static async getOrLoadLOD(e,t){var a,l,u,c;const s=x=="verbose",i=e.userData.LODS;if(!i)return null;const r=i==null?void 0:i.key;let o;if(e.isTexture===!0){const g=e;g.source&&g.source[me]&&(o=g.source[me])}if(o||(o=O.lodInfos.get(r)),o){if(t>0){let w=!1;const v=Array.isArray(o.lods);if(v&&t>=o.lods.length?w=!0:v||(w=!0),w)return this.lowresCache.get(r)}const g=Array.isArray(o.lods)?(a=o.lods[t])==null?void 0:a.path:o.lods;if(!g)return x&&!o["missing:uri"]&&(o["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+t,o)),null;const p=Ze(i.url,g);if(p.endsWith(".glb")||p.endsWith(".gltf")){if(!o.guid)return console.warn("missing pointer for glb/gltf texture",o),null;const w=p+"_"+o.guid,v=this.previouslyLoaded.get(w);if(v!==void 0){s&&console.log(`LOD ${t} was already loading/loaded: ${w}`);let h=await v.catch($=>(console.error(`Error loading LOD ${t} from ${p}
2
+ `,$),null)),G=!1;if(h==null||(h instanceof y.Texture&&e instanceof y.Texture?(l=h.image)!=null&&l.data||(u=h.source)!=null&&u.data?h=this.copySettings(e,h):(G=!0,this.previouslyLoaded.delete(w)):h instanceof y.BufferGeometry&&e instanceof y.BufferGeometry&&((c=h.attributes.position)!=null&&c.array||(G=!0,this.previouslyLoaded.delete(w)))),!G)return h}const M=o,V=new Promise(async(h,G)=>{const $=new Oe.GLTFLoader;be($),x&&(await new Promise(T=>setTimeout(T,1e3)),s&&console.warn("Start loading (delayed) "+p,M.guid));let I=p;if(M&&Array.isArray(M.lods)){const T=M.lods[t];T.hash&&(I+="?v="+T.hash)}const E=await $.loadAsync(I).catch(T=>(console.error(`Error loading LOD ${t} from ${p}
3
+ `,T),null));if(!E)return null;const z=E.parser;s&&console.log("Loading finished "+p,M.guid);let S=0;if(E.parser.json.textures){let T=!1;for(const f of E.parser.json.textures){if(f!=null&&f.extensions){const L=f==null?void 0:f.extensions[U];if(L!=null&&L.guid&&L.guid===M.guid){T=!0;break}}S++}if(T){let f=await z.getDependency("texture",S);return f&&O.assignLODInformation(i.url,f,r,t,void 0,void 0),s&&console.log('change "'+e.name+'" → "'+f.name+'"',p,S,f,w),e instanceof y.Texture&&(f=this.copySettings(e,f)),f&&(f.guid=M.guid),h(f)}else x&&console.warn("Could not find texture with guid",M.guid,E.parser.json)}if(S=0,E.parser.json.meshes){let T=!1;for(const f of E.parser.json.meshes){if(f!=null&&f.extensions){const L=f==null?void 0:f.extensions[U];if(L!=null&&L.guid&&L.guid===M.guid){T=!0;break}}S++}if(T){const f=await z.getDependency("mesh",S),L=M;if(s&&console.log(`Loaded Mesh "${f.name}"`,p,S,f,w),f.isMesh===!0){const _=f.geometry;return O.assignLODInformation(i.url,_,r,t,void 0,L.density),h(_)}else{const _=new Array;for(let A=0;A<f.children.length;A++){const P=f.children[A];if(P.isMesh===!0){const X=P.geometry;O.assignLODInformation(i.url,X,r,t,A,L.density),_.push(X)}}return h(_)}}else x&&console.warn("Could not find mesh with guid",M.guid,E.parser.json)}return h(null)});return this.previouslyLoaded.set(w,V),await V}else if(e instanceof y.Texture){s&&console.log("Load texture from uri: "+p);const v=await new y.TextureLoader().loadAsync(p);return v?(v.guid=o.guid,v.flipY=!1,v.needsUpdate=!0,v.colorSpace=e.colorSpace,s&&console.log(o,v)):x&&console.warn("failed loading",p),v}}else x&&console.warn(`Can not load LOD ${t}: no LOD info found for "${r}" ${e.name}`,e.type);return null}static assignLODInformation(e,t,s,i,r,o){if(!t)return;t.userData||(t.userData={});const a=new rt(e,s,i,r,o);t.userData.LODS=a}static getAssignedLODInformation(e){var t;return((t=e==null?void 0:e.userData)==null?void 0:t.LODS)||null}static copySettings(e,t){return x&&console.warn(`Copy texture settings
4
4
  `,e.uuid,`
5
- `,t.uuid),t.offset=e.offset,t.repeat=e.repeat,t.colorSpace=e.colorSpace,t.magFilter=e.magFilter,t.minFilter=e.minFilter,t.wrapS=e.wrapS,t.wrapT=e.wrapT,t.flipY=e.flipY,t.anisotropy=e.anisotropy,t.mipmaps||(t.generateMipmaps=e.generateMipmaps),t}};let O=_;d(O,"registerTexture",(e,t,s,o,r)=>{if(x&&console.log("> Progressive: register texture",o,t.name,t.uuid,t,r),!t){x&&console.error("gltf-progressive: Register texture without texture");return}t.source&&(t.source[Le]=r);const i=r.guid;_.assignLODInformation(e,t,i,s,o,void 0),_.lodInfos.set(i,r),_.lowresCache.set(i,t)}),d(O,"registerMesh",(e,t,s,o,r,i)=>{var u;x&&console.log("> Progressive: register mesh",r,s.name,i,s.uuid,s);const a=s.geometry;if(!a){x&&console.warn("gltf-progressive: Register mesh without geometry");return}a.userData||(a.userData={}),_.assignLODInformation(e,a,t,o,r,i.density),_.lodInfos.set(t,i);let l=_.lowresCache.get(t);l?l.push(s.geometry):l=[s.geometry],_.lowresCache.set(t,l),o>0&&!te(s)&&Ie(s,a);for(const c of Y)(u=c.onRegisteredNewMesh)==null||u.call(c,s,i)}),d(O,"lodInfos",new Map),d(O,"previouslyLoaded",new Map),d(O,"lowresCache",new Map);class rt{constructor(e,t,s,o,r){d(this,"url");d(this,"key");d(this,"level");d(this,"index");d(this,"density");this.url=e,this.key=t,this.level=s,o!=null&&(this.index=o),r!=null&&(this.density=r)}}const G=ae("debugprogressive"),it=ae("noprogressive"),xe=Symbol("Needle:LODSManager"),Me=Symbol("Needle:LODState"),J=Symbol("Needle:CurrentLOD"),F={mesh_lod:-1,texture_lod:-1};var B,z,he,Q,Z,ge,W;const C=class{constructor(e,t){d(this,"context");d(this,"renderer");d(this,"projectionScreenMatrix",new p.Matrix4);d(this,"targetTriangleDensity",2e5);d(this,"updateInterval","auto");K(this,B,1);d(this,"pause",!1);d(this,"manual",!1);d(this,"_lodchangedlisteners",[]);K(this,z,void 0);K(this,he,new p.Clock);K(this,Q,0);K(this,Z,0);K(this,ge,0);K(this,W,0);d(this,"_fpsBuffer",[60,60,60,60,60]);d(this,"_sphere",new p.Sphere);d(this,"_tempBox",new p.Box3);d(this,"_tempBox2",new p.Box3);d(this,"tempMatrix",new p.Matrix4);d(this,"_tempWorldPosition",new p.Vector3);d(this,"_tempBoxSize",new p.Vector3);d(this,"_tempBox2Size",new p.Vector3);this.renderer=e,this.context={...t}}static getObjectLODState(e){return e[Me]}static addPlugin(e){Y.push(e)}static removePlugin(e){const t=Y.indexOf(e);t>=0&&Y.splice(t,1)}static get(e,t){if(e[xe])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),e[xe];const s=new C(e,{engine:"unknown",...t});return e[xe]=s,s}get plugins(){return Y}addEventListener(e,t){e==="changed"&&this._lodchangedlisteners.push(t)}removeEventListener(e,t){if(e==="changed"){const s=this._lodchangedlisteners.indexOf(t);s>=0&&this._lodchangedlisteners.splice(s,1)}}enable(){if(L(this,z))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let e=0;N(this,z,this.renderer.render);const t=this;Se(this.renderer),this.renderer.render=function(s,o){const r=t.renderer.getRenderTarget();(r==null||"isXRRenderTarget"in r&&r.isXRRenderTarget)&&(e=0,N(t,Q,L(t,Q)+1),N(t,Z,L(t,he).getDelta()),N(t,ge,L(t,ge)+L(t,Z)),t._fpsBuffer.shift(),t._fpsBuffer.push(1/L(t,Z)),N(t,W,t._fpsBuffer.reduce((a,l)=>a+l)/t._fpsBuffer.length),G&&L(t,Q)%200===0&&console.log("FPS",Math.round(L(t,W)),"Interval:",L(t,B)));const i=e++;L(t,z).call(this,s,o),t.onAfterRender(s,o,i)}}disable(){L(this,z)&&(console.debug("[gltf-progressive] Disabling LODsManager for renderer"),this.renderer.render=L(this,z),N(this,z,void 0))}update(e,t){this.internalUpdate(e,t)}onAfterRender(e,t,s){if(this.pause)return;const r=this.renderer.renderLists.get(e,0).opaque;let i=!0;if(r.length===1){const a=r[0].material;(a.name==="EffectMaterial"||a.name==="CopyShader")&&(i=!1)}if((t.parent&&t.parent.type==="CubeCamera"||s>=1&&t.type==="OrthographicCamera")&&(i=!1),i){if(it||(this.updateInterval==="auto"?L(this,W)<40&&L(this,B)<10?(N(this,B,L(this,B)+1),G&&console.warn("↓ Reducing LOD updates",L(this,B),L(this,W).toFixed(0))):L(this,W)>=60&&L(this,B)>1&&(N(this,B,L(this,B)-1),G&&console.warn("↑ Increasing LOD updates",L(this,B),L(this,W).toFixed(0))):N(this,B,this.updateInterval),L(this,B)>0&&L(this,Q)%L(this,B)!=0))return;this.internalUpdate(e,t)}}internalUpdate(e,t){var l,u;const s=this.renderer.renderLists.get(e,0),o=s.opaque;this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse);const r=this.targetTriangleDensity;for(const c of o){if(c.material&&(((l=c.geometry)==null?void 0:l.type)==="BoxGeometry"||((u=c.geometry)==null?void 0:u.type)==="BufferGeometry")&&(c.material.name==="SphericalGaussianBlur"||c.material.name=="BackgroundCubeMaterial"||c.material.name==="CubemapFromEquirect"||c.material.name==="EquirectangularToCubeUV")){G&&(c.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(c.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",c,c.material.name,c.material.type)));continue}switch(c.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}if(G==="color"&&c.material&&!c.object.progressive_debug_color){c.object.progressive_debug_color=!0;const y=Math.random()*16777215,D=new p.MeshStandardMaterial({color:y});c.object.material=D}const g=c.object;(g instanceof p.Mesh||g.isMesh)&&this.updateLODs(e,t,g,r)}const i=s.transparent;for(const c of i){const g=c.object;(g instanceof p.Mesh||g.isMesh)&&this.updateLODs(e,t,g,r)}const a=s.transmissive;for(const c of a){const g=c.object;(g instanceof p.Mesh||g.isMesh)&&this.updateLODs(e,t,g,r)}}updateLODs(e,t,s,o){var a,l;s.userData||(s.userData={});let r=s[Me];if(r||(r=new ot,s[Me]=r),r.frames++<2)return;for(const u of Y)(a=u.onBeforeUpdateLOD)==null||a.call(u,this.renderer,e,t,s);this.calculateLodLevel(t,s,r,o,F),F.mesh_lod=Math.round(F.mesh_lod),F.texture_lod=Math.round(F.texture_lod),F.mesh_lod>=0&&this.loadProgressiveMeshes(s,F.mesh_lod);let i=F.texture_lod;if(s.material&&i>=0){const u=s["DEBUG:LOD"];u!=null&&(i=u),this.loadProgressiveTextures(s.material,i)}for(const u of Y)(l=u.onAfterUpdatedLOD)==null||l.call(u,this.renderer,e,t,s,F);r.lastLodLevel_Mesh=F.mesh_lod,r.lastLodLevel_Texture=F.texture_lod}loadProgressiveTextures(e,t){if(!e)return;if(Array.isArray(e)){for(const o of e)this.loadProgressiveTextures(o,t);return}let s=!1;(e[J]===void 0||t<e[J])&&(s=!0),s&&(e[J]=t,O.assignTextureLOD(e,t).then(o=>{this._lodchangedlisteners.forEach(r=>r({type:"texture",level:t,object:e}))}))}loadProgressiveMeshes(e,t){if(!e)return Promise.resolve(null);if(e[J]!==t){e[J]=t;const s=e.geometry;return O.assignMeshLOD(e,t).then(o=>(o&&e[J]==t&&s!=e.geometry&&this._lodchangedlisteners.forEach(r=>r({type:"mesh",level:t,object:e})),o))}return Promise.resolve(null)}static isInside(e,t){const s=e.min,o=e.max,r=(s.x+o.x)*.5,i=(s.y+o.y)*.5;return this._tempPtInside.set(r,i,s.z).applyMatrix4(t).z<0}calculateLodLevel(e,t,s,o,r){var V;if(!t){r.mesh_lod=-1,r.texture_lod=-1;return}if(!e){r.mesh_lod=-1,r.texture_lod=-1;return}let a=10+1,l=!1;if(G&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const u=O.getMeshLODInformation(t.geometry),c=u==null?void 0:u.lods,g=c&&c.length>0,y=O.getMaterialMinMaxLODsCount(t.material),D=(y==null?void 0:y.min_count)!=1/0&&y.min_count>0&&y.max_count>0;if(!g&&!D){r.mesh_lod=0,r.texture_lod=0;return}g||(l=!0,a=0);const v=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let M=t.geometry.boundingBox;if(t.type==="SkinnedMesh"){const w=t;if(!w.boundingBox)w.computeBoundingBox();else if(s.frames%30===0){const h=te(w),k=w.geometry;h&&(w.geometry=h),w.computeBoundingBox(),w.geometry=k}M=w.boundingBox}if(M&&e.isPerspectiveCamera){const w=e;if(t.geometry.attributes.color&&t.geometry.attributes.color.count<100&&t.geometry.boundingSphere){this._sphere.copy(t.geometry.boundingSphere),this._sphere.applyMatrix4(t.matrixWorld);const f=e.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(f)){r.mesh_lod=0,r.texture_lod=0;return}}if(this._tempBox.copy(M),this._tempBox.applyMatrix4(t.matrixWorld),C.isInside(this._tempBox,this.projectionScreenMatrix)){r.mesh_lod=0,r.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&w.fov>70){const f=this._tempBox.min,m=this._tempBox.max;let S=f.x,T=f.y,P=m.x,X=m.y;const le=2,pe=1.5,ce=(f.x+m.x)*.5,ue=(f.y+m.y)*.5;S=(S-ce)*le+ce,T=(T-ue)*le+ue,P=(P-ce)*le+ce,X=(X-ue)*le+ue;const $e=S<0&&P>0?0:Math.min(Math.abs(f.x),Math.abs(m.x)),Ne=T<0&&X>0?0:Math.min(Math.abs(f.y),Math.abs(m.y)),ye=Math.max($e,Ne);s.lastCentrality=(pe-ye)*(pe-ye)*(pe-ye)}else s.lastCentrality=1;const h=this._tempBox.getSize(this._tempBoxSize);h.multiplyScalar(.5),screen.availHeight>0&&v>0&&h.multiplyScalar(v/screen.availHeight),h.x*=w.aspect;const k=e.matrixWorldInverse,$=this._tempBox2;$.copy(M),$.applyMatrix4(t.matrixWorld),$.applyMatrix4(k);const I=$.getSize(this._tempBox2Size),b=Math.max(I.x,I.y);if(Math.max(h.x,h.y)!=0&&b!=0&&(h.z=I.z/Math.max(I.x,I.y)*Math.max(h.x,h.y)),s.lastScreenCoverage=Math.max(h.x,h.y,h.z),s.lastScreenspaceVolume.copy(h),s.lastScreenCoverage*=s.lastCentrality,G&&C.debugDrawLine){const f=this.tempMatrix.copy(this.projectionScreenMatrix);f.invert();const m=C.corner0,S=C.corner1,T=C.corner2,P=C.corner3;m.copy(this._tempBox.min),S.copy(this._tempBox.max),S.x=m.x,T.copy(this._tempBox.max),T.y=m.y,P.copy(this._tempBox.max);const X=(m.z+P.z)*.5;m.z=S.z=T.z=P.z=X,m.applyMatrix4(f),S.applyMatrix4(f),T.applyMatrix4(f),P.applyMatrix4(f),C.debugDrawLine(m,S,255),C.debugDrawLine(m,T,255),C.debugDrawLine(S,P,255),C.debugDrawLine(T,P,255)}let A=999;if(c&&s.lastScreenCoverage>0){for(let f=0;f<c.length;f++)if(c[f].density/s.lastScreenCoverage<o){A=f;break}}A<a&&(a=A,l=!0)}if(l?r.mesh_lod=a:r.mesh_lod=s.lastLodLevel_Mesh,G&&r.mesh_lod!=s.lastLodLevel_Mesh){const h=c==null?void 0:c[r.mesh_lod];h&&console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} → ${r.mesh_lod} (${h.density.toFixed(0)}) - ${t.name}`)}if(D){const w="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(s.lastLodLevel_Texture<0){if(r.texture_lod=y.max_count-1,G){const h=y.lods[y.max_count-1];G&&console.log(`First Texture LOD ${r.texture_lod} (${h.max_height}px) - ${t.name}`)}}else{const h=s.lastScreenspaceVolume.x+s.lastScreenspaceVolume.y+s.lastScreenspaceVolume.z;let k=s.lastScreenCoverage*4;((V=this.context)==null?void 0:V.engine)==="model-viewer"&&(k*=1.5);const I=v/window.devicePixelRatio*k;for(let b=y.lods.length-1;b>=0;b--){let q=y.lods[b];if(!(w&&q.max_height>=2048)&&!(et()&&q.max_height>4096)&&q.max_height>I){if(r.texture_lod=b,r.texture_lod<s.lastLodLevel_Texture){const A=q.max_height;G&&console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${r.texture_lod} = ${A}px
5
+ `,t.uuid),t=t.clone(),t.offset=e.offset,t.repeat=e.repeat,t.colorSpace=e.colorSpace,t.magFilter=e.magFilter,t.minFilter=e.minFilter,t.wrapS=e.wrapS,t.wrapT=e.wrapT,t.flipY=e.flipY,t.anisotropy=e.anisotropy,t.mipmaps||(t.generateMipmaps=e.generateMipmaps),t}};let b=O;d(b,"registerTexture",(e,t,s,i,r)=>{if(x&&console.log("> Progressive: register texture",i,t.name,t.uuid,t,r),!t){x&&console.error("gltf-progressive: Register texture without texture");return}t.source&&(t.source[me]=r);const o=r.guid;O.assignLODInformation(e,t,o,s,i,void 0),O.lodInfos.set(o,r),O.lowresCache.set(o,t)}),d(b,"registerMesh",(e,t,s,i,r,o)=>{var u;x&&console.log("> Progressive: register mesh",r,s.name,o,s.uuid,s);const a=s.geometry;if(!a){x&&console.warn("gltf-progressive: Register mesh without geometry");return}a.userData||(a.userData={}),O.assignLODInformation(e,a,t,i,r,o.density),O.lodInfos.set(t,o);let l=O.lowresCache.get(t);l?l.push(s.geometry):l=[s.geometry],O.lowresCache.set(t,l),i>0&&!te(s)&&Ie(s,a);for(const c of H)(u=c.onRegisteredNewMesh)==null||u.call(c,s,o)}),d(b,"lodInfos",new Map),d(b,"previouslyLoaded",new Map),d(b,"lowresCache",new Map);class rt{constructor(e,t,s,i,r){d(this,"url");d(this,"key");d(this,"level");d(this,"index");d(this,"density");this.url=e,this.key=t,this.level=s,i!=null&&(this.index=i),r!=null&&(this.density=r)}}const k=ae("debugprogressive"),ot=ae("noprogressive"),xe=Symbol("Needle:LODSManager"),Me=Symbol("Needle:LODState"),Y=Symbol("Needle:CurrentLOD"),F={mesh_lod:-1,texture_lod:-1};var B,W,he,Q,Z,ge,q;const C=class{constructor(e,t){d(this,"context");d(this,"renderer");d(this,"projectionScreenMatrix",new y.Matrix4);d(this,"targetTriangleDensity",2e5);d(this,"updateInterval","auto");K(this,B,1);d(this,"pause",!1);d(this,"manual",!1);d(this,"_lodchangedlisteners",[]);K(this,W,void 0);K(this,he,new y.Clock);K(this,Q,0);K(this,Z,0);K(this,ge,0);K(this,q,0);d(this,"_fpsBuffer",[60,60,60,60,60]);d(this,"_sphere",new y.Sphere);d(this,"_tempBox",new y.Box3);d(this,"_tempBox2",new y.Box3);d(this,"tempMatrix",new y.Matrix4);d(this,"_tempWorldPosition",new y.Vector3);d(this,"_tempBoxSize",new y.Vector3);d(this,"_tempBox2Size",new y.Vector3);this.renderer=e,this.context={...t}}static getObjectLODState(e){return e[Me]}static addPlugin(e){H.push(e)}static removePlugin(e){const t=H.indexOf(e);t>=0&&H.splice(t,1)}static get(e,t){if(e[xe])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),e[xe];const s=new C(e,{engine:"unknown",...t});return e[xe]=s,s}get plugins(){return H}addEventListener(e,t){e==="changed"&&this._lodchangedlisteners.push(t)}removeEventListener(e,t){if(e==="changed"){const s=this._lodchangedlisteners.indexOf(t);s>=0&&this._lodchangedlisteners.splice(s,1)}}enable(){if(m(this,W))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let e=0;N(this,W,this.renderer.render);const t=this;Se(this.renderer),this.renderer.render=function(s,i){const r=t.renderer.getRenderTarget();(r==null||"isXRRenderTarget"in r&&r.isXRRenderTarget)&&(e=0,N(t,Q,m(t,Q)+1),N(t,Z,m(t,he).getDelta()),N(t,ge,m(t,ge)+m(t,Z)),t._fpsBuffer.shift(),t._fpsBuffer.push(1/m(t,Z)),N(t,q,t._fpsBuffer.reduce((a,l)=>a+l)/t._fpsBuffer.length),k&&m(t,Q)%200===0&&console.log("FPS",Math.round(m(t,q)),"Interval:",m(t,B)));const o=e++;m(t,W).call(this,s,i),t.onAfterRender(s,i,o)}}disable(){m(this,W)&&(console.debug("[gltf-progressive] Disabling LODsManager for renderer"),this.renderer.render=m(this,W),N(this,W,void 0))}update(e,t){this.internalUpdate(e,t)}onAfterRender(e,t,s){if(this.pause)return;const r=this.renderer.renderLists.get(e,0).opaque;let o=!0;if(r.length===1){const a=r[0].material;(a.name==="EffectMaterial"||a.name==="CopyShader")&&(o=!1)}if((t.parent&&t.parent.type==="CubeCamera"||s>=1&&t.type==="OrthographicCamera")&&(o=!1),o){if(ot||(this.updateInterval==="auto"?m(this,q)<40&&m(this,B)<10?(N(this,B,m(this,B)+1),k&&console.warn("↓ Reducing LOD updates",m(this,B),m(this,q).toFixed(0))):m(this,q)>=60&&m(this,B)>1&&(N(this,B,m(this,B)-1),k&&console.warn("↑ Increasing LOD updates",m(this,B),m(this,q).toFixed(0))):N(this,B,this.updateInterval),m(this,B)>0&&m(this,Q)%m(this,B)!=0))return;this.internalUpdate(e,t)}}internalUpdate(e,t){var l,u;const s=this.renderer.renderLists.get(e,0),i=s.opaque;this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse);const r=this.targetTriangleDensity;for(const c of i){if(c.material&&(((l=c.geometry)==null?void 0:l.type)==="BoxGeometry"||((u=c.geometry)==null?void 0:u.type)==="BufferGeometry")&&(c.material.name==="SphericalGaussianBlur"||c.material.name=="BackgroundCubeMaterial"||c.material.name==="CubemapFromEquirect"||c.material.name==="EquirectangularToCubeUV")){k&&(c.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(c.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",c,c.material.name,c.material.type)));continue}switch(c.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}if(k==="color"&&c.material&&!c.object.progressive_debug_color){c.object.progressive_debug_color=!0;const p=Math.random()*16777215,w=new y.MeshStandardMaterial({color:p});c.object.material=w}const g=c.object;(g instanceof y.Mesh||g.isMesh)&&this.updateLODs(e,t,g,r)}const o=s.transparent;for(const c of o){const g=c.object;(g instanceof y.Mesh||g.isMesh)&&this.updateLODs(e,t,g,r)}const a=s.transmissive;for(const c of a){const g=c.object;(g instanceof y.Mesh||g.isMesh)&&this.updateLODs(e,t,g,r)}}updateLODs(e,t,s,i){var a,l;s.userData||(s.userData={});let r=s[Me];if(r||(r=new it,s[Me]=r),r.frames++<2)return;for(const u of H)(a=u.onBeforeUpdateLOD)==null||a.call(u,this.renderer,e,t,s);this.calculateLodLevel(t,s,r,i,F),F.mesh_lod=Math.round(F.mesh_lod),F.texture_lod=Math.round(F.texture_lod),F.mesh_lod>=0&&this.loadProgressiveMeshes(s,F.mesh_lod);let o=F.texture_lod;s.material&&o>=0&&this.loadProgressiveTextures(s.material,o);for(const u of H)(l=u.onAfterUpdatedLOD)==null||l.call(u,this.renderer,e,t,s,F);r.lastLodLevel_Mesh=F.mesh_lod,r.lastLodLevel_Texture=F.texture_lod}loadProgressiveTextures(e,t){if(!e)return;if(Array.isArray(e)){for(const r of e)this.loadProgressiveTextures(r,t);return}let s=!1;(e[Y]===void 0||t<e[Y])&&(s=!0);const i=e["DEBUG:LOD"];i!=null&&(s=e[Y]!=i,t=i),s&&(e[Y]=t,b.assignTextureLOD(e,t).then(r=>{this._lodchangedlisteners.forEach(o=>o({type:"texture",level:t,object:e}))}))}loadProgressiveMeshes(e,t){if(!e)return Promise.resolve(null);let s=e[Y]!==t;const i=e["DEBUG:LOD"];if(i!=null&&(s=e[Y]!=i,t=i),s){e[Y]=t;const r=e.geometry;return b.assignMeshLOD(e,t).then(o=>(o&&e[Y]==t&&r!=e.geometry&&this._lodchangedlisteners.forEach(a=>a({type:"mesh",level:t,object:e})),o))}return Promise.resolve(null)}static isInside(e,t){const s=e.min,i=e.max,r=(s.x+i.x)*.5,o=(s.y+i.y)*.5;return this._tempPtInside.set(r,o,s.z).applyMatrix4(t).z<0}calculateLodLevel(e,t,s,i,r){var V;if(!t){r.mesh_lod=-1,r.texture_lod=-1;return}if(!e){r.mesh_lod=-1,r.texture_lod=-1;return}let a=10+1,l=!1;if(k&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const u=b.getMeshLODInformation(t.geometry),c=u==null?void 0:u.lods,g=c&&c.length>0,p=b.getMaterialMinMaxLODsCount(t.material),w=(p==null?void 0:p.min_count)!=1/0&&p.min_count>0&&p.max_count>0;if(!g&&!w){r.mesh_lod=0,r.texture_lod=0;return}g||(l=!0,a=0);const v=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let M=t.geometry.boundingBox;if(t.type==="SkinnedMesh"){const D=t;if(!D.boundingBox)D.computeBoundingBox();else if(s.frames%30===0){const h=te(D),G=D.geometry;h&&(D.geometry=h),D.computeBoundingBox(),D.geometry=G}M=D.boundingBox}if(M){const D=e;if(t.geometry.attributes.color&&t.geometry.attributes.color.count<100&&t.geometry.boundingSphere){this._sphere.copy(t.geometry.boundingSphere),this._sphere.applyMatrix4(t.matrixWorld);const f=e.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(f)){r.mesh_lod=0,r.texture_lod=0;return}}if(this._tempBox.copy(M),this._tempBox.applyMatrix4(t.matrixWorld),D.isPerspectiveCamera&&C.isInside(this._tempBox,this.projectionScreenMatrix)){r.mesh_lod=0,r.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&D.isPerspectiveCamera&&D.fov>70){const f=this._tempBox.min,L=this._tempBox.max;let _=f.x,A=f.y,P=L.x,X=L.y;const le=2,pe=1.5,ce=(f.x+L.x)*.5,ue=(f.y+L.y)*.5;_=(_-ce)*le+ce,A=(A-ue)*le+ue,P=(P-ce)*le+ce,X=(X-ue)*le+ue;const $e=_<0&&P>0?0:Math.min(Math.abs(f.x),Math.abs(L.x)),Ne=A<0&&X>0?0:Math.min(Math.abs(f.y),Math.abs(L.y)),ye=Math.max($e,Ne);s.lastCentrality=(pe-ye)*(pe-ye)*(pe-ye)}else s.lastCentrality=1;const h=this._tempBox.getSize(this._tempBoxSize);h.multiplyScalar(.5),screen.availHeight>0&&v>0&&h.multiplyScalar(v/screen.availHeight),e.isPerspectiveCamera?h.x*=e.aspect:e.isOrthographicCamera;const G=e.matrixWorldInverse,$=this._tempBox2;$.copy(M),$.applyMatrix4(t.matrixWorld),$.applyMatrix4(G);const I=$.getSize(this._tempBox2Size),E=Math.max(I.x,I.y);if(Math.max(h.x,h.y)!=0&&E!=0&&(h.z=I.z/Math.max(I.x,I.y)*Math.max(h.x,h.y)),s.lastScreenCoverage=Math.max(h.x,h.y,h.z),s.lastScreenspaceVolume.copy(h),s.lastScreenCoverage*=s.lastCentrality,k&&C.debugDrawLine){const f=this.tempMatrix.copy(this.projectionScreenMatrix);f.invert();const L=C.corner0,_=C.corner1,A=C.corner2,P=C.corner3;L.copy(this._tempBox.min),_.copy(this._tempBox.max),_.x=L.x,A.copy(this._tempBox.max),A.y=L.y,P.copy(this._tempBox.max);const X=(L.z+P.z)*.5;L.z=_.z=A.z=P.z=X,L.applyMatrix4(f),_.applyMatrix4(f),A.applyMatrix4(f),P.applyMatrix4(f),C.debugDrawLine(L,_,255),C.debugDrawLine(L,A,255),C.debugDrawLine(_,P,255),C.debugDrawLine(A,P,255)}let S=999;if(c&&s.lastScreenCoverage>0){for(let f=0;f<c.length;f++)if(c[f].density/s.lastScreenCoverage<i){S=f;break}}S<a&&(a=S,l=!0)}if(l?r.mesh_lod=a:r.mesh_lod=s.lastLodLevel_Mesh,k&&r.mesh_lod!=s.lastLodLevel_Mesh){const h=c==null?void 0:c[r.mesh_lod];h&&console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} → ${r.mesh_lod} (${h.density.toFixed(0)}) - ${t.name}`)}if(w){const D="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(s.lastLodLevel_Texture<0){if(r.texture_lod=p.max_count-1,k){const h=p.lods[p.max_count-1];k&&console.log(`First Texture LOD ${r.texture_lod} (${h.max_height}px) - ${t.name}`)}}else{const h=s.lastScreenspaceVolume.x+s.lastScreenspaceVolume.y+s.lastScreenspaceVolume.z;let G=s.lastScreenCoverage*4;((V=this.context)==null?void 0:V.engine)==="model-viewer"&&(G*=1.5);const I=v/window.devicePixelRatio*G;let E=!1;for(let z=p.lods.length-1;z>=0;z--){let S=p.lods[z];if(!(D&&S.max_height>=2048)&&!(et()&&S.max_height>4096)&&(S.max_height>I||!E&&z===0)){if(E=!0,r.texture_lod=z,r.texture_lod<s.lastLodLevel_Texture){const T=S.max_height;k&&console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${r.texture_lod} = ${T}px
6
6
  Screensize: ${I.toFixed(0)}px, Coverage: ${(100*s.lastScreenCoverage).toFixed(2)}%, Volume ${h.toFixed(1)}
7
- ${t.name}`)}break}}}}else r.texture_lod=0}};let R=C;B=new WeakMap,z=new WeakMap,he=new WeakMap,Q=new WeakMap,Z=new WeakMap,ge=new WeakMap,W=new WeakMap,d(R,"debugDrawLine"),d(R,"corner0",new p.Vector3),d(R,"corner1",new p.Vector3),d(R,"corner2",new p.Vector3),d(R,"corner3",new p.Vector3),d(R,"_tempPtInside",new p.Vector3);class ot{constructor(){d(this,"frames",0);d(this,"lastLodLevel_Mesh",-1);d(this,"lastLodLevel_Texture",-1);d(this,"lastScreenCoverage",0);d(this,"lastScreenspaceVolume",new p.Vector3);d(this,"lastCentrality",0)}}const Ce=Symbol("NEEDLE_mesh_lod"),fe=Symbol("NEEDLE_texture_lod");let ie=null;function Ae(){const n=nt();n&&(n.mapURLs(function(e){return Be(),e}),Be(),ie==null||ie.disconnect(),ie=new MutationObserver(e=>{e.forEach(t=>{t.addedNodes.forEach(s=>{s instanceof HTMLElement&&s.tagName.toLowerCase()==="model-viewer"&&Fe(s)})})}),ie.observe(document,{childList:!0,subtree:!0}))}function nt(){if(typeof customElements>"u")return null;const n=customElements.get("model-viewer");return n||(customElements.whenDefined("model-viewer").then(()=>{console.debug("[gltf-progressive] model-viewer defined"),Ae()}),null)}function Be(){if(typeof document>"u")return;document.querySelectorAll("model-viewer").forEach(e=>{Fe(e)})}const Re=new WeakSet;let at=0;function Fe(n){if(!n||Re.has(n))return null;Re.add(n),console.debug("[gltf-progressive] found new model-viewer..."+ ++at+`
8
- `,n.getAttribute("src"));let e=null,t=null,s=null;for(let o=n;o!=null;o=Object.getPrototypeOf(o)){const r=Object.getOwnPropertySymbols(o),i=r.find(u=>u.toString()=="Symbol(renderer)"),a=r.find(u=>u.toString()=="Symbol(scene)"),l=r.find(u=>u.toString()=="Symbol(needsRender)");!e&&i!=null&&(e=n[i].threeRenderer),!t&&a!=null&&(t=n[a]),!s&&l!=null&&(s=n[l])}if(e&&t){let o=function(){if(s){let i=0,a=setInterval(()=>{if(i++>5){clearInterval(a);return}s==null||s.call(n)},300)}};console.debug("[gltf-progressive] setup model-viewer");const r=R.get(e,{engine:"model-viewer"});return R.addPlugin(new lt),r.enable(),r.addEventListener("changed",()=>{s==null||s.call(n)}),n.addEventListener("model-visibility",i=>{i.detail.visible&&(s==null||s.call(n))}),n.addEventListener("load",()=>{o()}),()=>{r.disable()}}return null}class lt{constructor(){d(this,"_didWarnAboutMissingUrl",!1)}onBeforeUpdateLOD(e,t,s,o){this.tryParseMeshLOD(t,o),this.tryParseTextureLOD(t,o)}getUrl(e){if(!e)return null;let t=e.getAttribute("src");return t||(t=e.src),t||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",e),this._didWarnAboutMissingUrl=!0),t}tryGetCurrentGLTF(e){return e._currentGLTF}tryGetCurrentModelViewer(e){return e.element}tryParseTextureLOD(e,t){if(t[fe]==!0)return;t[fe]=!0;const s=this.tryGetCurrentGLTF(e),o=this.tryGetCurrentModelViewer(e),r=this.getUrl(o);if(r&&s&&t.material){let i=function(l){var c,g,y;if(l[fe]==!0)return;l[fe]=!0,l.userData&&(l.userData.LOD=-1);const u=Object.keys(l);for(let D=0;D<u.length;D++){const v=u[D],M=l[v];if((M==null?void 0:M.isTexture)===!0){const V=(g=(c=M.userData)==null?void 0:c.associations)==null?void 0:g.textures;if(V==null)continue;const w=s.parser.json.textures[V];if(!w){console.warn("Texture data not found for texture index "+V);continue}if((y=w==null?void 0:w.extensions)!=null&&y[U]){const h=w.extensions[U];h&&r&&O.registerTexture(r,M,h.lods.length,V,h)}}}};const a=t.material;if(Array.isArray(a))for(const l of a)i(l);else i(a)}}tryParseMeshLOD(e,t){var i,a;if(t[Ce]==!0)return;t[Ce]=!0;const s=this.tryGetCurrentModelViewer(e),o=this.getUrl(s);if(!o)return;const r=(a=(i=t.userData)==null?void 0:i.gltfExtensions)==null?void 0:a[U];if(r&&o){const l=t.uuid;O.registerMesh(o,l,t,0,r.lods.length,r)}}}function Ve(n,e,t,s){Se(e),be(t),Te(t,{progressive:!0,...s==null?void 0:s.hints}),t.register(r=>new O(r,n));const o=R.get(e);return(s==null?void 0:s.enableLODsManager)!==!1&&o.enable(),o}Ae();if(!tt){const n={gltfProgressive:{useNeedleProgressive:Ve,LODsManager:R,configureLoader:Te,getRaycastMesh:te,useRaycastMeshes:Ge}};if(!globalThis.Needle)globalThis.Needle=n;else for(const e in n)globalThis.Needle[e]=n[e]}exports.EXTENSION_NAME=U;exports.LODsManager=R;exports.NEEDLE_progressive=O;exports.VERSION=Oe;exports.addDracoAndKTX2Loaders=be;exports.configureLoader=Te;exports.createLoaders=Se;exports.getRaycastMesh=te;exports.patchModelViewer=Ae;exports.registerRaycastMesh=Ie;exports.setDracoDecoderLocation=je;exports.setKTX2TranscoderLocation=Je;exports.useNeedleProgressive=Ve;exports.useRaycastMeshes=Ge;
7
+ ${t.name}`)}break}}}}else r.texture_lod=0}};let R=C;B=new WeakMap,W=new WeakMap,he=new WeakMap,Q=new WeakMap,Z=new WeakMap,ge=new WeakMap,q=new WeakMap,d(R,"debugDrawLine"),d(R,"corner0",new y.Vector3),d(R,"corner1",new y.Vector3),d(R,"corner2",new y.Vector3),d(R,"corner3",new y.Vector3),d(R,"_tempPtInside",new y.Vector3);class it{constructor(){d(this,"frames",0);d(this,"lastLodLevel_Mesh",-1);d(this,"lastLodLevel_Texture",-1);d(this,"lastScreenCoverage",0);d(this,"lastScreenspaceVolume",new y.Vector3);d(this,"lastCentrality",0)}}const Ce=Symbol("NEEDLE_mesh_lod"),fe=Symbol("NEEDLE_texture_lod");let oe=null;function Ae(){const n=nt();n&&(n.mapURLs(function(e){return Be(),e}),Be(),oe==null||oe.disconnect(),oe=new MutationObserver(e=>{e.forEach(t=>{t.addedNodes.forEach(s=>{s instanceof HTMLElement&&s.tagName.toLowerCase()==="model-viewer"&&Fe(s)})})}),oe.observe(document,{childList:!0,subtree:!0}))}function nt(){if(typeof customElements>"u")return null;const n=customElements.get("model-viewer");return n||(customElements.whenDefined("model-viewer").then(()=>{console.debug("[gltf-progressive] model-viewer defined"),Ae()}),null)}function Be(){if(typeof document>"u")return;document.querySelectorAll("model-viewer").forEach(e=>{Fe(e)})}const Re=new WeakSet;let at=0;function Fe(n){if(!n||Re.has(n))return null;Re.add(n),console.debug("[gltf-progressive] found new model-viewer..."+ ++at+`
8
+ `,n.getAttribute("src"));let e=null,t=null,s=null;for(let 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)");!e&&o!=null&&(e=n[o].threeRenderer),!t&&a!=null&&(t=n[a]),!s&&l!=null&&(s=n[l])}if(e&&t){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=R.get(e,{engine:"model-viewer"});return R.addPlugin(new lt),r.enable(),r.addEventListener("changed",()=>{s==null||s.call(n)}),n.addEventListener("model-visibility",o=>{o.detail.visible&&(s==null||s.call(n))}),n.addEventListener("load",()=>{i()}),()=>{r.disable()}}return null}class lt{constructor(){d(this,"_didWarnAboutMissingUrl",!1)}onBeforeUpdateLOD(e,t,s,i){this.tryParseMeshLOD(t,i),this.tryParseTextureLOD(t,i)}getUrl(e){if(!e)return null;let t=e.getAttribute("src");return t||(t=e.src),t||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",e),this._didWarnAboutMissingUrl=!0),t}tryGetCurrentGLTF(e){return e._currentGLTF}tryGetCurrentModelViewer(e){return e.element}tryParseTextureLOD(e,t){if(t[fe]==!0)return;t[fe]=!0;const s=this.tryGetCurrentGLTF(e),i=this.tryGetCurrentModelViewer(e),r=this.getUrl(i);if(r&&s&&t.material){let o=function(l){var c,g,p;if(l[fe]==!0)return;l[fe]=!0,l.userData&&(l.userData.LOD=-1);const u=Object.keys(l);for(let w=0;w<u.length;w++){const v=u[w],M=l[v];if((M==null?void 0:M.isTexture)===!0){const V=(g=(c=M.userData)==null?void 0:c.associations)==null?void 0:g.textures;if(V==null)continue;const D=s.parser.json.textures[V];if(!D){console.warn("Texture data not found for texture index "+V);continue}if((p=D==null?void 0:D.extensions)!=null&&p[U]){const h=D.extensions[U];h&&r&&b.registerTexture(r,M,h.lods.length,V,h)}}}};const a=t.material;if(Array.isArray(a))for(const l of a)o(l);else o(a)}}tryParseMeshLOD(e,t){var o,a;if(t[Ce]==!0)return;t[Ce]=!0;const s=this.tryGetCurrentModelViewer(e),i=this.getUrl(s);if(!i)return;const r=(a=(o=t.userData)==null?void 0:o.gltfExtensions)==null?void 0:a[U];if(r&&i){const l=t.uuid;b.registerMesh(i,l,t,0,r.lods.length,r)}}}function Ve(n,e,t,s){Se(e),be(t),Te(t,{progressive:!0,...s==null?void 0:s.hints}),t.register(r=>new b(r,n));const i=R.get(e);return(s==null?void 0:s.enableLODsManager)!==!1&&i.enable(),i}Ae();if(!tt){const n={gltfProgressive:{useNeedleProgressive:Ve,LODsManager:R,configureLoader:Te,getRaycastMesh:te,useRaycastMeshes:ke}};if(!globalThis.Needle)globalThis.Needle=n;else for(const e in n)globalThis.Needle[e]=n[e]}exports.EXTENSION_NAME=U;exports.LODsManager=R;exports.NEEDLE_progressive=b;exports.VERSION=_e;exports.addDracoAndKTX2Loaders=be;exports.configureLoader=Te;exports.createLoaders=Se;exports.getRaycastMesh=te;exports.patchModelViewer=Ae;exports.registerRaycastMesh=Ie;exports.setDracoDecoderLocation=je;exports.setKTX2TranscoderLocation=Je;exports.useNeedleProgressive=Ve;exports.useRaycastMeshes=ke;
package/lib/extension.js CHANGED
@@ -1,4 +1,4 @@
1
- import { BufferGeometry, Material, Mesh, Texture, TextureLoader } from "three";
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
4
  import { getParam, resolveUrl } from "./utils.internal.js";
@@ -29,15 +29,14 @@ if (debug) {
29
29
  if (cur.isBufferGeometry === true) {
30
30
  const info = NEEDLE_progressive.getMeshLODInformation(cur);
31
31
  const level = !info ? 0 : Math.min(currentDebugLodLevel, info.lods.length);
32
- obj["DEBUG:LOD"] = currentDebugLodLevel;
33
- NEEDLE_progressive.assignMeshLOD(obj, level);
32
+ obj["DEBUG:LOD"] = level;
33
+ // NEEDLE_progressive.assignMeshLOD(obj as Mesh, level);
34
34
  if (info)
35
35
  maxLevel = Math.max(maxLevel, info.lods.length - 1);
36
36
  }
37
37
  else if (obj.isMaterial === true) {
38
38
  obj["DEBUG:LOD"] = currentDebugLodLevel;
39
- NEEDLE_progressive.assignTextureLOD(obj, currentDebugLodLevel);
40
- break;
39
+ // NEEDLE_progressive.assignTextureLOD(obj as Material, currentDebugLodLevel);
41
40
  }
42
41
  }
43
42
  });
@@ -308,7 +307,7 @@ export class NEEDLE_progressive {
308
307
  return this.assignTextureLOD(mesh.material, level);
309
308
  }
310
309
  }
311
- if (materialOrTexture instanceof Material || materialOrTexture.isMaterial === true) {
310
+ if (materialOrTexture.isMaterial === true) {
312
311
  const material = materialOrTexture;
313
312
  const promises = [];
314
313
  const slots = new Array();
@@ -365,8 +364,9 @@ export class NEEDLE_progressive {
365
364
  return Promise.resolve(null);
366
365
  }
367
366
  static assignTextureLODForSlot(current, level, material, slot) {
368
- if (current?.isTexture !== true)
367
+ if (current?.isTexture !== true) {
369
368
  return Promise.resolve(null);
369
+ }
370
370
  if (slot === "glyphMap") {
371
371
  return Promise.resolve(current);
372
372
  }
@@ -380,7 +380,7 @@ export class NEEDLE_progressive {
380
380
  const assigned = material[slot];
381
381
  // Check if the assigned texture LOD is higher quality than the current LOD
382
382
  // This is necessary for cases where e.g. a texture is updated via an explicit call to assignTextureLOD
383
- if (assigned) {
383
+ if (assigned && !debug) {
384
384
  const assignedLOD = this.getAssignedLODInformation(assigned);
385
385
  if (assignedLOD && assignedLOD?.level < level) {
386
386
  if (debug === "verbose")
@@ -395,6 +395,8 @@ export class NEEDLE_progressive {
395
395
  const lodinfo = this.getAssignedLODInformation(current);
396
396
  if (lodinfo)
397
397
  registerDebug(material, slot, lodinfo.url);
398
+ else
399
+ console.warn("No LOD info for texture", current);
398
400
  }
399
401
  // check if the old texture is still used by other objects
400
402
  // if not we dispose it...
@@ -809,9 +811,9 @@ export class NEEDLE_progressive {
809
811
  // This should only happen once ever for every texture
810
812
  // const original = target;
811
813
  {
812
- target = target.clone();
813
814
  if (debug)
814
- console.warn("Copying texture settings\n", source.uuid, "\n", target.uuid);
815
+ console.warn("Copy texture settings\n", source.uuid, "\n", target.uuid);
816
+ target = target.clone();
815
817
  }
816
818
  // else {
817
819
  // source = existingCopy;
@@ -309,9 +309,6 @@ export class LODsManager {
309
309
  // TODO: we currently can not switch texture lods because we need better caching for the textures internally (see copySettings in progressive + NE-4431)
310
310
  let textureLOD = levels.texture_lod;
311
311
  if (object.material && textureLOD >= 0) {
312
- const debugLevel = object["DEBUG:LOD"];
313
- if (debugLevel != undefined)
314
- textureLOD = debugLevel;
315
312
  this.loadProgressiveTextures(object.material, textureLOD);
316
313
  }
317
314
  for (const plugin of plugins) {
@@ -343,6 +340,11 @@ export class LODsManager {
343
340
  else if (level < material[$currentLOD]) {
344
341
  update = true;
345
342
  }
343
+ const debugLevel = material["DEBUG:LOD"];
344
+ if (debugLevel != undefined) {
345
+ update = material[$currentLOD] != debugLevel;
346
+ level = debugLevel;
347
+ }
346
348
  if (update) {
347
349
  material[$currentLOD] = level;
348
350
  NEEDLE_progressive.assignTextureLOD(material, level).then(_ => {
@@ -359,7 +361,13 @@ export class LODsManager {
359
361
  loadProgressiveMeshes(mesh, level) {
360
362
  if (!mesh)
361
363
  return Promise.resolve(null);
362
- if (mesh[$currentLOD] !== level) {
364
+ let update = mesh[$currentLOD] !== level;
365
+ const debugLevel = mesh["DEBUG:LOD"];
366
+ if (debugLevel != undefined) {
367
+ update = mesh[$currentLOD] != debugLevel;
368
+ level = debugLevel;
369
+ }
370
+ if (update) {
363
371
  mesh[$currentLOD] = level;
364
372
  const originalGeometry = mesh.geometry;
365
373
  return NEEDLE_progressive.assignMeshLOD(mesh, level).then(res => {
@@ -456,7 +464,7 @@ export class LODsManager {
456
464
  }
457
465
  boundingBox = skinnedMesh.boundingBox;
458
466
  }
459
- if (boundingBox && camera.isPerspectiveCamera) {
467
+ if (boundingBox) {
460
468
  const cam = camera;
461
469
  // hack: if the mesh has vertex colors, has less than 100 vertices we always select the highest LOD
462
470
  if (mesh.geometry.attributes.color && mesh.geometry.attributes.color.count < 100) {
@@ -481,7 +489,7 @@ export class LODsManager {
481
489
  // High distortions would lead to lower LOD levels.
482
490
  // "Centrality" of the calculated screen-space bounding box could be a factor here –
483
491
  // what's the distance of the bounding box to the center of the screen?
484
- if (LODsManager.isInside(this._tempBox, this.projectionScreenMatrix)) {
492
+ if (cam.isPerspectiveCamera && LODsManager.isInside(this._tempBox, this.projectionScreenMatrix)) {
485
493
  result.mesh_lod = 0;
486
494
  result.texture_lod = 0;
487
495
  return;
@@ -489,7 +497,7 @@ export class LODsManager {
489
497
  this._tempBox.applyMatrix4(this.projectionScreenMatrix);
490
498
  // TODO might need to be adjusted for cameras that are rendered during an XR session but are
491
499
  // actually not XR cameras (e.g. a render texture)
492
- if (this.renderer.xr.enabled && cam.fov > 70) {
500
+ if (this.renderer.xr.enabled && (cam.isPerspectiveCamera) && cam.fov > 70) {
493
501
  // calculate centrality of the bounding box - how close is it to the screen center
494
502
  const min = this._tempBox.min;
495
503
  const max = this._tempBox.max;
@@ -522,7 +530,13 @@ export class LODsManager {
522
530
  if (canvasHeight > 0)
523
531
  boxSize.multiplyScalar(canvasHeight / screen.availHeight);
524
532
  }
525
- boxSize.x *= cam.aspect;
533
+ if (camera.isPerspectiveCamera) {
534
+ boxSize.x *= camera.aspect;
535
+ }
536
+ else if (camera.isOrthographicCamera) {
537
+ // const cam = camera as OrthographicCamera;
538
+ // boxSize.x *= cam.zoom * .01;
539
+ }
526
540
  const matView = camera.matrixWorldInverse;
527
541
  const box2 = this._tempBox2;
528
542
  box2.copy(boundingBox);
@@ -618,6 +632,7 @@ export class LODsManager {
618
632
  }
619
633
  const screenSize = canvasHeight / window.devicePixelRatio;
620
634
  const pixelSizeOnScreen = screenSize * factor;
635
+ let foundLod = false;
621
636
  for (let i = texture_lods_minmax.lods.length - 1; i >= 0; i--) {
622
637
  let lod = texture_lods_minmax.lods[i];
623
638
  if (saveDataEnabled && lod.max_height >= 2048) {
@@ -625,7 +640,8 @@ export class LODsManager {
625
640
  }
626
641
  if (isMobileDevice() && lod.max_height > 4096)
627
642
  continue; // skip 8k textures on mobile devices (for now)
628
- if (lod.max_height > pixelSizeOnScreen) {
643
+ if (lod.max_height > pixelSizeOnScreen || (!foundLod && i === 0)) {
644
+ foundLod = true;
629
645
  result.texture_lod = i;
630
646
  if (result.texture_lod < state.lastLodLevel_Texture) {
631
647
  const lod_pixel_height = lod.max_height;
package/lib/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  // replaced at build time
2
- export const version = "2.1.0-experimental.3";
2
+ export const version = "2.1.0";
3
3
  globalThis["GLTF_PROGRESSIVE_VERSION"] = version;
4
4
  console.debug(`[gltf-progressive] version ${version}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/gltf-progressive",
3
- "version": "2.1.0-experimental.3",
3
+ "version": "2.1.0",
4
4
  "description": "three.js support for loading glTF or GLB files that contain progressive loading data",
5
5
  "homepage": "https://needle.tools",
6
6
  "author": {