@needle-tools/gltf-progressive 1.2.2-alpha.4 → 1.2.3-alpha

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 be=Object.defineProperty,Se=(t,e,r)=>e in t?be(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,c=(t,e,r)=>(Se(t,typeof e!="symbol"?e+"":e,r),r);import{BufferGeometry as J,Mesh as F,Material as Te,Texture as z,TextureLoader as Ee,Matrix4 as pe,Frustum as Ae,Sphere as Ie,Box3 as xe,Vector3 as C}from"three";import{GLTFLoader as Pe}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as Be}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as Re}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as Ce}from"three/examples/jsm/loaders/KTX2Loader.js";const ne="";globalThis.GLTF_PROGRESSIVE_VERSION=ne,console.debug(`[gltf-progressive] version ${ne}`);let Q="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",ie="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(Q+"draco_decoder.js",{method:"head"}).catch(t=>{Q="./include/draco/",ie="./include/ktx2/"});function ke(t){Q=t}function je(t){ie=t}let U,le,V;function ae(t){U||(U=new Re,U.setDecoderPath(Q),U.setDecoderConfig({type:"js"})),V||(V=new Ce,V.setTranscoderPath(ie)),le||(le=Be),t?V.detectSupport(t):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function ue(t){t.dracoLoader||t.setDRACOLoader(U),t.ktx2Loader||t.setKTX2Loader(V),t.meshoptDecoder||t.setMeshoptDecoder(le)}q("debugprogressive");function q(t){const e=new URL(window.location.href).searchParams.get(t);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function Ge(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 Z;function Ne(){return Z!==void 0||(Z=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),q("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",Z)),Z}const ce=Symbol("needle:raycast-mesh");function ee(t){return t?.[ce]instanceof J?t[ce]:null}function ye(t,e){if((t.type==="Mesh"||t.type==="SkinnedMesh")&&!ee(t)){const r=Fe(e);r.userData={isRaycastMesh:!0},t[ce]=r}}function $e(t=!0){if(t){if(K)return;const e=K=F.prototype.raycast;F.prototype.raycast=function(r,n){const s=this,o=ee(s);let i;o&&s.isMesh&&(i=s.geometry,s.geometry=o),e.call(this,r,n),i&&(s.geometry=i)}}else{if(!K)return;F.prototype.raycast=K,K=null}}let K=null;function Fe(t){const e=new J;for(const r in t.attributes)e.setAttribute(r,t.getAttribute(r));return e.setIndex(t.getIndex()),e}const j=new Array,B="NEEDLE_progressive",y=q("debugprogressive"),de=Symbol("needle-progressive-texture"),X=new Map,he=new Set;if(y){let t=function(){e+=1,console.log("Toggle LOD level",e,X),X.forEach((s,o)=>{for(const i of s.keys){const l=o[i];if(l!=null){if(l.isBufferGeometry===!0){const u=_.getMeshLODInformation(l),a=u?Math.min(e,u.lods.length):0;o["DEBUG:LOD"]=e,_.assignMeshLOD(o,a),u&&(r=Math.max(r,u.lods.length-1))}else if(o.isMaterial===!0){o["DEBUG:LOD"]=e,_.assignTextureLOD(o,e);break}}}}),e>=r&&(e=-1)},e=-1,r=2,n=!1;window.addEventListener("keyup",s=>{s.key==="p"&&t(),s.key==="w"&&(n=!n,he&&he.forEach(o=>{o.name!="BackgroundCubeMaterial"&&o.glyphMap==null&&"wireframe"in o&&(o.wireframe=n)}))})}function ve(t,e,r){var n;if(!y)return;X.has(t)||X.set(t,{keys:[],sourceId:r});const s=X.get(t);((n=s?.keys)==null?void 0:n.includes(e))==!1&&s.keys.push(e)}const M=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[B];return o?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",r).then(i=>{var l;return this._isLoadingMesh=!1,i&&M.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 B}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 p=0;p<a.lods.length;p++){const h=a.lods[p];h.width&&(l.lods[p]=l.lods[p]||{min_height:1/0,max_height:0},l.lods[p].min_height=Math.min(l.lods[p].min_height,h.height),l.lods[p].max_height=Math.max(l.lods[p].max_height,h.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 F||t.isMesh===!0){const n=t.geometry,s=this.getAssignedLODInformation(n);if(!s)return Promise.resolve(null);for(const o of j)(r=o.onBeforeGetLODMesh)==null||r.call(o,t,e);return t["LOD:requested level"]=e,M.getOrLoadLOD(n,e).then(o=>{if(t["LOD:requested level"]===e){if(delete t["LOD:requested level"],Array.isArray(o)){const i=s.index||0;o=o[i]}o&&n!=o&&(o?.isBufferGeometry?(t.geometry=o,y&&ve(t,"geometry",s.url)):y&&console.error("Invalid LOD geometry",o))}return 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 instanceof Te||t.isMaterial===!0){const r=t,n=[],s=new Array;if(y&&he.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);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 z||t.isTexture===!0){const r=t;return this.assignTextureLODForSlot(r,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,r,n){return t?.isTexture!==!0?Promise.resolve(null):n==="glyphMap"?Promise.resolve(t):M.getOrLoadLOD(t,e).then(s=>{if(Array.isArray(s))return null;if(s?.isTexture===!0){if(s!=t){if(r&&n){const o=r[n];if(o){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&&ve(r,n,o.url)}}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[B];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())u.isTexture===!0&&this.parser.associations.get(u).textures===s&&(l=!0,M.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&&M.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[B];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&&M.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 p=t;p.source&&p.source[de]&&(a=p.source[de])}if(a||(a=M.lodInfos.get(u)),a){if(e>0){let g=!1;const S=Array.isArray(a.lods);if(S&&e>=a.lods.length?g=!0:S||(g=!0),g)return this.lowresCache.get(u)}const p=Array.isArray(a.lods)?(r=a.lods[e])==null?void 0:r.path:a.lods;if(!p)return y&&!a["missing:uri"]&&(a["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,a)),null;const h=Ge(l.url,p);if(h.endsWith(".glb")||h.endsWith(".gltf")){if(!a.guid)return console.warn("missing pointer for glb/gltf texture",a),null;const g=h+"_"+a.guid,S=this.previouslyLoaded.get(g);if(S!==void 0){i&&console.log(`LOD ${e} was already loading/loaded: ${g}`);let f=await S.catch(b=>(console.error(`Error loading LOD ${e} from ${h}
2
- `,b),null)),x=!1;if(f==null||(f instanceof z&&t instanceof z?(n=f.image)!=null&&n.data||(s=f.source)!=null&&s.data?f=this.copySettings(t,f):(x=!0,this.previouslyLoaded.delete(g)):f instanceof J&&t instanceof J&&((o=f.attributes.position)!=null&&o.array||(x=!0,this.previouslyLoaded.delete(g)))),!x)return f}const D=a,T=new Promise(async(f,x)=>{const b=new Pe;ue(b),y&&(await new Promise(m=>setTimeout(m,1e3)),i&&console.warn("Start loading (delayed) "+h,D.guid));let E=h;if(D&&Array.isArray(D.lods)){const m=D.lods[e];m.hash&&(E+="?v="+m.hash)}const L=await b.loadAsync(E).catch(m=>(console.error(`Error loading LOD ${e} from ${h}
3
- `,m),null));if(!L)return null;const $=L.parser;i&&console.log("Loading finished "+h,D.guid);let I=0;if(L.parser.json.textures){let m=!1;for(const d of L.parser.json.textures){if(d!=null&&d.extensions){const v=d?.extensions[B];if(v!=null&&v.guid&&v.guid===D.guid){m=!0;break}}I++}if(m){let d=await $.getDependency("texture",I);return d&&M.assignLODInformation(l.url,d,u,e,void 0,void 0),i&&console.log('change "'+t.name+'" \u2192 "'+d.name+'"',h,I,d,g),t instanceof z&&(d=this.copySettings(t,d)),d&&(d.guid=D.guid),f(d)}else y&&console.warn("Could not find texture with guid",D.guid,L.parser.json)}if(I=0,L.parser.json.meshes){let m=!1;for(const d of L.parser.json.meshes){if(d!=null&&d.extensions){const v=d?.extensions[B];if(v!=null&&v.guid&&v.guid===D.guid){m=!0;break}}I++}if(m){const d=await $.getDependency("mesh",I),v=D;if(i&&console.log(`Loaded Mesh "${d.name}"`,h,I,d,g),d.isMesh===!0){const w=d.geometry;return M.assignLODInformation(l.url,w,u,e,void 0,v.density),f(w)}else{const w=new Array;for(let O=0;O<d.children.length;O++){const k=d.children[O];if(k.isMesh===!0){const G=k.geometry;M.assignLODInformation(l.url,G,u,e,O,v.density),w.push(G)}}return f(w)}}else y&&console.warn("Could not find mesh with guid",D.guid,L.parser.json)}return f(null)});return this.previouslyLoaded.set(g,T),await T}else if(t instanceof z){i&&console.log("Load texture from uri: "+h);const g=await new Ee().loadAsync(h);return g?(g.guid=a.guid,g.flipY=!1,g.needsUpdate=!0,g.colorSpace=t.colorSpace,i&&console.log(a,g)):y&&console.warn("failed loading",h),g}}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 We(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=e.clone(),y&&console.warn(`Copying texture settings
1
+ var Re=Object.defineProperty,Ge=(t,e,s)=>e in t?Re(t,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):t[e]=s,d=(t,e,s)=>(Ge(t,typeof e!="symbol"?e+"":e,s),s),Oe=(t,e,s)=>{if(!e.has(t))throw TypeError("Cannot "+s)},y=(t,e,s)=>(Oe(t,e,"read from private field"),s?s.call(t):e.get(t)),V=(t,e,s)=>{if(e.has(t))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(t):e.set(t,s)},G=(t,e,s,o)=>(Oe(t,e,"write to private field"),o?o.call(t,s):e.set(t,s),s);import{BufferGeometry as oe,Mesh as K,Material as Fe,Texture as Y,TextureLoader as We,Matrix4 as Se,Frustum as Ne,Clock as $e,MeshStandardMaterial as ze,Sphere as Ue,Box3 as Te,Vector3 as F}from"three";import{GLTFLoader as Ve}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as qe}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as Ke}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as Xe}from"three/examples/jsm/loaders/KTX2Loader.js";const ge="";globalThis.GLTF_PROGRESSIVE_VERSION=ge,console.debug(`[gltf-progressive] version ${ge}`);let ie="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",me="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(ie+"draco_decoder.js",{method:"head"}).catch(t=>{ie="./include/draco/",me="./include/ktx2/"});function He(t){ie=t}function Ye(t){me=t}let J,pe,Q;function xe(t){J||(J=new Ke,J.setDecoderPath(ie),J.setDecoderConfig({type:"js"})),Q||(Q=new Xe,Q.setTranscoderPath(me)),pe||(pe=qe),t?Q.detectSupport(t):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function ye(t){t.dracoLoader||t.setDRACOLoader(J),t.ktx2Loader||t.setKTX2Loader(Q),t.meshoptDecoder||t.setMeshoptDecoder(pe)}Z("debugprogressive");function Z(t){const e=new URL(window.location.href).searchParams.get(t);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function Je(t,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||t===void 0)return e;const s=t.lastIndexOf("/");if(s>=0){const o=t.substring(0,s+1);for(;o.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return o+e}return e}let le;function Qe(){return le!==void 0||(le=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),Z("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",le)),le}const ve=Symbol("needle:raycast-mesh");function ae(t){return t?.[ve]instanceof oe?t[ve]:null}function Ee(t,e){if((t.type==="Mesh"||t.type==="SkinnedMesh")&&!ae(t)){const s=et(e);s.userData={isRaycastMesh:!0},t[ve]=s}}function Ze(t=!0){if(t){if(ee)return;const e=ee=K.prototype.raycast;K.prototype.raycast=function(s,o){const r=this,n=ae(r);let i;n&&r.isMesh&&(i=r.geometry,r.geometry=n),e.call(this,s,o),i&&(r.geometry=i)}}else{if(!ee)return;K.prototype.raycast=ee,ee=null}}let ee=null;function et(t){const e=new oe;for(const s in t.attributes)e.setAttribute(s,t.getAttribute(s));return e.setIndex(t.getIndex()),e}const N=new Array,j="NEEDLE_progressive",v=Z("debugprogressive"),Le=Symbol("needle-progressive-texture"),te=new Map,Me=new Set;if(v){let t=function(){e+=1,console.log("Toggle LOD level",e,te),te.forEach((r,n)=>{for(const i of r.keys){const l=n[i];if(l!=null){if(l.isBufferGeometry===!0){const u=b.getMeshLODInformation(l),a=u?Math.min(e,u.lods.length):0;n["DEBUG:LOD"]=e,b.assignMeshLOD(n,a),u&&(s=Math.max(s,u.lods.length-1))}else if(n.isMaterial===!0){n["DEBUG:LOD"]=e,b.assignTextureLOD(n,e);break}}}}),e>=s&&(e=-1)},e=-1,s=2,o=!1;window.addEventListener("keyup",r=>{r.key==="p"&&t(),r.key==="w"&&(o=!o,Me&&Me.forEach(n=>{n.name!="BackgroundCubeMaterial"&&n.glyphMap==null&&"wireframe"in n&&(n.wireframe=o)}))})}function Ae(t,e,s){var o;if(!v)return;te.has(t)||te.set(t,{keys:[],sourceId:s});const r=te.get(t);((o=r?.keys)==null?void 0:o.includes(e))==!1&&r.keys.push(e)}const w=class{constructor(t,e){d(this,"parser"),d(this,"url"),d(this,"_isLoadingMesh"),d(this,"loadMesh",s=>{var o,r;if(this._isLoadingMesh)return null;const n=(r=(o=this.parser.json.meshes[s])==null?void 0:o.extensions)==null?void 0:r[j];return n?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",s).then(i=>{var l;return this._isLoadingMesh=!1,i&&w.registerMesh(this.url,n.guid,i,(l=n.lods)==null?void 0:l.length,void 0,n),i})):null}),v&&console.log("Progressive extension registered for",e),this.parser=t,this.url=e}get name(){return j}static getMeshLODInformation(t){const e=this.getAssignedLODInformation(t);return e!=null&&e.key?this.lodInfos.get(e.key):null}static getMaterialMinMaxLODsCount(t,e){const s=this,o="LODS:minmax",r=t[o];if(r!=null)return r;if(e||(e={min_count:1/0,max_count:0,lods:[]}),Array.isArray(t)){for(const i of t)this.getMaterialMinMaxLODsCount(i,e);return t[o]=e,e}if(v==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const i=t;for(const l of Object.keys(i.uniforms)){const u=i.uniforms[l].value;u?.isTexture===!0&&n(u,e)}}else if(t.isMaterial)for(const i of Object.keys(t)){const l=t[i];l?.isTexture===!0&&n(l,e)}return t[o]=e,e;function n(i,l){const u=s.getAssignedLODInformation(i);if(u){const a=s.lodInfos.get(u.key);if(a&&a.lods){l.min_count=Math.min(l.min_count,a.lods.length),l.max_count=Math.max(l.max_count,a.lods.length);for(let p=0;p<a.lods.length;p++){const c=a.lods[p];c.width&&(l.lods[p]=l.lods[p]||{min_height:1/0,max_height:0},l.lods[p].min_height=Math.min(l.lods[p].min_height,c.height),l.lods[p].max_height=Math.max(l.lods[p].max_height,c.height))}}}}}static hasLODLevelAvailable(t,e){var s;if(Array.isArray(t)){for(const n of t)if(this.hasLODLevelAvailable(n,e))return!0;return!1}if(t.isMaterial===!0){for(const n of Object.keys(t)){const i=t[n];if(i&&i.isTexture&&this.hasLODLevelAvailable(i,e))return!0}return!1}else if(t.isGroup===!0){for(const n of t.children)if(n.isMesh===!0&&this.hasLODLevelAvailable(n,e))return!0}let o,r;if(t.isMesh?o=t.geometry:(t.isBufferGeometry||t.isTexture)&&(o=t),o&&(s=o?.userData)!=null&&s.LODS){const n=o.userData.LODS;if(r=this.lodInfos.get(n.key),e===void 0)return r!=null;if(r)return Array.isArray(r.lods)?e<r.lods.length:e===0}return!1}static assignMeshLOD(t,e){var s;if(!t)return Promise.resolve(null);if(t instanceof K||t.isMesh===!0){const o=t.geometry,r=this.getAssignedLODInformation(o);if(!r)return Promise.resolve(null);for(const n of N)(s=n.onBeforeGetLODMesh)==null||s.call(n,t,e);return t["LOD:requested level"]=e,w.getOrLoadLOD(o,e).then(n=>{if(t["LOD:requested level"]===e){if(delete t["LOD:requested level"],Array.isArray(n)){const i=r.index||0;n=n[i]}n&&o!=n&&(n?.isBufferGeometry?(t.geometry=n,v&&Ae(t,"geometry",r.url)):v&&console.error("Invalid LOD geometry",n))}return n}).catch(n=>(console.error("Error loading mesh LOD",t,n),null))}else v&&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 instanceof Fe||t.isMaterial===!0){const s=t,o=[],r=new Array;if(v&&Me.add(s),s.uniforms&&s.isRawShaderMaterial||s.isShaderMaterial===!0){const n=s;for(const i of Object.keys(n.uniforms)){const l=n.uniforms[i].value;if(l?.isTexture===!0){const u=this.assignTextureLODForSlot(l,e,s,i);o.push(u),r.push(i)}}}else for(const n of Object.keys(s)){const i=s[n];if(i?.isTexture===!0){const l=this.assignTextureLODForSlot(i,e,s,n);o.push(l),r.push(n)}}return Promise.all(o).then(n=>{const i=new Array;for(let l=0;l<n.length;l++){const u=n[l],a=r[l];u&&u.isTexture===!0?i.push({material:s,slot:a,texture:u,level:e}):i.push({material:s,slot:a,texture:null,level:e})}return i})}if(t instanceof Y||t.isTexture===!0){const s=t;return this.assignTextureLODForSlot(s,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,s,o){return t?.isTexture!==!0?Promise.resolve(null):o==="glyphMap"?Promise.resolve(t):w.getOrLoadLOD(t,e).then(r=>{if(Array.isArray(r))return null;if(r?.isTexture===!0){if(r!=t){if(s&&o){const n=s[o];if(n){const i=this.getAssignedLODInformation(n);if(i&&i?.level<e)return v==="verbose"&&console.warn("Assigned texture level is already higher: ",i.level,e,s,n,r),null}s[o]=r}if(v&&o&&s){const n=this.getAssignedLODInformation(t);n&&Ae(s,o,n.url)}}return r}else v=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(r=>(console.error("Error loading LOD",t,r),null))}afterRoot(t){var e,s;return v&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((o,r)=>{var n;if(o!=null&&o.extensions){const i=o?.extensions[j];if(i){if(!i.lods){v&&console.warn("Texture has no LODs",i);return}let l=!1;for(const u of this.parser.associations.keys())u.isTexture===!0&&this.parser.associations.get(u).textures===r&&(l=!0,w.registerTexture(this.url,u,(n=i.lods)==null?void 0:n.length,r,i));l||this.parser.getDependency("texture",r).then(u=>{var a;u&&w.registerTexture(this.url,u,(a=i.lods)==null?void 0:a.length,r,i)})}}}),(s=this.parser.json.meshes)==null||s.forEach((o,r)=>{if(o!=null&&o.extensions){const n=o?.extensions[j];if(n&&n.lods){for(const i of this.parser.associations.keys())if(i.isMesh){const l=this.parser.associations.get(i);l.meshes===r&&w.registerMesh(this.url,n.guid,i,n.lods.length,l.primitives,n)}}}}),null}static async getOrLoadLOD(t,e){var s,o,r,n;const i=v=="verbose",l=t.userData.LODS;if(!l)return null;const u=l?.key;let a;if(t.isTexture===!0){const p=t;p.source&&p.source[Le]&&(a=p.source[Le])}if(a||(a=w.lodInfos.get(u)),a){if(e>0){let f=!1;const S=Array.isArray(a.lods);if(S&&e>=a.lods.length?f=!0:S||(f=!0),f)return this.lowresCache.get(u)}const p=Array.isArray(a.lods)?(s=a.lods[e])==null?void 0:s.path:a.lods;if(!p)return v&&!a["missing:uri"]&&(a["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,a)),null;const c=Je(l.url,p);if(c.endsWith(".glb")||c.endsWith(".gltf")){if(!a.guid)return console.warn("missing pointer for glb/gltf texture",a),null;const f=c+"_"+a.guid,S=this.previouslyLoaded.get(f);if(S!==void 0){i&&console.log(`LOD ${e} was already loading/loaded: ${f}`);let g=await S.catch(E=>(console.error(`Error loading LOD ${e} from ${c}
2
+ `,E),null)),x=!1;if(g==null||(g instanceof Y&&t instanceof Y?(o=g.image)!=null&&o.data||(r=g.source)!=null&&r.data?g=this.copySettings(t,g):(x=!0,this.previouslyLoaded.delete(f)):g instanceof oe&&t instanceof oe&&((n=g.attributes.position)!=null&&n.array||(x=!0,this.previouslyLoaded.delete(f)))),!x)return g}const M=a,A=new Promise(async(g,x)=>{const E=new Ve;ye(E),v&&(await new Promise(m=>setTimeout(m,1e3)),i&&console.warn("Start loading (delayed) "+c,M.guid));let I=c;if(M&&Array.isArray(M.lods)){const m=M.lods[e];m.hash&&(I+="?v="+m.hash)}const D=await E.loadAsync(I).catch(m=>(console.error(`Error loading LOD ${e} from ${c}
3
+ `,m),null));if(!D)return null;const q=D.parser;i&&console.log("Loading finished "+c,M.guid);let B=0;if(D.parser.json.textures){let m=!1;for(const h of D.parser.json.textures){if(h!=null&&h.extensions){const L=h?.extensions[j];if(L!=null&&L.guid&&L.guid===M.guid){m=!0;break}}B++}if(m){let h=await q.getDependency("texture",B);return h&&w.assignLODInformation(l.url,h,u,e,void 0,void 0),i&&console.log('change "'+t.name+'" \u2192 "'+h.name+'"',c,B,h,f),t instanceof Y&&(h=this.copySettings(t,h)),h&&(h.guid=M.guid),g(h)}else v&&console.warn("Could not find texture with guid",M.guid,D.parser.json)}if(B=0,D.parser.json.meshes){let m=!1;for(const h of D.parser.json.meshes){if(h!=null&&h.extensions){const L=h?.extensions[j];if(L!=null&&L.guid&&L.guid===M.guid){m=!0;break}}B++}if(m){const h=await q.getDependency("mesh",B),L=M;if(i&&console.log(`Loaded Mesh "${h.name}"`,c,B,h,f),h.isMesh===!0){const _=h.geometry;return w.assignLODInformation(l.url,_,u,e,void 0,L.density),g(_)}else{const _=new Array;for(let O=0;O<h.children.length;O++){const W=h.children[O];if(W.isMesh===!0){const U=W.geometry;w.assignLODInformation(l.url,U,u,e,O,L.density),_.push(U)}}return g(_)}}else v&&console.warn("Could not find mesh with guid",M.guid,D.parser.json)}return g(null)});return this.previouslyLoaded.set(f,A),await A}else if(t instanceof Y){i&&console.log("Load texture from uri: "+c);const f=await new We().loadAsync(c);return f?(f.guid=a.guid,f.flipY=!1,f.needsUpdate=!0,f.colorSpace=t.colorSpace,i&&console.log(a,f)):v&&console.warn("failed loading",c),f}}else v&&console.warn(`Can not load LOD ${e}: no LOD info found for "${u}" ${t.name}`,t.type);return null}static assignLODInformation(t,e,s,o,r,n){if(!e)return;e.userData||(e.userData={});const i=new tt(t,s,o,r,n);e.userData.LODS=i}static getAssignedLODInformation(t){var e;return((e=t?.userData)==null?void 0:e.LODS)||null}static copySettings(t,e){return e=e.clone(),v&&console.warn(`Copying texture settings
4
4
  `,t.uuid,`
5
- `,e.uuid),e.offset=t.offset,e.repeat=t.repeat,e.colorSpace=t.colorSpace,e.magFilter=t.magFilter,e.minFilter=t.minFilter,e.wrapS=t.wrapS,e.wrapT=t.wrapT,e.flipY=t.flipY,e.anisotropy=t.anisotropy,e.mipmaps||(e.generateMipmaps=t.generateMipmaps),e}};let _=M;c(_,"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;M.assignLODInformation(t,e,o,r,n,void 0),M.lodInfos.set(o,s),M.lowresCache.set(o,e)}),c(_,"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={}),M.assignLODInformation(t,l,e,n,s,o.density),M.lodInfos.set(e,o);let u=M.lowresCache.get(e);u?u.push(r.geometry):u=[r.geometry],M.lowresCache.set(e,u),n>0&&!ee(r)&&ye(r,l);for(const a of j)(i=a.onRegisteredNewMesh)==null||i.call(a,r,o)}),c(_,"lodInfos",new Map),c(_,"previouslyLoaded",new Map),c(_,"lowresCache",new Map);class We{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 N=q("debugprogressive"),ze=q("noprogressive"),ge=Symbol("Needle:LODSManager"),fe=Symbol("Needle:LODState"),W=Symbol("Needle:CurrentLOD"),P={mesh_lod:-1,texture_lod:-1},A=class{constructor(t,e){c(this,"context"),c(this,"renderer"),c(this,"projectionScreenMatrix",new pe),c(this,"cameraFrustrum",new Ae),c(this,"targetTriangleDensity",2e5),c(this,"updateInterval",0),c(this,"pause",!1),c(this,"_lodchangedlisteners",[]),c(this,"_frame",0),c(this,"_originalRender"),c(this,"_sphere",new Ie),c(this,"_tempBox",new xe),c(this,"_tempBox2",new xe),c(this,"tempMatrix",new pe),c(this,"_tempWorldPosition",new C),c(this,"_tempBoxSize",new C),c(this,"_tempBox2Size",new C),this.renderer=t,this.context={...e}}static getObjectLODState(t){return t[fe]}static addPlugin(t){j.push(t)}static removePlugin(t){const e=j.indexOf(t);e>=0&&j.splice(e,1)}static get(t,e){if(t[ge])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[ge];const r=new A(t,{engine:"unknown",...e});return t[ge]=r,r}get plugins(){return j}addEventListener(t,e){t==="changed"&&this._lodchangedlisteners.push(e)}enable(){if(this._originalRender)return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let t=0;this._originalRender=this.renderer.render;const e=this;ae(this.renderer),this.renderer.render=function(r,n){e.renderer.getRenderTarget()==null&&(t=0,e._frame+=1);const s=e._frame,o=t++;e.onBeforeRender(r,n,o,s),e._originalRender.call(this,r,n),e.onAfterRender(r,n,o,s)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(t,e,r,n){}onAfterRender(t,e,r,n){var s,o;if(this.pause)return;const i=this.renderer.renderLists.get(t,0),l=i.opaque;let u=!0;if(l.length===1){const a=l[0].material;(a.name==="EffectMaterial"||a.name==="CopyShader")&&(u=!1)}if((e.parent&&e.parent.type==="CubeCamera"||r>=1&&e.type==="OrthographicCamera")&&(u=!1),u){if(ze||this.updateInterval>0&&n%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const a=this.targetTriangleDensity;for(const h of l){if(h.material&&(((s=h.geometry)==null?void 0:s.type)==="BoxGeometry"||((o=h.geometry)==null?void 0:o.type)==="BufferGeometry")&&(h.material.name==="SphericalGaussianBlur"||h.material.name=="BackgroundCubeMaterial"||h.material.name==="CubemapFromEquirect"||h.material.name==="EquirectangularToCubeUV")){N&&(h.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(h.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",h,h.material.name,h.material.type)));continue}switch(h.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}const g=h.object;(g instanceof F||g.isMesh)&&this.updateLODs(t,e,g,a,n)}const p=i.transparent;for(const h of p){const g=h.object;(g instanceof F||g.isMesh)&&this.updateLODs(t,e,g,a,n)}}}updateLODs(t,e,r,n,s){var o,i;r.userData||(r.userData={});let l=r[fe];if(l||(l=new Ue,r[fe]=l),l.frames++<2)return;for(const a of j)(o=a.onBeforeUpdateLOD)==null||o.call(a,this.renderer,t,e,r);this.calculateLodLevel(e,r,l,n,P),P.mesh_lod=Math.round(P.mesh_lod),P.texture_lod=Math.round(P.texture_lod),P.mesh_lod>=0&&this.loadProgressiveMeshes(r,P.mesh_lod);let u=P.texture_lod;if(r.material&&u>=0){const a=r["DEBUG:LOD"];a!=null&&(u=a),this.loadProgressiveTextures(r.material,u)}for(const a of j)(i=a.onAfterUpdatedLOD)==null||i.call(a,this.renderer,t,e,r,P);l.lastLodLevel_Mesh=P.mesh_lod,l.lastLodLevel_Texture=P.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const n of t)this.loadProgressiveTextures(n,e);return}let r=!1;(t[W]===void 0||e<t[W])&&(r=!0),r&&(t[W]=e,_.assignTextureLOD(t,e).then(n=>{this._lodchangedlisteners.forEach(s=>s({type:"texture",level:e,object:t}))}))}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);if(t[W]!==e){t[W]=e;const r=t.geometry;return _.assignMeshLOD(t,e).then(n=>(n&&t[W]==e&&r!=t.geometry&&this._lodchangedlisteners.forEach(s=>s({type:"mesh",level:e,object:t})),n))}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,i;if(!e){s.mesh_lod=-1,s.texture_lod=-1;return}if(!t){s.mesh_lod=-1,s.texture_lod=-1;return}let l=10+1,u=!1;if(N&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const a=_.getMeshLODInformation(e.geometry),p=a?.lods,h=p&&p.length>0,g=_.getMaterialMinMaxLODsCount(e.material),S=g?.min_count!=1/0&&g.min_count>0&&g.max_count>0;if(!h&&!S){s.mesh_lod=0,s.texture_lod=0;return}if(h||(u=!0,l=0),!((o=this.cameraFrustrum)!=null&&o.intersectsObject(e))){s.mesh_lod=99,s.texture_lod=99;return}const D=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let T=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const f=e;f.boundingBox||f.computeBoundingBox(),T=f.boundingBox}if(T&&t.isPerspectiveCamera){const f=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(T),this._tempBox.applyMatrix4(e.matrixWorld),A.isInside(this._tempBox,this.projectionScreenMatrix)){s.mesh_lod=0,s.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&f.fov>70){const m=this._tempBox.min,d=this._tempBox.max;let v=m.x,w=m.y,O=d.x,k=d.y;const G=2,se=1.5,H=(m.x+d.x)*.5,Y=(m.y+d.y)*.5;v=(v-H)*G+H,w=(w-Y)*G+Y,O=(O-H)*G+H,k=(k-Y)*G+Y;const _e=v<0&&O>0?0:Math.min(Math.abs(m.x),Math.abs(d.x)),Oe=w<0&&k>0?0:Math.min(Math.abs(m.y),Math.abs(d.y)),oe=Math.max(_e,Oe);r.lastCentrality=(se-oe)*(se-oe)*(se-oe)}else r.lastCentrality=1;const x=this._tempBox.getSize(this._tempBoxSize);x.multiplyScalar(.5),screen.availHeight>0&&D>0&&x.multiplyScalar(D/screen.availHeight),x.x*=f.aspect;const b=t.matrixWorldInverse,E=this._tempBox2;E.copy(T),E.applyMatrix4(e.matrixWorld),E.applyMatrix4(b);const L=E.getSize(this._tempBox2Size),$=Math.max(L.x,L.y);if(Math.max(x.x,x.y)!=0&&$!=0&&(x.z=L.z/Math.max(L.x,L.y)*Math.max(x.x,x.y)),r.lastScreenCoverage=Math.max(x.x,x.y,x.z),r.lastScreenspaceVolume.copy(x),r.lastScreenCoverage*=r.lastCentrality,N&&A.debugDrawLine){const m=this.tempMatrix.copy(this.projectionScreenMatrix);m.invert();const d=A.corner0,v=A.corner1,w=A.corner2,O=A.corner3;d.copy(this._tempBox.min),v.copy(this._tempBox.max),v.x=d.x,w.copy(this._tempBox.max),w.y=d.y,O.copy(this._tempBox.max);const k=(d.z+O.z)*.5;d.z=v.z=w.z=O.z=k,d.applyMatrix4(m),v.applyMatrix4(m),w.applyMatrix4(m),O.applyMatrix4(m),A.debugDrawLine(d,v,255),A.debugDrawLine(d,w,255),A.debugDrawLine(v,O,255),A.debugDrawLine(w,O,255)}let I=999;if(p&&r.lastScreenCoverage>0){for(let m=0;m<p.length;m++)if(p[m].density/r.lastScreenCoverage<n){I=m;break}}I<l&&(l=I,u=!0)}if(u?s.mesh_lod=l:s.mesh_lod=r.lastLodLevel_Mesh,N&&s.mesh_lod!=r.lastLodLevel_Mesh){const f=p?.[s.mesh_lod];f&&console.log(`Mesh LOD changed: ${r.lastLodLevel_Mesh} \u2192 ${s.mesh_lod} (${f.density.toFixed(0)}) - ${e.name}`)}if(S)if(r.lastLodLevel_Texture<0){if(s.texture_lod=g.max_count-1,N){const f=g.lods[g.max_count-1];N&&console.log(`First Texture LOD ${s.texture_lod} (${f.max_height}px) - ${e.name}`)}}else{const f=r.lastScreenspaceVolume.x+r.lastScreenspaceVolume.y+r.lastScreenspaceVolume.z;let x=r.lastScreenCoverage*2;((i=this.context)==null?void 0:i.engine)==="model-viewer"&&(x*=2);const b=D/window.devicePixelRatio*x;for(let E=g.lods.length-1;E>=0;E--){let L=g.lods[E];if(!(Ne()&&L.max_height>4096)&&L.max_height>b){if(s.texture_lod=E,s.texture_lod<r.lastLodLevel_Texture){const $=L.max_height;N&&console.log(`Texture LOD changed: ${r.lastLodLevel_Texture} \u2192 ${s.texture_lod} = ${$}px
6
- Screensize: ${b.toFixed(0)}px, Coverage: ${(100*r.lastScreenCoverage).toFixed(2)}%, Volume ${f.toFixed(1)}
7
- ${e.name}`)}break}}}else s.texture_lod=0}};let R=A;c(R,"debugDrawLine"),c(R,"corner0",new C),c(R,"corner1",new C),c(R,"corner2",new C),c(R,"corner3",new C),c(R,"_tempPtInside",new C);class Ue{constructor(){c(this,"frames",0),c(this,"lastLodLevel_Mesh",-1),c(this,"lastLodLevel_Texture",-1),c(this,"lastScreenCoverage",0),c(this,"lastScreenspaceVolume",new C),c(this,"lastCentrality",0)}}const Le=Symbol("NEEDLE_mesh_lod"),te=Symbol("NEEDLE_texture_lod");let re=null;function me(){const t=Ve();t&&(t.mapURLs(function(e){return Me(),e}),Me(),re?.disconnect(),re=new MutationObserver(e=>{e.forEach(r=>{r.addedNodes.forEach(n=>{n instanceof HTMLElement&&n.tagName.toLowerCase()==="model-viewer"&&we(n)})})}),re.observe(document,{childList:!0,subtree:!0}))}function Ve(){return customElements.get("model-viewer")||(customElements.whenDefined("model-viewer").then(()=>{console.debug("[gltf-progressive] model-viewer defined"),me()}),null)}function Me(){document.querySelectorAll("model-viewer").forEach(t=>{we(t)})}const De=new WeakSet;let qe=0;function we(t){if(!t||De.has(t))return null;De.add(t),console.debug("[gltf-progressive] found new model-viewer..."+ ++qe+`
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 Ke),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 Ke{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[te]==!0)return;r[te]=!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,p,h;if(u[te]==!0)return;u[te]=!0,u.userData&&(u.userData.LOD=-1);const g=Object.keys(u);for(let S=0;S<g.length;S++){const D=g[S],T=u[D];if(T?.isTexture===!0){const f=(p=(a=T.userData)==null?void 0:a.associations)==null?void 0:p.textures;if(f==null)continue;const x=n.parser.json.textures[f];if(!x){console.warn("Texture data not found for texture index "+f);continue}if((h=x?.extensions)!=null&&h[B]){const b=x.extensions[B];b&&o&&_.registerTexture(o,T,b.lods.length,f,b)}}}};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[Le]==!0)return;r[Le]=!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[B];if(l&&i){const u=r.uuid;_.registerMesh(i,u,r,0,l.lods.length,l)}}}function Xe(t,e,r,n){ae(e),ue(r),r.register(o=>new _(o,t));const s=R.get(e);return n?.enableLODsManager!==!1&&s.enable(),s}me();export{B as EXTENSION_NAME,R as LODsManager,_ as NEEDLE_progressive,ne as VERSION,ue as addDracoAndKTX2Loaders,ae as createLoaders,ee as getRaycastMesh,me as patchModelViewer,ke as setDracoDecoderLocation,je as setKTX2TranscoderLocation,ye as setRaycastMesh,Xe as useNeedleProgressive,$e as useRaycastMeshes};
5
+ `,e.uuid),e.offset=t.offset,e.repeat=t.repeat,e.colorSpace=t.colorSpace,e.magFilter=t.magFilter,e.minFilter=t.minFilter,e.wrapS=t.wrapS,e.wrapT=t.wrapT,e.flipY=t.flipY,e.anisotropy=t.anisotropy,e.mipmaps||(e.generateMipmaps=t.generateMipmaps),e}};let b=w;d(b,"registerTexture",(t,e,s,o,r)=>{if(v&&console.log("> Progressive: register texture",o,e.name,e.uuid,e,r),!e){v&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[Le]=r);const n=r.guid;w.assignLODInformation(t,e,n,s,o,void 0),w.lodInfos.set(n,r),w.lowresCache.set(n,e)}),d(b,"registerMesh",(t,e,s,o,r,n)=>{var i;v&&console.log("> Progressive: register mesh",r,s.name,n,s.uuid,s);const l=s.geometry;if(!l){v&&console.warn("gltf-progressive: Register mesh without geometry");return}l.userData||(l.userData={}),w.assignLODInformation(t,l,e,o,r,n.density),w.lodInfos.set(e,n);let u=w.lowresCache.get(e);u?u.push(s.geometry):u=[s.geometry],w.lowresCache.set(e,u),o>0&&!ae(s)&&Ee(s,l);for(const a of N)(i=a.onRegisteredNewMesh)==null||i.call(a,s,n)}),d(b,"lodInfos",new Map),d(b,"previouslyLoaded",new Map),d(b,"lowresCache",new Map);class tt{constructor(e,s,o,r,n){d(this,"url"),d(this,"key"),d(this,"level"),d(this,"index"),d(this,"density"),this.url=e,this.key=s,this.level=o,r!=null&&(this.index=r),n!=null&&(this.density=n)}}const C=Z("debugprogressive"),st=Z("noprogressive"),De=Symbol("Needle:LODSManager"),we=Symbol("Needle:LODState"),X=Symbol("Needle:CurrentLOD"),k={mesh_lod:-1,texture_lod:-1};var T,$,_e,H,se,ue,z;const P=class{constructor(t,e){d(this,"context"),d(this,"renderer"),d(this,"projectionScreenMatrix",new Se),d(this,"cameraFrustrum",new Ne),d(this,"targetTriangleDensity",2e5),d(this,"updateInterval","auto"),V(this,T,1),d(this,"pause",!1),d(this,"_lodchangedlisteners",[]),V(this,$,void 0),V(this,_e,new $e),V(this,H,0),V(this,se,0),V(this,ue,0),V(this,z,0),d(this,"_fpsBuffer",[60,60,60,60,60]),d(this,"_sphere",new Ue),d(this,"_tempBox",new Te),d(this,"_tempBox2",new Te),d(this,"tempMatrix",new Se),d(this,"_tempWorldPosition",new F),d(this,"_tempBoxSize",new F),d(this,"_tempBox2Size",new F),this.renderer=t,this.context={...e}}static getObjectLODState(t){return t[we]}static addPlugin(t){N.push(t)}static removePlugin(t){const e=N.indexOf(t);e>=0&&N.splice(e,1)}static get(t,e){if(t[De])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[De];const s=new P(t,{engine:"unknown",...e});return t[De]=s,s}get plugins(){return N}addEventListener(t,e){t==="changed"&&this._lodchangedlisteners.push(e)}enable(){if(y(this,$))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let t=0;G(this,$,this.renderer.render);const e=this;xe(this.renderer),this.renderer.render=function(s,o){e.renderer.getRenderTarget()==null&&(t=0,G(e,H,y(e,H)+1),G(e,se,y(e,_e).getDelta()),G(e,ue,y(e,ue)+y(e,se)),e._fpsBuffer.shift(),e._fpsBuffer.push(1/y(e,se)),G(e,z,e._fpsBuffer.reduce((i,l)=>i+l)/e._fpsBuffer.length),C&&y(e,H)%30===0&&console.log("FPS",Math.round(y(e,z)),"Interval:",y(e,T)));const r=y(e,H),n=t++;e.onBeforeRender(s,o,n,r),y(e,$).call(this,s,o),e.onAfterRender(s,o,n,r)}}disable(){y(this,$)&&(this.renderer.render=y(this,$),G(this,$,void 0))}onBeforeRender(t,e,s,o){}onAfterRender(t,e,s,o){var r,n;if(this.pause)return;const i=this.renderer.renderLists.get(t,0),l=i.opaque;let u=!0;if(l.length===1){const a=l[0].material;(a.name==="EffectMaterial"||a.name==="CopyShader")&&(u=!1)}if((e.parent&&e.parent.type==="CubeCamera"||s>=1&&e.type==="OrthographicCamera")&&(u=!1),u){if(st||(this.updateInterval==="auto"?y(this,z)<40&&y(this,T)<10?(G(this,T,y(this,T)+1),C&&console.warn("\u2193 Reducing LOD updates",y(this,T),y(this,z).toFixed(0))):y(this,z)>=80&&y(this,T)>1&&(G(this,T,y(this,T)-1),C&&console.warn("\u2191 Increasing LOD updates",y(this,T),y(this,z).toFixed(0))):G(this,T,this.updateInterval),y(this,T)>0&&o%y(this,T)!=0))return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const a=this.targetTriangleDensity;for(const c of l){if(c.material&&(((r=c.geometry)==null?void 0:r.type)==="BoxGeometry"||((n=c.geometry)==null?void 0:n.type)==="BufferGeometry")&&(c.material.name==="SphericalGaussianBlur"||c.material.name=="BackgroundCubeMaterial"||c.material.name==="CubemapFromEquirect"||c.material.name==="EquirectangularToCubeUV")){C&&(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(C==="color"&&c.material&&!c.object.progressive_debug_color){c.object.progressive_debug_color=!0;const S=Math.random()*16777215,M=new ze({color:S});c.object.material=M}const f=c.object;(f instanceof K||f.isMesh)&&this.updateLODs(t,e,f,a,o)}const p=i.transparent;for(const c of p){const f=c.object;(f instanceof K||f.isMesh)&&this.updateLODs(t,e,f,a,o)}}}updateLODs(t,e,s,o,r){var n,i;s.userData||(s.userData={});let l=s[we];if(l||(l=new rt,s[we]=l),l.frames++<2)return;for(const a of N)(n=a.onBeforeUpdateLOD)==null||n.call(a,this.renderer,t,e,s);this.calculateLodLevel(e,s,l,o,k),k.mesh_lod=Math.round(k.mesh_lod),k.texture_lod=Math.round(k.texture_lod),k.mesh_lod>=0&&this.loadProgressiveMeshes(s,k.mesh_lod);let u=k.texture_lod;if(s.material&&u>=0){const a=s["DEBUG:LOD"];a!=null&&(u=a),this.loadProgressiveTextures(s.material,u)}for(const a of N)(i=a.onAfterUpdatedLOD)==null||i.call(a,this.renderer,t,e,s,k);l.lastLodLevel_Mesh=k.mesh_lod,l.lastLodLevel_Texture=k.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const o of t)this.loadProgressiveTextures(o,e);return}let s=!1;(t[X]===void 0||e<t[X])&&(s=!0),s&&(t[X]=e,b.assignTextureLOD(t,e).then(o=>{this._lodchangedlisteners.forEach(r=>r({type:"texture",level:e,object:t}))}))}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);if(t[X]!==e){t[X]=e;const s=t.geometry;return b.assignMeshLOD(t,e).then(o=>(o&&t[X]==e&&s!=t.geometry&&this._lodchangedlisteners.forEach(r=>r({type:"mesh",level:e,object:t})),o))}return Promise.resolve(null)}static isInside(t,e){const s=t.min,o=t.max,r=(s.x+o.x)*.5,n=(s.y+o.y)*.5;return this._tempPtInside.set(r,n,s.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,s,o,r){var n,i;if(!e){r.mesh_lod=-1,r.texture_lod=-1;return}if(!t){r.mesh_lod=-1,r.texture_lod=-1;return}let l=10+1,u=!1;if(C&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const a=b.getMeshLODInformation(e.geometry),p=a?.lods,c=p&&p.length>0,f=b.getMaterialMinMaxLODsCount(e.material),S=f?.min_count!=1/0&&f.min_count>0&&f.max_count>0;if(!c&&!S){r.mesh_lod=0,r.texture_lod=0;return}if(c||(u=!0,l=0),!((n=this.cameraFrustrum)!=null&&n.intersectsObject(e))){r.mesh_lod=99,r.texture_lod=99;return}const M=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let A=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const g=e;g.boundingBox||g.computeBoundingBox(),A=g.boundingBox}if(A&&t.isPerspectiveCamera){const g=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)){r.mesh_lod=0,r.texture_lod=0;return}}if(this._tempBox.copy(A),this._tempBox.applyMatrix4(e.matrixWorld),P.isInside(this._tempBox,this.projectionScreenMatrix)){r.mesh_lod=0,r.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&g.fov>70){const m=this._tempBox.min,h=this._tempBox.max;let L=m.x,_=m.y,O=h.x,W=h.y;const U=2,he=1.5,re=(m.x+h.x)*.5,ne=(m.y+h.y)*.5;L=(L-re)*U+re,_=(_-ne)*U+ne,O=(O-re)*U+re,W=(W-ne)*U+ne;const ke=L<0&&O>0?0:Math.min(Math.abs(m.x),Math.abs(h.x)),je=_<0&&W>0?0:Math.min(Math.abs(m.y),Math.abs(h.y)),fe=Math.max(ke,je);s.lastCentrality=(he-fe)*(he-fe)*(he-fe)}else s.lastCentrality=1;const x=this._tempBox.getSize(this._tempBoxSize);x.multiplyScalar(.5),screen.availHeight>0&&M>0&&x.multiplyScalar(M/screen.availHeight),x.x*=g.aspect;const E=t.matrixWorldInverse,I=this._tempBox2;I.copy(A),I.applyMatrix4(e.matrixWorld),I.applyMatrix4(E);const D=I.getSize(this._tempBox2Size),q=Math.max(D.x,D.y);if(Math.max(x.x,x.y)!=0&&q!=0&&(x.z=D.z/Math.max(D.x,D.y)*Math.max(x.x,x.y)),s.lastScreenCoverage=Math.max(x.x,x.y,x.z),s.lastScreenspaceVolume.copy(x),s.lastScreenCoverage*=s.lastCentrality,C&&P.debugDrawLine){const m=this.tempMatrix.copy(this.projectionScreenMatrix);m.invert();const h=P.corner0,L=P.corner1,_=P.corner2,O=P.corner3;h.copy(this._tempBox.min),L.copy(this._tempBox.max),L.x=h.x,_.copy(this._tempBox.max),_.y=h.y,O.copy(this._tempBox.max);const W=(h.z+O.z)*.5;h.z=L.z=_.z=O.z=W,h.applyMatrix4(m),L.applyMatrix4(m),_.applyMatrix4(m),O.applyMatrix4(m),P.debugDrawLine(h,L,255),P.debugDrawLine(h,_,255),P.debugDrawLine(L,O,255),P.debugDrawLine(_,O,255)}let B=999;if(p&&s.lastScreenCoverage>0){for(let m=0;m<p.length;m++)if(p[m].density/s.lastScreenCoverage<o){B=m;break}}B<l&&(l=B,u=!0)}if(u?r.mesh_lod=l:r.mesh_lod=s.lastLodLevel_Mesh,C&&r.mesh_lod!=s.lastLodLevel_Mesh){const g=p?.[r.mesh_lod];g&&console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} \u2192 ${r.mesh_lod} (${g.density.toFixed(0)}) - ${e.name}`)}if(S)if(s.lastLodLevel_Texture<0){if(r.texture_lod=f.max_count-1,C){const g=f.lods[f.max_count-1];C&&console.log(`First Texture LOD ${r.texture_lod} (${g.max_height}px) - ${e.name}`)}}else{const g=s.lastScreenspaceVolume.x+s.lastScreenspaceVolume.y+s.lastScreenspaceVolume.z;let x=s.lastScreenCoverage*2;((i=this.context)==null?void 0:i.engine)==="model-viewer"&&(x*=2);const E=M/window.devicePixelRatio*x;for(let I=f.lods.length-1;I>=0;I--){let D=f.lods[I];if(!(Qe()&&D.max_height>4096)&&D.max_height>E){if(r.texture_lod=I,r.texture_lod<s.lastLodLevel_Texture){const q=D.max_height;C&&console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} \u2192 ${r.texture_lod} = ${q}px
6
+ Screensize: ${E.toFixed(0)}px, Coverage: ${(100*s.lastScreenCoverage).toFixed(2)}%, Volume ${g.toFixed(1)}
7
+ ${e.name}`)}break}}}else r.texture_lod=0}};let R=P;T=new WeakMap,$=new WeakMap,_e=new WeakMap,H=new WeakMap,se=new WeakMap,ue=new WeakMap,z=new WeakMap,d(R,"debugDrawLine"),d(R,"corner0",new F),d(R,"corner1",new F),d(R,"corner2",new F),d(R,"corner3",new F),d(R,"_tempPtInside",new F);class rt{constructor(){d(this,"frames",0),d(this,"lastLodLevel_Mesh",-1),d(this,"lastLodLevel_Texture",-1),d(this,"lastScreenCoverage",0),d(this,"lastScreenspaceVolume",new F),d(this,"lastCentrality",0)}}const Ie=Symbol("NEEDLE_mesh_lod"),ce=Symbol("NEEDLE_texture_lod");let de=null;function be(){const t=nt();t&&(t.mapURLs(function(e){return Pe(),e}),Pe(),de?.disconnect(),de=new MutationObserver(e=>{e.forEach(s=>{s.addedNodes.forEach(o=>{o instanceof HTMLElement&&o.tagName.toLowerCase()==="model-viewer"&&Ce(o)})})}),de.observe(document,{childList:!0,subtree:!0}))}function nt(){return customElements.get("model-viewer")||(customElements.whenDefined("model-viewer").then(()=>{console.debug("[gltf-progressive] model-viewer defined"),be()}),null)}function Pe(){document.querySelectorAll("model-viewer").forEach(t=>{Ce(t)})}const Be=new WeakSet;let ot=0;function Ce(t){if(!t||Be.has(t))return null;Be.add(t),console.debug("[gltf-progressive] found new model-viewer..."+ ++ot+`
8
+ `,t.getAttribute("src"));let e=null,s=null,o=null;for(let r=t;r!=null;r=Object.getPrototypeOf(r)){const n=Object.getOwnPropertySymbols(r),i=n.find(a=>a.toString()=="Symbol(renderer)"),l=n.find(a=>a.toString()=="Symbol(scene)"),u=n.find(a=>a.toString()=="Symbol(needsRender)");!e&&i!=null&&(e=t[i].threeRenderer),!s&&l!=null&&(s=t[l]),!o&&u!=null&&(o=t[u])}if(e&&s){let r=function(){if(o){let i=0,l=setInterval(()=>{if(i++>5){clearInterval(l);return}o?.call(t)},300)}};console.debug("[gltf-progressive] setup model-viewer");const n=R.get(e,{engine:"model-viewer"});return R.addPlugin(new it),n.enable(),n.addEventListener("changed",()=>{o?.call(t)}),t.addEventListener("model-visibility",i=>{i.detail.visible&&o?.call(t)}),t.addEventListener("load",()=>{r()}),()=>{n.disable()}}return null}class it{constructor(){d(this,"_didWarnAboutMissingUrl",!1)}onBeforeUpdateLOD(e,s,o,r){this.tryParseMeshLOD(s,r),this.tryParseTextureLOD(s,r)}getUrl(e){if(!e)return null;let s=e.getAttribute("src");return s||(s=e.src),s||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",e),this._didWarnAboutMissingUrl=!0),s}tryGetCurrentGLTF(e){return e._currentGLTF}tryGetCurrentModelViewer(e){return e.element}tryParseTextureLOD(e,s){if(s[ce]==!0)return;s[ce]=!0;const o=this.tryGetCurrentGLTF(e),r=this.tryGetCurrentModelViewer(e),n=this.getUrl(r);if(n&&o&&s.material){let i=function(u){var a,p,c;if(u[ce]==!0)return;u[ce]=!0,u.userData&&(u.userData.LOD=-1);const f=Object.keys(u);for(let S=0;S<f.length;S++){const M=f[S],A=u[M];if(A?.isTexture===!0){const g=(p=(a=A.userData)==null?void 0:a.associations)==null?void 0:p.textures;if(g==null)continue;const x=o.parser.json.textures[g];if(!x){console.warn("Texture data not found for texture index "+g);continue}if((c=x?.extensions)!=null&&c[j]){const E=x.extensions[j];E&&n&&b.registerTexture(n,A,E.lods.length,g,E)}}}};const l=s.material;if(Array.isArray(l))for(const u of l)i(u);else i(l)}}tryParseMeshLOD(e,s){var o,r;if(s[Ie]==!0)return;s[Ie]=!0;const n=this.tryGetCurrentModelViewer(e),i=this.getUrl(n);if(!i)return;const l=(r=(o=s.userData)==null?void 0:o.gltfExtensions)==null?void 0:r[j];if(l&&i){const u=s.uuid;b.registerMesh(i,u,s,0,l.lods.length,l)}}}function lt(t,e,s,o){xe(e),ye(s),s.register(n=>new b(n,t));const r=R.get(e);return o?.enableLODsManager!==!1&&r.enable(),r}be();export{j as EXTENSION_NAME,R as LODsManager,b as NEEDLE_progressive,ge as VERSION,ye as addDracoAndKTX2Loaders,xe as createLoaders,ae as getRaycastMesh,be as patchModelViewer,He as setDracoDecoderLocation,Ye as setKTX2TranscoderLocation,Ee as setRaycastMesh,lt as useNeedleProgressive,Ze as useRaycastMeshes};
@@ -1,8 +1,8 @@
1
- "use strict";var Oe=Object.defineProperty;var Se=(a,e,t)=>e in a?Oe(a,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):a[e]=t;var f=(a,e,t)=>(Se(a,typeof e!="symbol"?e+"":e,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const g=require("three"),be=require("three/examples/jsm/loaders/GLTFLoader.js"),Te=require("three/examples/jsm/libs/meshopt_decoder.module.js"),Ae=require("three/examples/jsm/loaders/DRACOLoader.js"),Ee=require("three/examples/jsm/loaders/KTX2Loader.js"),fe="";globalThis.GLTF_PROGRESSIVE_VERSION=fe;console.debug(`[gltf-progressive] version ${fe}`);let re="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",he="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(re+"draco_decoder.js",{method:"head"}).catch(a=>{re="./include/draco/",he="./include/ktx2/"});function Pe(a){re=a}function Ce(a){he=a}let Y,ce,H;function ge(a){Y||(Y=new Ae.DRACOLoader,Y.setDecoderPath(re),Y.setDecoderConfig({type:"js"})),H||(H=new Ee.KTX2Loader,H.setTranscoderPath(he)),ce||(ce=Te.MeshoptDecoder),a?H.detectSupport(a):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function pe(a){a.dracoLoader||a.setDRACOLoader(Y),a.ktx2Loader||a.setKTX2Loader(H),a.meshoptDecoder||a.setMeshoptDecoder(ce)}Q("debugprogressive");function Q(a){const t=new URL(window.location.href).searchParams.get(a);return t==null||t==="0"||t==="false"?!1:t===""?!0:t}function Be(a,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||a===void 0)return e;const t=a.lastIndexOf("/");if(t>=0){const r=a.substring(0,t+1);for(;r.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return r+e}return e}let q;function Re(){return q!==void 0||(q=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),Q("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",q)),q}const ue=Symbol("needle:raycast-mesh");function se(a){return(a==null?void 0:a[ue])instanceof g.BufferGeometry?a[ue]:null}function De(a,e){if((a.type==="Mesh"||a.type==="SkinnedMesh")&&!se(a)){const r=Ie(e);r.userData={isRaycastMesh:!0},a[ue]=r}}function ke(a=!0){if(a){if(K)return;const e=K=g.Mesh.prototype.raycast;g.Mesh.prototype.raycast=function(t,r){const o=this,i=se(o);let s;i&&o.isMesh&&(s=o.geometry,o.geometry=i),e.call(this,t,r),s&&(o.geometry=s)}}else{if(!K)return;g.Mesh.prototype.raycast=K,K=null}}let K=null;function Ie(a){const e=new g.BufferGeometry;for(const t in a.attributes)e.setAttribute(t,a.getAttribute(t));return e.setIndex(a.getIndex()),e}const $=new Array,G="NEEDLE_progressive",x=Q("debugprogressive"),ne=Symbol("needle-progressive-texture"),J=new Map,de=new Set;if(x){let a=function(){e+=1,console.log("Toggle LOD level",e,J),J.forEach((o,i)=>{for(const s of o.keys){const n=i[s];if(n!=null){if(n.isBufferGeometry===!0){const l=S.getMeshLODInformation(n),d=l?Math.min(e,l.lods.length):0;i["DEBUG:LOD"]=e,S.assignMeshLOD(i,d),l&&(t=Math.max(t,l.lods.length-1))}else if(i.isMaterial===!0){i["DEBUG:LOD"]=e,S.assignTextureLOD(i,e);break}}}}),e>=t&&(e=-1)},e=-1,t=2,r=!1;window.addEventListener("keyup",o=>{o.key==="p"&&a(),o.key==="w"&&(r=!r,de&&de.forEach(i=>{i.name!="BackgroundCubeMaterial"&&i.glyphMap==null&&"wireframe"in i&&(i.wireframe=r)}))})}function me(a,e,t){var o;if(!x)return;J.has(a)||J.set(a,{keys:[],sourceId:t});const r=J.get(a);((o=r==null?void 0:r.keys)==null?void 0:o.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,o;if(this._isLoadingMesh)return null;const t=(o=(r=this.parser.json.meshes[e])==null?void 0:r.extensions)==null?void 0:o[G];return t?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",e).then(i=>{var s;return this._isLoadingMesh=!1,i&&O.registerMesh(this.url,t.guid,i,(s=t.lods)==null?void 0:s.length,void 0,t),i})):null});x&&console.log("Progressive extension registered for",t),this.parser=e,this.url=t}get name(){return G}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,o="LODS:minmax",i=e[o];if(i!=null)return i;if(t||(t={min_count:1/0,max_count:0,lods:[]}),Array.isArray(e)){for(const n of e)this.getMaterialMinMaxLODsCount(n,t);return e[o]=t,t}if(x==="verbose"&&console.log("getMaterialMinMaxLODsCount",e),e.type==="ShaderMaterial"||e.type==="RawShaderMaterial"){const n=e;for(const l of Object.keys(n.uniforms)){const d=n.uniforms[l].value;(d==null?void 0:d.isTexture)===!0&&s(d,t)}}else if(e.isMaterial)for(const n of Object.keys(e)){const l=e[n];(l==null?void 0:l.isTexture)===!0&&s(l,t)}return e[o]=t,t;function s(n,l){const d=r.getAssignedLODInformation(n);if(d){const c=r.lodInfos.get(d.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 L=0;L<c.lods.length;L++){const u=c.lods[L];u.width&&(l.lods[L]=l.lods[L]||{min_height:1/0,max_height:0},l.lods[L].min_height=Math.min(l.lods[L].min_height,u.height),l.lods[L].max_height=Math.max(l.lods[L].max_height,u.height))}}}}}static hasLODLevelAvailable(e,t){var i;if(Array.isArray(e)){for(const s of e)if(this.hasLODLevelAvailable(s,t))return!0;return!1}if(e.isMaterial===!0){for(const s of Object.keys(e)){const n=e[s];if(n&&n.isTexture&&this.hasLODLevelAvailable(n,t))return!0}return!1}else if(e.isGroup===!0){for(const s of e.children)if(s.isMesh===!0&&this.hasLODLevelAvailable(s,t))return!0}let r,o;if(e.isMesh?r=e.geometry:(e.isBufferGeometry||e.isTexture)&&(r=e),r&&(i=r==null?void 0:r.userData)!=null&&i.LODS){const s=r.userData.LODS;if(o=this.lodInfos.get(s.key),t===void 0)return o!=null;if(o)return Array.isArray(o.lods)?t<o.lods.length:t===0}return!1}static assignMeshLOD(e,t){var r;if(!e)return Promise.resolve(null);if(e instanceof g.Mesh||e.isMesh===!0){const o=e.geometry,i=this.getAssignedLODInformation(o);if(!i)return Promise.resolve(null);for(const s of $)(r=s.onBeforeGetLODMesh)==null||r.call(s,e,t);return e["LOD:requested level"]=t,O.getOrLoadLOD(o,t).then(s=>{if(e["LOD:requested level"]===t){if(delete e["LOD:requested level"],Array.isArray(s)){const n=i.index||0;s=s[n]}s&&o!=s&&((s==null?void 0:s.isBufferGeometry)?(e.geometry=s,x&&me(e,"geometry",i.url)):x&&console.error("Invalid LOD geometry",s))}return s}).catch(s=>(console.error("Error loading mesh LOD",e,s),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 instanceof g.Material||e.isMaterial===!0){const r=e,o=[],i=new Array;if(x&&de.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const s=r;for(const n of Object.keys(s.uniforms)){const l=s.uniforms[n].value;if((l==null?void 0:l.isTexture)===!0){const d=this.assignTextureLODForSlot(l,t,r,n);o.push(d),i.push(n)}}}else for(const s of Object.keys(r)){const n=r[s];if((n==null?void 0:n.isTexture)===!0){const l=this.assignTextureLODForSlot(n,t,r,s);o.push(l),i.push(s)}}return Promise.all(o).then(s=>{const n=new Array;for(let l=0;l<s.length;l++){const d=s[l],c=i[l];d&&d.isTexture===!0?n.push({material:r,slot:c,texture:d,level:t}):n.push({material:r,slot:c,texture:null,level:t})}return n})}if(e instanceof g.Texture||e.isTexture===!0){const r=e;return this.assignTextureLODForSlot(r,t,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(e,t,r,o){return(e==null?void 0:e.isTexture)!==!0?Promise.resolve(null):o==="glyphMap"?Promise.resolve(e):O.getOrLoadLOD(e,t).then(i=>{if(Array.isArray(i))return null;if((i==null?void 0:i.isTexture)===!0){if(i!=e){if(r&&o){const s=r[o];if(s){const n=this.getAssignedLODInformation(s);if(n&&(n==null?void 0:n.level)<t)return x==="verbose"&&console.warn("Assigned texture level is already higher: ",n.level,t,r,s,i),null}r[o]=i}if(x&&o&&r){const s=this.getAssignedLODInformation(e);s&&me(r,o,s.url)}}return i}else x=="verbose"&&console.warn("No LOD found for",e,t);return null}).catch(i=>(console.error("Error loading LOD",e,i),null))}afterRoot(e){var t,r;return x&&console.log("AFTER",this.url,e),(t=this.parser.json.textures)==null||t.forEach((o,i)=>{var s;if(o!=null&&o.extensions){const n=o==null?void 0:o.extensions[G];if(n){if(!n.lods){x&&console.warn("Texture has no LODs",n);return}let l=!1;for(const d of this.parser.associations.keys())d.isTexture===!0&&this.parser.associations.get(d).textures===i&&(l=!0,O.registerTexture(this.url,d,(s=n.lods)==null?void 0:s.length,i,n));l||this.parser.getDependency("texture",i).then(d=>{var c;d&&O.registerTexture(this.url,d,(c=n.lods)==null?void 0:c.length,i,n)})}}}),(r=this.parser.json.meshes)==null||r.forEach((o,i)=>{if(o!=null&&o.extensions){const s=o==null?void 0:o.extensions[G];if(s&&s.lods){for(const n of this.parser.associations.keys())if(n.isMesh){const l=this.parser.associations.get(n);l.meshes===i&&O.registerMesh(this.url,s.guid,n,s.lods.length,l.primitives,s)}}}}),null}static async getOrLoadLOD(e,t){var n,l,d,c;const r=x=="verbose",o=e.userData.LODS;if(!o)return null;const i=o==null?void 0:o.key;let s;if(e.isTexture===!0){const L=e;L.source&&L.source[ne]&&(s=L.source[ne])}if(s||(s=O.lodInfos.get(i)),s){if(t>0){let m=!1;const _=Array.isArray(s.lods);if(_&&t>=s.lods.length?m=!0:_||(m=!0),m)return this.lowresCache.get(i)}const L=Array.isArray(s.lods)?(n=s.lods[t])==null?void 0:n.path:s.lods;if(!L)return x&&!s["missing:uri"]&&(s["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+t,s)),null;const u=Be(o.url,L);if(u.endsWith(".glb")||u.endsWith(".gltf")){if(!s.guid)return console.warn("missing pointer for glb/gltf texture",s),null;const m=u+"_"+s.guid,_=this.previouslyLoaded.get(m);if(_!==void 0){r&&console.log(`LOD ${t} was already loading/loaded: ${m}`);let y=await _.catch(N=>(console.error(`Error loading LOD ${t} from ${u}
2
- `,N),null)),D=!1;if(y==null||(y instanceof g.Texture&&e instanceof g.Texture?(l=y.image)!=null&&l.data||(d=y.source)!=null&&d.data?y=this.copySettings(e,y):(D=!0,this.previouslyLoaded.delete(m)):y instanceof g.BufferGeometry&&e instanceof g.BufferGeometry&&((c=y.attributes.position)!=null&&c.array||(D=!0,this.previouslyLoaded.delete(m)))),!D)return y}const M=s,R=new Promise(async(y,D)=>{const N=new be.GLTFLoader;pe(N),x&&(await new Promise(b=>setTimeout(b,1e3)),r&&console.warn("Start loading (delayed) "+u,M.guid));let k=u;if(M&&Array.isArray(M.lods)){const b=M.lods[t];b.hash&&(k+="?v="+b.hash)}const v=await N.loadAsync(k).catch(b=>(console.error(`Error loading LOD ${t} from ${u}
3
- `,b),null));if(!v)return null;const V=v.parser;r&&console.log("Loading finished "+u,M.guid);let I=0;if(v.parser.json.textures){let b=!1;for(const p of v.parser.json.textures){if(p!=null&&p.extensions){const h=p==null?void 0:p.extensions[G];if(h!=null&&h.guid&&h.guid===M.guid){b=!0;break}}I++}if(b){let p=await V.getDependency("texture",I);return p&&O.assignLODInformation(o.url,p,i,t,void 0,void 0),r&&console.log('change "'+e.name+'" → "'+p.name+'"',u,I,p,m),e instanceof g.Texture&&(p=this.copySettings(e,p)),p&&(p.guid=M.guid),y(p)}else x&&console.warn("Could not find texture with guid",M.guid,v.parser.json)}if(I=0,v.parser.json.meshes){let b=!1;for(const p of v.parser.json.meshes){if(p!=null&&p.extensions){const h=p==null?void 0:p.extensions[G];if(h!=null&&h.guid&&h.guid===M.guid){b=!0;break}}I++}if(b){const p=await V.getDependency("mesh",I),h=M;if(r&&console.log(`Loaded Mesh "${p.name}"`,u,I,p,m),p.isMesh===!0){const w=p.geometry;return O.assignLODInformation(o.url,w,i,t,void 0,h.density),y(w)}else{const w=new Array;for(let T=0;T<p.children.length;T++){const A=p.children[T];if(A.isMesh===!0){const E=A.geometry;O.assignLODInformation(o.url,E,i,t,T,h.density),w.push(E)}}return y(w)}}else x&&console.warn("Could not find mesh with guid",M.guid,v.parser.json)}return y(null)});return this.previouslyLoaded.set(m,R),await R}else if(e instanceof g.Texture){r&&console.log("Load texture from uri: "+u);const _=await new g.TextureLoader().loadAsync(u);return _?(_.guid=s.guid,_.flipY=!1,_.needsUpdate=!0,_.colorSpace=e.colorSpace,r&&console.log(s,_)):x&&console.warn("failed loading",u),_}}else x&&console.warn(`Can not load LOD ${t}: no LOD info found for "${i}" ${e.name}`,e.type);return null}static assignLODInformation(e,t,r,o,i,s){if(!t)return;t.userData||(t.userData={});const n=new Ge(e,r,o,i,s);t.userData.LODS=n}static getAssignedLODInformation(e){var t;return((t=e==null?void 0:e.userData)==null?void 0:t.LODS)||null}static copySettings(e,t){return t=t.clone(),x&&console.warn(`Copying texture settings
4
- `,e.uuid,`
5
- `,t.uuid),t.offset=e.offset,t.repeat=e.repeat,t.colorSpace=e.colorSpace,t.magFilter=e.magFilter,t.minFilter=e.minFilter,t.wrapS=e.wrapS,t.wrapT=e.wrapT,t.flipY=e.flipY,t.anisotropy=e.anisotropy,t.mipmaps||(t.generateMipmaps=e.generateMipmaps),t}};let S=O;f(S,"registerTexture",(e,t,r,o,i)=>{if(x&&console.log("> Progressive: register texture",o,t.name,t.uuid,t,i),!t){x&&console.error("gltf-progressive: Register texture without texture");return}t.source&&(t.source[ne]=i);const s=i.guid;O.assignLODInformation(e,t,s,r,o,void 0),O.lodInfos.set(s,i),O.lowresCache.set(s,t)}),f(S,"registerMesh",(e,t,r,o,i,s)=>{var d;x&&console.log("> Progressive: register mesh",i,r.name,s,r.uuid,r);const n=r.geometry;if(!n){x&&console.warn("gltf-progressive: Register mesh without geometry");return}n.userData||(n.userData={}),O.assignLODInformation(e,n,t,o,i,s.density),O.lodInfos.set(t,s);let l=O.lowresCache.get(t);l?l.push(r.geometry):l=[r.geometry],O.lowresCache.set(t,l),o>0&&!se(r)&&De(r,n);for(const c of $)(d=c.onRegisteredNewMesh)==null||d.call(c,r,s)}),f(S,"lodInfos",new Map),f(S,"previouslyLoaded",new Map),f(S,"lowresCache",new Map);class Ge{constructor(e,t,r,o,i){f(this,"url");f(this,"key");f(this,"level");f(this,"index");f(this,"density");this.url=e,this.key=t,this.level=r,o!=null&&(this.index=o),i!=null&&(this.density=i)}}const z=Q("debugprogressive"),Fe=Q("noprogressive"),ae=Symbol("Needle:LODSManager"),le=Symbol("Needle:LODState"),U=Symbol("Needle:CurrentLOD"),B={mesh_lod:-1,texture_lod:-1},P=class{constructor(e,t){f(this,"context");f(this,"renderer");f(this,"projectionScreenMatrix",new g.Matrix4);f(this,"cameraFrustrum",new g.Frustum);f(this,"targetTriangleDensity",2e5);f(this,"updateInterval",0);f(this,"pause",!1);f(this,"_lodchangedlisteners",[]);f(this,"_frame",0);f(this,"_originalRender");f(this,"_sphere",new g.Sphere);f(this,"_tempBox",new g.Box3);f(this,"_tempBox2",new g.Box3);f(this,"tempMatrix",new g.Matrix4);f(this,"_tempWorldPosition",new g.Vector3);f(this,"_tempBoxSize",new g.Vector3);f(this,"_tempBox2Size",new g.Vector3);this.renderer=e,this.context={...t}}static getObjectLODState(e){return e[le]}static addPlugin(e){$.push(e)}static removePlugin(e){const t=$.indexOf(e);t>=0&&$.splice(t,1)}static get(e,t){if(e[ae])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),e[ae];const r=new P(e,{engine:"unknown",...t});return e[ae]=r,r}get plugins(){return $}addEventListener(e,t){e==="changed"&&this._lodchangedlisteners.push(t)}enable(){if(this._originalRender)return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let e=0;this._originalRender=this.renderer.render;const t=this;ge(this.renderer),this.renderer.render=function(r,o){t.renderer.getRenderTarget()==null&&(e=0,t._frame+=1);const s=t._frame,n=e++;t.onBeforeRender(r,o,n,s),t._originalRender.call(this,r,o),t.onAfterRender(r,o,n,s)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(e,t,r,o){}onAfterRender(e,t,r,o){var l,d;if(this.pause)return;const i=this.renderer.renderLists.get(e,0),s=i.opaque;let n=!0;if(s.length===1){const c=s[0].material;(c.name==="EffectMaterial"||c.name==="CopyShader")&&(n=!1)}if((t.parent&&t.parent.type==="CubeCamera"||r>=1&&t.type==="OrthographicCamera")&&(n=!1),n){if(Fe||this.updateInterval>0&&o%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const c=this.targetTriangleDensity;for(const u of s){if(u.material&&(((l=u.geometry)==null?void 0:l.type)==="BoxGeometry"||((d=u.geometry)==null?void 0:d.type)==="BufferGeometry")&&(u.material.name==="SphericalGaussianBlur"||u.material.name=="BackgroundCubeMaterial"||u.material.name==="CubemapFromEquirect"||u.material.name==="EquirectangularToCubeUV")){z&&(u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",u,u.material.name,u.material.type)));continue}switch(u.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}const m=u.object;(m instanceof g.Mesh||m.isMesh)&&this.updateLODs(e,t,m,c,o)}const L=i.transparent;for(const u of L){const m=u.object;(m instanceof g.Mesh||m.isMesh)&&this.updateLODs(e,t,m,c,o)}}}updateLODs(e,t,r,o,i){var l,d;r.userData||(r.userData={});let s=r[le];if(s||(s=new Ve,r[le]=s),s.frames++<2)return;for(const c of $)(l=c.onBeforeUpdateLOD)==null||l.call(c,this.renderer,e,t,r);this.calculateLodLevel(t,r,s,o,B),B.mesh_lod=Math.round(B.mesh_lod),B.texture_lod=Math.round(B.texture_lod),B.mesh_lod>=0&&this.loadProgressiveMeshes(r,B.mesh_lod);let n=B.texture_lod;if(r.material&&n>=0){const c=r["DEBUG:LOD"];c!=null&&(n=c),this.loadProgressiveTextures(r.material,n)}for(const c of $)(d=c.onAfterUpdatedLOD)==null||d.call(c,this.renderer,e,t,r,B);s.lastLodLevel_Mesh=B.mesh_lod,s.lastLodLevel_Texture=B.texture_lod}loadProgressiveTextures(e,t){if(!e)return;if(Array.isArray(e)){for(const o of e)this.loadProgressiveTextures(o,t);return}let r=!1;(e[U]===void 0||t<e[U])&&(r=!0),r&&(e[U]=t,S.assignTextureLOD(e,t).then(o=>{this._lodchangedlisteners.forEach(i=>i({type:"texture",level:t,object:e}))}))}loadProgressiveMeshes(e,t){if(!e)return Promise.resolve(null);if(e[U]!==t){e[U]=t;const r=e.geometry;return S.assignMeshLOD(e,t).then(o=>(o&&e[U]==t&&r!=e.geometry&&this._lodchangedlisteners.forEach(i=>i({type:"mesh",level:t,object:e})),o))}return Promise.resolve(null)}static isInside(e,t){const r=e.min,o=e.max,i=(r.x+o.x)*.5,s=(r.y+o.y)*.5;return this._tempPtInside.set(i,s,r.z).applyMatrix4(t).z<0}calculateLodLevel(e,t,r,o,i){var R,F;if(!t){i.mesh_lod=-1,i.texture_lod=-1;return}if(!e){i.mesh_lod=-1,i.texture_lod=-1;return}let n=10+1,l=!1;if(z&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const d=S.getMeshLODInformation(t.geometry),c=d==null?void 0:d.lods,L=c&&c.length>0,u=S.getMaterialMinMaxLODsCount(t.material),m=(u==null?void 0:u.min_count)!=1/0&&u.min_count>0&&u.max_count>0;if(!L&&!m){i.mesh_lod=0,i.texture_lod=0;return}if(L||(l=!0,n=0),!((R=this.cameraFrustrum)!=null&&R.intersectsObject(t))){i.mesh_lod=99,i.texture_lod=99;return}const _=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let M=t.geometry.boundingBox;if(t.type==="SkinnedMesh"){const y=t;y.boundingBox||y.computeBoundingBox(),M=y.boundingBox}if(M&&e.isPerspectiveCamera){const y=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 h=e.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(h)){i.mesh_lod=0,i.texture_lod=0;return}}if(this._tempBox.copy(M),this._tempBox.applyMatrix4(t.matrixWorld),P.isInside(this._tempBox,this.projectionScreenMatrix)){i.mesh_lod=0,i.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&y.fov>70){const h=this._tempBox.min,w=this._tempBox.max;let T=h.x,A=h.y,E=w.x,W=w.y;const Z=2,ie=1.5,j=(h.x+w.x)*.5,ee=(h.y+w.y)*.5;T=(T-j)*Z+j,A=(A-ee)*Z+ee,E=(E-j)*Z+j,W=(W-ee)*Z+ee;const _e=T<0&&E>0?0:Math.min(Math.abs(h.x),Math.abs(w.x)),ve=A<0&&W>0?0:Math.min(Math.abs(h.y),Math.abs(w.y)),oe=Math.max(_e,ve);r.lastCentrality=(ie-oe)*(ie-oe)*(ie-oe)}else r.lastCentrality=1;const D=this._tempBox.getSize(this._tempBoxSize);D.multiplyScalar(.5),screen.availHeight>0&&_>0&&D.multiplyScalar(_/screen.availHeight),D.x*=y.aspect;const N=e.matrixWorldInverse,k=this._tempBox2;k.copy(M),k.applyMatrix4(t.matrixWorld),k.applyMatrix4(N);const v=k.getSize(this._tempBox2Size),V=Math.max(v.x,v.y);if(Math.max(D.x,D.y)!=0&&V!=0&&(D.z=v.z/Math.max(v.x,v.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,z&&P.debugDrawLine){const h=this.tempMatrix.copy(this.projectionScreenMatrix);h.invert();const w=P.corner0,T=P.corner1,A=P.corner2,E=P.corner3;w.copy(this._tempBox.min),T.copy(this._tempBox.max),T.x=w.x,A.copy(this._tempBox.max),A.y=w.y,E.copy(this._tempBox.max);const W=(w.z+E.z)*.5;w.z=T.z=A.z=E.z=W,w.applyMatrix4(h),T.applyMatrix4(h),A.applyMatrix4(h),E.applyMatrix4(h),P.debugDrawLine(w,T,255),P.debugDrawLine(w,A,255),P.debugDrawLine(T,E,255),P.debugDrawLine(A,E,255)}let b=999;if(c&&r.lastScreenCoverage>0){for(let h=0;h<c.length;h++)if(c[h].density/r.lastScreenCoverage<o){b=h;break}}b<n&&(n=b,l=!0)}if(l?i.mesh_lod=n:i.mesh_lod=r.lastLodLevel_Mesh,z&&i.mesh_lod!=r.lastLodLevel_Mesh){const D=c==null?void 0:c[i.mesh_lod];D&&console.log(`Mesh LOD changed: ${r.lastLodLevel_Mesh} → ${i.mesh_lod} (${D.density.toFixed(0)}) - ${t.name}`)}if(m)if(r.lastLodLevel_Texture<0){if(i.texture_lod=u.max_count-1,z){const y=u.lods[u.max_count-1];z&&console.log(`First Texture LOD ${i.texture_lod} (${y.max_height}px) - ${t.name}`)}}else{const y=r.lastScreenspaceVolume.x+r.lastScreenspaceVolume.y+r.lastScreenspaceVolume.z;let D=r.lastScreenCoverage*2;((F=this.context)==null?void 0:F.engine)==="model-viewer"&&(D*=2);const k=_/window.devicePixelRatio*D;for(let v=u.lods.length-1;v>=0;v--){let V=u.lods[v];if(!(Re()&&V.max_height>4096)&&V.max_height>k){if(i.texture_lod=v,i.texture_lod<r.lastLodLevel_Texture){const I=V.max_height;z&&console.log(`Texture LOD changed: ${r.lastLodLevel_Texture} → ${i.texture_lod} = ${I}px
6
- Screensize: ${k.toFixed(0)}px, Coverage: ${(100*r.lastScreenCoverage).toFixed(2)}%, Volume ${y.toFixed(1)}
7
- ${t.name}`)}break}}}else i.texture_lod=0}};let C=P;f(C,"debugDrawLine"),f(C,"corner0",new g.Vector3),f(C,"corner1",new g.Vector3),f(C,"corner2",new g.Vector3),f(C,"corner3",new g.Vector3),f(C,"_tempPtInside",new g.Vector3);class Ve{constructor(){f(this,"frames",0);f(this,"lastLodLevel_Mesh",-1);f(this,"lastLodLevel_Texture",-1);f(this,"lastScreenCoverage",0);f(this,"lastScreenspaceVolume",new g.Vector3);f(this,"lastCentrality",0)}}const xe=Symbol("NEEDLE_mesh_lod"),te=Symbol("NEEDLE_texture_lod");let X=null;function ye(){const a=$e();a&&(a.mapURLs(function(e){return Le(),e}),Le(),X==null||X.disconnect(),X=new MutationObserver(e=>{e.forEach(t=>{t.addedNodes.forEach(r=>{r instanceof HTMLElement&&r.tagName.toLowerCase()==="model-viewer"&&we(r)})})}),X.observe(document,{childList:!0,subtree:!0}))}function $e(){const a=customElements.get("model-viewer");return a||(customElements.whenDefined("model-viewer").then(()=>{console.debug("[gltf-progressive] model-viewer defined"),ye()}),null)}function Le(){document.querySelectorAll("model-viewer").forEach(e=>{we(e)})}const Me=new WeakSet;let Ne=0;function we(a){if(!a||Me.has(a))return null;Me.add(a),console.debug("[gltf-progressive] found new model-viewer..."+ ++Ne+`
8
- `,a.getAttribute("src"));let e=null,t=null,r=null;for(let o=a;o!=null;o=Object.getPrototypeOf(o)){const i=Object.getOwnPropertySymbols(o),s=i.find(d=>d.toString()=="Symbol(renderer)"),n=i.find(d=>d.toString()=="Symbol(scene)"),l=i.find(d=>d.toString()=="Symbol(needsRender)");!e&&s!=null&&(e=a[s].threeRenderer),!t&&n!=null&&(t=a[n]),!r&&l!=null&&(r=a[l])}if(e&&t){let o=function(){if(r){let s=0,n=setInterval(()=>{if(s++>5){clearInterval(n);return}r==null||r.call(a)},300)}};console.debug("[gltf-progressive] setup model-viewer");const i=C.get(e,{engine:"model-viewer"});return C.addPlugin(new ze),i.enable(),i.addEventListener("changed",()=>{r==null||r.call(a)}),a.addEventListener("model-visibility",s=>{s.detail.visible&&(r==null||r.call(a))}),a.addEventListener("load",()=>{o()}),()=>{i.disable()}}return null}class ze{constructor(){f(this,"_didWarnAboutMissingUrl",!1)}onBeforeUpdateLOD(e,t,r,o){this.tryParseMeshLOD(t,o),this.tryParseTextureLOD(t,o)}getUrl(e){if(!e)return null;let t=e.getAttribute("src");return t||(t=e.src),t||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",e),this._didWarnAboutMissingUrl=!0),t}tryGetCurrentGLTF(e){return e._currentGLTF}tryGetCurrentModelViewer(e){return e.element}tryParseTextureLOD(e,t){if(t[te]==!0)return;t[te]=!0;const r=this.tryGetCurrentGLTF(e),o=this.tryGetCurrentModelViewer(e),i=this.getUrl(o);if(i&&r&&t.material){let s=function(l){var c,L,u;if(l[te]==!0)return;l[te]=!0,l.userData&&(l.userData.LOD=-1);const d=Object.keys(l);for(let m=0;m<d.length;m++){const _=d[m],M=l[_];if((M==null?void 0:M.isTexture)===!0){const R=(L=(c=M.userData)==null?void 0:c.associations)==null?void 0:L.textures;if(R==null)continue;const F=r.parser.json.textures[R];if(!F){console.warn("Texture data not found for texture index "+R);continue}if((u=F==null?void 0:F.extensions)!=null&&u[G]){const y=F.extensions[G];y&&i&&S.registerTexture(i,M,y.lods.length,R,y)}}}};const n=t.material;if(Array.isArray(n))for(const l of n)s(l);else s(n)}}tryParseMeshLOD(e,t){var s,n;if(t[xe]==!0)return;t[xe]=!0;const r=this.tryGetCurrentModelViewer(e),o=this.getUrl(r);if(!o)return;const i=(n=(s=t.userData)==null?void 0:s.gltfExtensions)==null?void 0:n[G];if(i&&o){const l=t.uuid;S.registerMesh(o,l,t,0,i.lods.length,i)}}}function Ue(a,e,t,r){ge(e),pe(t),t.register(i=>new S(i,a));const o=C.get(e);return(r==null?void 0:r.enableLODsManager)!==!1&&o.enable(),o}ye();exports.EXTENSION_NAME=G;exports.LODsManager=C;exports.NEEDLE_progressive=S;exports.VERSION=fe;exports.addDracoAndKTX2Loaders=pe;exports.createLoaders=ge;exports.getRaycastMesh=se;exports.patchModelViewer=ye;exports.setDracoDecoderLocation=Pe;exports.setKTX2TranscoderLocation=Ce;exports.setRaycastMesh=De;exports.useNeedleProgressive=Ue;exports.useRaycastMeshes=ke;
1
+ "use strict";var Re=Object.defineProperty;var Ge=(a,t,e)=>t in a?Re(a,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):a[t]=e;var d=(a,t,e)=>(Ge(a,typeof t!="symbol"?t+"":t,e),e),be=(a,t,e)=>{if(!t.has(a))throw TypeError("Cannot "+e)};var x=(a,t,e)=>(be(a,t,"read from private field"),e?e.call(a):t.get(a)),K=(a,t,e)=>{if(t.has(a))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(a):t.set(a,e)},$=(a,t,e,r)=>(be(a,t,"write to private field"),r?r.call(a,e):t.set(a,e),e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const h=require("three"),Fe=require("three/examples/jsm/loaders/GLTFLoader.js"),Ve=require("three/examples/jsm/libs/meshopt_decoder.module.js"),$e=require("three/examples/jsm/loaders/DRACOLoader.js"),Ne=require("three/examples/jsm/loaders/KTX2Loader.js"),we="";globalThis.GLTF_PROGRESSIVE_VERSION=we;console.debug(`[gltf-progressive] version ${we}`);let ue="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",ve="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(ue+"draco_decoder.js",{method:"head"}).catch(a=>{ue="./include/draco/",ve="./include/ktx2/"});function ze(a){ue=a}function Ue(a){ve=a}let re,Le,se;function _e(a){re||(re=new $e.DRACOLoader,re.setDecoderPath(ue),re.setDecoderConfig({type:"js"})),se||(se=new Ne.KTX2Loader,se.setTranscoderPath(ve)),Le||(Le=Ve.MeshoptDecoder),a?se.detectSupport(a):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function Oe(a){a.dracoLoader||a.setDRACOLoader(re),a.ktx2Loader||a.setKTX2Loader(se),a.meshoptDecoder||a.setMeshoptDecoder(Le)}ie("debugprogressive");function ie(a){const e=new URL(window.location.href).searchParams.get(a);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function We(a,t){if(t===void 0||t.startsWith("./")||t.startsWith("http")||a===void 0)return t;const e=a.lastIndexOf("/");if(e>=0){const r=a.substring(0,e+1);for(;r.endsWith("/")&&t.startsWith("/");)t=t.substring(1);return r+t}return t}let Z;function qe(){return Z!==void 0||(Z=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),ie("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",Z)),Z}const Me=Symbol("needle:raycast-mesh");function he(a){return(a==null?void 0:a[Me])instanceof h.BufferGeometry?a[Me]:null}function Ce(a,t){if((a.type==="Mesh"||a.type==="SkinnedMesh")&&!he(a)){const r=Xe(t);r.userData={isRaycastMesh:!0},a[Me]=r}}function Ke(a=!0){if(a){if(ee)return;const t=ee=h.Mesh.prototype.raycast;h.Mesh.prototype.raycast=function(e,r){const i=this,o=he(i);let s;o&&i.isMesh&&(s=i.geometry,i.geometry=o),t.call(this,e,r),s&&(i.geometry=s)}}else{if(!ee)return;h.Mesh.prototype.raycast=ee,ee=null}}let ee=null;function Xe(a){const t=new h.BufferGeometry;for(const e in a.attributes)t.setAttribute(e,a.getAttribute(e));return t.setIndex(a.getIndex()),t}const X=new Array,N="NEEDLE_progressive",M=ie("debugprogressive"),ye=Symbol("needle-progressive-texture"),oe=new Map,De=new Set;if(M){let a=function(){t+=1,console.log("Toggle LOD level",t,oe),oe.forEach((i,o)=>{for(const s of i.keys){const n=o[s];if(n!=null){if(n.isBufferGeometry===!0){const l=b.getMeshLODInformation(n),u=l?Math.min(t,l.lods.length):0;o["DEBUG:LOD"]=t,b.assignMeshLOD(o,u),l&&(e=Math.max(e,l.lods.length-1))}else if(o.isMaterial===!0){o["DEBUG:LOD"]=t,b.assignTextureLOD(o,t);break}}}}),t>=e&&(t=-1)},t=-1,e=2,r=!1;window.addEventListener("keyup",i=>{i.key==="p"&&a(),i.key==="w"&&(r=!r,De&&De.forEach(o=>{o.name!="BackgroundCubeMaterial"&&o.glyphMap==null&&"wireframe"in o&&(o.wireframe=r)}))})}function Te(a,t,e){var i;if(!M)return;oe.has(a)||oe.set(a,{keys:[],sourceId:e});const r=oe.get(a);((i=r==null?void 0:r.keys)==null?void 0:i.includes(t))==!1&&r.keys.push(t)}const S=class{constructor(t,e){d(this,"parser");d(this,"url");d(this,"_isLoadingMesh");d(this,"loadMesh",t=>{var r,i;if(this._isLoadingMesh)return null;const e=(i=(r=this.parser.json.meshes[t])==null?void 0:r.extensions)==null?void 0:i[N];return e?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",t).then(o=>{var s;return this._isLoadingMesh=!1,o&&S.registerMesh(this.url,e.guid,o,(s=e.lods)==null?void 0:s.length,void 0,e),o})):null});M&&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,i="LODS:minmax",o=t[i];if(o!=null)return o;if(e||(e={min_count:1/0,max_count:0,lods:[]}),Array.isArray(t)){for(const n of t)this.getMaterialMinMaxLODsCount(n,e);return t[i]=e,e}if(M==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const n=t;for(const l of Object.keys(n.uniforms)){const u=n.uniforms[l].value;(u==null?void 0:u.isTexture)===!0&&s(u,e)}}else if(t.isMaterial)for(const n of Object.keys(t)){const l=t[n];(l==null?void 0:l.isTexture)===!0&&s(l,e)}return t[i]=e,e;function s(n,l){const u=r.getAssignedLODInformation(n);if(u){const f=r.lodInfos.get(u.key);if(f&&f.lods){l.min_count=Math.min(l.min_count,f.lods.length),l.max_count=Math.max(l.max_count,f.lods.length);for(let D=0;D<f.lods.length;D++){const c=f.lods[D];c.width&&(l.lods[D]=l.lods[D]||{min_height:1/0,max_height:0},l.lods[D].min_height=Math.min(l.lods[D].min_height,c.height),l.lods[D].max_height=Math.max(l.lods[D].max_height,c.height))}}}}}static hasLODLevelAvailable(t,e){var o;if(Array.isArray(t)){for(const s of t)if(this.hasLODLevelAvailable(s,e))return!0;return!1}if(t.isMaterial===!0){for(const s of Object.keys(t)){const n=t[s];if(n&&n.isTexture&&this.hasLODLevelAvailable(n,e))return!0}return!1}else if(t.isGroup===!0){for(const s of t.children)if(s.isMesh===!0&&this.hasLODLevelAvailable(s,e))return!0}let r,i;if(t.isMesh?r=t.geometry:(t.isBufferGeometry||t.isTexture)&&(r=t),r&&(o=r==null?void 0:r.userData)!=null&&o.LODS){const s=r.userData.LODS;if(i=this.lodInfos.get(s.key),e===void 0)return i!=null;if(i)return Array.isArray(i.lods)?e<i.lods.length:e===0}return!1}static assignMeshLOD(t,e){var r;if(!t)return Promise.resolve(null);if(t instanceof h.Mesh||t.isMesh===!0){const i=t.geometry,o=this.getAssignedLODInformation(i);if(!o)return Promise.resolve(null);for(const s of X)(r=s.onBeforeGetLODMesh)==null||r.call(s,t,e);return t["LOD:requested level"]=e,S.getOrLoadLOD(i,e).then(s=>{if(t["LOD:requested level"]===e){if(delete t["LOD:requested level"],Array.isArray(s)){const n=o.index||0;s=s[n]}s&&i!=s&&((s==null?void 0:s.isBufferGeometry)?(t.geometry=s,M&&Te(t,"geometry",o.url)):M&&console.error("Invalid LOD geometry",s))}return s}).catch(s=>(console.error("Error loading mesh LOD",t,s),null))}else M&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",t);return Promise.resolve(null)}static assignTextureLOD(t,e=0){if(!t)return Promise.resolve(null);if(t instanceof h.Material||t.isMaterial===!0){const r=t,i=[],o=new Array;if(M&&De.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const s=r;for(const n of Object.keys(s.uniforms)){const l=s.uniforms[n].value;if((l==null?void 0:l.isTexture)===!0){const u=this.assignTextureLODForSlot(l,e,r,n);i.push(u),o.push(n)}}}else for(const s of Object.keys(r)){const n=r[s];if((n==null?void 0:n.isTexture)===!0){const l=this.assignTextureLODForSlot(n,e,r,s);i.push(l),o.push(s)}}return Promise.all(i).then(s=>{const n=new Array;for(let l=0;l<s.length;l++){const u=s[l],f=o[l];u&&u.isTexture===!0?n.push({material:r,slot:f,texture:u,level:e}):n.push({material:r,slot:f,texture:null,level:e})}return n})}if(t instanceof h.Texture||t.isTexture===!0){const r=t;return this.assignTextureLODForSlot(r,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,r,i){return(t==null?void 0:t.isTexture)!==!0?Promise.resolve(null):i==="glyphMap"?Promise.resolve(t):S.getOrLoadLOD(t,e).then(o=>{if(Array.isArray(o))return null;if((o==null?void 0:o.isTexture)===!0){if(o!=t){if(r&&i){const s=r[i];if(s){const n=this.getAssignedLODInformation(s);if(n&&(n==null?void 0:n.level)<e)return M==="verbose"&&console.warn("Assigned texture level is already higher: ",n.level,e,r,s,o),null}r[i]=o}if(M&&i&&r){const s=this.getAssignedLODInformation(t);s&&Te(r,i,s.url)}}return o}else M=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(o=>(console.error("Error loading LOD",t,o),null))}afterRoot(t){var e,r;return M&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((i,o)=>{var s;if(i!=null&&i.extensions){const n=i==null?void 0:i.extensions[N];if(n){if(!n.lods){M&&console.warn("Texture has no LODs",n);return}let l=!1;for(const u of this.parser.associations.keys())u.isTexture===!0&&this.parser.associations.get(u).textures===o&&(l=!0,S.registerTexture(this.url,u,(s=n.lods)==null?void 0:s.length,o,n));l||this.parser.getDependency("texture",o).then(u=>{var f;u&&S.registerTexture(this.url,u,(f=n.lods)==null?void 0:f.length,o,n)})}}}),(r=this.parser.json.meshes)==null||r.forEach((i,o)=>{if(i!=null&&i.extensions){const s=i==null?void 0:i.extensions[N];if(s&&s.lods){for(const n of this.parser.associations.keys())if(n.isMesh){const l=this.parser.associations.get(n);l.meshes===o&&S.registerMesh(this.url,s.guid,n,s.lods.length,l.primitives,s)}}}}),null}static async getOrLoadLOD(t,e){var n,l,u,f;const r=M=="verbose",i=t.userData.LODS;if(!i)return null;const o=i==null?void 0:i.key;let s;if(t.isTexture===!0){const D=t;D.source&&D.source[ye]&&(s=D.source[ye])}if(s||(s=S.lodInfos.get(o)),s){if(e>0){let m=!1;const _=Array.isArray(s.lods);if(_&&e>=s.lods.length?m=!0:_||(m=!0),m)return this.lowresCache.get(o)}const D=Array.isArray(s.lods)?(n=s.lods[e])==null?void 0:n.path:s.lods;if(!D)return M&&!s["missing:uri"]&&(s["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,s)),null;const c=We(i.url,D);if(c.endsWith(".glb")||c.endsWith(".gltf")){if(!s.guid)return console.warn("missing pointer for glb/gltf texture",s),null;const m=c+"_"+s.guid,_=this.previouslyLoaded.get(m);if(_!==void 0){r&&console.log(`LOD ${e} was already loading/loaded: ${m}`);let y=await _.catch(Y=>(console.error(`Error loading LOD ${e} from ${c}
2
+ `,Y),null)),w=!1;if(y==null||(y instanceof h.Texture&&t instanceof h.Texture?(l=y.image)!=null&&l.data||(u=y.source)!=null&&u.data?y=this.copySettings(t,y):(w=!0,this.previouslyLoaded.delete(m)):y instanceof h.BufferGeometry&&t instanceof h.BufferGeometry&&((f=y.attributes.position)!=null&&f.array||(w=!0,this.previouslyLoaded.delete(m)))),!w)return y}const L=s,G=new Promise(async(y,w)=>{const Y=new Fe.GLTFLoader;Oe(Y),M&&(await new Promise(T=>setTimeout(T,1e3)),r&&console.warn("Start loading (delayed) "+c,L.guid));let F=c;if(L&&Array.isArray(L.lods)){const T=L.lods[e];T.hash&&(F+="?v="+T.hash)}const O=await Y.loadAsync(F).catch(T=>(console.error(`Error loading LOD ${e} from ${c}
3
+ `,T),null));if(!O)return null;const q=O.parser;r&&console.log("Loading finished "+c,L.guid);let V=0;if(O.parser.json.textures){let T=!1;for(const p of O.parser.json.textures){if(p!=null&&p.extensions){const g=p==null?void 0:p.extensions[N];if(g!=null&&g.guid&&g.guid===L.guid){T=!0;break}}V++}if(T){let p=await q.getDependency("texture",V);return p&&S.assignLODInformation(i.url,p,o,e,void 0,void 0),r&&console.log('change "'+t.name+'" → "'+p.name+'"',c,V,p,m),t instanceof h.Texture&&(p=this.copySettings(t,p)),p&&(p.guid=L.guid),y(p)}else M&&console.warn("Could not find texture with guid",L.guid,O.parser.json)}if(V=0,O.parser.json.meshes){let T=!1;for(const p of O.parser.json.meshes){if(p!=null&&p.extensions){const g=p==null?void 0:p.extensions[N];if(g!=null&&g.guid&&g.guid===L.guid){T=!0;break}}V++}if(T){const p=await q.getDependency("mesh",V),g=L;if(r&&console.log(`Loaded Mesh "${p.name}"`,c,V,p,m),p.isMesh===!0){const v=p.geometry;return S.assignLODInformation(i.url,v,o,e,void 0,g.density),y(v)}else{const v=new Array;for(let A=0;A<p.children.length;A++){const E=p.children[A];if(E.isMesh===!0){const P=E.geometry;S.assignLODInformation(i.url,P,o,e,A,g.density),v.push(P)}}return y(v)}}else M&&console.warn("Could not find mesh with guid",L.guid,O.parser.json)}return y(null)});return this.previouslyLoaded.set(m,G),await G}else if(t instanceof h.Texture){r&&console.log("Load texture from uri: "+c);const _=await new h.TextureLoader().loadAsync(c);return _?(_.guid=s.guid,_.flipY=!1,_.needsUpdate=!0,_.colorSpace=t.colorSpace,r&&console.log(s,_)):M&&console.warn("failed loading",c),_}}else M&&console.warn(`Can not load LOD ${e}: no LOD info found for "${o}" ${t.name}`,t.type);return null}static assignLODInformation(t,e,r,i,o,s){if(!e)return;e.userData||(e.userData={});const n=new Ye(t,r,i,o,s);e.userData.LODS=n}static getAssignedLODInformation(t){var e;return((e=t==null?void 0:t.userData)==null?void 0:e.LODS)||null}static copySettings(t,e){return e=e.clone(),M&&console.warn(`Copying texture settings
4
+ `,t.uuid,`
5
+ `,e.uuid),e.offset=t.offset,e.repeat=t.repeat,e.colorSpace=t.colorSpace,e.magFilter=t.magFilter,e.minFilter=t.minFilter,e.wrapS=t.wrapS,e.wrapT=t.wrapT,e.flipY=t.flipY,e.anisotropy=t.anisotropy,e.mipmaps||(e.generateMipmaps=t.generateMipmaps),e}};let b=S;d(b,"registerTexture",(t,e,r,i,o)=>{if(M&&console.log("> Progressive: register texture",i,e.name,e.uuid,e,o),!e){M&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[ye]=o);const s=o.guid;S.assignLODInformation(t,e,s,r,i,void 0),S.lodInfos.set(s,o),S.lowresCache.set(s,e)}),d(b,"registerMesh",(t,e,r,i,o,s)=>{var u;M&&console.log("> Progressive: register mesh",o,r.name,s,r.uuid,r);const n=r.geometry;if(!n){M&&console.warn("gltf-progressive: Register mesh without geometry");return}n.userData||(n.userData={}),S.assignLODInformation(t,n,e,i,o,s.density),S.lodInfos.set(e,s);let l=S.lowresCache.get(e);l?l.push(r.geometry):l=[r.geometry],S.lowresCache.set(e,l),i>0&&!he(r)&&Ce(r,n);for(const f of X)(u=f.onRegisteredNewMesh)==null||u.call(f,r,s)}),d(b,"lodInfos",new Map),d(b,"previouslyLoaded",new Map),d(b,"lowresCache",new Map);class Ye{constructor(t,e,r,i,o){d(this,"url");d(this,"key");d(this,"level");d(this,"index");d(this,"density");this.url=t,this.key=e,this.level=r,i!=null&&(this.index=i),o!=null&&(this.density=o)}}const k=ie("debugprogressive"),He=ie("noprogressive"),me=Symbol("Needle:LODSManager"),xe=Symbol("Needle:LODState"),H=Symbol("Needle:CurrentLOD"),R={mesh_lod:-1,texture_lod:-1};var B,U,fe,j,J,de,W;const C=class{constructor(t,e){d(this,"context");d(this,"renderer");d(this,"projectionScreenMatrix",new h.Matrix4);d(this,"cameraFrustrum",new h.Frustum);d(this,"targetTriangleDensity",2e5);d(this,"updateInterval","auto");K(this,B,1);d(this,"pause",!1);d(this,"_lodchangedlisteners",[]);K(this,U,void 0);K(this,fe,new h.Clock);K(this,j,0);K(this,J,0);K(this,de,0);K(this,W,0);d(this,"_fpsBuffer",[60,60,60,60,60]);d(this,"_sphere",new h.Sphere);d(this,"_tempBox",new h.Box3);d(this,"_tempBox2",new h.Box3);d(this,"tempMatrix",new h.Matrix4);d(this,"_tempWorldPosition",new h.Vector3);d(this,"_tempBoxSize",new h.Vector3);d(this,"_tempBox2Size",new h.Vector3);this.renderer=t,this.context={...e}}static getObjectLODState(t){return t[xe]}static addPlugin(t){X.push(t)}static removePlugin(t){const e=X.indexOf(t);e>=0&&X.splice(e,1)}static get(t,e){if(t[me])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[me];const r=new C(t,{engine:"unknown",...e});return t[me]=r,r}get plugins(){return X}addEventListener(t,e){t==="changed"&&this._lodchangedlisteners.push(e)}enable(){if(x(this,U))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let t=0;$(this,U,this.renderer.render);const e=this;_e(this.renderer),this.renderer.render=function(r,i){e.renderer.getRenderTarget()==null&&(t=0,$(e,j,x(e,j)+1),$(e,J,x(e,fe).getDelta()),$(e,de,x(e,de)+x(e,J)),e._fpsBuffer.shift(),e._fpsBuffer.push(1/x(e,J)),$(e,W,e._fpsBuffer.reduce((l,u)=>l+u)/e._fpsBuffer.length),k&&x(e,j)%30===0&&console.log("FPS",Math.round(x(e,W)),"Interval:",x(e,B)));const s=x(e,j),n=t++;e.onBeforeRender(r,i,n,s),x(e,U).call(this,r,i),e.onAfterRender(r,i,n,s)}}disable(){x(this,U)&&(this.renderer.render=x(this,U),$(this,U,void 0))}onBeforeRender(t,e,r,i){}onAfterRender(t,e,r,i){var l,u;if(this.pause)return;const o=this.renderer.renderLists.get(t,0),s=o.opaque;let n=!0;if(s.length===1){const f=s[0].material;(f.name==="EffectMaterial"||f.name==="CopyShader")&&(n=!1)}if((e.parent&&e.parent.type==="CubeCamera"||r>=1&&e.type==="OrthographicCamera")&&(n=!1),n){if(He||(this.updateInterval==="auto"?x(this,W)<40&&x(this,B)<10?($(this,B,x(this,B)+1),k&&console.warn("↓ Reducing LOD updates",x(this,B),x(this,W).toFixed(0))):x(this,W)>=80&&x(this,B)>1&&($(this,B,x(this,B)-1),k&&console.warn("↑ Increasing LOD updates",x(this,B),x(this,W).toFixed(0))):$(this,B,this.updateInterval),x(this,B)>0&&i%x(this,B)!=0))return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const f=this.targetTriangleDensity;for(const c of s){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 _=Math.random()*16777215,L=new h.MeshStandardMaterial({color:_});c.object.material=L}const m=c.object;(m instanceof h.Mesh||m.isMesh)&&this.updateLODs(t,e,m,f,i)}const D=o.transparent;for(const c of D){const m=c.object;(m instanceof h.Mesh||m.isMesh)&&this.updateLODs(t,e,m,f,i)}}}updateLODs(t,e,r,i,o){var l,u;r.userData||(r.userData={});let s=r[xe];if(s||(s=new je,r[xe]=s),s.frames++<2)return;for(const f of X)(l=f.onBeforeUpdateLOD)==null||l.call(f,this.renderer,t,e,r);this.calculateLodLevel(e,r,s,i,R),R.mesh_lod=Math.round(R.mesh_lod),R.texture_lod=Math.round(R.texture_lod),R.mesh_lod>=0&&this.loadProgressiveMeshes(r,R.mesh_lod);let n=R.texture_lod;if(r.material&&n>=0){const f=r["DEBUG:LOD"];f!=null&&(n=f),this.loadProgressiveTextures(r.material,n)}for(const f of X)(u=f.onAfterUpdatedLOD)==null||u.call(f,this.renderer,t,e,r,R);s.lastLodLevel_Mesh=R.mesh_lod,s.lastLodLevel_Texture=R.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const i of t)this.loadProgressiveTextures(i,e);return}let r=!1;(t[H]===void 0||e<t[H])&&(r=!0),r&&(t[H]=e,b.assignTextureLOD(t,e).then(i=>{this._lodchangedlisteners.forEach(o=>o({type:"texture",level:e,object:t}))}))}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);if(t[H]!==e){t[H]=e;const r=t.geometry;return b.assignMeshLOD(t,e).then(i=>(i&&t[H]==e&&r!=t.geometry&&this._lodchangedlisteners.forEach(o=>o({type:"mesh",level:e,object:t})),i))}return Promise.resolve(null)}static isInside(t,e){const r=t.min,i=t.max,o=(r.x+i.x)*.5,s=(r.y+i.y)*.5;return this._tempPtInside.set(o,s,r.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,r,i,o){var G,z;if(!e){o.mesh_lod=-1,o.texture_lod=-1;return}if(!t){o.mesh_lod=-1,o.texture_lod=-1;return}let n=10+1,l=!1;if(k&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const u=b.getMeshLODInformation(e.geometry),f=u==null?void 0:u.lods,D=f&&f.length>0,c=b.getMaterialMinMaxLODsCount(e.material),m=(c==null?void 0:c.min_count)!=1/0&&c.min_count>0&&c.max_count>0;if(!D&&!m){o.mesh_lod=0,o.texture_lod=0;return}if(D||(l=!0,n=0),!((G=this.cameraFrustrum)!=null&&G.intersectsObject(e))){o.mesh_lod=99,o.texture_lod=99;return}const _=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let L=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const y=e;y.boundingBox||y.computeBoundingBox(),L=y.boundingBox}if(L&&t.isPerspectiveCamera){const y=t;if(e.geometry.attributes.color&&e.geometry.attributes.color.count<100&&e.geometry.boundingSphere){this._sphere.copy(e.geometry.boundingSphere),this._sphere.applyMatrix4(e.matrixWorld);const g=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(g)){o.mesh_lod=0,o.texture_lod=0;return}}if(this._tempBox.copy(L),this._tempBox.applyMatrix4(e.matrixWorld),C.isInside(this._tempBox,this.projectionScreenMatrix)){o.mesh_lod=0,o.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&y.fov>70){const g=this._tempBox.min,v=this._tempBox.max;let A=g.x,E=g.y,P=v.x,Q=v.y;const ne=2,ge=1.5,ae=(g.x+v.x)*.5,le=(g.y+v.y)*.5;A=(A-ae)*ne+ae,E=(E-le)*ne+le,P=(P-ae)*ne+ae,Q=(Q-le)*ne+le;const Ie=A<0&&P>0?0:Math.min(Math.abs(g.x),Math.abs(v.x)),ke=E<0&&Q>0?0:Math.min(Math.abs(g.y),Math.abs(v.y)),pe=Math.max(Ie,ke);r.lastCentrality=(ge-pe)*(ge-pe)*(ge-pe)}else r.lastCentrality=1;const w=this._tempBox.getSize(this._tempBoxSize);w.multiplyScalar(.5),screen.availHeight>0&&_>0&&w.multiplyScalar(_/screen.availHeight),w.x*=y.aspect;const Y=t.matrixWorldInverse,F=this._tempBox2;F.copy(L),F.applyMatrix4(e.matrixWorld),F.applyMatrix4(Y);const O=F.getSize(this._tempBox2Size),q=Math.max(O.x,O.y);if(Math.max(w.x,w.y)!=0&&q!=0&&(w.z=O.z/Math.max(O.x,O.y)*Math.max(w.x,w.y)),r.lastScreenCoverage=Math.max(w.x,w.y,w.z),r.lastScreenspaceVolume.copy(w),r.lastScreenCoverage*=r.lastCentrality,k&&C.debugDrawLine){const g=this.tempMatrix.copy(this.projectionScreenMatrix);g.invert();const v=C.corner0,A=C.corner1,E=C.corner2,P=C.corner3;v.copy(this._tempBox.min),A.copy(this._tempBox.max),A.x=v.x,E.copy(this._tempBox.max),E.y=v.y,P.copy(this._tempBox.max);const Q=(v.z+P.z)*.5;v.z=A.z=E.z=P.z=Q,v.applyMatrix4(g),A.applyMatrix4(g),E.applyMatrix4(g),P.applyMatrix4(g),C.debugDrawLine(v,A,255),C.debugDrawLine(v,E,255),C.debugDrawLine(A,P,255),C.debugDrawLine(E,P,255)}let T=999;if(f&&r.lastScreenCoverage>0){for(let g=0;g<f.length;g++)if(f[g].density/r.lastScreenCoverage<i){T=g;break}}T<n&&(n=T,l=!0)}if(l?o.mesh_lod=n:o.mesh_lod=r.lastLodLevel_Mesh,k&&o.mesh_lod!=r.lastLodLevel_Mesh){const w=f==null?void 0:f[o.mesh_lod];w&&console.log(`Mesh LOD changed: ${r.lastLodLevel_Mesh} → ${o.mesh_lod} (${w.density.toFixed(0)}) - ${e.name}`)}if(m)if(r.lastLodLevel_Texture<0){if(o.texture_lod=c.max_count-1,k){const y=c.lods[c.max_count-1];k&&console.log(`First Texture LOD ${o.texture_lod} (${y.max_height}px) - ${e.name}`)}}else{const y=r.lastScreenspaceVolume.x+r.lastScreenspaceVolume.y+r.lastScreenspaceVolume.z;let w=r.lastScreenCoverage*2;((z=this.context)==null?void 0:z.engine)==="model-viewer"&&(w*=2);const F=_/window.devicePixelRatio*w;for(let O=c.lods.length-1;O>=0;O--){let q=c.lods[O];if(!(qe()&&q.max_height>4096)&&q.max_height>F){if(o.texture_lod=O,o.texture_lod<r.lastLodLevel_Texture){const V=q.max_height;k&&console.log(`Texture LOD changed: ${r.lastLodLevel_Texture} → ${o.texture_lod} = ${V}px
6
+ Screensize: ${F.toFixed(0)}px, Coverage: ${(100*r.lastScreenCoverage).toFixed(2)}%, Volume ${y.toFixed(1)}
7
+ ${e.name}`)}break}}}else o.texture_lod=0}};let I=C;B=new WeakMap,U=new WeakMap,fe=new WeakMap,j=new WeakMap,J=new WeakMap,de=new WeakMap,W=new WeakMap,d(I,"debugDrawLine"),d(I,"corner0",new h.Vector3),d(I,"corner1",new h.Vector3),d(I,"corner2",new h.Vector3),d(I,"corner3",new h.Vector3),d(I,"_tempPtInside",new h.Vector3);class je{constructor(){d(this,"frames",0);d(this,"lastLodLevel_Mesh",-1);d(this,"lastLodLevel_Texture",-1);d(this,"lastScreenCoverage",0);d(this,"lastScreenspaceVolume",new h.Vector3);d(this,"lastCentrality",0)}}const Ae=Symbol("NEEDLE_mesh_lod"),ce=Symbol("NEEDLE_texture_lod");let te=null;function Se(){const a=Je();a&&(a.mapURLs(function(t){return Ee(),t}),Ee(),te==null||te.disconnect(),te=new MutationObserver(t=>{t.forEach(e=>{e.addedNodes.forEach(r=>{r instanceof HTMLElement&&r.tagName.toLowerCase()==="model-viewer"&&Be(r)})})}),te.observe(document,{childList:!0,subtree:!0}))}function Je(){const a=customElements.get("model-viewer");return a||(customElements.whenDefined("model-viewer").then(()=>{console.debug("[gltf-progressive] model-viewer defined"),Se()}),null)}function Ee(){document.querySelectorAll("model-viewer").forEach(t=>{Be(t)})}const Pe=new WeakSet;let Qe=0;function Be(a){if(!a||Pe.has(a))return null;Pe.add(a),console.debug("[gltf-progressive] found new model-viewer..."+ ++Qe+`
8
+ `,a.getAttribute("src"));let t=null,e=null,r=null;for(let i=a;i!=null;i=Object.getPrototypeOf(i)){const o=Object.getOwnPropertySymbols(i),s=o.find(u=>u.toString()=="Symbol(renderer)"),n=o.find(u=>u.toString()=="Symbol(scene)"),l=o.find(u=>u.toString()=="Symbol(needsRender)");!t&&s!=null&&(t=a[s].threeRenderer),!e&&n!=null&&(e=a[n]),!r&&l!=null&&(r=a[l])}if(t&&e){let i=function(){if(r){let s=0,n=setInterval(()=>{if(s++>5){clearInterval(n);return}r==null||r.call(a)},300)}};console.debug("[gltf-progressive] setup model-viewer");const o=I.get(t,{engine:"model-viewer"});return I.addPlugin(new Ze),o.enable(),o.addEventListener("changed",()=>{r==null||r.call(a)}),a.addEventListener("model-visibility",s=>{s.detail.visible&&(r==null||r.call(a))}),a.addEventListener("load",()=>{i()}),()=>{o.disable()}}return null}class Ze{constructor(){d(this,"_didWarnAboutMissingUrl",!1)}onBeforeUpdateLOD(t,e,r,i){this.tryParseMeshLOD(e,i),this.tryParseTextureLOD(e,i)}getUrl(t){if(!t)return null;let e=t.getAttribute("src");return e||(e=t.src),e||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",t),this._didWarnAboutMissingUrl=!0),e}tryGetCurrentGLTF(t){return t._currentGLTF}tryGetCurrentModelViewer(t){return t.element}tryParseTextureLOD(t,e){if(e[ce]==!0)return;e[ce]=!0;const r=this.tryGetCurrentGLTF(t),i=this.tryGetCurrentModelViewer(t),o=this.getUrl(i);if(o&&r&&e.material){let s=function(l){var f,D,c;if(l[ce]==!0)return;l[ce]=!0,l.userData&&(l.userData.LOD=-1);const u=Object.keys(l);for(let m=0;m<u.length;m++){const _=u[m],L=l[_];if((L==null?void 0:L.isTexture)===!0){const G=(D=(f=L.userData)==null?void 0:f.associations)==null?void 0:D.textures;if(G==null)continue;const z=r.parser.json.textures[G];if(!z){console.warn("Texture data not found for texture index "+G);continue}if((c=z==null?void 0:z.extensions)!=null&&c[N]){const y=z.extensions[N];y&&o&&b.registerTexture(o,L,y.lods.length,G,y)}}}};const n=e.material;if(Array.isArray(n))for(const l of n)s(l);else s(n)}}tryParseMeshLOD(t,e){var s,n;if(e[Ae]==!0)return;e[Ae]=!0;const r=this.tryGetCurrentModelViewer(t),i=this.getUrl(r);if(!i)return;const o=(n=(s=e.userData)==null?void 0:s.gltfExtensions)==null?void 0:n[N];if(o&&i){const l=e.uuid;b.registerMesh(i,l,e,0,o.lods.length,o)}}}function et(a,t,e,r){_e(t),Oe(e),e.register(o=>new b(o,a));const i=I.get(t);return(r==null?void 0:r.enableLODsManager)!==!1&&i.enable(),i}Se();exports.EXTENSION_NAME=N;exports.LODsManager=I;exports.NEEDLE_progressive=b;exports.VERSION=we;exports.addDracoAndKTX2Loaders=Oe;exports.createLoaders=_e;exports.getRaycastMesh=he;exports.patchModelViewer=Se;exports.setDracoDecoderLocation=ze;exports.setKTX2TranscoderLocation=Ue;exports.setRaycastMesh=Ce;exports.useNeedleProgressive=et;exports.useRaycastMeshes=Ke;
@@ -42,6 +42,7 @@ declare type LODChangedEventListener = (args: {
42
42
  * ```
43
43
  */
44
44
  export declare class LODsManager {
45
+ #private;
45
46
  /** Assign a function to draw debug lines for the LODs. This function will be called with the start and end position of the line and the color of the line when the `debugprogressive` query parameter is set.
46
47
  */
47
48
  static debugDrawLine?: (a: Vector3, b: Vector3, color: number) => void;
@@ -67,9 +68,9 @@ export declare class LODsManager {
67
68
  */
68
69
  targetTriangleDensity: number;
69
70
  /**
70
- * The update interval in frames. If set to 0, the LODs will be updated every frame. If set to 1, the LODs will be updated every second frame, etc.
71
+ * The update interval in frames. If set to 0, the LODs will be updated every frame. If set to 2, the LODs will be updated every second frame, etc.
71
72
  */
72
- updateInterval: number;
73
+ updateInterval: "auto" | number;
73
74
  /**
74
75
  * If set to true, the LODsManager will not update the LODs.
75
76
  */
@@ -77,8 +78,7 @@ export declare class LODsManager {
77
78
  private readonly _lodchangedlisteners;
78
79
  addEventListener(evt: "changed", listener: LODChangedEventListener): void;
79
80
  private constructor();
80
- private _frame;
81
- private _originalRender?;
81
+ private _fpsBuffer;
82
82
  /**
83
83
  * Enable the LODsManager. This will replace the render method of the renderer with a method that updates the LODs.
84
84
  */
@@ -1,4 +1,4 @@
1
- import { Box3, Frustum, Matrix4, Mesh, Sphere, Vector3 } from "three";
1
+ import { Box3, Clock, Frustum, Matrix4, Mesh, MeshStandardMaterial, Sphere, Vector3 } from "three";
2
2
  import { NEEDLE_progressive } from "./extension.js";
3
3
  import { createLoaders } from "./loaders.js";
4
4
  import { getParam, isMobileDevice } from "./utils.internal.js";
@@ -83,9 +83,10 @@ export class LODsManager {
83
83
  */
84
84
  targetTriangleDensity = 200_000;
85
85
  /**
86
- * The update interval in frames. If set to 0, the LODs will be updated every frame. If set to 1, the LODs will be updated every second frame, etc.
86
+ * The update interval in frames. If set to 0, the LODs will be updated every frame. If set to 2, the LODs will be updated every second frame, etc.
87
87
  */
88
- updateInterval = 0;
88
+ updateInterval = "auto";
89
+ #updateInterval = 1;
89
90
  /**
90
91
  * If set to true, the LODsManager will not update the LODs.
91
92
  */
@@ -101,18 +102,23 @@ export class LODsManager {
101
102
  this.renderer = renderer;
102
103
  this.context = { ...context };
103
104
  }
104
- _frame = 0;
105
- _originalRender;
105
+ #originalRender;
106
+ #clock = new Clock();
107
+ #frame = 0;
108
+ #delta = 0;
109
+ #time = 0;
110
+ #fps = 0;
111
+ _fpsBuffer = [60, 60, 60, 60, 60];
106
112
  /**
107
113
  * Enable the LODsManager. This will replace the render method of the renderer with a method that updates the LODs.
108
114
  */
109
115
  enable() {
110
- if (this._originalRender)
116
+ if (this.#originalRender)
111
117
  return;
112
118
  console.debug("[gltf-progressive] Enabling LODsManager for renderer");
113
119
  let stack = 0;
114
120
  // Save the original render method
115
- this._originalRender = this.renderer.render;
121
+ this.#originalRender = this.renderer.render;
116
122
  const self = this;
117
123
  createLoaders(this.renderer);
118
124
  this.renderer.render = function (scene, camera) {
@@ -122,20 +128,27 @@ export class LODsManager {
122
128
  const renderTarget = self.renderer.getRenderTarget();
123
129
  if (renderTarget == null) {
124
130
  stack = 0;
125
- self._frame += 1;
131
+ self.#frame += 1;
132
+ self.#delta = self.#clock.getDelta();
133
+ self.#time += self.#delta;
134
+ self._fpsBuffer.shift();
135
+ self._fpsBuffer.push(1 / self.#delta);
136
+ self.#fps = self._fpsBuffer.reduce((a, b) => a + b) / self._fpsBuffer.length;
137
+ if (debugProgressiveLoading && self.#frame % 30 === 0)
138
+ console.log("FPS", Math.round(self.#fps), "Interval:", self.#updateInterval);
126
139
  }
127
- const frame = self._frame;
140
+ const frame = self.#frame;
128
141
  const stack_level = stack++;
129
142
  self.onBeforeRender(scene, camera, stack_level, frame);
130
- self._originalRender.call(this, scene, camera);
143
+ self.#originalRender.call(this, scene, camera);
131
144
  self.onAfterRender(scene, camera, stack_level, frame);
132
145
  };
133
146
  }
134
147
  disable() {
135
- if (!this._originalRender)
148
+ if (!this.#originalRender)
136
149
  return;
137
- this.renderer.render = this._originalRender;
138
- this._originalRender = undefined;
150
+ this.renderer.render = this.#originalRender;
151
+ this.#originalRender = undefined;
139
152
  }
140
153
  onBeforeRender(_scene, _camera, _stack, _frame) {
141
154
  }
@@ -170,8 +183,27 @@ export class LODsManager {
170
183
  if (updateLODs) {
171
184
  if (suppressProgressiveLoading)
172
185
  return;
173
- if (this.updateInterval > 0 && frame % this.updateInterval != 0)
186
+ // If the update interval is set to auto then we check the FPS and adjust the update interval accordingly
187
+ // If performance is low we increase the update interval to reduce the amount of LOD updates
188
+ if (this.updateInterval === "auto") {
189
+ if (this.#fps < 40 && this.#updateInterval < 10) {
190
+ this.#updateInterval += 1;
191
+ if (debugProgressiveLoading)
192
+ console.warn("↓ Reducing LOD updates", this.#updateInterval, this.#fps.toFixed(0));
193
+ }
194
+ else if (this.#fps >= 80 && this.#updateInterval > 1) {
195
+ this.#updateInterval -= 1;
196
+ if (debugProgressiveLoading)
197
+ console.warn("↑ Increasing LOD updates", this.#updateInterval, this.#fps.toFixed(0));
198
+ }
199
+ }
200
+ else {
201
+ this.#updateInterval = this.updateInterval;
202
+ }
203
+ // Check if we should update LODs this frame
204
+ if (this.#updateInterval > 0 && frame % this.#updateInterval != 0) {
174
205
  return;
206
+ }
175
207
  this.projectionScreenMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
176
208
  this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix, this.renderer.coordinateSystem);
177
209
  const desiredDensity = this.targetTriangleDensity;
@@ -207,6 +239,16 @@ export class LODsManager {
207
239
  case "MeshDepthMaterial":
208
240
  continue;
209
241
  }
242
+ if (debugProgressiveLoading === "color") {
243
+ if (entry.material) {
244
+ if (!entry.object["progressive_debug_color"]) {
245
+ entry.object["progressive_debug_color"] = true;
246
+ const randomColor = Math.random() * 0xffffff;
247
+ const newMaterial = new MeshStandardMaterial({ color: randomColor });
248
+ entry.object.material = newMaterial;
249
+ }
250
+ }
251
+ }
210
252
  const object = entry.object;
211
253
  if (object instanceof Mesh || (object.isMesh)) {
212
254
  this.updateLODs(scene, camera, object, desiredDensity, frame);
package/lib/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  // replaced at build time
2
- export const version = "1.2.2-alpha.4";
2
+ export const version = "1.2.3-alpha";
3
3
  globalThis["GLTF_PROGRESSIVE_VERSION"] = version;
4
4
  console.debug(`[gltf-progressive] version ${version}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/gltf-progressive",
3
- "version": "1.2.2-alpha.4",
3
+ "version": "1.2.3-alpha",
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": {