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

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,7 +1,8 @@
1
- var we=Object.defineProperty,Oe=(t,e,r)=>e in t?we(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,c=(t,e,r)=>(Oe(t,typeof e!="symbol"?e+"":e,r),r);import{BufferGeometry as Z,Mesh as N,Material as be,Texture as z,TextureLoader as Se,Matrix4 as me,Frustum as Te,Sphere as Ee,Box3 as pe,Vector3 as R}from"three";import{GLTFLoader as Ae}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as Ie}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as Pe}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as Be}from"three/examples/jsm/loaders/KTX2Loader.js";const oe="";globalThis.GLTF_PROGRESSIVE_VERSION=oe,console.debug(`[gltf-progressive] version ${oe}`);let J="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",ne="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(J+"draco_decoder.js",{method:"head"}).catch(t=>{J="./include/draco/",ne="./include/ktx2/"});function Ce(t){J=t}function Re(t){ne=t}let U,ie,V;function ae(t){U||(U=new Pe,U.setDecoderPath(J),U.setDecoderConfig({type:"js"})),V||(V=new Be,V.setTranscoderPath(ne)),ie||(ie=Ie),t?V.detectSupport(t):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function le(t){t.dracoLoader||t.setDRACOLoader(U),t.ktx2Loader||t.setKTX2Loader(V),t.meshoptDecoder||t.setMeshoptDecoder(ie)}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 ke(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 Q;function je(){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 ee(t){return t?.[ue]instanceof Z?t[ue]:null}function xe(t,e){if((t.type==="Mesh"||t.type==="SkinnedMesh")&&!ee(t)){const r=$e(e);r.userData={isRaycastMesh:!0},t[ue]=r}}function Ge(t=!0){if(t){if(K)return;const e=K=N.prototype.raycast;N.prototype.raycast=function(r,n){const o=this,s=ee(o);let i;s&&o.isMesh&&(i=o.geometry,o.geometry=s),e.call(this,r,n),i&&(o.geometry=i)}}else{if(!K)return;N.prototype.raycast=K,K=null}}let K=null;function $e(t){const e=new Z;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"),ce=Symbol("needle-progressive-texture"),X=new Map,de=new Set;if(y){let t=function(){e+=1,console.log("Toggle LOD level",e,X),X.forEach((o,s)=>{for(const i of o.keys){const a=s[i];if(a!=null){if(a.isBufferGeometry===!0){const l=w.getMeshLODInformation(a),u=l?Math.min(e,l.lods.length):0;s["DEBUG:LOD"]=e,w.assignMeshLOD(s,u),l&&(r=Math.max(r,l.lods.length-1))}else if(s.isMaterial===!0){s["DEBUG:LOD"]=e,w.assignTextureLOD(s,e);break}}}}),e>=r&&(e=-1)},e=-1,r=2,n=!1;window.addEventListener("keyup",o=>{o.key==="p"&&t(),o.key==="w"&&(n=!n,de&&de.forEach(s=>{s.name!="BackgroundCubeMaterial"&&s.glyphMap==null&&"wireframe"in s&&(s.wireframe=n)}))})}function ye(t,e,r){var n;if(!y)return;X.has(t)||X.set(t,{keys:[],sourceId:r});const o=X.get(t);((n=o?.keys)==null?void 0:n.includes(e))==!1&&o.keys.push(e)}const M=class{constructor(t,e){c(this,"parser"),c(this,"url"),c(this,"_isLoadingMesh"),c(this,"loadMesh",r=>{var n,o;if(this._isLoadingMesh)return null;const s=(o=(n=this.parser.json.meshes[r])==null?void 0:n.extensions)==null?void 0:o[B];return s?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",r).then(i=>{var a;return this._isLoadingMesh=!1,i&&M.registerMesh(this.url,s.guid,i,(a=s.lods)==null?void 0:a.length,void 0,s),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",o=t[n];if(o!=null)return o;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 a of Object.keys(i.uniforms)){const l=i.uniforms[a].value;l?.isTexture===!0&&s(l,e)}}else if(t.isMaterial)for(const i of Object.keys(t)){const a=t[i];a?.isTexture===!0&&s(a,e)}return t[n]=e,e;function s(i,a){const l=r.getAssignedLODInformation(i);if(l){const u=r.lodInfos.get(l.key);if(u&&u.lods){a.min_count=Math.min(a.min_count,u.lods.length),a.max_count=Math.max(a.max_count,u.lods.length);for(let g=0;g<u.lods.length;g++){const h=u.lods[g];h.width&&(a.lods[g]=a.lods[g]||{min_height:1/0,max_height:0},a.lods[g].min_height=Math.min(a.lods[g].min_height,h.height),a.lods[g].max_height=Math.max(a.lods[g].max_height,h.height))}}}}}static hasLODLevelAvailable(t,e){var r;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 i=t[s];if(i&&i.isTexture&&this.hasLODLevelAvailable(i,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 n,o;if(t.isMesh?n=t.geometry:(t.isBufferGeometry||t.isTexture)&&(n=t),n&&(r=n?.userData)!=null&&r.LODS){const s=n.userData.LODS;if(o=this.lodInfos.get(s.key),e===void 0)return o!=null;if(o)return Array.isArray(o.lods)?e<o.lods.length:e===0}return!1}static assignMeshLOD(t,e){var r;if(!t)return Promise.resolve(null);if(t instanceof N||t.isMesh===!0){const n=t.geometry,o=this.getAssignedLODInformation(n);if(!o)return Promise.resolve(null);for(const s of j)(r=s.onBeforeGetLODMesh)==null||r.call(s,t,e);return t["LOD:requested level"]=e,M.getOrLoadLOD(n,e).then(s=>{if(t["LOD:requested level"]===e){if(delete t["LOD:requested level"],Array.isArray(s)){const i=o.index||0;s=s[i]}s&&n!=s&&(s?.isBufferGeometry?(t.geometry=s,y&&ye(t,"geometry",o.url)):y&&console.error("Invalid LOD geometry",s))}return s}).catch(s=>(console.error("Error loading mesh LOD",t,s),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 be||t.isMaterial===!0){const r=t,n=[],o=new Array;if(y&&de.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const s=r;for(const i of Object.keys(s.uniforms)){const a=s.uniforms[i].value;if(a?.isTexture===!0){const l=this.assignTextureLODForSlot(a,e,r,i);n.push(l),o.push(i)}}}else for(const s of Object.keys(r)){const i=r[s];if(i?.isTexture===!0){const a=this.assignTextureLODForSlot(i,e,r,s);n.push(a),o.push(s)}}return Promise.all(n).then(s=>{const i=new Array;for(let a=0;a<s.length;a++){const l=s[a],u=o[a];l&&l.isTexture===!0?i.push({material:r,slot:u,texture:l,level:e}):i.push({material:r,slot:u,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(o=>{if(Array.isArray(o))return null;if(o?.isTexture===!0){if(o!=t){if(r&&n){const s=r[n];if(s){const i=this.getAssignedLODInformation(s);if(i&&i?.level<e)return y==="verbose"&&console.warn("Assigned texture level is already higher: ",i.level,e,r,s,o),null}r[n]=o}if(y&&n&&r){const s=this.getAssignedLODInformation(t);s&&ye(r,n,s.url)}}return o}else y=="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 y&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((n,o)=>{var s;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 a=!1;for(const l of this.parser.associations.keys())l.isTexture===!0&&this.parser.associations.get(l).textures===o&&(a=!0,M.registerTexture(this.url,l,(s=i.lods)==null?void 0:s.length,o,i));a||this.parser.getDependency("texture",o).then(l=>{var u;l&&M.registerTexture(this.url,l,(u=i.lods)==null?void 0:u.length,o,i)})}}}),(r=this.parser.json.meshes)==null||r.forEach((n,o)=>{if(n!=null&&n.extensions){const s=n?.extensions[B];if(s&&s.lods){for(const i of this.parser.associations.keys())if(i.isMesh){const a=this.parser.associations.get(i);a.meshes===o&&M.registerMesh(this.url,s.guid,i,s.lods.length,a.primitives,s)}}}}),null}static async getOrLoadLOD(t,e){var r,n,o,s;const i=y=="verbose",a=t.userData.LODS;if(!a)return null;const l=a?.key;let u;if(t.isTexture===!0){const g=t;g.source&&g.source[ce]&&(u=g.source[ce])}if(u||(u=M.lodInfos.get(l)),u){if(e>0){let f=!1;const S=Array.isArray(u.lods);if(S&&e>=u.lods.length?f=!0:S||(f=!0),f)return this.lowresCache.get(l)}const g=Array.isArray(u.lods)?(r=u.lods[e])==null?void 0:r.path:u.lods;if(!g)return y&&!u["missing:uri"]&&(u["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,u)),null;const h=ke(a.url,g);if(h.endsWith(".glb")||h.endsWith(".gltf")){if(!u.guid)return console.warn("missing pointer for glb/gltf texture",u),null;const f=h+"_"+u.guid,S=this.previouslyLoaded.get(f);if(S!==void 0){i&&console.log(`LOD ${e} was already loading/loaded: ${f}`);let m=await S.catch(b=>(console.error(`Error loading LOD ${e} from ${h}
2
- `,b),null)),x=!1;if(m==null||(m instanceof z&&t instanceof z?(n=m.image)!=null&&n.data||(o=m.source)!=null&&o.data?m=this.copySettings(t,m):(x=!0,this.previouslyLoaded.delete(f)):m instanceof Z&&t instanceof Z&&((s=m.attributes.position)!=null&&s.array||(x=!0,this.previouslyLoaded.delete(f)))),!x)return m}const D=u,T=new Promise(async(m,x)=>{const b=new Ae;le(b),y&&(await new Promise(p=>setTimeout(p,1e3)),i&&console.warn("Start loading (delayed) "+h,D.guid));let E=h;if(D&&Array.isArray(D.lods)){const p=D.lods[e];p.hash&&(E+="?v="+p.hash)}const L=await b.loadAsync(E).catch(p=>(console.error(`Error loading LOD ${e} from ${h}
3
- `,p),null));if(!L)return null;const F=L.parser;i&&console.log("Loading finished "+h,D.guid);let I=0;if(L.parser.json.textures){let p=!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){p=!0;break}}I++}if(p){let d=await F.getDependency("texture",I);return d&&M.assignLODInformation(a.url,d,l,e,void 0,void 0),i&&console.log('change "'+t.name+'" \u2192 "'+d.name+'"',h,I,d,f),t instanceof z&&(d=this.copySettings(t,d)),d&&(d.guid=D.guid),m(d)}else y&&console.warn("Could not find texture with guid",D.guid,L.parser.json)}if(I=0,L.parser.json.meshes){let p=!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){p=!0;break}}I++}if(p){const d=await F.getDependency("mesh",I),v=D;if(i&&console.log(`Loaded Mesh "${d.name}"`,h,I,d,f),d.isMesh===!0){const _=d.geometry;return M.assignLODInformation(a.url,_,l,e,void 0,v.density),m(_)}else{const _=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(a.url,G,l,e,O,v.density),_.push(G)}}return m(_)}}else y&&console.warn("Could not find mesh with guid",D.guid,L.parser.json)}return m(null)});return this.previouslyLoaded.set(f,T),await T}else if(t instanceof z){i&&console.log("Load texture from uri: "+h);const f=await new Se().loadAsync(h);return f?(f.guid=u.guid,f.flipY=!1,f.needsUpdate=!0,f.colorSpace=t.colorSpace,i&&console.log(u,f)):y&&console.warn("failed loading",h),f}}else y&&console.warn(`Can not load LOD ${e}: no LOD info found for "${l}" ${t.name}`,t.type);return null}static assignLODInformation(t,e,r,n,o,s){if(!e)return;e.userData||(e.userData={});const i=new Fe(t,r,n,o,s);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 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
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 w=M;c(w,"registerTexture",(t,e,r,n,o)=>{if(y&&console.log("> Progressive: register texture",n,e.name,e.uuid,e,o),!e){y&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[ce]=o);const s=o.guid;M.assignLODInformation(t,e,s,r,n,void 0),M.lodInfos.set(s,o),M.lowresCache.set(s,e)}),c(w,"registerMesh",(t,e,r,n,o,s)=>{var i;y&&console.log("> Progressive: register mesh",o,r.name,s,r.uuid,r);const a=r.geometry;if(!a){y&&console.warn("gltf-progressive: Register mesh without geometry");return}a.userData||(a.userData={}),M.assignLODInformation(t,a,e,n,o,s.density),M.lodInfos.set(e,s);let l=M.lowresCache.get(e);l?l.push(r.geometry):l=[r.geometry],M.lowresCache.set(e,l),n>0&&!ee(r)&&xe(r,a);for(const u of j)(i=u.onRegisteredNewMesh)==null||i.call(u,r,s)}),c(w,"lodInfos",new Map),c(w,"previouslyLoaded",new Map),c(w,"lowresCache",new Map);class Fe{constructor(e,r,n,o,s){c(this,"url"),c(this,"key"),c(this,"level"),c(this,"index"),c(this,"density"),this.url=e,this.key=r,this.level=n,o!=null&&(this.index=o),s!=null&&(this.density=s)}}const $=q("debugprogressive"),Ne=q("noprogressive"),he=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 me),c(this,"cameraFrustrum",new Te),c(this,"targetTriangleDensity",2e5),c(this,"updateInterval",0),c(this,"pause",!1),c(this,"_frame",0),c(this,"_originalRender"),c(this,"_sphere",new Ee),c(this,"_tempBox",new pe),c(this,"_tempBox2",new pe),c(this,"tempMatrix",new me),c(this,"_tempWorldPosition",new R),c(this,"_tempBoxSize",new R),c(this,"_tempBox2Size",new R),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[he])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[he];const r=new A(t,{engine:"unknown",...e});return t[he]=r,r}get plugins(){return j}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 o=e._frame,s=t++;e.onBeforeRender(r,n,s,o),e._originalRender.call(this,r,n),e.onAfterRender(r,n,s,o)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(t,e,r,n){}onAfterRender(t,e,r,n){var o,s;if(this.pause)return;const i=this.renderer.renderLists.get(t,0),a=i.opaque;let l=!0;if(a.length===1){const u=a[0].material;(u.name==="EffectMaterial"||u.name==="CopyShader")&&(l=!1)}if((e.parent&&e.parent.type==="CubeCamera"||r>=1&&e.type==="OrthographicCamera")&&(l=!1),l){if(Ne||this.updateInterval>0&&n%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const u=this.targetTriangleDensity;for(const h of a){if(h.material&&(((o=h.geometry)==null?void 0:o.type)==="BoxGeometry"||((s=h.geometry)==null?void 0:s.type)==="BufferGeometry")&&(h.material.name==="SphericalGaussianBlur"||h.material.name=="BackgroundCubeMaterial"||h.material.name==="CubemapFromEquirect"||h.material.name==="EquirectangularToCubeUV")){$&&(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 f=h.object;(f instanceof N||f.isMesh)&&this.updateLODs(t,e,f,u,n)}const g=i.transparent;for(const h of g){const f=h.object;(f instanceof N||f.isMesh)&&this.updateLODs(t,e,f,u,n)}}}updateLODs(t,e,r,n,o){var s,i;r.userData||(r.userData={});let a=r[fe];if(a||(a=new We,r[fe]=a),a.frames++<2)return;for(const u of j)(s=u.onBeforeUpdateLOD)==null||s.call(u,this.renderer,t,e,r);this.calculateLodLevel(e,r,a,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 l=P.texture_lod;if(r.material&&l>=0){const u=r["DEBUG:LOD"];u!=null&&(l=u),this.loadProgressiveTextures(r.material,l)}for(const u of j)(i=u.onAfterUpdatedLOD)==null||i.call(u,this.renderer,t,e,r,P);a.lastLodLevel_Mesh=P.mesh_lod,a.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,w.assignTextureLOD(t,e))}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);if(t[W]!==e){t[W]=e;const r=t.geometry;return w.assignMeshLOD(t,e).then(n=>(n&&t[W]==e&&r!=t.geometry,n))}return Promise.resolve(null)}static isInside(t,e){const r=t.min,n=t.max,o=(r.x+n.x)*.5,s=(r.y+n.y)*.5;return this._tempPtInside.set(o,s,r.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,r,n,o){var s,i;if(!e){o.mesh_lod=-1,o.texture_lod=-1;return}if(!t){o.mesh_lod=-1,o.texture_lod=-1;return}let a=10+1,l=!1;if($&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const u=w.getMeshLODInformation(e.geometry),g=u?.lods,h=g&&g.length>0,f=w.getMaterialMinMaxLODsCount(e.material),S=f?.min_count!=1/0&&f.min_count>0&&f.max_count>0;if(!h&&!S){o.mesh_lod=0,o.texture_lod=0;return}if(h||(l=!0,a=0),!((s=this.cameraFrustrum)!=null&&s.intersectsObject(e))){o.mesh_lod=99,o.texture_lod=99;return}const D=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let T=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const m=e;m.boundingBox||m.computeBoundingBox(),T=m.boundingBox}if(T&&t.isPerspectiveCamera){const m=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 p=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(p)){o.mesh_lod=0,o.texture_lod=0;return}}if(this._tempBox.copy(T),this._tempBox.applyMatrix4(e.matrixWorld),A.isInside(this._tempBox,this.projectionScreenMatrix)){o.mesh_lod=0,o.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&m.fov>70){const p=this._tempBox.min,d=this._tempBox.max;let v=p.x,_=p.y,O=d.x,k=d.y;const G=2,re=1.5,H=(p.x+d.x)*.5,Y=(p.y+d.y)*.5;v=(v-H)*G+H,_=(_-Y)*G+Y,O=(O-H)*G+H,k=(k-Y)*G+Y;const De=v<0&&O>0?0:Math.min(Math.abs(p.x),Math.abs(d.x)),_e=_<0&&k>0?0:Math.min(Math.abs(p.y),Math.abs(d.y)),se=Math.max(De,_e);r.lastCentrality=(re-se)*(re-se)*(re-se)}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*=m.aspect;const b=t.matrixWorldInverse,E=this._tempBox2;E.copy(T),E.applyMatrix4(e.matrixWorld),E.applyMatrix4(b);const L=E.getSize(this._tempBox2Size),F=Math.max(L.x,L.y);if(Math.max(x.x,x.y)!=0&&F!=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,$&&A.debugDrawLine){const p=this.tempMatrix.copy(this.projectionScreenMatrix);p.invert();const d=A.corner0,v=A.corner1,_=A.corner2,O=A.corner3;d.copy(this._tempBox.min),v.copy(this._tempBox.max),v.x=d.x,_.copy(this._tempBox.max),_.y=d.y,O.copy(this._tempBox.max);const k=(d.z+O.z)*.5;d.z=v.z=_.z=O.z=k,d.applyMatrix4(p),v.applyMatrix4(p),_.applyMatrix4(p),O.applyMatrix4(p),A.debugDrawLine(d,v,255),A.debugDrawLine(d,_,255),A.debugDrawLine(v,O,255),A.debugDrawLine(_,O,255)}let I=999;if(g&&r.lastScreenCoverage>0){for(let p=0;p<g.length;p++)if(g[p].density/r.lastScreenCoverage<n){I=p;break}}I<a&&(a=I,l=!0)}if(l?o.mesh_lod=a:o.mesh_lod=r.lastLodLevel_Mesh,$&&o.mesh_lod!=r.lastLodLevel_Mesh){const m=g?.[o.mesh_lod];m&&console.log(`Mesh LOD changed: ${r.lastLodLevel_Mesh} \u2192 ${o.mesh_lod} (${m.density.toFixed(0)}) - ${e.name}`)}if(S)if(r.lastLodLevel_Texture<0){if(o.texture_lod=f.max_count-1,$){const m=f.lods[f.max_count-1];$&&console.log(`First Texture LOD ${o.texture_lod} (${m.max_height}px) - ${e.name}`)}}else{const m=r.lastScreenspaceVolume.x+r.lastScreenspaceVolume.y+r.lastScreenspaceVolume.z;let 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=f.lods.length-1;E>=0;E--){let L=f.lods[E];if(!(je()&&L.max_height>4096)&&L.max_height>b){if(o.texture_lod=E,o.texture_lod<r.lastLodLevel_Texture){const F=L.max_height;$&&console.log(`Texture LOD changed: ${r.lastLodLevel_Texture} \u2192 ${o.texture_lod} = ${F}px
6
- Screensize: ${b.toFixed(0)}px, Coverage: ${(100*r.lastScreenCoverage).toFixed(2)}%, Volume ${m.toFixed(1)}
7
- ${e.name}`)}break}}}else o.texture_lod=0}};let C=A;c(C,"debugDrawLine"),c(C,"corner0",new R),c(C,"corner1",new R),c(C,"corner2",new R),c(C,"corner3",new R),c(C,"_tempPtInside",new R);class We{constructor(){c(this,"frames",0),c(this,"lastLodLevel_Mesh",-1),c(this,"lastLodLevel_Texture",-1),c(this,"lastScreenCoverage",0),c(this,"lastScreenspaceVolume",new R),c(this,"lastCentrality",0)}}const ve=Symbol("NEEDLE_mesh_lod"),te=Symbol("NEEDLE_texture_lod");function Le(){document.removeEventListener("DOMContentLoaded",ge),document.addEventListener("DOMContentLoaded",ge),ge()}function ge(){document.querySelectorAll("model-viewer").forEach((t,e)=>{ze(t,e)})}const Me=new WeakSet;function ze(t,e){if(!t||Me.has(t))return null;Me.add(t),console.debug("[gltf-progressive] found model-viewer..."+e);let r=null,n=null,o=null;for(let s=t;s!=null;s=Object.getPrototypeOf(s)){const i=Object.getOwnPropertySymbols(s),a=i.find(g=>g.toString()=="Symbol(renderer)"),l=i.find(g=>g.toString()=="Symbol(scene)"),u=i.find(g=>g.toString()=="Symbol(needsRender)");!r&&a!=null&&(r=t[a].threeRenderer),!n&&l!=null&&(n=t[l]),!o&&u!=null&&(o=t[u])}if(r&&n){console.debug("[gltf-progressive] setup model-viewer");const s=C.get(r,{engine:"model-viewer"});if(C.addPlugin(new Ue),s.enable(),n&&o){let i=0,a=setInterval(()=>{if(i++>10){clearInterval(a);return}o?.call(t)},150)}return()=>{s.disable()}}return null}class Ue{constructor(){c(this,"_didWarnAboutMissingUrl",!1)}onBeforeUpdateLOD(e,r,n,o){this.tryParseMeshLOD(r,o),this.tryParseTextureLOD(r,o)}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),o=this.tryGetCurrentModelViewer(e),s=this.getUrl(o);if(s&&n&&r.material){let i=function(l){var u,g,h;if(l[te]==!0)return;l[te]=!0,l.userData&&(l.userData.LOD=-1);const f=Object.keys(l);for(let S=0;S<f.length;S++){const D=f[S],T=l[D];if(T?.isTexture===!0){const m=(g=(u=T.userData)==null?void 0:u.associations)==null?void 0:g.textures;if(m==null)continue;const x=n.parser.json.textures[m];if(!x){console.warn("Texture data not found for texture index "+m);continue}if((h=x?.extensions)!=null&&h[B]){const b=x.extensions[B];b&&s&&w.registerTexture(s,T,b.lods.length,m,b)}}}};const a=r.material;if(Array.isArray(a))for(const l of a)i(l);else i(a)}}tryParseMeshLOD(e,r){var n,o;if(r[ve]==!0)return;r[ve]=!0;const s=this.tryGetCurrentModelViewer(e),i=this.getUrl(s);if(!i)return;const a=(o=(n=r.userData)==null?void 0:n.gltfExtensions)==null?void 0:o[B];if(a&&i){const l=r.uuid;w.registerMesh(i,l,r,0,a.lods.length,a)}}}Le();function Ve(t,e,r,n){ae(e),le(r),r.register(s=>new w(s,t));const o=C.get(e);return n?.enableLODsManager!==!1&&o.enable(),o}export{B as EXTENSION_NAME,C as LODsManager,w as NEEDLE_progressive,oe as VERSION,le as addDracoAndKTX2Loaders,ae as createLoaders,ee as getRaycastMesh,Le as patchModelViewer,Ce as setDracoDecoderLocation,Re as setKTX2TranscoderLocation,xe as setRaycastMesh,Ve as useNeedleProgressive,Ge 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 _=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};
@@ -1,7 +1,8 @@
1
- "use strict";var _e=Object.defineProperty;var ve=(l,e,t)=>e in l?_e(l,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):l[e]=t;var d=(l,e,t)=>(ve(l,typeof e!="symbol"?e+"":e,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const g=require("three"),Oe=require("three/examples/jsm/loaders/GLTFLoader.js"),Se=require("three/examples/jsm/libs/meshopt_decoder.module.js"),Te=require("three/examples/jsm/loaders/DRACOLoader.js"),be=require("three/examples/jsm/loaders/KTX2Loader.js"),de="";globalThis.GLTF_PROGRESSIVE_VERSION=de;console.debug(`[gltf-progressive] version ${de}`);let te="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",he="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(te+"draco_decoder.js",{method:"head"}).catch(l=>{te="./include/draco/",he="./include/ktx2/"});function Ae(l){te=l}function Pe(l){he=l}let X,ce,Y;function ge(l){X||(X=new Te.DRACOLoader,X.setDecoderPath(te),X.setDecoderConfig({type:"js"})),Y||(Y=new be.KTX2Loader,Y.setTranscoderPath(he)),ce||(ce=Se.MeshoptDecoder),l?Y.detectSupport(l):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function pe(l){l.dracoLoader||l.setDRACOLoader(X),l.ktx2Loader||l.setKTX2Loader(Y),l.meshoptDecoder||l.setMeshoptDecoder(ce)}J("debugprogressive");function J(l){const t=new URL(window.location.href).searchParams.get(l);return t==null||t==="0"||t==="false"?!1:t===""?!0:t}function Ce(l,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||l===void 0)return e;const t=l.lastIndexOf("/");if(t>=0){const r=l.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),J("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",q)),q}const ue=Symbol("needle:raycast-mesh");function re(l){return(l==null?void 0:l[ue])instanceof g.BufferGeometry?l[ue]:null}function Le(l,e){if((l.type==="Mesh"||l.type==="SkinnedMesh")&&!re(l)){const r=Be(e);r.userData={isRaycastMesh:!0},l[ue]=r}}function Ee(l=!0){if(l){if(K)return;const e=K=g.Mesh.prototype.raycast;g.Mesh.prototype.raycast=function(t,r){const i=this,o=re(i);let s;o&&i.isMesh&&(s=i.geometry,i.geometry=o),e.call(this,t,r),s&&(i.geometry=s)}}else{if(!K)return;g.Mesh.prototype.raycast=K,K=null}}let K=null;function Be(l){const e=new g.BufferGeometry;for(const t in l.attributes)e.setAttribute(t,l.getAttribute(t));return e.setIndex(l.getIndex()),e}const V=new Array,G="NEEDLE_progressive",m=J("debugprogressive"),ie=Symbol("needle-progressive-texture"),H=new Map,fe=new Set;if(m){let l=function(){e+=1,console.log("Toggle LOD level",e,H),H.forEach((i,o)=>{for(const s of i.keys){const n=o[s];if(n!=null){if(n.isBufferGeometry===!0){const a=S.getMeshLODInformation(n),f=a?Math.min(e,a.lods.length):0;o["DEBUG:LOD"]=e,S.assignMeshLOD(o,f),a&&(t=Math.max(t,a.lods.length-1))}else if(o.isMaterial===!0){o["DEBUG:LOD"]=e,S.assignTextureLOD(o,e);break}}}}),e>=t&&(e=-1)},e=-1,t=2,r=!1;window.addEventListener("keyup",i=>{i.key==="p"&&l(),i.key==="w"&&(r=!r,fe&&fe.forEach(o=>{o.name!="BackgroundCubeMaterial"&&o.glyphMap==null&&"wireframe"in o&&(o.wireframe=r)}))})}function ye(l,e,t){var i;if(!m)return;H.has(l)||H.set(l,{keys:[],sourceId:t});const r=H.get(l);((i=r==null?void 0:r.keys)==null?void 0:i.includes(e))==!1&&r.keys.push(e)}const O=class{constructor(e,t){d(this,"parser");d(this,"url");d(this,"_isLoadingMesh");d(this,"loadMesh",e=>{var r,i;if(this._isLoadingMesh)return null;const t=(i=(r=this.parser.json.meshes[e])==null?void 0:r.extensions)==null?void 0:i[G];return t?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",e).then(o=>{var s;return this._isLoadingMesh=!1,o&&O.registerMesh(this.url,t.guid,o,(s=t.lods)==null?void 0:s.length,void 0,t),o})):null});m&&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,i="LODS:minmax",o=e[i];if(o!=null)return o;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[i]=t,t}if(m==="verbose"&&console.log("getMaterialMinMaxLODsCount",e),e.type==="ShaderMaterial"||e.type==="RawShaderMaterial"){const n=e;for(const a of Object.keys(n.uniforms)){const f=n.uniforms[a].value;(f==null?void 0:f.isTexture)===!0&&s(f,t)}}else if(e.isMaterial)for(const n of Object.keys(e)){const a=e[n];(a==null?void 0:a.isTexture)===!0&&s(a,t)}return e[i]=t,t;function s(n,a){const f=r.getAssignedLODInformation(n);if(f){const c=r.lodInfos.get(f.key);if(c&&c.lods){a.min_count=Math.min(a.min_count,c.lods.length),a.max_count=Math.max(a.max_count,c.lods.length);for(let L=0;L<c.lods.length;L++){const u=c.lods[L];u.width&&(a.lods[L]=a.lods[L]||{min_height:1/0,max_height:0},a.lods[L].min_height=Math.min(a.lods[L].min_height,u.height),a.lods[L].max_height=Math.max(a.lods[L].max_height,u.height))}}}}}static hasLODLevelAvailable(e,t){var o;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,i;if(e.isMesh?r=e.geometry:(e.isBufferGeometry||e.isTexture)&&(r=e),r&&(o=r==null?void 0:r.userData)!=null&&o.LODS){const s=r.userData.LODS;if(i=this.lodInfos.get(s.key),t===void 0)return i!=null;if(i)return Array.isArray(i.lods)?t<i.lods.length:t===0}return!1}static assignMeshLOD(e,t){var r;if(!e)return Promise.resolve(null);if(e instanceof g.Mesh||e.isMesh===!0){const i=e.geometry,o=this.getAssignedLODInformation(i);if(!o)return Promise.resolve(null);for(const s of V)(r=s.onBeforeGetLODMesh)==null||r.call(s,e,t);return e["LOD:requested level"]=t,O.getOrLoadLOD(i,t).then(s=>{if(e["LOD:requested level"]===t){if(delete e["LOD:requested level"],Array.isArray(s)){const n=o.index||0;s=s[n]}s&&i!=s&&((s==null?void 0:s.isBufferGeometry)?(e.geometry=s,m&&ye(e,"geometry",o.url)):m&&console.error("Invalid LOD geometry",s))}return s}).catch(s=>(console.error("Error loading mesh LOD",e,s),null))}else m&&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,i=[],o=new Array;if(m&&fe.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const s=r;for(const n of Object.keys(s.uniforms)){const a=s.uniforms[n].value;if((a==null?void 0:a.isTexture)===!0){const f=this.assignTextureLODForSlot(a,t,r,n);i.push(f),o.push(n)}}}else for(const s of Object.keys(r)){const n=r[s];if((n==null?void 0:n.isTexture)===!0){const a=this.assignTextureLODForSlot(n,t,r,s);i.push(a),o.push(s)}}return Promise.all(i).then(s=>{const n=new Array;for(let a=0;a<s.length;a++){const f=s[a],c=o[a];f&&f.isTexture===!0?n.push({material:r,slot:c,texture:f,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,i){return(e==null?void 0:e.isTexture)!==!0?Promise.resolve(null):i==="glyphMap"?Promise.resolve(e):O.getOrLoadLOD(e,t).then(o=>{if(Array.isArray(o))return null;if((o==null?void 0:o.isTexture)===!0){if(o!=e){if(r&&i){const s=r[i];if(s){const n=this.getAssignedLODInformation(s);if(n&&(n==null?void 0:n.level)<t)return m==="verbose"&&console.warn("Assigned texture level is already higher: ",n.level,t,r,s,o),null}r[i]=o}if(m&&i&&r){const s=this.getAssignedLODInformation(e);s&&ye(r,i,s.url)}}return o}else m=="verbose"&&console.warn("No LOD found for",e,t);return null}).catch(o=>(console.error("Error loading LOD",e,o),null))}afterRoot(e){var t,r;return m&&console.log("AFTER",this.url,e),(t=this.parser.json.textures)==null||t.forEach((i,o)=>{var s;if(i!=null&&i.extensions){const n=i==null?void 0:i.extensions[G];if(n){if(!n.lods){m&&console.warn("Texture has no LODs",n);return}let a=!1;for(const f of this.parser.associations.keys())f.isTexture===!0&&this.parser.associations.get(f).textures===o&&(a=!0,O.registerTexture(this.url,f,(s=n.lods)==null?void 0:s.length,o,n));a||this.parser.getDependency("texture",o).then(f=>{var c;f&&O.registerTexture(this.url,f,(c=n.lods)==null?void 0:c.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[G];if(s&&s.lods){for(const n of this.parser.associations.keys())if(n.isMesh){const a=this.parser.associations.get(n);a.meshes===o&&O.registerMesh(this.url,s.guid,n,s.lods.length,a.primitives,s)}}}}),null}static async getOrLoadLOD(e,t){var n,a,f,c;const r=m=="verbose",i=e.userData.LODS;if(!i)return null;const o=i==null?void 0:i.key;let s;if(e.isTexture===!0){const L=e;L.source&&L.source[ie]&&(s=L.source[ie])}if(s||(s=O.lodInfos.get(o)),s){if(t>0){let x=!1;const _=Array.isArray(s.lods);if(_&&t>=s.lods.length?x=!0:_||(x=!0),x)return this.lowresCache.get(o)}const L=Array.isArray(s.lods)?(n=s.lods[t])==null?void 0:n.path:s.lods;if(!L)return m&&!s["missing:uri"]&&(s["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+t,s)),null;const u=Ce(i.url,L);if(u.endsWith(".glb")||u.endsWith(".gltf")){if(!s.guid)return console.warn("missing pointer for glb/gltf texture",s),null;const x=u+"_"+s.guid,_=this.previouslyLoaded.get(x);if(_!==void 0){r&&console.log(`LOD ${t} was already loading/loaded: ${x}`);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?(a=y.image)!=null&&a.data||(f=y.source)!=null&&f.data?y=this.copySettings(e,y):(D=!0,this.previouslyLoaded.delete(x)):y instanceof g.BufferGeometry&&e instanceof g.BufferGeometry&&((c=y.attributes.position)!=null&&c.array||(D=!0,this.previouslyLoaded.delete(x)))),!D)return y}const M=s,B=new Promise(async(y,D)=>{const N=new Oe.GLTFLoader;pe(N),m&&(await new Promise(T=>setTimeout(T,1e3)),r&&console.warn("Start loading (delayed) "+u,M.guid));let k=u;if(M&&Array.isArray(M.lods)){const T=M.lods[t];T.hash&&(k+="?v="+T.hash)}const v=await N.loadAsync(k).catch(T=>(console.error(`Error loading LOD ${t} from ${u}
3
- `,T),null));if(!v)return null;const $=v.parser;r&&console.log("Loading finished "+u,M.guid);let I=0;if(v.parser.json.textures){let T=!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){T=!0;break}}I++}if(T){let p=await $.getDependency("texture",I);return p&&O.assignLODInformation(i.url,p,o,t,void 0,void 0),r&&console.log('change "'+e.name+'" → "'+p.name+'"',u,I,p,x),e instanceof g.Texture&&(p=this.copySettings(e,p)),p&&(p.guid=M.guid),y(p)}else m&&console.warn("Could not find texture with guid",M.guid,v.parser.json)}if(I=0,v.parser.json.meshes){let T=!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){T=!0;break}}I++}if(T){const p=await $.getDependency("mesh",I),h=M;if(r&&console.log(`Loaded Mesh "${p.name}"`,u,I,p,x),p.isMesh===!0){const w=p.geometry;return O.assignLODInformation(i.url,w,o,t,void 0,h.density),y(w)}else{const w=new Array;for(let b=0;b<p.children.length;b++){const A=p.children[b];if(A.isMesh===!0){const P=A.geometry;O.assignLODInformation(i.url,P,o,t,b,h.density),w.push(P)}}return y(w)}}else m&&console.warn("Could not find mesh with guid",M.guid,v.parser.json)}return y(null)});return this.previouslyLoaded.set(x,B),await B}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,_)):m&&console.warn("failed loading",u),_}}else m&&console.warn(`Can not load LOD ${t}: no LOD info found for "${o}" ${e.name}`,e.type);return null}static assignLODInformation(e,t,r,i,o,s){if(!t)return;t.userData||(t.userData={});const n=new ke(e,r,i,o,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(),m&&console.warn(`Copying texture settings
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
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;d(S,"registerTexture",(e,t,r,i,o)=>{if(m&&console.log("> Progressive: register texture",i,t.name,t.uuid,t,o),!t){m&&console.error("gltf-progressive: Register texture without texture");return}t.source&&(t.source[ie]=o);const s=o.guid;O.assignLODInformation(e,t,s,r,i,void 0),O.lodInfos.set(s,o),O.lowresCache.set(s,t)}),d(S,"registerMesh",(e,t,r,i,o,s)=>{var f;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={}),O.assignLODInformation(e,n,t,i,o,s.density),O.lodInfos.set(t,s);let a=O.lowresCache.get(t);a?a.push(r.geometry):a=[r.geometry],O.lowresCache.set(t,a),i>0&&!re(r)&&Le(r,n);for(const c of V)(f=c.onRegisteredNewMesh)==null||f.call(c,r,s)}),d(S,"lodInfos",new Map),d(S,"previouslyLoaded",new Map),d(S,"lowresCache",new Map);class ke{constructor(e,t,r,i,o){d(this,"url");d(this,"key");d(this,"level");d(this,"index");d(this,"density");this.url=e,this.key=t,this.level=r,i!=null&&(this.index=i),o!=null&&(this.density=o)}}const z=J("debugprogressive"),Ie=J("noprogressive"),ne=Symbol("Needle:LODSManager"),ae=Symbol("Needle:LODState"),U=Symbol("Needle:CurrentLOD"),E={mesh_lod:-1,texture_lod:-1},C=class{constructor(e,t){d(this,"context");d(this,"renderer");d(this,"projectionScreenMatrix",new g.Matrix4);d(this,"cameraFrustrum",new g.Frustum);d(this,"targetTriangleDensity",2e5);d(this,"updateInterval",0);d(this,"pause",!1);d(this,"_frame",0);d(this,"_originalRender");d(this,"_sphere",new g.Sphere);d(this,"_tempBox",new g.Box3);d(this,"_tempBox2",new g.Box3);d(this,"tempMatrix",new g.Matrix4);d(this,"_tempWorldPosition",new g.Vector3);d(this,"_tempBoxSize",new g.Vector3);d(this,"_tempBox2Size",new g.Vector3);this.renderer=e,this.context={...t}}static getObjectLODState(e){return e[ae]}static addPlugin(e){V.push(e)}static removePlugin(e){const t=V.indexOf(e);t>=0&&V.splice(t,1)}static get(e,t){if(e[ne])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),e[ne];const r=new C(e,{engine:"unknown",...t});return e[ne]=r,r}get plugins(){return V}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,i){t.renderer.getRenderTarget()==null&&(e=0,t._frame+=1);const s=t._frame,n=e++;t.onBeforeRender(r,i,n,s),t._originalRender.call(this,r,i),t.onAfterRender(r,i,n,s)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(e,t,r,i){}onAfterRender(e,t,r,i){var a,f;if(this.pause)return;const o=this.renderer.renderLists.get(e,0),s=o.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(Ie||this.updateInterval>0&&i%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&&(((a=u.geometry)==null?void 0:a.type)==="BoxGeometry"||((f=u.geometry)==null?void 0:f.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 x=u.object;(x instanceof g.Mesh||x.isMesh)&&this.updateLODs(e,t,x,c,i)}const L=o.transparent;for(const u of L){const x=u.object;(x instanceof g.Mesh||x.isMesh)&&this.updateLODs(e,t,x,c,i)}}}updateLODs(e,t,r,i,o){var a,f;r.userData||(r.userData={});let s=r[ae];if(s||(s=new Ge,r[ae]=s),s.frames++<2)return;for(const c of V)(a=c.onBeforeUpdateLOD)==null||a.call(c,this.renderer,e,t,r);this.calculateLodLevel(t,r,s,i,E),E.mesh_lod=Math.round(E.mesh_lod),E.texture_lod=Math.round(E.texture_lod),E.mesh_lod>=0&&this.loadProgressiveMeshes(r,E.mesh_lod);let n=E.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 V)(f=c.onAfterUpdatedLOD)==null||f.call(c,this.renderer,e,t,r,E);s.lastLodLevel_Mesh=E.mesh_lod,s.lastLodLevel_Texture=E.texture_lod}loadProgressiveTextures(e,t){if(!e)return;if(Array.isArray(e)){for(const i of e)this.loadProgressiveTextures(i,t);return}let r=!1;(e[U]===void 0||t<e[U])&&(r=!0),r&&(e[U]=t,S.assignTextureLOD(e,t))}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(i=>(i&&e[U]==t&&r!=e.geometry,i))}return Promise.resolve(null)}static isInside(e,t){const r=e.min,i=e.max,o=(r.x+i.x)*.5,s=(r.y+i.y)*.5;return this._tempPtInside.set(o,s,r.z).applyMatrix4(t).z<0}calculateLodLevel(e,t,r,i,o){var B,F;if(!t){o.mesh_lod=-1,o.texture_lod=-1;return}if(!e){o.mesh_lod=-1,o.texture_lod=-1;return}let n=10+1,a=!1;if(z&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const f=S.getMeshLODInformation(t.geometry),c=f==null?void 0:f.lods,L=c&&c.length>0,u=S.getMaterialMinMaxLODsCount(t.material),x=(u==null?void 0:u.min_count)!=1/0&&u.min_count>0&&u.max_count>0;if(!L&&!x){o.mesh_lod=0,o.texture_lod=0;return}if(L||(a=!0,n=0),!((B=this.cameraFrustrum)!=null&&B.intersectsObject(t))){o.mesh_lod=99,o.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)){o.mesh_lod=0,o.texture_lod=0;return}}if(this._tempBox.copy(M),this._tempBox.applyMatrix4(t.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 h=this._tempBox.min,w=this._tempBox.max;let b=h.x,A=h.y,P=w.x,W=w.y;const Q=2,se=1.5,Z=(h.x+w.x)*.5,j=(h.y+w.y)*.5;b=(b-Z)*Q+Z,A=(A-j)*Q+j,P=(P-Z)*Q+Z,W=(W-j)*Q+j;const De=b<0&&P>0?0:Math.min(Math.abs(h.x),Math.abs(w.x)),we=A<0&&W>0?0:Math.min(Math.abs(h.y),Math.abs(w.y)),oe=Math.max(De,we);r.lastCentrality=(se-oe)*(se-oe)*(se-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),$=Math.max(v.x,v.y);if(Math.max(D.x,D.y)!=0&&$!=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&&C.debugDrawLine){const h=this.tempMatrix.copy(this.projectionScreenMatrix);h.invert();const w=C.corner0,b=C.corner1,A=C.corner2,P=C.corner3;w.copy(this._tempBox.min),b.copy(this._tempBox.max),b.x=w.x,A.copy(this._tempBox.max),A.y=w.y,P.copy(this._tempBox.max);const W=(w.z+P.z)*.5;w.z=b.z=A.z=P.z=W,w.applyMatrix4(h),b.applyMatrix4(h),A.applyMatrix4(h),P.applyMatrix4(h),C.debugDrawLine(w,b,255),C.debugDrawLine(w,A,255),C.debugDrawLine(b,P,255),C.debugDrawLine(A,P,255)}let T=999;if(c&&r.lastScreenCoverage>0){for(let h=0;h<c.length;h++)if(c[h].density/r.lastScreenCoverage<i){T=h;break}}T<n&&(n=T,a=!0)}if(a?o.mesh_lod=n:o.mesh_lod=r.lastLodLevel_Mesh,z&&o.mesh_lod!=r.lastLodLevel_Mesh){const D=c==null?void 0:c[o.mesh_lod];D&&console.log(`Mesh LOD changed: ${r.lastLodLevel_Mesh} → ${o.mesh_lod} (${D.density.toFixed(0)}) - ${t.name}`)}if(x)if(r.lastLodLevel_Texture<0){if(o.texture_lod=u.max_count-1,z){const y=u.lods[u.max_count-1];z&&console.log(`First Texture LOD ${o.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 $=u.lods[v];if(!(Re()&&$.max_height>4096)&&$.max_height>k){if(o.texture_lod=v,o.texture_lod<r.lastLodLevel_Texture){const I=$.max_height;z&&console.log(`Texture LOD changed: ${r.lastLodLevel_Texture} → ${o.texture_lod} = ${I}px
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
6
  Screensize: ${k.toFixed(0)}px, Coverage: ${(100*r.lastScreenCoverage).toFixed(2)}%, Volume ${y.toFixed(1)}
7
- ${t.name}`)}break}}}else o.texture_lod=0}};let R=C;d(R,"debugDrawLine"),d(R,"corner0",new g.Vector3),d(R,"corner1",new g.Vector3),d(R,"corner2",new g.Vector3),d(R,"corner3",new g.Vector3),d(R,"_tempPtInside",new g.Vector3);class Ge{constructor(){d(this,"frames",0);d(this,"lastLodLevel_Mesh",-1);d(this,"lastLodLevel_Texture",-1);d(this,"lastScreenCoverage",0);d(this,"lastScreenspaceVolume",new g.Vector3);d(this,"lastCentrality",0)}}const xe=Symbol("NEEDLE_mesh_lod"),ee=Symbol("NEEDLE_texture_lod");function Me(){document.removeEventListener("DOMContentLoaded",le),document.addEventListener("DOMContentLoaded",le),le()}function le(){document.querySelectorAll("model-viewer").forEach((e,t)=>{Fe(e,t)})}const me=new WeakSet;function Fe(l,e){if(!l||me.has(l))return null;me.add(l),console.debug("[gltf-progressive] found model-viewer..."+e);let t=null,r=null,i=null;for(let o=l;o!=null;o=Object.getPrototypeOf(o)){const s=Object.getOwnPropertySymbols(o),n=s.find(c=>c.toString()=="Symbol(renderer)"),a=s.find(c=>c.toString()=="Symbol(scene)"),f=s.find(c=>c.toString()=="Symbol(needsRender)");!t&&n!=null&&(t=l[n].threeRenderer),!r&&a!=null&&(r=l[a]),!i&&f!=null&&(i=l[f])}if(t&&r){console.debug("[gltf-progressive] setup model-viewer");const o=R.get(t,{engine:"model-viewer"});if(R.addPlugin(new $e),o.enable(),r&&i){let s=0,n=setInterval(()=>{if(s++>10){clearInterval(n);return}i==null||i.call(l)},150)}return()=>{o.disable()}}return null}class $e{constructor(){d(this,"_didWarnAboutMissingUrl",!1)}onBeforeUpdateLOD(e,t,r,i){this.tryParseMeshLOD(t,i),this.tryParseTextureLOD(t,i)}getUrl(e){if(!e)return null;let t=e.getAttribute("src");return t||(t=e.src),t||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",e),this._didWarnAboutMissingUrl=!0),t}tryGetCurrentGLTF(e){return e._currentGLTF}tryGetCurrentModelViewer(e){return e.element}tryParseTextureLOD(e,t){if(t[ee]==!0)return;t[ee]=!0;const r=this.tryGetCurrentGLTF(e),i=this.tryGetCurrentModelViewer(e),o=this.getUrl(i);if(o&&r&&t.material){let s=function(a){var c,L,u;if(a[ee]==!0)return;a[ee]=!0,a.userData&&(a.userData.LOD=-1);const f=Object.keys(a);for(let x=0;x<f.length;x++){const _=f[x],M=a[_];if((M==null?void 0:M.isTexture)===!0){const B=(L=(c=M.userData)==null?void 0:c.associations)==null?void 0:L.textures;if(B==null)continue;const F=r.parser.json.textures[B];if(!F){console.warn("Texture data not found for texture index "+B);continue}if((u=F==null?void 0:F.extensions)!=null&&u[G]){const y=F.extensions[G];y&&o&&S.registerTexture(o,M,y.lods.length,B,y)}}}};const n=t.material;if(Array.isArray(n))for(const a of n)s(a);else s(n)}}tryParseMeshLOD(e,t){var s,n;if(t[xe]==!0)return;t[xe]=!0;const r=this.tryGetCurrentModelViewer(e),i=this.getUrl(r);if(!i)return;const o=(n=(s=t.userData)==null?void 0:s.gltfExtensions)==null?void 0:n[G];if(o&&i){const a=t.uuid;S.registerMesh(i,a,t,0,o.lods.length,o)}}}Me();function Ve(l,e,t,r){ge(e),pe(t),t.register(o=>new S(o,l));const i=R.get(e);return(r==null?void 0:r.enableLODsManager)!==!1&&i.enable(),i}exports.EXTENSION_NAME=G;exports.LODsManager=R;exports.NEEDLE_progressive=S;exports.VERSION=de;exports.addDracoAndKTX2Loaders=pe;exports.createLoaders=ge;exports.getRaycastMesh=re;exports.patchModelViewer=Me;exports.setDracoDecoderLocation=Ae;exports.setKTX2TranscoderLocation=Pe;exports.setRaycastMesh=Le;exports.useNeedleProgressive=Ve;exports.useRaycastMeshes=Ee;
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;
package/lib/index.js CHANGED
@@ -4,9 +4,6 @@ export * from "./plugins/index.js";
4
4
  export { LODsManager } from "./lods_manager.js";
5
5
  export { setDracoDecoderLocation, setKTX2TranscoderLocation, createLoaders, addDracoAndKTX2Loaders } from "./loaders.js";
6
6
  export * from "./utils.js";
7
- /** Modelviewer */
8
- import { patchModelViewer } from "./plugins/modelviewer.js";
9
- patchModelViewer();
10
7
  import { addDracoAndKTX2Loaders, createLoaders } from "./loaders.js";
11
8
  import { NEEDLE_progressive } from "./extension.js";
12
9
  import { LODsManager } from "./lods_manager.js";
@@ -36,3 +33,6 @@ export function useNeedleProgressive(url, renderer, loader, opts) {
36
33
  }
37
34
  return lod;
38
35
  }
36
+ /** Modelviewer */
37
+ import { patchModelViewer } from "./plugins/modelviewer.js";
38
+ patchModelViewer();
@@ -1,4 +1,4 @@
1
- import { Frustum, Matrix4, Object3D, Vector3, WebGLRenderer } from "three";
1
+ import { Frustum, Material, Matrix4, Object3D, Texture, Vector3, WebGLRenderer } from "three";
2
2
  import { NEEDLE_progressive_plugin } from "./plugins/plugin.js";
3
3
  export type LODManagerContext = {
4
4
  engine: "three" | "needle-engine" | "model-viewer" | "react-three-fiber" | "unknown";
@@ -7,6 +7,11 @@ export declare type LOD_Results = {
7
7
  mesh_lod: number;
8
8
  texture_lod: number;
9
9
  };
10
+ declare type LODChangedEventListener = (args: {
11
+ type: "mesh" | "texture";
12
+ level: number;
13
+ object: Object3D | Material | Texture;
14
+ }) => void;
10
15
  /**
11
16
  * The LODsManager class is responsible for managing the LODs and progressive assets in the scene. It will automatically update the LODs based on the camera position, screen coverage and mesh density of the objects.
12
17
  * It must be enabled by calling the `enable` method.
@@ -69,6 +74,8 @@ export declare class LODsManager {
69
74
  * If set to true, the LODsManager will not update the LODs.
70
75
  */
71
76
  pause: boolean;
77
+ private readonly _lodchangedlisteners;
78
+ addEventListener(evt: "changed", listener: LODChangedEventListener): void;
72
79
  private constructor();
73
80
  private _frame;
74
81
  private _originalRender?;
@@ -90,6 +90,12 @@ export class LODsManager {
90
90
  * If set to true, the LODsManager will not update the LODs.
91
91
  */
92
92
  pause = false;
93
+ _lodchangedlisteners = [];
94
+ addEventListener(evt, listener) {
95
+ if (evt === "changed") {
96
+ this._lodchangedlisteners.push(listener);
97
+ }
98
+ }
93
99
  // readonly plugins: NEEDLE_progressive_plugin[] = [];
94
100
  constructor(renderer, context) {
95
101
  this.renderer = renderer;
@@ -278,7 +284,9 @@ export class LODsManager {
278
284
  }
279
285
  if (update) {
280
286
  material[$currentLOD] = level;
281
- NEEDLE_progressive.assignTextureLOD(material, level);
287
+ NEEDLE_progressive.assignTextureLOD(material, level).then(_ => {
288
+ this._lodchangedlisteners.forEach(l => l({ type: "texture", level, object: material }));
289
+ });
282
290
  }
283
291
  }
284
292
  /** Load progressive meshes for the given mesh
@@ -295,6 +303,7 @@ export class LODsManager {
295
303
  const originalGeometry = mesh.geometry;
296
304
  return NEEDLE_progressive.assignMeshLOD(mesh, level).then(res => {
297
305
  if (res && mesh[$currentLOD] == level && originalGeometry != mesh.geometry) {
306
+ this._lodchangedlisteners.forEach(l => l({ type: "mesh", level, object: mesh }));
298
307
  // if (this.handles) {
299
308
  // for (const inst of this.handles) {
300
309
  // // if (inst["LOD"] < level) continue;
@@ -2,29 +2,64 @@ import { LODsManager } from "../lods_manager.js";
2
2
  import { EXTENSION_NAME, NEEDLE_progressive } from "../extension.js";
3
3
  const $meshLODSymbol = Symbol("NEEDLE_mesh_lod");
4
4
  const $textureLODSymbol = Symbol("NEEDLE_texture_lod");
5
+ let documentObserver = null;
5
6
  export function patchModelViewer() {
6
- document.removeEventListener("DOMContentLoaded", searchModelViewers);
7
- document.addEventListener("DOMContentLoaded", searchModelViewers);
7
+ const ModelViewerElement = tryGetModelViewerConstructor();
8
+ if (!ModelViewerElement) {
9
+ return;
10
+ }
11
+ ModelViewerElement.mapURLs(function (url) {
12
+ searchModelViewers();
13
+ return url;
14
+ });
8
15
  searchModelViewers();
16
+ // observe the document for new model-viewers
17
+ documentObserver?.disconnect();
18
+ documentObserver = new MutationObserver((mutations) => {
19
+ mutations.forEach((mutation) => {
20
+ mutation.addedNodes.forEach((node) => {
21
+ if (node instanceof HTMLElement && node.tagName.toLowerCase() === "model-viewer") {
22
+ _patchModelViewer(node);
23
+ }
24
+ });
25
+ });
26
+ });
27
+ documentObserver.observe(document, { childList: true, subtree: true });
28
+ }
29
+ /**
30
+ * Tries to get the mode-viewer constructor from the custom element registry. If it doesnt exist yet we will wait for it to be loaded in case it's added to the document at a later point
31
+ */
32
+ function tryGetModelViewerConstructor() {
33
+ // If model-viewer is already registered we can ignore this
34
+ const ModelViewerElement = customElements.get('model-viewer');
35
+ if (ModelViewerElement)
36
+ return ModelViewerElement;
37
+ // wait for model-viewer to be defined
38
+ customElements.whenDefined('model-viewer').then(() => {
39
+ console.debug("[gltf-progressive] model-viewer defined");
40
+ patchModelViewer();
41
+ });
42
+ return null;
9
43
  }
10
44
  function searchModelViewers() {
11
45
  // Query once for model viewer. If a user does not have model-viewer in their page, this will return null.
12
46
  const modelviewers = document.querySelectorAll("model-viewer");
13
- modelviewers.forEach((modelviewer, index) => {
14
- _patchModelViewer(modelviewer, index);
47
+ modelviewers.forEach((modelviewer) => {
48
+ _patchModelViewer(modelviewer);
15
49
  });
16
50
  }
17
51
  const foundModelViewers = new WeakSet();
52
+ let modelViewerCount = 0;
18
53
  /** Patch modelviewer to support NEEDLE progressive system
19
54
  * @returns a function to remove the patch
20
55
  */
21
- function _patchModelViewer(modelviewer, index) {
56
+ function _patchModelViewer(modelviewer) {
22
57
  if (!modelviewer)
23
58
  return null;
24
59
  if (foundModelViewers.has(modelviewer))
25
60
  return null;
26
61
  foundModelViewers.add(modelviewer);
27
- console.debug("[gltf-progressive] found model-viewer..." + index);
62
+ console.debug("[gltf-progressive] found new model-viewer..." + (++modelViewerCount) + "\n", modelviewer.getAttribute("src"));
28
63
  // Find the necessary internal methods and properties. We need access to the scene, renderer
29
64
  let renderer = null;
30
65
  let scene = null;
@@ -49,20 +84,33 @@ function _patchModelViewer(modelviewer, index) {
49
84
  const lod = LODsManager.get(renderer, { engine: "model-viewer" });
50
85
  LODsManager.addPlugin(new RegisterModelviewerDataPlugin());
51
86
  lod.enable();
52
- if (scene) {
53
- /**
54
- * For model viewer to immediately update without interaction we need to trigger a few renders
55
- * We do this so that the LODs are loaded
56
- */
87
+ // Trigger a render when a LOD has changed
88
+ lod.addEventListener("changed", () => {
89
+ needsRender?.call(modelviewer);
90
+ });
91
+ // Trigger a render when the model viewer visibility changes
92
+ modelviewer.addEventListener("model-visibility", (evt) => {
93
+ const visible = evt.detail.visible;
94
+ if (visible)
95
+ needsRender?.call(modelviewer);
96
+ });
97
+ modelviewer.addEventListener("load", () => {
98
+ renderFrames();
99
+ });
100
+ /**
101
+ * For model viewer to immediately update without interaction we need to trigger a few renders
102
+ * We do this so that the LODs are loaded
103
+ */
104
+ function renderFrames() {
57
105
  if (needsRender) {
58
106
  let forcedFrames = 0;
59
107
  let interval = setInterval(() => {
60
- if (forcedFrames++ > 10) {
108
+ if (forcedFrames++ > 5) {
61
109
  clearInterval(interval);
62
110
  return;
63
111
  }
64
112
  needsRender?.call(modelviewer);
65
- }, 150);
113
+ }, 300);
66
114
  }
67
115
  }
68
116
  return () => {
package/lib/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  // replaced at build time
2
- export const version = "1.2.2-alpha.2";
2
+ export const version = "1.2.2-alpha.4";
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.2",
3
+ "version": "1.2.2-alpha.4",
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": {