@needle-tools/gltf-progressive 2.1.0 → 2.1.1

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,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
1
+ var qe=Object.defineProperty,Xe=(t,e,r)=>e in t?qe(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,c=(t,e,r)=>(Xe(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)),K=(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)},F=(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 Y,Texture as te,TextureLoader as He,Matrix4 as Ee,Clock as Ke,MeshStandardMaterial as Ye,Sphere as Je,Box3 as Ae,Vector3 as U}from"three";import{GLTFLoader as me}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as Qe}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as Ze}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as et}from"three/examples/jsm/loaders/KTX2Loader.js";const Pe="";globalThis.GLTF_PROGRESSIVE_VERSION=Pe,console.debug("[gltf-progressive] version -");let W="https://www.gstatic.com/draco/versioned/decoders/1.5.7/",Q="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";const tt=W,rt=Q,st=new URL(W+"draco_decoder.js");fetch(st,{method:"GET",headers:{Range:"bytes=0-1"}}).catch(t=>{console.debug(`Failed to fetch remote Draco decoder from ${W} (offline: ${typeof navigator<"u"?navigator.onLine:"unknown"})`),W===tt&&Ie("./include/draco/"),Q===rt&&ke("./include/ktx2/")}).finally(()=>{Be()});function Ie(t){W=t,P&&P[pe]!=W?(console.debug("Updating Draco decoder path to "+t),P[pe]=W,P.setDecoderPath(W),P.preload()):console.debug("Setting Draco decoder path to "+t)}function ke(t){Q=t,C&&C.transcoderPath!=Q?(console.debug("Updating KTX2 transcoder path to "+t),C.setTranscoderPath(Q),C.init()):console.debug("Setting KTX2 transcoder path to "+t)}const pe=Symbol("dracoDecoderPath");let P,ue,C;function Be(){P||(P=new Ze,P[pe]=W,P.setDecoderPath(W),P.setDecoderConfig({type:"js"}),P.preload()),C||(C=new et,C.setTranscoderPath(Q),C.init()),ue||(ue=Qe)}function ve(t){return Be(),t?C.detectSupport(t):t!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:P,ktx2Loader:C,meshoptDecoder:ue}}function ye(t){t.dracoLoader||t.setDRACOLoader(P),t.ktx2Loader||t.setKTX2Loader(C),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 Ce=me.prototype.load;function ot(...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,Ce?.call(this,...t)}me.prototype.load=ot,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 nt(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 it(){return ce!==void 0||(ce=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),re("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",ce)),ce}const at=typeof window>"u"&&typeof document>"u",Me=Symbol("needle:raycast-mesh");function Z(t){return t?.[Me]instanceof le?t[Me]:null}function Re(t,e){if((t.type==="Mesh"||t.type==="SkinnedMesh")&&!Z(t)){const r=lt(e);r.userData={isRaycastMesh:!0},t[Me]=r}}function je(t=!0){if(t){if(se)return;const e=se=Y.prototype.raycast;Y.prototype.raycast=function(r,n){const s=this,o=Z(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;Y.prototype.raycast=se,se=null}}let se=null;function lt(t){const e=new le;for(const r in t.attributes)e.setAttribute(r,t.getAttribute(r));return e.setIndex(t.getIndex()),e}const z=new Array,$="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 Ne(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[$];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 $}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 g=0;g<a.lods.length;g++){const f=a.lods[g];f.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,f.height),l.lods[g].max_height=Math.max(l.lods[g].max_height,f.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 Y||t.isMesh===!0){const n=t.geometry,s=this.getAssignedLODInformation(n);if(!s)return Promise.resolve(null);for(const o of z)(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&&Ne(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 te||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?Ne(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[$];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[$];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 g=t;g.source&&g.source[De]&&(a=g.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 g=Array.isArray(a.lods)?(r=a.lods[e])==null?void 0:r.path:a.lods;if(!g)return y&&!a["missing:uri"]&&(a["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,a)),null;const f=nt(l.url,g);if(f.endsWith(".glb")||f.endsWith(".gltf")){if(!a.guid)return console.warn("missing pointer for glb/gltf texture",a),null;const v=f+"_"+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(O=>(console.error(`Error loading LOD ${e} from ${f}
2
+ `,O),null)),b=!1;if(d==null||(d instanceof te&&t instanceof te?(n=d.image)!=null&&n.data||(s=d.source)!=null&&s.data?d=this.copySettings(t,d):(b=!0,this.previouslyLoaded.delete(v)):d instanceof le&&t instanceof le&&((o=d.attributes.position)!=null&&o.array||(b=!0,this.previouslyLoaded.delete(v)))),!b)return d}const D=a,x=new Promise(async(d,b)=>{const O=new me;ye(O),y&&(await new Promise(p=>setTimeout(p,1e3)),i&&console.warn("Start loading (delayed) "+f,D.guid));let k=f;if(D&&Array.isArray(D.lods)){const p=D.lods[e];p.hash&&(k+="?v="+p.hash)}const _=await O.loadAsync(k).catch(p=>(console.error(`Error loading LOD ${e} from ${f}
3
+ `,p),null));if(!_)return null;const B=_.parser;i&&console.log("Loading finished "+f,D.guid);let m=0;if(_.parser.json.textures){let p=!1;for(const h of _.parser.json.textures){if(h!=null&&h.extensions){const M=h?.extensions[$];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+'"',f,m,h,v),t instanceof te&&(h=this.copySettings(t,h)),h&&(h.guid=D.guid),d(h)}else y&&console.warn("Could not find texture with guid",D.guid,_.parser.json)}if(m=0,_.parser.json.meshes){let p=!1;for(const h of _.parser.json.meshes){if(h!=null&&h.extensions){const M=h?.extensions[$];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}"`,f,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 G=0;G<h.children.length;G++){const H=h.children[G];if(H.isMesh===!0){const J=H.geometry;w.assignLODInformation(l.url,J,u,e,G,M.density),S.push(J)}}return d(S)}}else y&&console.warn("Could not find mesh with guid",D.guid,_.parser.json)}return d(null)});return this.previouslyLoaded.set(v,x),await x}else if(t instanceof te){i&&console.log("Load texture from uri: "+f);const v=await new He().loadAsync(f);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",f),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 ut(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 e?(y&&console.warn(`Copy texture settings
4
4
  `,t.uuid,`
5
- `,e.uuid),e=e.clone(),e.offset=t.offset,e.repeat=t.repeat,e.colorSpace=t.colorSpace,e.magFilter=t.magFilter,e.minFilter=t.minFilter,e.wrapS=t.wrapS,e.wrapT=t.wrapT,e.flipY=t.flipY,e.anisotropy=t.anisotropy,e.mipmaps||(e.generateMipmaps=t.generateMipmaps),e}};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};
5
+ `,e.uuid),e=e.clone(),e.offset=t.offset,e.repeat=t.repeat,e.colorSpace=t.colorSpace,e.magFilter=t.magFilter,e.minFilter=t.minFilter,e.wrapS=t.wrapS,e.wrapT=t.wrapT,e.flipY=t.flipY,e.anisotropy=t.anisotropy,e.mipmaps||(e.generateMipmaps=t.generateMipmaps),e):t}};let T=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&&!Z(r)&&Re(r,l);for(const a of z)(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 ut{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 R=re("debugprogressive"),ct=re("noprogressive"),be=Symbol("Needle:LODSManager"),Oe=Symbol("Needle:LODState"),V=Symbol("Needle:CurrentLOD"),j={mesh_lod:-1,texture_lod:-1};var E,q,_e,ee,ne,de,X;const I=class{constructor(t,e){c(this,"context"),c(this,"renderer"),c(this,"projectionScreenMatrix",new Ee),c(this,"targetTriangleDensity",2e5),c(this,"updateInterval","auto"),K(this,E,1),c(this,"pause",!1),c(this,"manual",!1),c(this,"_lodchangedlisteners",[]),K(this,q,void 0),K(this,_e,new Ke),K(this,ee,0),K(this,ne,0),K(this,de,0),K(this,X,0),c(this,"_fpsBuffer",[60,60,60,60,60]),c(this,"_sphere",new Je),c(this,"_tempBox",new Ae),c(this,"_tempBox2",new Ae),c(this,"tempMatrix",new Ee),c(this,"_tempWorldPosition",new U),c(this,"_tempBoxSize",new U),c(this,"_tempBox2Size",new U),this.renderer=t,this.context={...e}}static getObjectLODState(t){return t[Oe]}static addPlugin(t){z.push(t)}static removePlugin(t){const e=z.indexOf(t);e>=0&&z.splice(e,1)}static get(t,e){if(t[be])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[be];const r=new I(t,{engine:"unknown",...e});return t[be]=r,r}get plugins(){return z}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,q))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let t=0;F(this,q,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,F(e,ee,L(e,ee)+1),F(e,ne,L(e,_e).getDelta()),F(e,de,L(e,de)+L(e,ne)),e._fpsBuffer.shift(),e._fpsBuffer.push(1/L(e,ne)),F(e,X,e._fpsBuffer.reduce((i,l)=>i+l)/e._fpsBuffer.length),R&&L(e,ee)%200===0&&console.log("FPS",Math.round(L(e,X)),"Interval:",L(e,E)));const o=t++;L(e,q).call(this,r,n),e.onAfterRender(r,n,o)}}disable(){L(this,q)&&(console.debug("[gltf-progressive] Disabling LODsManager for renderer"),this.renderer.render=L(this,q),F(this,q,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(ct||(this.updateInterval==="auto"?L(this,X)<40&&L(this,E)<10?(F(this,E,L(this,E)+1),R&&console.warn("\u2193 Reducing LOD updates",L(this,E),L(this,X).toFixed(0))):L(this,X)>=60&&L(this,E)>1&&(F(this,E,L(this,E)-1),R&&console.warn("\u2191 Increasing LOD updates",L(this,E),L(this,X).toFixed(0))):F(this,E,this.updateInterval),L(this,E)>0&&L(this,ee)%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")){R&&(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(R==="color"&&a.material&&!a.object.progressive_debug_color){a.object.progressive_debug_color=!0;const f=Math.random()*16777215,v=new Ye({color:f});a.object.material=v}const g=a.object;(g instanceof Y||g.isMesh)&&this.updateLODs(t,e,g,i)}const l=s.transparent;for(const a of l){const g=a.object;(g instanceof Y||g.isMesh)&&this.updateLODs(t,e,g,i)}const u=s.transmissive;for(const a of u){const g=a.object;(g instanceof Y||g.isMesh)&&this.updateLODs(t,e,g,i)}}updateLODs(t,e,r,n){var s,o;r.userData||(r.userData={});let i=r[Oe];if(i||(i=new dt,r[Oe]=i),i.frames++<2)return;for(const u of z)(s=u.onBeforeUpdateLOD)==null||s.call(u,this.renderer,t,e,r);this.calculateLodLevel(e,r,i,n,j),j.mesh_lod=Math.round(j.mesh_lod),j.texture_lod=Math.round(j.texture_lod),j.mesh_lod>=0&&this.loadProgressiveMeshes(r,j.mesh_lod);let l=j.texture_lod;r.material&&l>=0&&this.loadProgressiveTextures(r.material,l);for(const u of z)(o=u.onAfterUpdatedLOD)==null||o.call(u,this.renderer,t,e,r,j);i.lastLodLevel_Mesh=j.mesh_lod,i.lastLodLevel_Texture=j.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[V]===void 0||e<t[V])&&(r=!0);const n=t["DEBUG:LOD"];n!=null&&(r=t[V]!=n,e=n),r&&(t[V]=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[V]!==e;const n=t["DEBUG:LOD"];if(n!=null&&(r=t[V]!=n,e=n),r){t[V]=e;const s=t.geometry;return T.assignMeshLOD(t,e).then(o=>(o&&t[V]==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(R&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const u=T.getMeshLODInformation(e.geometry),a=u?.lods,g=a&&a.length>0,f=T.getMaterialMinMaxLODsCount(e.material),v=f?.min_count!=1/0&&f.min_count>0&&f.max_count>0;if(!g&&!v){s.mesh_lod=0,s.texture_lod=0;return}g||(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=Z(x),b=x.geometry;d&&(x.geometry=d),x.computeBoundingBox(),x.geometry=b}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&&I.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,G=p.y;const H=2,J=1.5,ie=(m.x+p.x)*.5,ae=(m.y+p.y)*.5;h=(h-ie)*H+ie,M=(M-ae)*H+ae,S=(S-ie)*H+ie,G=(G-ae)*H+ae;const ze=h<0&&S>0?0:Math.min(Math.abs(m.x),Math.abs(p.x)),Ve=M<0&&G>0?0:Math.min(Math.abs(m.y),Math.abs(p.y)),fe=Math.max(ze,Ve);r.lastCentrality=(J-fe)*(J-fe)*(J-fe)}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 b=t.matrixWorldInverse,O=this._tempBox2;O.copy(D),O.applyMatrix4(e.matrixWorld),O.applyMatrix4(b);const k=O.getSize(this._tempBox2Size),_=Math.max(k.x,k.y);if(Math.max(d.x,d.y)!=0&&_!=0&&(d.z=k.z/Math.max(k.x,k.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,R&&I.debugDrawLine){const m=this.tempMatrix.copy(this.projectionScreenMatrix);m.invert();const p=I.corner0,h=I.corner1,M=I.corner2,S=I.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 G=(p.z+S.z)*.5;p.z=h.z=M.z=S.z=G,p.applyMatrix4(m),h.applyMatrix4(m),M.applyMatrix4(m),S.applyMatrix4(m),I.debugDrawLine(p,h,255),I.debugDrawLine(p,M,255),I.debugDrawLine(h,S,255),I.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,R&&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=f.max_count-1,R){const d=f.lods[f.max_count-1];R&&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 b=r.lastScreenCoverage*4;((o=this.context)==null?void 0:o.engine)==="model-viewer"&&(b*=1.5);const O=A/window.devicePixelRatio*b;let k=!1;for(let _=f.lods.length-1;_>=0;_--){let B=f.lods[_];if(!(x&&B.max_height>=2048)&&!(it()&&B.max_height>4096)&&(B.max_height>O||!k&&_===0)){if(k=!0,s.texture_lod=_,s.texture_lod<r.lastLodLevel_Texture){const m=B.max_height;R&&console.log(`Texture LOD changed: ${r.lastLodLevel_Texture} \u2192 ${s.texture_lod} = ${m}px
6
+ Screensize: ${O.toFixed(0)}px, Coverage: ${(100*r.lastScreenCoverage).toFixed(2)}%, Volume ${d.toFixed(1)}
7
+ ${e.name}`)}break}}}}else s.texture_lod=0}};let N=I;E=new WeakMap,q=new WeakMap,_e=new WeakMap,ee=new WeakMap,ne=new WeakMap,de=new WeakMap,X=new WeakMap,c(N,"debugDrawLine"),c(N,"corner0",new U),c(N,"corner1",new U),c(N,"corner2",new U),c(N,"corner3",new U),c(N,"_tempPtInside",new U);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 U),c(this,"lastCentrality",0)}}const Ge=Symbol("NEEDLE_mesh_lod"),he=Symbol("NEEDLE_texture_lod");let ge=null;function Se(){const t=ht();t&&(t.mapURLs(function(e){return We(),e}),We(),ge?.disconnect(),ge=new MutationObserver(e=>{e.forEach(r=>{r.addedNodes.forEach(n=>{n instanceof HTMLElement&&n.tagName.toLowerCase()==="model-viewer"&&Fe(n)})})}),ge.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 We(){typeof document>"u"||document.querySelectorAll("model-viewer").forEach(t=>{Fe(t)})}const $e=new WeakSet;let gt=0;function Fe(t){if(!t||$e.has(t))return null;$e.add(t),console.debug("[gltf-progressive] found new model-viewer..."+ ++gt+`
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=N.get(e,{engine:"model-viewer"});return N.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,g,f;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=(g=(a=x.userData)==null?void 0:a.associations)==null?void 0:g.textures;if(d==null)continue;const b=n.parser.json.textures[d];if(!b){console.warn("Texture data not found for texture index "+d);continue}if((f=b?.extensions)!=null&&f[$]){const O=b.extensions[$];O&&o&&T.registerTexture(o,x,O.lods.length,d,O)}}}};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[Ge]==!0)return;r[Ge]=!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[$];if(l&&i){const u=r.uuid;T.registerMesh(i,u,r,0,l.lods.length,l)}}}function Ue(t,e,r,n){ve(e),ye(r),Le(r,{progressive:!0,...n?.hints}),r.register(o=>new T(o,t));const s=N.get(e);return n?.enableLODsManager!==!1&&s.enable(),s}if(Se(),!at){const t={gltfProgressive:{useNeedleProgressive:Ue,LODsManager:N,configureLoader:Le,getRaycastMesh:Z,useRaycastMeshes:je}};if(!globalThis.Needle)globalThis.Needle=t;else for(const e in t)globalThis.Needle[e]=t[e]}export{$ as EXTENSION_NAME,N as LODsManager,T as NEEDLE_progressive,Pe as VERSION,ye as addDracoAndKTX2Loaders,Le as configureLoader,ve as createLoaders,Z as getRaycastMesh,Se as patchModelViewer,Re as registerRaycastMesh,Ie as setDracoDecoderLocation,ke as setKTX2TranscoderLocation,Ue as useNeedleProgressive,je 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 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
1
+ "use strict";var qe=Object.defineProperty;var Xe=(n,e,t)=>e in n?qe(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var f=(n,e,t)=>(Xe(n,typeof e!="symbol"?e+"":e,t),t),Pe=(n,e,t)=>{if(!e.has(n))throw TypeError("Cannot "+t)};var m=(n,e,t)=>(Pe(n,e,"read from private field"),t?t.call(n):e.get(n)),j=(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)},z=(n,e,t,r)=>(Pe(n,e,"write to private field"),r?r.call(n,t):e.set(n,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const y=require("three"),_e=require("three/examples/jsm/loaders/GLTFLoader.js"),Ke=require("three/examples/jsm/libs/meshopt_decoder.module.js"),Ye=require("three/examples/jsm/loaders/DRACOLoader.js"),He=require("three/examples/jsm/loaders/KTX2Loader.js"),ke="";globalThis.GLTF_PROGRESSIVE_VERSION=ke;console.debug("[gltf-progressive] version -");let q="https://www.gstatic.com/draco/versioned/decoders/1.5.7/",Z="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";const je=q,Je=Z,Qe=new URL(q+"draco_decoder.js");fetch(Qe,{method:"GET",headers:{Range:"bytes=0-1"}}).catch(n=>{console.debug(`Failed to fetch remote Draco decoder from ${q} (offline: ${typeof navigator<"u"?navigator.onLine:"unknown"})`),q===je&&Ge("./include/draco/"),Z===Je&&Ie("./include/ktx2/")}).finally(()=>{$e()});function Ge(n){q=n,k&&k[De]!=q?(console.debug("Updating Draco decoder path to "+n),k[De]=q,k.setDecoderPath(q),k.preload()):console.debug("Setting Draco decoder path to "+n)}function Ie(n){Z=n,V&&V.transcoderPath!=Z?(console.debug("Updating KTX2 transcoder path to "+n),V.setTranscoderPath(Z),V.init()):console.debug("Setting KTX2 transcoder path to "+n)}const De=Symbol("dracoDecoderPath");let k,fe,V;function $e(){k||(k=new Ye.DRACOLoader,k[De]=q,k.setDecoderPath(q),k.setDecoderConfig({type:"js"}),k.preload()),V||(V=new He.KTX2Loader,V.setTranscoderPath(Z),V.init()),fe||(fe=Ke.MeshoptDecoder)}function be(n){return $e(),n?V.detectSupport(n):n!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:k,ktx2Loader:V,meshoptDecoder:fe}}function Se(n){n.dracoLoader||n.setDRACOLoader(k),n.ktx2Loader||n.setKTX2Loader(V),n.meshoptDecoder||n.setMeshoptDecoder(fe)}const we=new WeakMap;function Te(n,e){let t=we.get(n);t?t=Object.assign(t,e):t=e,we.set(n,t)}const Le=_e.GLTFLoader.prototype.load;function Ze(...n){const e=we.get(this);let t=n[0];const r=new URL(t,window.location.href);if(r.hostname.endsWith("needle.tools")){const s=(e==null?void 0: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}`,t=r.toString()}return n[0]=t,Le==null?void 0:Le.call(this,...n)}_e.GLTFLoader.prototype.load=Ze;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 et(n,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||n===void 0)return e;const t=n.lastIndexOf("/");if(t>=0){const r=n.substring(0,t+1);for(;r.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return r+e}return e}let se;function tt(){return se!==void 0||(se=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),ae("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",se)),se}const rt=typeof window>"u"&&typeof document>"u",ve=Symbol("needle:raycast-mesh");function re(n){return(n==null?void 0:n[ve])instanceof y.BufferGeometry?n[ve]:null}function Fe(n,e){if((n.type==="Mesh"||n.type==="SkinnedMesh")&&!re(n)){const r=st(e);r.userData={isRaycastMesh:!0},n[ve]=r}}function Ve(n=!0){if(n){if(oe)return;const e=oe=y.Mesh.prototype.raycast;y.Mesh.prototype.raycast=function(t,r){const i=this,s=re(i);let o;s&&i.isMesh&&(o=i.geometry,i.geometry=s),e.call(this,t,r),o&&(i.geometry=o)}}else{if(!oe)return;y.Mesh.prototype.raycast=oe,oe=null}}let oe=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 Q=new Array,W="NEEDLE_progressive",x=ae("debugprogressive"),me=Symbol("needle-progressive-texture"),ne=new Map,Oe=new Set;if(x){let n=function(){e+=1,console.log("Toggle LOD level",e,ne),ne.forEach((i,s)=>{for(const o of i.keys){const a=s[o];if(a!=null)if(a.isBufferGeometry===!0){const l=S.getMeshLODInformation(a),u=l?Math.min(e,l.lods.length):0;s["DEBUG:LOD"]=u,l&&(t=Math.max(t,l.lods.length-1))}else s.isMaterial===!0&&(s["DEBUG:LOD"]=e)}}),e>=t&&(e=-1)},e=-1,t=2,r=!1;window.addEventListener("keyup",i=>{i.key==="p"&&n(),i.key==="w"&&(r=!r,Oe&&Oe.forEach(s=>{s.name!="BackgroundCubeMaterial"&&s.glyphMap==null&&"wireframe"in s&&(s.wireframe=r)}))})}function Ee(n,e,t){var i;if(!x)return;ne.has(n)||ne.set(n,{keys:[],sourceId:t});const r=ne.get(n);((i=r==null?void 0:r.keys)==null?void 0:i.includes(e))==!1&&r.keys.push(e)}const O=class{constructor(e,t){f(this,"parser");f(this,"url");f(this,"_isLoadingMesh");f(this,"loadMesh",e=>{var r,i;if(this._isLoadingMesh)return null;const t=(i=(r=this.parser.json.meshes[e])==null?void 0:r.extensions)==null?void 0:i[W];return t?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",e).then(s=>{var o;return this._isLoadingMesh=!1,s&&O.registerMesh(this.url,t.guid,s,(o=t.lods)==null?void 0:o.length,void 0,t),s})):null});x&&console.log("Progressive extension registered for",t),this.parser=e,this.url=t}get name(){return W}static getMeshLODInformation(e){const t=this.getAssignedLODInformation(e);return t!=null&&t.key?this.lodInfos.get(t.key):null}static getMaterialMinMaxLODsCount(e,t){const r=this,i="LODS:minmax",s=e[i];if(s!=null)return s;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=r.getAssignedLODInformation(a);if(u){const c=r.lodInfos.get(u.key);if(c&&c.lods){l.min_count=Math.min(l.min_count,c.lods.length),l.max_count=Math.max(l.max_count,c.lods.length);for(let 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 s;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 r,i;if(e.isMesh?r=e.geometry:(e.isBufferGeometry||e.isTexture)&&(r=e),r&&(s=r==null?void 0:r.userData)!=null&&s.LODS){const o=r.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 r;if(!e)return Promise.resolve(null);if(e instanceof y.Mesh||e.isMesh===!0){const i=e.geometry,s=this.getAssignedLODInformation(i);if(!s)return Promise.resolve(null);for(const o of Q)(r=o.onBeforeGetLODMesh)==null||r.call(o,e,t);return e["LOD:requested level"]=t,O.getOrLoadLOD(i,t).then(o=>{if(Array.isArray(o)){const a=s.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&&Ee(e,"geometry",s.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 r=e;if(Array.isArray(r.material)){const i=new Array;for(const s of r.material){const o=this.assignTextureLOD(s,t);i.push(o)}return Promise.all(i).then(s=>{const o=new Array;for(const a of s)Array.isArray(a)&&o.push(...a);return o})}else return this.assignTextureLOD(r.material,t)}if(e.isMaterial===!0){const r=e,i=[],s=new Array;if(x&&Oe.add(r),r.uniforms&&(r.isRawShaderMaterial||r.isShaderMaterial===!0)){const o=r;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,r,a).then(c=>(c&&o.uniforms[a].value!=c&&(o.uniforms[a].value=c,o.uniformsNeedUpdate=!0),c));i.push(u),s.push(a)}}}else for(const o of Object.keys(r)){const a=r[o];if((a==null?void 0:a.isTexture)===!0){const l=this.assignTextureLODForSlot(a,t,r,o);i.push(l),s.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=s[l];u&&u.isTexture===!0?a.push({material:r,slot:c,texture:u,level:t}):a.push({material:r,slot:c,texture:null,level:t})}return a})}if(e instanceof y.Texture||e.isTexture===!0){const r=e;return this.assignTextureLODForSlot(r,t,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(e,t,r,i){return(e==null?void 0:e.isTexture)!==!0?Promise.resolve(null):i==="glyphMap"?Promise.resolve(e):O.getOrLoadLOD(e,t).then(s=>{if(Array.isArray(s))return null;if((s==null?void 0:s.isTexture)===!0){if(s!=e){if(r&&i){const o=r[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,r,o,s),null}r[i]=s}if(x&&i&&r){const o=this.getAssignedLODInformation(e);o?Ee(r,i,o.url):console.warn("No LOD info for texture",e)}}return s}else x=="verbose"&&console.warn("No LOD found for",e,t);return null}).catch(s=>(console.error("Error loading LOD",e,s),null))}afterRoot(e){var t,r;return x&&console.log("AFTER",this.url,e),(t=this.parser.json.textures)==null||t.forEach((i,s)=>{var o;if(i!=null&&i.extensions){const a=i==null?void 0:i.extensions[W];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)===s&&(l=!0,O.registerTexture(this.url,u,(o=a.lods)==null?void 0:o.length,s,a))}l||this.parser.getDependency("texture",s).then(u=>{var c;u&&O.registerTexture(this.url,u,(c=a.lods)==null?void 0:c.length,s,a)})}}}),(r=this.parser.json.meshes)==null||r.forEach((i,s)=>{if(i!=null&&i.extensions){const o=i==null?void 0:i.extensions[W];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)===s&&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 r=x=="verbose",i=e.userData.LODS;if(!i)return null;const s=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(s)),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(s)}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=et(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){r&&console.log(`LOD ${t} was already loading/loaded: ${w}`);let h=await v.catch(U=>(console.error(`Error loading LOD ${t} from ${p}
2
+ `,U),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,N=new Promise(async(h,G)=>{const U=new _e.GLTFLoader;Se(U),x&&(await new Promise(T=>setTimeout(T,1e3)),r&&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 P=await U.loadAsync(I).catch(T=>(console.error(`Error loading LOD ${t} from ${p}
3
+ `,T),null));if(!P)return null;const X=P.parser;r&&console.log("Loading finished "+p,M.guid);let b=0;if(P.parser.json.textures){let T=!1;for(const d of P.parser.json.textures){if(d!=null&&d.extensions){const L=d==null?void 0:d.extensions[W];if(L!=null&&L.guid&&L.guid===M.guid){T=!0;break}}b++}if(T){let d=await X.getDependency("texture",b);return d&&O.assignLODInformation(i.url,d,s,t,void 0,void 0),r&&console.log('change "'+e.name+'" → "'+d.name+'"',p,b,d,w),e instanceof y.Texture&&(d=this.copySettings(e,d)),d&&(d.guid=M.guid),h(d)}else x&&console.warn("Could not find texture with guid",M.guid,P.parser.json)}if(b=0,P.parser.json.meshes){let T=!1;for(const d of P.parser.json.meshes){if(d!=null&&d.extensions){const L=d==null?void 0:d.extensions[W];if(L!=null&&L.guid&&L.guid===M.guid){T=!0;break}}b++}if(T){const d=await X.getDependency("mesh",b),L=M;if(r&&console.log(`Loaded Mesh "${d.name}"`,p,b,d,w),d.isMesh===!0){const _=d.geometry;return O.assignLODInformation(i.url,_,s,t,void 0,L.density),h(_)}else{const _=new Array;for(let A=0;A<d.children.length;A++){const E=d.children[A];if(E.isMesh===!0){const H=E.geometry;O.assignLODInformation(i.url,H,s,t,A,L.density),_.push(H)}}return h(_)}}else x&&console.warn("Could not find mesh with guid",M.guid,P.parser.json)}return h(null)});return this.previouslyLoaded.set(w,N),await N}else if(e instanceof y.Texture){r&&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,r&&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 "${s}" ${e.name}`,e.type);return null}static assignLODInformation(e,t,r,i,s,o){if(!t)return;t.userData||(t.userData={});const a=new ot(e,r,i,s,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 t?(x&&console.warn(`Copy texture settings
4
4
  `,e.uuid,`
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
- 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,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;
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):e}};let S=O;f(S,"registerTexture",(e,t,r,i,s)=>{if(x&&console.log("> Progressive: register texture",i,t.name,t.uuid,t,s),!t){x&&console.error("gltf-progressive: Register texture without texture");return}t.source&&(t.source[me]=s);const o=s.guid;O.assignLODInformation(e,t,o,r,i,void 0),O.lodInfos.set(o,s),O.lowresCache.set(o,t)}),f(S,"registerMesh",(e,t,r,i,s,o)=>{var u;x&&console.log("> Progressive: register mesh",s,r.name,o,r.uuid,r);const a=r.geometry;if(!a){x&&console.warn("gltf-progressive: Register mesh without geometry");return}a.userData||(a.userData={}),O.assignLODInformation(e,a,t,i,s,o.density),O.lodInfos.set(t,o);let l=O.lowresCache.get(t);l?l.push(r.geometry):l=[r.geometry],O.lowresCache.set(t,l),i>0&&!re(r)&&Fe(r,a);for(const c of Q)(u=c.onRegisteredNewMesh)==null||u.call(c,r,o)}),f(S,"lodInfos",new Map),f(S,"previouslyLoaded",new Map),f(S,"lowresCache",new Map);class ot{constructor(e,t,r,i,s){f(this,"url");f(this,"key");f(this,"level");f(this,"index");f(this,"density");this.url=e,this.key=t,this.level=r,i!=null&&(this.index=i),s!=null&&(this.density=s)}}const $=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,K,he,ee,te,ge,Y;const C=class{constructor(e,t){f(this,"context");f(this,"renderer");f(this,"projectionScreenMatrix",new y.Matrix4);f(this,"targetTriangleDensity",2e5);f(this,"updateInterval","auto");j(this,B,1);f(this,"pause",!1);f(this,"manual",!1);f(this,"_lodchangedlisteners",[]);j(this,K,void 0);j(this,he,new y.Clock);j(this,ee,0);j(this,te,0);j(this,ge,0);j(this,Y,0);f(this,"_fpsBuffer",[60,60,60,60,60]);f(this,"_sphere",new y.Sphere);f(this,"_tempBox",new y.Box3);f(this,"_tempBox2",new y.Box3);f(this,"tempMatrix",new y.Matrix4);f(this,"_tempWorldPosition",new y.Vector3);f(this,"_tempBoxSize",new y.Vector3);f(this,"_tempBox2Size",new y.Vector3);this.renderer=e,this.context={...t}}static getObjectLODState(e){return e[Me]}static addPlugin(e){Q.push(e)}static removePlugin(e){const t=Q.indexOf(e);t>=0&&Q.splice(t,1)}static get(e,t){if(e[xe])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),e[xe];const r=new C(e,{engine:"unknown",...t});return e[xe]=r,r}get plugins(){return Q}addEventListener(e,t){e==="changed"&&this._lodchangedlisteners.push(t)}removeEventListener(e,t){if(e==="changed"){const r=this._lodchangedlisteners.indexOf(t);r>=0&&this._lodchangedlisteners.splice(r,1)}}enable(){if(m(this,K))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let e=0;z(this,K,this.renderer.render);const t=this;be(this.renderer),this.renderer.render=function(r,i){const s=t.renderer.getRenderTarget();(s==null||"isXRRenderTarget"in s&&s.isXRRenderTarget)&&(e=0,z(t,ee,m(t,ee)+1),z(t,te,m(t,he).getDelta()),z(t,ge,m(t,ge)+m(t,te)),t._fpsBuffer.shift(),t._fpsBuffer.push(1/m(t,te)),z(t,Y,t._fpsBuffer.reduce((a,l)=>a+l)/t._fpsBuffer.length),$&&m(t,ee)%200===0&&console.log("FPS",Math.round(m(t,Y)),"Interval:",m(t,B)));const o=e++;m(t,K).call(this,r,i),t.onAfterRender(r,i,o)}}disable(){m(this,K)&&(console.debug("[gltf-progressive] Disabling LODsManager for renderer"),this.renderer.render=m(this,K),z(this,K,void 0))}update(e,t){this.internalUpdate(e,t)}onAfterRender(e,t,r){if(this.pause)return;const s=this.renderer.renderLists.get(e,0).opaque;let o=!0;if(s.length===1){const a=s[0].material;(a.name==="EffectMaterial"||a.name==="CopyShader")&&(o=!1)}if((t.parent&&t.parent.type==="CubeCamera"||r>=1&&t.type==="OrthographicCamera")&&(o=!1),o){if(it||(this.updateInterval==="auto"?m(this,Y)<40&&m(this,B)<10?(z(this,B,m(this,B)+1),$&&console.warn("↓ Reducing LOD updates",m(this,B),m(this,Y).toFixed(0))):m(this,Y)>=60&&m(this,B)>1&&(z(this,B,m(this,B)-1),$&&console.warn("↑ Increasing LOD updates",m(this,B),m(this,Y).toFixed(0))):z(this,B,this.updateInterval),m(this,B)>0&&m(this,ee)%m(this,B)!=0))return;this.internalUpdate(e,t)}}internalUpdate(e,t){var l,u;const r=this.renderer.renderLists.get(e,0),i=r.opaque;this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse);const s=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")){$&&(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($==="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,s)}const o=r.transparent;for(const c of o){const g=c.object;(g instanceof y.Mesh||g.isMesh)&&this.updateLODs(e,t,g,s)}const a=r.transmissive;for(const c of a){const g=c.object;(g instanceof y.Mesh||g.isMesh)&&this.updateLODs(e,t,g,s)}}updateLODs(e,t,r,i){var a,l;r.userData||(r.userData={});let s=r[Me];if(s||(s=new nt,r[Me]=s),s.frames++<2)return;for(const u of Q)(a=u.onBeforeUpdateLOD)==null||a.call(u,this.renderer,e,t,r);this.calculateLodLevel(t,r,s,i,F),F.mesh_lod=Math.round(F.mesh_lod),F.texture_lod=Math.round(F.texture_lod),F.mesh_lod>=0&&this.loadProgressiveMeshes(r,F.mesh_lod);let o=F.texture_lod;r.material&&o>=0&&this.loadProgressiveTextures(r.material,o);for(const u of Q)(l=u.onAfterUpdatedLOD)==null||l.call(u,this.renderer,e,t,r,F);s.lastLodLevel_Mesh=F.mesh_lod,s.lastLodLevel_Texture=F.texture_lod}loadProgressiveTextures(e,t){if(!e)return;if(Array.isArray(e)){for(const s of e)this.loadProgressiveTextures(s,t);return}let r=!1;(e[J]===void 0||t<e[J])&&(r=!0);const i=e["DEBUG:LOD"];i!=null&&(r=e[J]!=i,t=i),r&&(e[J]=t,S.assignTextureLOD(e,t).then(s=>{this._lodchangedlisteners.forEach(o=>o({type:"texture",level:t,object:e}))}))}loadProgressiveMeshes(e,t){if(!e)return Promise.resolve(null);let r=e[J]!==t;const i=e["DEBUG:LOD"];if(i!=null&&(r=e[J]!=i,t=i),r){e[J]=t;const s=e.geometry;return S.assignMeshLOD(e,t).then(o=>(o&&e[J]==t&&s!=e.geometry&&this._lodchangedlisteners.forEach(a=>a({type:"mesh",level:t,object:e})),o))}return Promise.resolve(null)}static isInside(e,t){const r=e.min,i=e.max,s=(r.x+i.x)*.5,o=(r.y+i.y)*.5;return this._tempPtInside.set(s,o,r.z).applyMatrix4(t).z<0}calculateLodLevel(e,t,r,i,s){var N;if(!t){s.mesh_lod=-1,s.texture_lod=-1;return}if(!e){s.mesh_lod=-1,s.texture_lod=-1;return}let a=10+1,l=!1;if($&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const u=S.getMeshLODInformation(t.geometry),c=u==null?void 0:u.lods,g=c&&c.length>0,p=S.getMaterialMinMaxLODsCount(t.material),w=(p==null?void 0:p.min_count)!=1/0&&p.min_count>0&&p.max_count>0;if(!g&&!w){s.mesh_lod=0,s.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(r.frames%30===0){const h=re(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 d=e.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(d)){s.mesh_lod=0,s.texture_lod=0;return}}if(this._tempBox.copy(M),this._tempBox.applyMatrix4(t.matrixWorld),D.isPerspectiveCamera&&C.isInside(this._tempBox,this.projectionScreenMatrix)){s.mesh_lod=0,s.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&D.isPerspectiveCamera&&D.fov>70){const d=this._tempBox.min,L=this._tempBox.max;let _=d.x,A=d.y,E=L.x,H=L.y;const le=2,pe=1.5,ce=(d.x+L.x)*.5,ue=(d.y+L.y)*.5;_=(_-ce)*le+ce,A=(A-ue)*le+ue,E=(E-ce)*le+ce,H=(H-ue)*le+ue;const ze=_<0&&E>0?0:Math.min(Math.abs(d.x),Math.abs(L.x)),We=A<0&&H>0?0:Math.min(Math.abs(d.y),Math.abs(L.y)),ye=Math.max(ze,We);r.lastCentrality=(pe-ye)*(pe-ye)*(pe-ye)}else r.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,U=this._tempBox2;U.copy(M),U.applyMatrix4(t.matrixWorld),U.applyMatrix4(G);const I=U.getSize(this._tempBox2Size),P=Math.max(I.x,I.y);if(Math.max(h.x,h.y)!=0&&P!=0&&(h.z=I.z/Math.max(I.x,I.y)*Math.max(h.x,h.y)),r.lastScreenCoverage=Math.max(h.x,h.y,h.z),r.lastScreenspaceVolume.copy(h),r.lastScreenCoverage*=r.lastCentrality,$&&C.debugDrawLine){const d=this.tempMatrix.copy(this.projectionScreenMatrix);d.invert();const L=C.corner0,_=C.corner1,A=C.corner2,E=C.corner3;L.copy(this._tempBox.min),_.copy(this._tempBox.max),_.x=L.x,A.copy(this._tempBox.max),A.y=L.y,E.copy(this._tempBox.max);const H=(L.z+E.z)*.5;L.z=_.z=A.z=E.z=H,L.applyMatrix4(d),_.applyMatrix4(d),A.applyMatrix4(d),E.applyMatrix4(d),C.debugDrawLine(L,_,255),C.debugDrawLine(L,A,255),C.debugDrawLine(_,E,255),C.debugDrawLine(A,E,255)}let b=999;if(c&&r.lastScreenCoverage>0){for(let d=0;d<c.length;d++)if(c[d].density/r.lastScreenCoverage<i){b=d;break}}b<a&&(a=b,l=!0)}if(l?s.mesh_lod=a:s.mesh_lod=r.lastLodLevel_Mesh,$&&s.mesh_lod!=r.lastLodLevel_Mesh){const h=c==null?void 0:c[s.mesh_lod];h&&console.log(`Mesh LOD changed: ${r.lastLodLevel_Mesh} → ${s.mesh_lod} (${h.density.toFixed(0)}) - ${t.name}`)}if(w){const D="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(r.lastLodLevel_Texture<0){if(s.texture_lod=p.max_count-1,$){const h=p.lods[p.max_count-1];$&&console.log(`First Texture LOD ${s.texture_lod} (${h.max_height}px) - ${t.name}`)}}else{const h=r.lastScreenspaceVolume.x+r.lastScreenspaceVolume.y+r.lastScreenspaceVolume.z;let G=r.lastScreenCoverage*4;((N=this.context)==null?void 0:N.engine)==="model-viewer"&&(G*=1.5);const I=v/window.devicePixelRatio*G;let P=!1;for(let X=p.lods.length-1;X>=0;X--){let b=p.lods[X];if(!(D&&b.max_height>=2048)&&!(tt()&&b.max_height>4096)&&(b.max_height>I||!P&&X===0)){if(P=!0,s.texture_lod=X,s.texture_lod<r.lastLodLevel_Texture){const T=b.max_height;$&&console.log(`Texture LOD changed: ${r.lastLodLevel_Texture} → ${s.texture_lod} = ${T}px
6
+ Screensize: ${I.toFixed(0)}px, Coverage: ${(100*r.lastScreenCoverage).toFixed(2)}%, Volume ${h.toFixed(1)}
7
+ ${t.name}`)}break}}}}else s.texture_lod=0}};let R=C;B=new WeakMap,K=new WeakMap,he=new WeakMap,ee=new WeakMap,te=new WeakMap,ge=new WeakMap,Y=new WeakMap,f(R,"debugDrawLine"),f(R,"corner0",new y.Vector3),f(R,"corner1",new y.Vector3),f(R,"corner2",new y.Vector3),f(R,"corner3",new y.Vector3),f(R,"_tempPtInside",new y.Vector3);class nt{constructor(){f(this,"frames",0);f(this,"lastLodLevel_Mesh",-1);f(this,"lastLodLevel_Texture",-1);f(this,"lastScreenCoverage",0);f(this,"lastScreenspaceVolume",new y.Vector3);f(this,"lastCentrality",0)}}const Ce=Symbol("NEEDLE_mesh_lod"),de=Symbol("NEEDLE_texture_lod");let ie=null;function Ae(){const n=at();n&&(n.mapURLs(function(e){return Be(),e}),Be(),ie==null||ie.disconnect(),ie=new MutationObserver(e=>{e.forEach(t=>{t.addedNodes.forEach(r=>{r instanceof HTMLElement&&r.tagName.toLowerCase()==="model-viewer"&&Ne(r)})})}),ie.observe(document,{childList:!0,subtree:!0}))}function at(){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=>{Ne(e)})}const Re=new WeakSet;let lt=0;function Ne(n){if(!n||Re.has(n))return null;Re.add(n),console.debug("[gltf-progressive] found new model-viewer..."+ ++lt+`
8
+ `,n.getAttribute("src"));let e=null,t=null,r=null;for(let i=n;i!=null;i=Object.getPrototypeOf(i)){const s=Object.getOwnPropertySymbols(i),o=s.find(u=>u.toString()=="Symbol(renderer)"),a=s.find(u=>u.toString()=="Symbol(scene)"),l=s.find(u=>u.toString()=="Symbol(needsRender)");!e&&o!=null&&(e=n[o].threeRenderer),!t&&a!=null&&(t=n[a]),!r&&l!=null&&(r=n[l])}if(e&&t){let i=function(){if(r){let o=0,a=setInterval(()=>{if(o++>5){clearInterval(a);return}r==null||r.call(n)},300)}};console.debug("[gltf-progressive] setup model-viewer");const s=R.get(e,{engine:"model-viewer"});return R.addPlugin(new ct),s.enable(),s.addEventListener("changed",()=>{r==null||r.call(n)}),n.addEventListener("model-visibility",o=>{o.detail.visible&&(r==null||r.call(n))}),n.addEventListener("load",()=>{i()}),()=>{s.disable()}}return null}class ct{constructor(){f(this,"_didWarnAboutMissingUrl",!1)}onBeforeUpdateLOD(e,t,r,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[de]==!0)return;t[de]=!0;const r=this.tryGetCurrentGLTF(e),i=this.tryGetCurrentModelViewer(e),s=this.getUrl(i);if(s&&r&&t.material){let o=function(l){var c,g,p;if(l[de]==!0)return;l[de]=!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 N=(g=(c=M.userData)==null?void 0:c.associations)==null?void 0:g.textures;if(N==null)continue;const D=r.parser.json.textures[N];if(!D){console.warn("Texture data not found for texture index "+N);continue}if((p=D==null?void 0:D.extensions)!=null&&p[W]){const h=D.extensions[W];h&&s&&S.registerTexture(s,M,h.lods.length,N,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 r=this.tryGetCurrentModelViewer(e),i=this.getUrl(r);if(!i)return;const s=(a=(o=t.userData)==null?void 0:o.gltfExtensions)==null?void 0:a[W];if(s&&i){const l=t.uuid;S.registerMesh(i,l,t,0,s.lods.length,s)}}}function Ue(n,e,t,r){be(e),Se(t),Te(t,{progressive:!0,...r==null?void 0:r.hints}),t.register(s=>new S(s,n));const i=R.get(e);return(r==null?void 0:r.enableLODsManager)!==!1&&i.enable(),i}Ae();if(!rt){const n={gltfProgressive:{useNeedleProgressive:Ue,LODsManager:R,configureLoader:Te,getRaycastMesh:re,useRaycastMeshes:Ve}};if(!globalThis.Needle)globalThis.Needle=n;else for(const e in n)globalThis.Needle[e]=n[e]}exports.EXTENSION_NAME=W;exports.LODsManager=R;exports.NEEDLE_progressive=S;exports.VERSION=ke;exports.addDracoAndKTX2Loaders=Se;exports.configureLoader=Te;exports.createLoaders=be;exports.getRaycastMesh=re;exports.patchModelViewer=Ae;exports.registerRaycastMesh=Fe;exports.setDracoDecoderLocation=Ge;exports.setKTX2TranscoderLocation=Ie;exports.useNeedleProgressive=Ue;exports.useRaycastMeshes=Ve;
package/lib/extension.js CHANGED
@@ -799,6 +799,9 @@ export class NEEDLE_progressive {
799
799
  }
800
800
  // private static readonly _copiedTextures: WeakMap<Texture, Texture> = new Map();
801
801
  static copySettings(source, target) {
802
+ if (!target) {
803
+ return source;
804
+ }
802
805
  // const existingCopy = source["LODS:COPY"];
803
806
  // don't copy again if the texture was processed before
804
807
  // we clone the source if it's animated
package/lib/loaders.d.ts CHANGED
@@ -3,12 +3,12 @@ import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
3
3
  import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
4
4
  import { KTX2Loader } from 'three/examples/jsm/loaders/KTX2Loader.js';
5
5
  /**
6
- * Set the location of the Draco decoder.
7
- * @default 'https://www.gstatic.com/draco/versioned/decoders/1.4.1/'
6
+ * Set the location of the Draco decoder. If a draco loader has already been created, it will be updated.
7
+ * @default 'https://www.gstatic.com/draco/versioned/decoders/1.5.7/'
8
8
  */
9
9
  export declare function setDracoDecoderLocation(location: string): void;
10
10
  /**
11
- * Set the location of the KTX2 transcoder.
11
+ * Set the location of the KTX2 transcoder. If a KTX2 loader has already been created, it will be updated.
12
12
  * @default 'https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/'
13
13
  */
14
14
  export declare function setKTX2TranscoderLocation(location: string): void;
package/lib/loaders.js CHANGED
@@ -25,30 +25,52 @@ fetch(_remoteDracoDecoderUrl, {
25
25
  }
26
26
  })
27
27
  .catch(_ => {
28
+ console.debug(`Failed to fetch remote Draco decoder from ${DEFAULT_DRACO_DECODER_LOCATION} (offline: ${(typeof navigator !== "undefined") ? navigator.onLine : "unknown"})`);
28
29
  // check if the default values have been changed by the user.
29
30
  // If they didnt change / the default paths are not reachable, fall back to local versions
30
- if (DEFAULT_DRACO_DECODER_LOCATION === defaultDraco)
31
- DEFAULT_DRACO_DECODER_LOCATION = "./include/draco/";
32
- if (DEFAULT_KTX2_TRANSCODER_LOCATION === defaultKTX2)
33
- DEFAULT_KTX2_TRANSCODER_LOCATION = "./include/ktx2/";
31
+ if (DEFAULT_DRACO_DECODER_LOCATION === defaultDraco) {
32
+ setDracoDecoderLocation("./include/draco/");
33
+ }
34
+ if (DEFAULT_KTX2_TRANSCODER_LOCATION === defaultKTX2) {
35
+ setKTX2TranscoderLocation("./include/ktx2/");
36
+ }
34
37
  })
35
38
  .finally(() => {
36
39
  prepareLoaders();
37
40
  });
38
41
  /**
39
- * Set the location of the Draco decoder.
40
- * @default 'https://www.gstatic.com/draco/versioned/decoders/1.4.1/'
42
+ * Set the location of the Draco decoder. If a draco loader has already been created, it will be updated.
43
+ * @default 'https://www.gstatic.com/draco/versioned/decoders/1.5.7/'
41
44
  */
42
45
  export function setDracoDecoderLocation(location) {
43
46
  DEFAULT_DRACO_DECODER_LOCATION = location;
47
+ if (dracoLoader && dracoLoader[$dracoDecoderPath] != DEFAULT_DRACO_DECODER_LOCATION) {
48
+ console.debug("Updating Draco decoder path to " + location);
49
+ dracoLoader[$dracoDecoderPath] = DEFAULT_DRACO_DECODER_LOCATION;
50
+ dracoLoader.setDecoderPath(DEFAULT_DRACO_DECODER_LOCATION);
51
+ dracoLoader.preload();
52
+ }
53
+ else {
54
+ console.debug("Setting Draco decoder path to " + location);
55
+ }
44
56
  }
45
57
  /**
46
- * Set the location of the KTX2 transcoder.
58
+ * Set the location of the KTX2 transcoder. If a KTX2 loader has already been created, it will be updated.
47
59
  * @default 'https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/'
48
60
  */
49
61
  export function setKTX2TranscoderLocation(location) {
50
62
  DEFAULT_KTX2_TRANSCODER_LOCATION = location;
63
+ // if set from <needle-engine>
64
+ if (ktx2Loader && ktx2Loader.transcoderPath != DEFAULT_KTX2_TRANSCODER_LOCATION) {
65
+ console.debug("Updating KTX2 transcoder path to " + location);
66
+ ktx2Loader.setTranscoderPath(DEFAULT_KTX2_TRANSCODER_LOCATION);
67
+ ktx2Loader.init();
68
+ }
69
+ else {
70
+ console.debug("Setting KTX2 transcoder path to " + location);
71
+ }
51
72
  }
73
+ const $dracoDecoderPath = Symbol("dracoDecoderPath");
52
74
  let dracoLoader;
53
75
  let meshoptDecoder;
54
76
  let ktx2Loader;
@@ -56,6 +78,7 @@ let ktx2Loader;
56
78
  function prepareLoaders() {
57
79
  if (!dracoLoader) {
58
80
  dracoLoader = new DRACOLoader();
81
+ dracoLoader[$dracoDecoderPath] = DEFAULT_DRACO_DECODER_LOCATION;
59
82
  dracoLoader.setDecoderPath(DEFAULT_DRACO_DECODER_LOCATION);
60
83
  dracoLoader.setDecoderConfig({ type: 'js' });
61
84
  dracoLoader.preload();
package/lib/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  // replaced at build time
2
- export const version = "2.1.0";
2
+ export const version = "2.1.1";
3
3
  globalThis["GLTF_PROGRESSIVE_VERSION"] = version;
4
- console.debug(`[gltf-progressive] version ${version}`);
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",
3
+ "version": "2.1.1",
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": {