@needle-tools/gltf-progressive 1.2.1-alpha.3 → 1.2.2-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,7 @@
1
- var ve=Object.defineProperty,Le=(t,e,r)=>e in t?ve(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,d=(t,e,r)=>(Le(t,typeof e!="symbol"?e+"":e,r),r);import{BufferGeometry as K,Mesh as $,Material as Me,Texture as W,TextureLoader as De,Matrix4 as ce,Frustum as _e,Sphere as we,Box3 as de,Vector3 as R}from"three";import{GLTFLoader as Oe}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as be}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as Se}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as Te}from"three/examples/jsm/loaders/KTX2Loader.js";let Y="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",re="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(Y+"draco_decoder.js",{method:"head"}).catch(t=>{Y="./include/draco/",re="./include/ktx2/"});function Ae(t){Y=t}function Ee(t){re=t}let U,se,z;function ne(t){U||(U=new Se,U.setDecoderPath(Y),U.setDecoderConfig({type:"js"})),z||(z=new Te,z.setTranscoderPath(re)),se||(se=be),t?z.detectSupport(t):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function oe(t){t.dracoLoader||t.setDRACOLoader(U),t.ktx2Loader||t.setKTX2Loader(z),t.meshoptDecoder||t.setMeshoptDecoder(se)}function J(t){const e=new URL(window.location.href).searchParams.get(t);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function Pe(t,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||t===void 0)return e;const r=t.lastIndexOf("/");if(r>=0){const o=t.substring(0,r+1);for(;o.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return o+e}return e}let Q;function Ie(){return Q!==void 0||(Q=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),J("debugprogressive")&&console.log("isMobileDevice",Q)),Q}const ie=Symbol("needle:raycast-mesh");function Z(t){return t?.[ie]instanceof K?t[ie]:null}function he(t,e){if((t.type==="Mesh"||t.type==="SkinnedMesh")&&!Z(t)){const r=Ce(e);r.userData={isRaycastMesh:!0},t[ie]=r}}function Be(t=!0){if(t){if(q)return;const e=q=$.prototype.raycast;$.prototype.raycast=function(r,o){const s=this,n=Z(s);let i;n&&s.isMesh&&(i=s.geometry,s.geometry=n),e.call(this,r,o),i&&(s.geometry=i)}}else{if(!q)return;$.prototype.raycast=q,q=null}}let q=null;function Ce(t){const e=new K;for(const r in t.attributes)e.setAttribute(r,t.getAttribute(r));return e.setIndex(t.getIndex()),e}const k=new Array,I="NEEDLE_progressive",p=J("debugprogressive"),ae=Symbol("needle-progressive-texture"),V=new Map,le=new Set;if(p){let t=function(){e+=1,console.log("Toggle LOD level",e,V),V.forEach((s,n)=>{for(const i of s.keys){const a=n[i];if(a!=null){if(a.isBufferGeometry===!0){const u=O.getMeshLODInformation(a),l=u?Math.min(e,u.lods.length):0;n["DEBUG:LOD"]=e,O.assignMeshLOD(n,l),u&&(r=Math.max(r,u.lods.length-1))}else if(n.isMaterial===!0){n["DEBUG:LOD"]=e,O.assignTextureLOD(n,e);break}}}}),e>=r&&(e=-1)},e=-1,r=2,o=!1;window.addEventListener("keyup",s=>{s.key==="p"&&t(),s.key==="w"&&(o=!o,le&&le.forEach(n=>{n.name!="BackgroundCubeMaterial"&&n.glyphMap==null&&"wireframe"in n&&(n.wireframe=o)}))})}function fe(t,e,r){var o;if(!p)return;V.has(t)||V.set(t,{keys:[],sourceId:r});const s=V.get(t);((o=s?.keys)==null?void 0:o.includes(e))==!1&&s.keys.push(e)}const _=class{constructor(t,e){d(this,"parser"),d(this,"url"),d(this,"_isLoadingMesh"),d(this,"loadMesh",r=>{var o,s;if(this._isLoadingMesh)return null;const n=(s=(o=this.parser.json.meshes[r])==null?void 0:o.extensions)==null?void 0:s[I];return n?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",r).then(i=>{var a;return this._isLoadingMesh=!1,i&&_.registerMesh(this.url,n.guid,i,(a=n.lods)==null?void 0:a.length,void 0,n),i})):null}),p&&console.log("Progressive extension registered for",e),this.parser=t,this.url=e}get name(){return I}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,o="LODS:minmax",s=t[o];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[o]=e,e}if(p==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const i=t;for(const a of Object.keys(i.uniforms)){const u=i.uniforms[a].value;u?.isTexture===!0&&n(u,e)}}else if(t.isMaterial)for(const i of Object.keys(t)){const a=t[i];a?.isTexture===!0&&n(a,e)}return t[o]=e,e;function n(i,a){const u=r.getAssignedLODInformation(i);if(u){const l=r.lodInfos.get(u.key);if(l&&l.lods){a.min_count=Math.min(a.min_count,l.lods.length),a.max_count=Math.max(a.max_count,l.lods.length);for(let x=0;x<l.lods.length;x++){const c=l.lods[x];c.width&&(a.lods[x]=a.lods[x]||{min_height:1/0,max_height:0},a.lods[x].min_height=Math.min(a.lods[x].min_height,c.height),a.lods[x].max_height=Math.max(a.lods[x].max_height,c.height))}}}}}static hasLODLevelAvailable(t,e){var r;if(Array.isArray(t)){for(const n of t)if(this.hasLODLevelAvailable(n,e))return!0;return!1}if(t.isMaterial===!0){for(const n of Object.keys(t)){const i=t[n];if(i&&i.isTexture&&this.hasLODLevelAvailable(i,e))return!0}return!1}else if(t.isGroup===!0){for(const n of t.children)if(n.isMesh===!0&&this.hasLODLevelAvailable(n,e))return!0}let o,s;if(t.isMesh?o=t.geometry:(t.isBufferGeometry||t.isTexture)&&(o=t),o&&(r=o?.userData)!=null&&r.LODS){const n=o.userData.LODS;if(s=this.lodInfos.get(n.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 $||t.isMesh===!0){const o=t.geometry,s=this.getAssignedLODInformation(o);if(!s)return Promise.resolve(null);for(const n of k)(r=n.onBeforeGetLODMesh)==null||r.call(n,t,e);return t["LOD:requested level"]=e,_.getOrLoadLOD(o,e).then(n=>{if(t["LOD:requested level"]===e){if(delete t["LOD:requested level"],Array.isArray(n)){const i=s.index||0;n=n[i]}n&&o!=n&&(n?.isBufferGeometry?(t.geometry=n,p&&fe(t,"geometry",s.url)):p&&console.error("Invalid LOD geometry",n))}return n}).catch(n=>(console.error("Error loading mesh LOD",t,n),null))}else p&&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 Me||t.isMaterial===!0){const r=t,o=[],s=new Array;if(p&&le.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const n=r;for(const i of Object.keys(n.uniforms)){const a=n.uniforms[i].value;if(a?.isTexture===!0){const u=this.assignTextureLODForSlot(a,e,r,i);o.push(u),s.push(i)}}}else for(const n of Object.keys(r)){const i=r[n];if(i?.isTexture===!0){const a=this.assignTextureLODForSlot(i,e,r,n);o.push(a),s.push(n)}}return Promise.all(o).then(n=>{const i=new Array;for(let a=0;a<n.length;a++){const u=n[a],l=s[a];u&&u.isTexture===!0?i.push({material:r,slot:l,texture:u,level:e}):i.push({material:r,slot:l,texture:null,level:e})}return i})}if(t instanceof W||t.isTexture===!0){const r=t;return this.assignTextureLODForSlot(r,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,r,o){return t?.isTexture!==!0?Promise.resolve(null):o==="glyphMap"?Promise.resolve(t):_.getOrLoadLOD(t,e).then(s=>{if(Array.isArray(s))return null;if(s?.isTexture===!0){if(s!=t){if(r&&o){const n=r[o];if(n){const i=this.getAssignedLODInformation(n);if(i&&i?.level<e)return p==="verbose"&&console.warn("Assigned texture level is already higher: ",i.level,e,r,n,s),null}r[o]=s}if(p&&o&&r){const n=this.getAssignedLODInformation(t);n&&fe(r,o,n.url)}}return s}else p=="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 p&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((o,s)=>{var n;if(o!=null&&o.extensions){const i=o?.extensions[I];if(i){if(!i.lods){p&&console.warn("Texture has no LODs",i);return}let a=!1;for(const u of this.parser.associations.keys())u.isTexture===!0&&this.parser.associations.get(u).textures===s&&(a=!0,_.registerTexture(this.url,u,(n=i.lods)==null?void 0:n.length,s,i));a||this.parser.getDependency("texture",s).then(u=>{var l;u&&_.registerTexture(this.url,u,(l=i.lods)==null?void 0:l.length,s,i)})}}}),(r=this.parser.json.meshes)==null||r.forEach((o,s)=>{if(o!=null&&o.extensions){const n=o?.extensions[I];if(n&&n.lods){for(const i of this.parser.associations.keys())if(i.isMesh){const a=this.parser.associations.get(i);a.meshes===s&&_.registerMesh(this.url,n.guid,i,n.lods.length,a.primitives,n)}}}}),null}static async getOrLoadLOD(t,e){var r,o,s,n;const i=p=="verbose",a=t.userData.LODS;if(!a)return null;const u=a?.key;let l;if(t.isTexture===!0){const x=t;x.source&&x.source[ae]&&(l=x.source[ae])}if(l||(l=_.lodInfos.get(u)),l){if(e>0){let f=!1;const b=Array.isArray(l.lods);if(b&&e>=l.lods.length?f=!0:b||(f=!0),f)return this.lowresCache.get(u)}const x=Array.isArray(l.lods)?(r=l.lods[e])==null?void 0:r.path:l.lods;if(!x)return p&&!l["missing:uri"]&&(l["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,l)),null;const c=Pe(a.url,x);if(c.endsWith(".glb")||c.endsWith(".gltf")){if(!l.guid)return console.warn("missing pointer for glb/gltf texture",l),null;const f=c+"_"+l.guid,b=this.previouslyLoaded.get(f);if(b!==void 0){i&&console.log(`LOD ${e} was already loading/loaded: ${f}`);let m=await b.catch(P=>(console.error(`Error loading LOD ${e} from ${c}
2
- `,P),null)),w=!1;if(m==null||(m instanceof W&&t instanceof W?(o=m.image)!=null&&o.data||(s=m.source)!=null&&s.data?m=this.copySettings(t,m):(w=!0,this.previouslyLoaded.delete(f)):m instanceof K&&t instanceof K&&((n=m.attributes.position)!=null&&n.array||(w=!0,this.previouslyLoaded.delete(f)))),!w)return m}const g=l,L=new Promise(async(m,w)=>{const P=new Oe;oe(P),p&&(await new Promise(v=>setTimeout(v,1e3)),i&&console.warn("Start loading (delayed) "+c,g.guid));let X=c;if(g&&Array.isArray(g.lods)){const v=g.lods[e];v.hash&&(X+="?v="+v.hash)}const S=await P.loadAsync(X).catch(v=>(console.error(`Error loading LOD ${e} from ${c}
3
- `,v),null));if(!S)return null;const M=S.parser;i&&console.log("Loading finished "+c,g.guid);let y=0;if(S.parser.json.textures){let v=!1;for(const h of S.parser.json.textures){if(h!=null&&h.extensions){const D=h?.extensions[I];if(D!=null&&D.guid&&D.guid===g.guid){v=!0;break}}y++}if(v){let h=await M.getDependency("texture",y);return h&&_.assignLODInformation(a.url,h,u,e,void 0,void 0),i&&console.log('change "'+t.name+'" \u2192 "'+h.name+'"',c,y,h,f),t instanceof W&&(h=this.copySettings(t,h)),h&&(h.guid=g.guid),m(h)}else p&&console.warn("Could not find texture with guid",g.guid,S.parser.json)}if(y=0,S.parser.json.meshes){let v=!1;for(const h of S.parser.json.meshes){if(h!=null&&h.extensions){const D=h?.extensions[I];if(D!=null&&D.guid&&D.guid===g.guid){v=!0;break}}y++}if(v){const h=await M.getDependency("mesh",y),D=g;if(i&&console.log(`Loaded Mesh "${h.name}"`,c,y,h,f),h.isMesh===!0){const A=h.geometry;return _.assignLODInformation(a.url,A,u,e,void 0,D.density),m(A)}else{const A=new Array;for(let C=0;C<h.children.length;C++){const F=h.children[C];if(F.isMesh===!0){const j=F.geometry;_.assignLODInformation(a.url,j,u,e,C,D.density),A.push(j)}}return m(A)}}else p&&console.warn("Could not find mesh with guid",g.guid,S.parser.json)}return m(null)});return this.previouslyLoaded.set(f,L),await L}else if(t instanceof W){i&&console.log("Load texture from uri: "+c);const f=await new De().loadAsync(c);return f?(f.guid=l.guid,f.flipY=!1,f.needsUpdate=!0,f.colorSpace=t.colorSpace,i&&console.log(l,f)):p&&console.warn("failed loading",c),f}}else p&&console.warn(`Can not load LOD ${e}: no LOD info found for "${u}" ${t.name}`,t.type);return null}static assignLODInformation(t,e,r,o,s,n){if(!e)return;e.userData||(e.userData={});const i=new Re(t,r,o,s,n);e.userData.LODS=i}static getAssignedLODInformation(t){var e;return((e=t?.userData)==null?void 0:e.LODS)||null}static copySettings(t,e){return e=e.clone(),p&&console.warn(`Copying texture settings
1
+ var _e=Object.defineProperty,we=(t,e,r)=>e in t?_e(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,d=(t,e,r)=>(we(t,typeof e!="symbol"?e+"":e,r),r);import{BufferGeometry as Q,Mesh as $,Material as Oe,Texture as W,TextureLoader as be,Matrix4 as fe,Frustum as Se,Sphere as Te,Box3 as me,Vector3 as R}from"three";import{GLTFLoader as Ae}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as Ee}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as Ie}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as Pe}from"three/examples/jsm/loaders/KTX2Loader.js";const se="";globalThis.GLTF_PROGRESSIVE_VERSION=se,console.debug(`[gltf-progressive] version ${se}`);let Z="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",oe="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(Z+"draco_decoder.js",{method:"head"}).catch(t=>{Z="./include/draco/",oe="./include/ktx2/"});function Ce(t){Z=t}function Be(t){oe=t}let U,ne,V;function ie(t){U||(U=new Ie,U.setDecoderPath(Z),U.setDecoderConfig({type:"js"})),V||(V=new Pe,V.setTranscoderPath(oe)),ne||(ne=Ee),t?V.detectSupport(t):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function ae(t){t.dracoLoader||t.setDRACOLoader(U),t.ktx2Loader||t.setKTX2Loader(V),t.meshoptDecoder||t.setMeshoptDecoder(ne)}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 Re(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 J;function ke(){return J!==void 0||(J=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),q("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",J)),J}const le=Symbol("needle:raycast-mesh");function ee(t){return t?.[le]instanceof Q?t[le]:null}function pe(t,e){if((t.type==="Mesh"||t.type==="SkinnedMesh")&&!ee(t)){const r=Ge(e);r.userData={isRaycastMesh:!0},t[le]=r}}function je(t=!0){if(t){if(X)return;const e=X=$.prototype.raycast;$.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(!X)return;$.prototype.raycast=X,X=null}}let X=null;function Ge(t){const e=new Q;for(const r in t.attributes)e.setAttribute(r,t.getAttribute(r));return e.setIndex(t.getIndex()),e}const k=new Array,C="NEEDLE_progressive",y=q("debugprogressive"),ue=Symbol("needle-progressive-texture"),K=new Map,ce=new Set;if(y){let t=function(){e+=1,console.log("Toggle LOD level",e,K),K.forEach((o,s)=>{for(const i of o.keys){const a=s[i];if(a!=null){if(a.isBufferGeometry===!0){const u=O.getMeshLODInformation(a),l=u?Math.min(e,u.lods.length):0;s["DEBUG:LOD"]=e,O.assignMeshLOD(s,l),u&&(r=Math.max(r,u.lods.length-1))}else if(s.isMaterial===!0){s["DEBUG:LOD"]=e,O.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,ce&&ce.forEach(s=>{s.name!="BackgroundCubeMaterial"&&s.glyphMap==null&&"wireframe"in s&&(s.wireframe=n)}))})}function xe(t,e,r){var n;if(!y)return;K.has(t)||K.set(t,{keys:[],sourceId:r});const o=K.get(t);((n=o?.keys)==null?void 0:n.includes(e))==!1&&o.keys.push(e)}const _=class{constructor(t,e){d(this,"parser"),d(this,"url"),d(this,"_isLoadingMesh"),d(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[C];return s?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",r).then(i=>{var a;return this._isLoadingMesh=!1,i&&_.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 C}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 u=i.uniforms[a].value;u?.isTexture===!0&&s(u,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 u=r.getAssignedLODInformation(i);if(u){const l=r.lodInfos.get(u.key);if(l&&l.lods){a.min_count=Math.min(a.min_count,l.lods.length),a.max_count=Math.max(a.max_count,l.lods.length);for(let m=0;m<l.lods.length;m++){const c=l.lods[m];c.width&&(a.lods[m]=a.lods[m]||{min_height:1/0,max_height:0},a.lods[m].min_height=Math.min(a.lods[m].min_height,c.height),a.lods[m].max_height=Math.max(a.lods[m].max_height,c.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 $||t.isMesh===!0){const n=t.geometry,o=this.getAssignedLODInformation(n);if(!o)return Promise.resolve(null);for(const s of k)(r=s.onBeforeGetLODMesh)==null||r.call(s,t,e);return t["LOD:requested level"]=e,_.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&&xe(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 Oe||t.isMaterial===!0){const r=t,n=[],o=new Array;if(y&&ce.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 u=this.assignTextureLODForSlot(a,e,r,i);n.push(u),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 u=s[a],l=o[a];u&&u.isTexture===!0?i.push({material:r,slot:l,texture:u,level:e}):i.push({material:r,slot:l,texture:null,level:e})}return i})}if(t instanceof W||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):_.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&&xe(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[C];if(i){if(!i.lods){y&&console.warn("Texture has no LODs",i);return}let a=!1;for(const u of this.parser.associations.keys())u.isTexture===!0&&this.parser.associations.get(u).textures===o&&(a=!0,_.registerTexture(this.url,u,(s=i.lods)==null?void 0:s.length,o,i));a||this.parser.getDependency("texture",o).then(u=>{var l;u&&_.registerTexture(this.url,u,(l=i.lods)==null?void 0:l.length,o,i)})}}}),(r=this.parser.json.meshes)==null||r.forEach((n,o)=>{if(n!=null&&n.extensions){const s=n?.extensions[C];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&&_.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 u=a?.key;let l;if(t.isTexture===!0){const m=t;m.source&&m.source[ue]&&(l=m.source[ue])}if(l||(l=_.lodInfos.get(u)),l){if(e>0){let f=!1;const S=Array.isArray(l.lods);if(S&&e>=l.lods.length?f=!0:S||(f=!0),f)return this.lowresCache.get(u)}const m=Array.isArray(l.lods)?(r=l.lods[e])==null?void 0:r.path:l.lods;if(!m)return y&&!l["missing:uri"]&&(l["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,l)),null;const c=Re(a.url,m);if(c.endsWith(".glb")||c.endsWith(".gltf")){if(!l.guid)return console.warn("missing pointer for glb/gltf texture",l),null;const f=c+"_"+l.guid,S=this.previouslyLoaded.get(f);if(S!==void 0){i&&console.log(`LOD ${e} was already loading/loaded: ${f}`);let g=await S.catch(D=>(console.error(`Error loading LOD ${e} from ${c}
2
+ `,D),null)),b=!1;if(g==null||(g instanceof W&&t instanceof W?(n=g.image)!=null&&n.data||(o=g.source)!=null&&o.data?g=this.copySettings(t,g):(b=!0,this.previouslyLoaded.delete(f)):g instanceof Q&&t instanceof Q&&((s=g.attributes.position)!=null&&s.array||(b=!0,this.previouslyLoaded.delete(f)))),!b)return g}const M=l,v=new Promise(async(g,b)=>{const D=new Ae;ae(D),y&&(await new Promise(p=>setTimeout(p,1e3)),i&&console.warn("Start loading (delayed) "+c,M.guid));let T=c;if(M&&Array.isArray(M.lods)){const p=M.lods[e];p.hash&&(T+="?v="+p.hash)}const A=await D.loadAsync(T).catch(p=>(console.error(`Error loading LOD ${e} from ${c}
3
+ `,p),null));if(!A)return null;const F=A.parser;i&&console.log("Loading finished "+c,M.guid);let x=0;if(A.parser.json.textures){let p=!1;for(const h of A.parser.json.textures){if(h!=null&&h.extensions){const L=h?.extensions[C];if(L!=null&&L.guid&&L.guid===M.guid){p=!0;break}}x++}if(p){let h=await F.getDependency("texture",x);return h&&_.assignLODInformation(a.url,h,u,e,void 0,void 0),i&&console.log('change "'+t.name+'" \u2192 "'+h.name+'"',c,x,h,f),t instanceof W&&(h=this.copySettings(t,h)),h&&(h.guid=M.guid),g(h)}else y&&console.warn("Could not find texture with guid",M.guid,A.parser.json)}if(x=0,A.parser.json.meshes){let p=!1;for(const h of A.parser.json.meshes){if(h!=null&&h.extensions){const L=h?.extensions[C];if(L!=null&&L.guid&&L.guid===M.guid){p=!0;break}}x++}if(p){const h=await F.getDependency("mesh",x),L=M;if(i&&console.log(`Loaded Mesh "${h.name}"`,c,x,h,f),h.isMesh===!0){const w=h.geometry;return _.assignLODInformation(a.url,w,u,e,void 0,L.density),g(w)}else{const w=new Array;for(let P=0;P<h.children.length;P++){const j=h.children[P];if(j.isMesh===!0){const N=j.geometry;_.assignLODInformation(a.url,N,u,e,P,L.density),w.push(N)}}return g(w)}}else y&&console.warn("Could not find mesh with guid",M.guid,A.parser.json)}return g(null)});return this.previouslyLoaded.set(f,v),await v}else if(t instanceof W){i&&console.log("Load texture from uri: "+c);const f=await new be().loadAsync(c);return f?(f.guid=l.guid,f.flipY=!1,f.needsUpdate=!0,f.colorSpace=t.colorSpace,i&&console.log(l,f)):y&&console.warn("failed loading",c),f}}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,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
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 O=_;d(O,"registerTexture",(t,e,r,o,s)=>{if(p&&console.log("> Progressive: register texture",o,e.name,e.uuid,e,s),!e){p&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[ae]=s);const n=s.guid;_.assignLODInformation(t,e,n,r,o,void 0),_.lodInfos.set(n,s),_.lowresCache.set(n,e)}),d(O,"registerMesh",(t,e,r,o,s,n)=>{var i;p&&console.log("> Progressive: register mesh",s,r.name,n,r.uuid,r);const a=r.geometry;if(!a){p&&console.warn("gltf-progressive: Register mesh without geometry");return}a.userData||(a.userData={}),_.assignLODInformation(t,a,e,o,s,n.density),_.lodInfos.set(e,n);let u=_.lowresCache.get(e);u?u.push(r.geometry):u=[r.geometry],_.lowresCache.set(e,u),o>0&&!Z(r)&&he(r,a);for(const l of k)(i=l.onRegisteredNewMesh)==null||i.call(l,r,n)}),d(O,"lodInfos",new Map),d(O,"previouslyLoaded",new Map),d(O,"lowresCache",new Map);class Re{constructor(e,r,o,s,n){d(this,"url"),d(this,"key"),d(this,"level"),d(this,"index"),d(this,"density"),this.url=e,this.key=r,this.level=o,s!=null&&(this.index=s),n!=null&&(this.density=n)}}const G=J("debugprogressive"),ke=J("noprogressive"),ge=Symbol("Needle:LODSManager"),ue=Symbol("Needle:LODState"),N=Symbol("Needle:CurrentLOD"),E={mesh_lod:-1,texture_lod:-1},T=class{constructor(t){d(this,"renderer"),d(this,"projectionScreenMatrix",new ce),d(this,"cameraFrustrum",new _e),d(this,"targetTriangleDensity",2e5),d(this,"updateInterval",0),d(this,"pause",!1),d(this,"_frame",0),d(this,"_originalRender"),d(this,"_sphere",new we),d(this,"_tempBox",new de),d(this,"_tempBox2",new de),d(this,"tempMatrix",new ce),d(this,"_tempWorldPosition",new R),d(this,"_tempBoxSize",new R),d(this,"_tempBox2Size",new R),this.renderer=t}static getObjectLODState(t){return t[ue]}static addPlugin(t){k.push(t)}static removePlugin(t){const e=k.indexOf(t);e>=0&&k.splice(e,1)}static get(t){return t[ge]?t[ge]:new T(t)}get plugins(){return k}enable(){if(this._originalRender)return;let t=0;this._originalRender=this.renderer.render;const e=this;ne(this.renderer),this.renderer.render=function(r,o){e.renderer.getRenderTarget()==null&&(t=0,e._frame+=1);const s=e._frame,n=t++;e.onBeforeRender(r,o,n,s),e._originalRender.call(this,r,o),e.onAfterRender(r,o,n,s)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(t,e,r,o){}onAfterRender(t,e,r,o){var s,n;if(this.pause)return;const i=this.renderer.renderLists.get(t,0),a=i.opaque;let u=!0;if(a.length===1){const l=a[0].material;(l.name==="EffectMaterial"||l.name==="CopyShader")&&(u=!1)}if((e.parent&&e.parent.type==="CubeCamera"||r>=1&&e.type==="OrthographicCamera")&&(u=!1),u){if(ke||this.updateInterval>0&&o%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const l=this.targetTriangleDensity;for(const c of a){if(c.material&&(((s=c.geometry)==null?void 0:s.type)==="BoxGeometry"||((n=c.geometry)==null?void 0:n.type)==="BufferGeometry")&&(c.material.name==="SphericalGaussianBlur"||c.material.name=="BackgroundCubeMaterial"||c.material.name==="CubemapFromEquirect"||c.material.name==="EquirectangularToCubeUV")){G&&(c.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(c.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",c,c.material.name,c.material.type)));continue}switch(c.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}const f=c.object;(f instanceof $||f.isMesh)&&this.updateLODs(t,e,f,l,o)}const x=i.transparent;for(const c of x){const f=c.object;(f instanceof $||f.isMesh)&&this.updateLODs(t,e,f,l,o)}}}updateLODs(t,e,r,o,s){var n,i;r.userData||(r.userData={});let a=r[ue];if(a||(a=new je,r[ue]=a),a.frames++<2)return;for(const l of k)(n=l.onBeforeUpdateLOD)==null||n.call(l,this.renderer,t,e,r);this.calculateLodLevel(e,r,a,o,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 u=E.texture_lod;if(r.material&&u>=0){const l=r["DEBUG:LOD"];l!=null&&(u=l),this.loadProgressiveTextures(r.material,u)}for(const l of k)(i=l.onAfterUpdatedLOD)==null||i.call(l,this.renderer,t,e,r,E);a.lastLodLevel_Mesh=E.mesh_lod,a.lastLodLevel_Texture=E.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const o of t)this.loadProgressiveTextures(o,e);return}let r=!1;(t[N]===void 0||e<t[N])&&(r=!0),r&&(t[N]=e,O.assignTextureLOD(t,e))}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);if(t[N]!==e){t[N]=e;const r=t.geometry;return O.assignMeshLOD(t,e).then(o=>(o&&t[N]==e&&r!=t.geometry,o))}return Promise.resolve(null)}static isInside(t,e){const r=t.min,o=t.max,s=(r.x+o.x)*.5,n=(r.y+o.y)*.5;return this._tempPtInside.set(s,n,r.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,r,o,s){var n;if(!e){s.mesh_lod=-1,s.texture_lod=-1;return}if(!t){s.mesh_lod=-1,s.texture_lod=-1;return}let i=10+1,a=!1;if(G&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const u=O.getMeshLODInformation(e.geometry),l=u?.lods,x=l&&l.length>0,c=O.getMaterialMinMaxLODsCount(e.material),f=c?.min_count!=1/0&&c.min_count>0&&c.max_count>0;if(!x&&!f){s.mesh_lod=0,s.texture_lod=0;return}if(x||(a=!0,i=0),!((n=this.cameraFrustrum)!=null&&n.intersectsObject(e))){s.mesh_lod=99,s.texture_lod=99;return}let b=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const g=e;g.boundingBox||g.computeBoundingBox(),b=g.boundingBox}if(b&&t.isPerspectiveCamera){const g=t;if(e.geometry.attributes.color&&e.geometry.attributes.color.count<100&&e.geometry.boundingSphere){this._sphere.copy(e.geometry.boundingSphere),this._sphere.applyMatrix4(e.matrixWorld);const M=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(M)){s.mesh_lod=0,s.texture_lod=0;return}}if(this._tempBox.copy(b),e.type==="SkinnedMesh"?e.parent&&this._tempBox.applyMatrix4(e.parent.matrixWorld):this._tempBox.applyMatrix4(e.matrixWorld),T.isInside(this._tempBox,this.projectionScreenMatrix)){s.mesh_lod=0,s.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&g.fov>70){const M=this._tempBox.min,y=this._tempBox.max;let v=M.x,h=M.y,D=y.x,A=y.y;const C=2,F=1.5,j=(M.x+y.x)*.5,H=(M.y+y.y)*.5;v=(v-j)*C+j,h=(h-H)*C+H,D=(D-j)*C+j,A=(A-H)*C+H;const xe=v<0&&D>0?0:Math.min(Math.abs(M.x),Math.abs(y.x)),ye=h<0&&A>0?0:Math.min(Math.abs(M.y),Math.abs(y.y)),te=Math.max(xe,ye);r.lastCentrality=(F-te)*(F-te)*(F-te)}else r.lastCentrality=1;const L=this._tempBox.getSize(this._tempBoxSize);L.multiplyScalar(.5),screen.availHeight>0&&L.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),L.x*=g.aspect;const m=t.matrixWorldInverse,w=this._tempBox2;w.copy(b),w.applyMatrix4(e.matrixWorld),w.applyMatrix4(m);const P=w.getSize(this._tempBox2Size),X=Math.max(P.x,P.y);if(Math.max(L.x,L.y)!=0&&X!=0&&(L.z=P.z/Math.max(P.x,P.y)*Math.max(L.x,L.y)),r.lastScreenCoverage=Math.max(L.x,L.y,L.z),r.lastScreenspaceVolume.copy(L),r.lastScreenCoverage*=r.lastCentrality,G&&T.debugDrawLine){const M=this.tempMatrix.copy(this.projectionScreenMatrix);M.invert();const y=T.corner0,v=T.corner1,h=T.corner2,D=T.corner3;y.copy(this._tempBox.min),v.copy(this._tempBox.max),v.x=y.x,h.copy(this._tempBox.max),h.y=y.y,D.copy(this._tempBox.max);const A=(y.z+D.z)*.5;y.z=v.z=h.z=D.z=A,y.applyMatrix4(M),v.applyMatrix4(M),h.applyMatrix4(M),D.applyMatrix4(M),T.debugDrawLine(y,v,255),T.debugDrawLine(y,h,255),T.debugDrawLine(v,D,255),T.debugDrawLine(h,D,255)}let S=999;if(l&&r.lastScreenCoverage>0){for(let M=0;M<l.length;M++)if(l[M].density/r.lastScreenCoverage<o){S=M;break}}S<i&&(i=S,a=!0)}if(a?s.mesh_lod=i:s.mesh_lod=r.lastLodLevel_Mesh,G&&s.mesh_lod!=r.lastLodLevel_Mesh){const g=l?.[s.mesh_lod];g&&console.log(`Mesh LOD changed: ${r.lastLodLevel_Mesh} \u2192 ${s.mesh_lod} (${g.density.toFixed(0)}) - ${e.name}`)}if(f)if(r.lastLodLevel_Texture<0){if(s.texture_lod=c.max_count-1,G){const g=c.lods[c.max_count-1];G&&console.log(`First Texture LOD ${s.texture_lod} (${g.max_height}px) - ${e.name}`)}}else{const g=r.lastScreenCoverage*1.5,L=this.renderer.domElement.clientHeight/window.devicePixelRatio*g;for(let m=c.lods.length-1;m>=0;m--){const w=c.lods[m];if(!(Ie()&&w.max_height>4096)&&w.max_height>L){s.texture_lod=m,s.texture_lod<r.lastLodLevel_Texture&&G&&console.log(`Texture LOD changed: ${r.lastLodLevel_Texture} \u2192 ${s.texture_lod} (${w.max_height}px: ${(100*r.lastScreenCoverage).toFixed(2)} % = ${L.toFixed(0)}px) - ${e.name}`);break}}}else s.texture_lod=0}};let B=T;d(B,"debugDrawLine"),d(B,"corner0",new R),d(B,"corner1",new R),d(B,"corner2",new R),d(B,"corner3",new R),d(B,"_tempPtInside",new R);class je{constructor(){d(this,"frames",0),d(this,"lastLodLevel_Mesh",-1),d(this,"lastLodLevel_Texture",-1),d(this,"lastScreenCoverage",0),d(this,"lastScreenspaceVolume",new R),d(this,"lastCentrality",0)}}const me=Symbol("NEEDLE_mesh_lod"),ee=Symbol("NEEDLE_texture_lod");function pe(t){if(!t)return null;let e=null,r=null;for(let o=t;o!=null;o=Object.getPrototypeOf(o)){const s=Object.getOwnPropertySymbols(o),n=s.find(a=>a.toString()=="Symbol(renderer)"),i=s.find(a=>a.toString()=="Symbol(scene)");!e&&n!=null&&(e=t[n].threeRenderer),!r&&i!=null&&(r=t[i])}if(e){const o=B.get(e);if(B.addPlugin(new Ge(t)),o.enable(),r){const s=r.camera||r.traverse(n=>n.type=="PerspectiveCamera")[0];s&&e.render(r,s)}return()=>{o.disable()}}return null}class Ge{constructor(e){d(this,"modelviewer"),d(this,"_didWarnAboutMissingUrl",!1),this.modelviewer=e}onBeforeUpdateLOD(e,r,o,s){this.tryParseMeshLOD(r,s),this.tryParseTextureLOD(r,s)}getUrl(){let e=this.modelviewer.getAttribute("src");return e||(e=this.modelviewer.src),e||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",this.modelviewer),this._didWarnAboutMissingUrl=!0),e}tryGetCurrentGLTF(e){return e._currentGLTF}tryParseTextureLOD(e,r){if(r[ee]==!0)return;r[ee]=!0;const o=this.tryGetCurrentGLTF(e),s=this.getUrl();if(s&&o&&r.material){let n=function(a){var u,l,x;if(a[ee]==!0)return;a[ee]=!0,a.userData&&(a.userData.LOD=-1);const c=Object.keys(a);for(let f=0;f<c.length;f++){const b=c[f],g=a[b];if(g?.isTexture===!0){const L=(l=(u=g.userData)==null?void 0:u.associations)==null?void 0:l.textures,m=o.parser.json.textures[L];if(!m){console.warn("Texture data not found for texture index "+L);continue}if((x=m?.extensions)!=null&&x[I]){const w=m.extensions[I];w&&s&&O.registerTexture(s,g,w.lods.length,L,w)}}}};const i=r.material;if(Array.isArray(i))for(const a of i)n(a);else n(i)}}tryParseMeshLOD(e,r){var o,s;if(r[me]==!0)return;r[me]=!0;const n=this.getUrl();if(!n)return;const i=(s=(o=r.userData)==null?void 0:o.gltfExtensions)==null?void 0:s[I];if(i&&n){const a=r.uuid;O.registerMesh(n,a,r,0,i.lods.length,i)}}}document.addEventListener("DOMContentLoaded",()=>{pe(document.querySelector("model-viewer"))});function Fe(t,e,r,o){ne(e),oe(r),r.register(n=>new O(n,t));const s=B.get(e);return o?.enableLODsManager!==!1&&s.enable(),s}export{I as EXTENSION_NAME,B as LODsManager,O as NEEDLE_progressive,oe as addDracoAndKTX2Loaders,ne as createLoaders,Z as getRaycastMesh,pe as patchModelViewer,Ae as setDracoDecoderLocation,Ee as setKTX2TranscoderLocation,he as setRaycastMesh,Fe as useNeedleProgressive,Be 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 O=_;d(O,"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[ue]=o);const s=o.guid;_.assignLODInformation(t,e,s,r,n,void 0),_.lodInfos.set(s,o),_.lowresCache.set(s,e)}),d(O,"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={}),_.assignLODInformation(t,a,e,n,o,s.density),_.lodInfos.set(e,s);let u=_.lowresCache.get(e);u?u.push(r.geometry):u=[r.geometry],_.lowresCache.set(e,u),n>0&&!ee(r)&&pe(r,a);for(const l of k)(i=l.onRegisteredNewMesh)==null||i.call(l,r,s)}),d(O,"lodInfos",new Map),d(O,"previouslyLoaded",new Map),d(O,"lowresCache",new Map);class Fe{constructor(e,r,n,o,s){d(this,"url"),d(this,"key"),d(this,"level"),d(this,"index"),d(this,"density"),this.url=e,this.key=r,this.level=n,o!=null&&(this.index=o),s!=null&&(this.density=s)}}const G=q("debugprogressive"),Ne=q("noprogressive"),de=Symbol("Needle:LODSManager"),he=Symbol("Needle:LODState"),z=Symbol("Needle:CurrentLOD"),I={mesh_lod:-1,texture_lod:-1},E=class{constructor(t,e){d(this,"context"),d(this,"renderer"),d(this,"projectionScreenMatrix",new fe),d(this,"cameraFrustrum",new Se),d(this,"targetTriangleDensity",2e5),d(this,"updateInterval",0),d(this,"pause",!1),d(this,"_frame",0),d(this,"_originalRender"),d(this,"_sphere",new Te),d(this,"_tempBox",new me),d(this,"_tempBox2",new me),d(this,"tempMatrix",new fe),d(this,"_tempWorldPosition",new R),d(this,"_tempBoxSize",new R),d(this,"_tempBox2Size",new R),this.renderer=t,this.context={...e}}static getObjectLODState(t){return t[he]}static addPlugin(t){k.push(t)}static removePlugin(t){const e=k.indexOf(t);e>=0&&k.splice(e,1)}static get(t,e){if(t[de])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[de];const r=new E(t,{engine:"unknown",...e});return t[de]=r,r}get plugins(){return k}enable(){if(this._originalRender)return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let t=0;this._originalRender=this.renderer.render;const e=this;ie(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 u=!0;if(a.length===1){const l=a[0].material;(l.name==="EffectMaterial"||l.name==="CopyShader")&&(u=!1)}if((e.parent&&e.parent.type==="CubeCamera"||r>=1&&e.type==="OrthographicCamera")&&(u=!1),u){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 l=this.targetTriangleDensity;for(const c of a){if(c.material&&(((o=c.geometry)==null?void 0:o.type)==="BoxGeometry"||((s=c.geometry)==null?void 0:s.type)==="BufferGeometry")&&(c.material.name==="SphericalGaussianBlur"||c.material.name=="BackgroundCubeMaterial"||c.material.name==="CubemapFromEquirect"||c.material.name==="EquirectangularToCubeUV")){G&&(c.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(c.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",c,c.material.name,c.material.type)));continue}switch(c.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}const f=c.object;(f instanceof $||f.isMesh)&&this.updateLODs(t,e,f,l,n)}const m=i.transparent;for(const c of m){const f=c.object;(f instanceof $||f.isMesh)&&this.updateLODs(t,e,f,l,n)}}}updateLODs(t,e,r,n,o){var s,i;r.userData||(r.userData={});let a=r[he];if(a||(a=new $e,r[he]=a),a.frames++<2)return;for(const l of k)(s=l.onBeforeUpdateLOD)==null||s.call(l,this.renderer,t,e,r);this.calculateLodLevel(e,r,a,n,I),I.mesh_lod=Math.round(I.mesh_lod),I.texture_lod=Math.round(I.texture_lod),I.mesh_lod>=0&&this.loadProgressiveMeshes(r,I.mesh_lod);let u=I.texture_lod;if(r.material&&u>=0){const l=r["DEBUG:LOD"];l!=null&&(u=l),this.loadProgressiveTextures(r.material,u)}for(const l of k)(i=l.onAfterUpdatedLOD)==null||i.call(l,this.renderer,t,e,r,I);a.lastLodLevel_Mesh=I.mesh_lod,a.lastLodLevel_Texture=I.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[z]===void 0||e<t[z])&&(r=!0),r&&(t[z]=e,O.assignTextureLOD(t,e))}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);if(t[z]!==e){t[z]=e;const r=t.geometry;return O.assignMeshLOD(t,e).then(n=>(n&&t[z]==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;if(!e){o.mesh_lod=-1,o.texture_lod=-1;return}if(!t){o.mesh_lod=-1,o.texture_lod=-1;return}let i=10+1,a=!1;if(G&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const u=O.getMeshLODInformation(e.geometry),l=u?.lods,m=l&&l.length>0,c=O.getMaterialMinMaxLODsCount(e.material),f=c?.min_count!=1/0&&c.min_count>0&&c.max_count>0;if(!m&&!f){o.mesh_lod=0,o.texture_lod=0;return}if(m||(a=!0,i=0),!((s=this.cameraFrustrum)!=null&&s.intersectsObject(e))){o.mesh_lod=99,o.texture_lod=99;return}const S=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let M=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const v=e;v.boundingBox||v.computeBoundingBox(),M=v.boundingBox}if(M&&t.isPerspectiveCamera){const v=t;if(e.geometry.attributes.color&&e.geometry.attributes.color.count<100&&e.geometry.boundingSphere){this._sphere.copy(e.geometry.boundingSphere),this._sphere.applyMatrix4(e.matrixWorld);const x=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(x)){o.mesh_lod=0,o.texture_lod=0;return}}if(this._tempBox.copy(M),this._tempBox.applyMatrix4(e.matrixWorld),E.isInside(this._tempBox,this.projectionScreenMatrix)){o.mesh_lod=0,o.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&v.fov>70){const x=this._tempBox.min,p=this._tempBox.max;let h=x.x,L=x.y,w=p.x,P=p.y;const j=2,N=1.5,H=(x.x+p.x)*.5,Y=(x.y+p.y)*.5;h=(h-H)*j+H,L=(L-Y)*j+Y,w=(w-H)*j+H,P=(P-Y)*j+Y;const Me=h<0&&w>0?0:Math.min(Math.abs(x.x),Math.abs(p.x)),De=L<0&&P>0?0:Math.min(Math.abs(x.y),Math.abs(p.y)),re=Math.max(Me,De);r.lastCentrality=(N-re)*(N-re)*(N-re)}else r.lastCentrality=1;const g=this._tempBox.getSize(this._tempBoxSize);g.multiplyScalar(.5),screen.availHeight>0&&S>0&&g.multiplyScalar(S/screen.availHeight),g.x*=v.aspect;const b=t.matrixWorldInverse,D=this._tempBox2;D.copy(M),D.applyMatrix4(e.matrixWorld),D.applyMatrix4(b);const T=D.getSize(this._tempBox2Size),A=Math.max(T.x,T.y);if(Math.max(g.x,g.y)!=0&&A!=0&&(g.z=T.z/Math.max(T.x,T.y)*Math.max(g.x,g.y)),r.lastScreenCoverage=Math.max(g.x,g.y,g.z),r.lastScreenspaceVolume.copy(g),r.lastScreenCoverage*=r.lastCentrality,G&&E.debugDrawLine){const x=this.tempMatrix.copy(this.projectionScreenMatrix);x.invert();const p=E.corner0,h=E.corner1,L=E.corner2,w=E.corner3;p.copy(this._tempBox.min),h.copy(this._tempBox.max),h.x=p.x,L.copy(this._tempBox.max),L.y=p.y,w.copy(this._tempBox.max);const P=(p.z+w.z)*.5;p.z=h.z=L.z=w.z=P,p.applyMatrix4(x),h.applyMatrix4(x),L.applyMatrix4(x),w.applyMatrix4(x),E.debugDrawLine(p,h,255),E.debugDrawLine(p,L,255),E.debugDrawLine(h,w,255),E.debugDrawLine(L,w,255)}let F=999;if(l&&r.lastScreenCoverage>0){for(let x=0;x<l.length;x++)if(l[x].density/r.lastScreenCoverage<n){F=x;break}}F<i&&(i=F,a=!0)}if(a?o.mesh_lod=i:o.mesh_lod=r.lastLodLevel_Mesh,G&&o.mesh_lod!=r.lastLodLevel_Mesh){const v=l?.[o.mesh_lod];v&&console.log(`Mesh LOD changed: ${r.lastLodLevel_Mesh} \u2192 ${o.mesh_lod} (${v.density.toFixed(0)}) - ${e.name}`)}if(f)if(r.lastLodLevel_Texture<0){if(o.texture_lod=c.max_count-1,G){const v=c.lods[c.max_count-1];G&&console.log(`First Texture LOD ${o.texture_lod} (${v.max_height}px) - ${e.name}`)}}else{const v=r.lastScreenspaceVolume.x+r.lastScreenspaceVolume.y+r.lastScreenspaceVolume.z,g=r.lastScreenCoverage*2,b=S/window.devicePixelRatio*g;for(let D=c.lods.length-1;D>=0;D--){let T=c.lods[D];if(!(ke()&&T.max_height>4096)&&T.max_height>b){if(o.texture_lod=D,o.texture_lod<r.lastLodLevel_Texture){const A=T.max_height;G&&console.log(`Texture LOD changed: ${r.lastLodLevel_Texture} \u2192 ${o.texture_lod} = ${A}px
6
+ Screensize: ${b.toFixed(0)}px, Coverage: ${(100*r.lastScreenCoverage).toFixed(2)}%, Volume ${v.toFixed(1)}
7
+ ${e.name}`)}break}}}else o.texture_lod=0}};let B=E;d(B,"debugDrawLine"),d(B,"corner0",new R),d(B,"corner1",new R),d(B,"corner2",new R),d(B,"corner3",new R),d(B,"_tempPtInside",new R);class $e{constructor(){d(this,"frames",0),d(this,"lastLodLevel_Mesh",-1),d(this,"lastLodLevel_Texture",-1),d(this,"lastScreenCoverage",0),d(this,"lastScreenspaceVolume",new R),d(this,"lastCentrality",0)}}const ye=Symbol("NEEDLE_mesh_lod"),te=Symbol("NEEDLE_texture_lod");function ve(){document.removeEventListener("DOMContentLoaded",ge),document.addEventListener("DOMContentLoaded",ge),ge()}function ge(){document.querySelectorAll("model-viewer").forEach((t,e)=>{ze(t,e)})}const Le=new WeakSet;function ze(t,e){if(!t||Le.has(t))return null;Le.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(m=>m.toString()=="Symbol(renderer)"),u=i.find(m=>m.toString()=="Symbol(scene)"),l=i.find(m=>m.toString()=="Symbol(needsRender)");!r&&a!=null&&(r=t[a].threeRenderer),!n&&u!=null&&(n=t[u]),!o&&l!=null&&(o=t[l])}if(r&&n){console.debug("[gltf-progressive] setup model-viewer");const s=B.get(r,{engine:"model-viewer"});if(B.addPlugin(new We),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 We{constructor(){d(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(u){var l,m,c;if(u[te]==!0)return;u[te]=!0,u.userData&&(u.userData.LOD=-1);const f=Object.keys(u);for(let S=0;S<f.length;S++){const M=f[S],v=u[M];if(v?.isTexture===!0){const g=(m=(l=v.userData)==null?void 0:l.associations)==null?void 0:m.textures;if(g==null)continue;const b=n.parser.json.textures[g];if(!b){console.warn("Texture data not found for texture index "+g);continue}if((c=b?.extensions)!=null&&c[C]){const D=b.extensions[C];D&&s&&O.registerTexture(s,v,D.lods.length,g,D)}}}};const a=r.material;if(Array.isArray(a))for(const u of a)i(u);else i(a)}}tryParseMeshLOD(e,r){var n,o;if(r[ye]==!0)return;r[ye]=!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[C];if(a&&i){const u=r.uuid;O.registerMesh(i,u,r,0,a.lods.length,a)}}}ve();function Ue(t,e,r,n){ie(e),ae(r),r.register(s=>new O(s,t));const o=B.get(e);return n?.enableLODsManager!==!1&&o.enable(),o}export{C as EXTENSION_NAME,B as LODsManager,O as NEEDLE_progressive,se as VERSION,ae as addDracoAndKTX2Loaders,ie as createLoaders,ee as getRaycastMesh,ve as patchModelViewer,Ce as setDracoDecoderLocation,Be as setKTX2TranscoderLocation,pe as setRaycastMesh,Ue as useNeedleProgressive,je as useRaycastMeshes};
@@ -1,5 +1,7 @@
1
- "use strict";var Le=Object.defineProperty;var me=(l,e,t)=>e in l?Le(l,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):l[e]=t;var d=(l,e,t)=>(me(l,typeof e!="symbol"?e+"":e,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const p=require("three"),Me=require("three/examples/jsm/loaders/GLTFLoader.js"),De=require("three/examples/jsm/libs/meshopt_decoder.module.js"),_e=require("three/examples/jsm/loaders/DRACOLoader.js"),we=require("three/examples/jsm/loaders/KTX2Loader.js");let Z="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",le="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(Z+"draco_decoder.js",{method:"head"}).catch(l=>{Z="./include/draco/",le="./include/ktx2/"});function Oe(l){Z=l}function ve(l){le=l}let q,oe,K;function ce(l){q||(q=new _e.DRACOLoader,q.setDecoderPath(Z),q.setDecoderConfig({type:"js"})),K||(K=new we.KTX2Loader,K.setTranscoderPath(le)),oe||(oe=De.MeshoptDecoder),l?K.detectSupport(l):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function ue(l){l.dracoLoader||l.setDRACOLoader(q),l.ktx2Loader||l.setKTX2Loader(K),l.meshoptDecoder||l.setMeshoptDecoder(oe)}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 Se(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 W;function Te(){return W!==void 0||(W=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),j("debugprogressive")&&console.log("isMobileDevice",W)),W}const ne=Symbol("needle:raycast-mesh");function ee(l){return(l==null?void 0:l[ne])instanceof p.BufferGeometry?l[ne]:null}function ge(l,e){if((l.type==="Mesh"||l.type==="SkinnedMesh")&&!ee(l)){const r=Ae(e);r.userData={isRaycastMesh:!0},l[ne]=r}}function be(l=!0){if(l){if(V)return;const e=V=p.Mesh.prototype.raycast;p.Mesh.prototype.raycast=function(t,r){const i=this,o=ee(i);let s;o&&i.isMesh&&(s=i.geometry,i.geometry=o),e.call(this,t,r),s&&(i.geometry=s)}}else{if(!V)return;p.Mesh.prototype.raycast=V,V=null}}let V=null;function Ae(l){const e=new p.BufferGeometry;for(const t in l.attributes)e.setAttribute(t,l.getAttribute(t));return e.setIndex(l.getIndex()),e}const F=new Array,E="NEEDLE_progressive",x=j("debugprogressive"),se=Symbol("needle-progressive-texture"),X=new Map,ae=new Set;if(x){let l=function(){e+=1,console.log("Toggle LOD level",e,X),X.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),h=a?Math.min(e,a.lods.length):0;o["DEBUG:LOD"]=e,S.assignMeshLOD(o,h),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,ae&&ae.forEach(o=>{o.name!="BackgroundCubeMaterial"&&o.glyphMap==null&&"wireframe"in o&&(o.wireframe=r)}))})}function fe(l,e,t){var i;if(!x)return;X.has(l)||X.set(l,{keys:[],sourceId:t});const r=X.get(l);((i=r==null?void 0:r.keys)==null?void 0:i.includes(e))==!1&&r.keys.push(e)}const v=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[E];return t?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",e).then(o=>{var s;return this._isLoadingMesh=!1,o&&v.registerMesh(this.url,t.guid,o,(s=t.lods)==null?void 0:s.length,void 0,t),o})):null});x&&console.log("Progressive extension registered for",t),this.parser=e,this.url=t}get name(){return E}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(x==="verbose"&&console.log("getMaterialMinMaxLODsCount",e),e.type==="ShaderMaterial"||e.type==="RawShaderMaterial"){const n=e;for(const a of Object.keys(n.uniforms)){const h=n.uniforms[a].value;(h==null?void 0:h.isTexture)===!0&&s(h,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 h=r.getAssignedLODInformation(n);if(h){const c=r.lodInfos.get(h.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 p.Mesh||e.isMesh===!0){const i=e.geometry,o=this.getAssignedLODInformation(i);if(!o)return Promise.resolve(null);for(const s of F)(r=s.onBeforeGetLODMesh)==null||r.call(s,e,t);return e["LOD:requested level"]=t,v.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,x&&fe(e,"geometry",o.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 p.Material||e.isMaterial===!0){const r=e,i=[],o=new Array;if(x&&ae.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 h=this.assignTextureLODForSlot(a,t,r,n);i.push(h),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 h=s[a],c=o[a];h&&h.isTexture===!0?n.push({material:r,slot:c,texture:h,level:t}):n.push({material:r,slot:c,texture:null,level:t})}return n})}if(e instanceof p.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):v.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 x==="verbose"&&console.warn("Assigned texture level is already higher: ",n.level,t,r,s,o),null}r[i]=o}if(x&&i&&r){const s=this.getAssignedLODInformation(e);s&&fe(r,i,s.url)}}return o}else x=="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 x&&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[E];if(n){if(!n.lods){x&&console.warn("Texture has no LODs",n);return}let a=!1;for(const h of this.parser.associations.keys())h.isTexture===!0&&this.parser.associations.get(h).textures===o&&(a=!0,v.registerTexture(this.url,h,(s=n.lods)==null?void 0:s.length,o,n));a||this.parser.getDependency("texture",o).then(h=>{var c;h&&v.registerTexture(this.url,h,(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[E];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&&v.registerMesh(this.url,s.guid,n,s.lods.length,a.primitives,s)}}}}),null}static async getOrLoadLOD(e,t){var n,a,h,c;const r=x=="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[se]&&(s=L.source[se])}if(s||(s=v.lodInfos.get(o)),s){if(t>0){let y=!1;const m=Array.isArray(s.lods);if(m&&t>=s.lods.length?y=!0:m||(y=!0),y)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 x&&!s["missing:uri"]&&(s["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+t,s)),null;const u=Se(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 y=u+"_"+s.guid,m=this.previouslyLoaded.get(y);if(m!==void 0){r&&console.log(`LOD ${t} was already loading/loaded: ${y}`);let O=await m.catch(P=>(console.error(`Error loading LOD ${t} from ${u}
2
- `,P),null)),A=!1;if(O==null||(O instanceof p.Texture&&e instanceof p.Texture?(a=O.image)!=null&&a.data||(h=O.source)!=null&&h.data?O=this.copySettings(e,O):(A=!0,this.previouslyLoaded.delete(y)):O instanceof p.BufferGeometry&&e instanceof p.BufferGeometry&&((c=O.attributes.position)!=null&&c.array||(A=!0,this.previouslyLoaded.delete(y)))),!A)return O}const w=s,_=new Promise(async(O,A)=>{const P=new Me.GLTFLoader;ue(P),x&&(await new Promise(g=>setTimeout(g,1e3)),r&&console.warn("Start loading (delayed) "+u,w.guid));let Y=u;if(w&&Array.isArray(w.lods)){const g=w.lods[t];g.hash&&(Y+="?v="+g.hash)}const k=await P.loadAsync(Y).catch(g=>(console.error(`Error loading LOD ${t} from ${u}
3
- `,g),null));if(!k)return null;const z=k.parser;r&&console.log("Loading finished "+u,w.guid);let I=0;if(k.parser.json.textures){let g=!1;for(const f of k.parser.json.textures){if(f!=null&&f.extensions){const M=f==null?void 0:f.extensions[E];if(M!=null&&M.guid&&M.guid===w.guid){g=!0;break}}I++}if(g){let f=await z.getDependency("texture",I);return f&&v.assignLODInformation(i.url,f,o,t,void 0,void 0),r&&console.log('change "'+e.name+'" → "'+f.name+'"',u,I,f,y),e instanceof p.Texture&&(f=this.copySettings(e,f)),f&&(f.guid=w.guid),O(f)}else x&&console.warn("Could not find texture with guid",w.guid,k.parser.json)}if(I=0,k.parser.json.meshes){let g=!1;for(const f of k.parser.json.meshes){if(f!=null&&f.extensions){const M=f==null?void 0:f.extensions[E];if(M!=null&&M.guid&&M.guid===w.guid){g=!0;break}}I++}if(g){const f=await z.getDependency("mesh",I),M=w;if(r&&console.log(`Loaded Mesh "${f.name}"`,u,I,f,y),f.isMesh===!0){const T=f.geometry;return v.assignLODInformation(i.url,T,o,t,void 0,M.density),O(T)}else{const T=new Array;for(let b=0;b<f.children.length;b++){const G=f.children[b];if(G.isMesh===!0){const $=G.geometry;v.assignLODInformation(i.url,$,o,t,b,M.density),T.push($)}}return O(T)}}else x&&console.warn("Could not find mesh with guid",w.guid,k.parser.json)}return O(null)});return this.previouslyLoaded.set(y,_),await _}else if(e instanceof p.Texture){r&&console.log("Load texture from uri: "+u);const m=await new p.TextureLoader().loadAsync(u);return m?(m.guid=s.guid,m.flipY=!1,m.needsUpdate=!0,m.colorSpace=e.colorSpace,r&&console.log(s,m)):x&&console.warn("failed loading",u),m}}else x&&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 Pe(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(),x&&console.warn(`Copying texture settings
1
+ "use strict";var we=Object.defineProperty;var _e=(l,e,t)=>e in l?we(l,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):l[e]=t;var h=(l,e,t)=>(_e(l,typeof e!="symbol"?e+"":e,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const p=require("three"),ve=require("three/examples/jsm/loaders/GLTFLoader.js"),Oe=require("three/examples/jsm/libs/meshopt_decoder.module.js"),Se=require("three/examples/jsm/loaders/DRACOLoader.js"),Te=require("three/examples/jsm/loaders/KTX2Loader.js"),fe="";globalThis.GLTF_PROGRESSIVE_VERSION=fe;console.debug(`[gltf-progressive] version ${fe}`);let ee="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",de="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(ee+"draco_decoder.js",{method:"head"}).catch(l=>{ee="./include/draco/",de="./include/ktx2/"});function be(l){ee=l}function Ae(l){de=l}let K,le,X;function he(l){K||(K=new Se.DRACOLoader,K.setDecoderPath(ee),K.setDecoderConfig({type:"js"})),X||(X=new Te.KTX2Loader,X.setTranscoderPath(de)),le||(le=Oe.MeshoptDecoder),l?X.detectSupport(l):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function ge(l){l.dracoLoader||l.setDRACOLoader(K),l.ktx2Loader||l.setKTX2Loader(X),l.meshoptDecoder||l.setMeshoptDecoder(le)}H("debugprogressive");function H(l){const t=new URL(window.location.href).searchParams.get(l);return t==null||t==="0"||t==="false"?!1:t===""?!0:t}function Pe(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 W;function Ce(){return W!==void 0||(W=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),H("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",W)),W}const ce=Symbol("needle:raycast-mesh");function te(l){return(l==null?void 0:l[ce])instanceof p.BufferGeometry?l[ce]:null}function Le(l,e){if((l.type==="Mesh"||l.type==="SkinnedMesh")&&!te(l)){const r=Ee(e);r.userData={isRaycastMesh:!0},l[ce]=r}}function Re(l=!0){if(l){if(q)return;const e=q=p.Mesh.prototype.raycast;p.Mesh.prototype.raycast=function(t,r){const i=this,o=te(i);let s;o&&i.isMesh&&(s=i.geometry,i.geometry=o),e.call(this,t,r),s&&(i.geometry=s)}}else{if(!q)return;p.Mesh.prototype.raycast=q,q=null}}let q=null;function Ee(l){const e=new p.BufferGeometry;for(const t in l.attributes)e.setAttribute(t,l.getAttribute(t));return e.setIndex(l.getIndex()),e}const $=new Array,G="NEEDLE_progressive",L=H("debugprogressive"),oe=Symbol("needle-progressive-texture"),Y=new Map,ue=new Set;if(L){let l=function(){e+=1,console.log("Toggle LOD level",e,Y),Y.forEach((i,o)=>{for(const s of i.keys){const n=o[s];if(n!=null){if(n.isBufferGeometry===!0){const a=v.getMeshLODInformation(n),d=a?Math.min(e,a.lods.length):0;o["DEBUG:LOD"]=e,v.assignMeshLOD(o,d),a&&(t=Math.max(t,a.lods.length-1))}else if(o.isMaterial===!0){o["DEBUG:LOD"]=e,v.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,ue&&ue.forEach(o=>{o.name!="BackgroundCubeMaterial"&&o.glyphMap==null&&"wireframe"in o&&(o.wireframe=r)}))})}function pe(l,e,t){var i;if(!L)return;Y.has(l)||Y.set(l,{keys:[],sourceId:t});const r=Y.get(l);((i=r==null?void 0:r.keys)==null?void 0:i.includes(e))==!1&&r.keys.push(e)}const w=class{constructor(e,t){h(this,"parser");h(this,"url");h(this,"_isLoadingMesh");h(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&&w.registerMesh(this.url,t.guid,o,(s=t.lods)==null?void 0:s.length,void 0,t),o})):null});L&&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(L==="verbose"&&console.log("getMaterialMinMaxLODsCount",e),e.type==="ShaderMaterial"||e.type==="RawShaderMaterial"){const n=e;for(const a of Object.keys(n.uniforms)){const d=n.uniforms[a].value;(d==null?void 0:d.isTexture)===!0&&s(d,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 d=r.getAssignedLODInformation(n);if(d){const c=r.lodInfos.get(d.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 m=0;m<c.lods.length;m++){const f=c.lods[m];f.width&&(a.lods[m]=a.lods[m]||{min_height:1/0,max_height:0},a.lods[m].min_height=Math.min(a.lods[m].min_height,f.height),a.lods[m].max_height=Math.max(a.lods[m].max_height,f.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 p.Mesh||e.isMesh===!0){const i=e.geometry,o=this.getAssignedLODInformation(i);if(!o)return Promise.resolve(null);for(const s of $)(r=s.onBeforeGetLODMesh)==null||r.call(s,e,t);return e["LOD:requested level"]=t,w.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,L&&pe(e,"geometry",o.url)):L&&console.error("Invalid LOD geometry",s))}return s}).catch(s=>(console.error("Error loading mesh LOD",e,s),null))}else L&&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 p.Material||e.isMaterial===!0){const r=e,i=[],o=new Array;if(L&&ue.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 d=this.assignTextureLODForSlot(a,t,r,n);i.push(d),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 d=s[a],c=o[a];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 p.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):w.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 L==="verbose"&&console.warn("Assigned texture level is already higher: ",n.level,t,r,s,o),null}r[i]=o}if(L&&i&&r){const s=this.getAssignedLODInformation(e);s&&pe(r,i,s.url)}}return o}else L=="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 L&&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){L&&console.warn("Texture has no LODs",n);return}let a=!1;for(const d of this.parser.associations.keys())d.isTexture===!0&&this.parser.associations.get(d).textures===o&&(a=!0,w.registerTexture(this.url,d,(s=n.lods)==null?void 0:s.length,o,n));a||this.parser.getDependency("texture",o).then(d=>{var c;d&&w.registerTexture(this.url,d,(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&&w.registerMesh(this.url,s.guid,n,s.lods.length,a.primitives,s)}}}}),null}static async getOrLoadLOD(e,t){var n,a,d,c;const r=L=="verbose",i=e.userData.LODS;if(!i)return null;const o=i==null?void 0:i.key;let s;if(e.isTexture===!0){const m=e;m.source&&m.source[oe]&&(s=m.source[oe])}if(s||(s=w.lodInfos.get(o)),s){if(t>0){let x=!1;const D=Array.isArray(s.lods);if(D&&t>=s.lods.length?x=!0:D||(x=!0),x)return this.lowresCache.get(o)}const m=Array.isArray(s.lods)?(n=s.lods[t])==null?void 0:n.path:s.lods;if(!m)return L&&!s["missing:uri"]&&(s["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+t,s)),null;const f=Pe(i.url,m);if(f.endsWith(".glb")||f.endsWith(".gltf")){if(!s.guid)return console.warn("missing pointer for glb/gltf texture",s),null;const x=f+"_"+s.guid,D=this.previouslyLoaded.get(x);if(D!==void 0){r&&console.log(`LOD ${t} was already loading/loaded: ${x}`);let g=await D.catch(R=>(console.error(`Error loading LOD ${t} from ${f}
2
+ `,R),null)),V=!1;if(g==null||(g instanceof p.Texture&&e instanceof p.Texture?(a=g.image)!=null&&a.data||(d=g.source)!=null&&d.data?g=this.copySettings(e,g):(V=!0,this.previouslyLoaded.delete(x)):g instanceof p.BufferGeometry&&e instanceof p.BufferGeometry&&((c=g.attributes.position)!=null&&c.array||(V=!0,this.previouslyLoaded.delete(x)))),!V)return g}const M=s,I=new Promise(async(g,V)=>{const R=new ve.GLTFLoader;ge(R),L&&(await new Promise(A=>setTimeout(A,1e3)),r&&console.warn("Start loading (delayed) "+f,M.guid));let b=f;if(M&&Array.isArray(M.lods)){const A=M.lods[t];A.hash&&(b+="?v="+A.hash)}const T=await R.loadAsync(b).catch(A=>(console.error(`Error loading LOD ${t} from ${f}
3
+ `,A),null));if(!T)return null;const U=T.parser;r&&console.log("Loading finished "+f,M.guid);let B=0;if(T.parser.json.textures){let A=!1;for(const u of T.parser.json.textures){if(u!=null&&u.extensions){const y=u==null?void 0:u.extensions[G];if(y!=null&&y.guid&&y.guid===M.guid){A=!0;break}}B++}if(A){let u=await U.getDependency("texture",B);return u&&w.assignLODInformation(i.url,u,o,t,void 0,void 0),r&&console.log('change "'+e.name+'" → "'+u.name+'"',f,B,u,x),e instanceof p.Texture&&(u=this.copySettings(e,u)),u&&(u.guid=M.guid),g(u)}else L&&console.warn("Could not find texture with guid",M.guid,T.parser.json)}if(B=0,T.parser.json.meshes){let A=!1;for(const u of T.parser.json.meshes){if(u!=null&&u.extensions){const y=u==null?void 0:u.extensions[G];if(y!=null&&y.guid&&y.guid===M.guid){A=!0;break}}B++}if(A){const u=await U.getDependency("mesh",B),y=M;if(r&&console.log(`Loaded Mesh "${u.name}"`,f,B,u,x),u.isMesh===!0){const O=u.geometry;return w.assignLODInformation(i.url,O,o,t,void 0,y.density),g(O)}else{const O=new Array;for(let S=0;S<u.children.length;S++){const P=u.children[S];if(P.isMesh===!0){const F=P.geometry;w.assignLODInformation(i.url,F,o,t,S,y.density),O.push(F)}}return g(O)}}else L&&console.warn("Could not find mesh with guid",M.guid,T.parser.json)}return g(null)});return this.previouslyLoaded.set(x,I),await I}else if(e instanceof p.Texture){r&&console.log("Load texture from uri: "+f);const D=await new p.TextureLoader().loadAsync(f);return D?(D.guid=s.guid,D.flipY=!1,D.needsUpdate=!0,D.colorSpace=e.colorSpace,r&&console.log(s,D)):L&&console.warn("failed loading",f),D}}else L&&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 Be(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(),L&&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=v;d(S,"registerTexture",(e,t,r,i,o)=>{if(x&&console.log("> Progressive: register texture",i,t.name,t.uuid,t,o),!t){x&&console.error("gltf-progressive: Register texture without texture");return}t.source&&(t.source[se]=o);const s=o.guid;v.assignLODInformation(e,t,s,r,i,void 0),v.lodInfos.set(s,o),v.lowresCache.set(s,t)}),d(S,"registerMesh",(e,t,r,i,o,s)=>{var h;x&&console.log("> Progressive: register mesh",o,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={}),v.assignLODInformation(e,n,t,i,o,s.density),v.lodInfos.set(t,s);let a=v.lowresCache.get(t);a?a.push(r.geometry):a=[r.geometry],v.lowresCache.set(t,a),i>0&&!ee(r)&&ge(r,n);for(const c of F)(h=c.onRegisteredNewMesh)==null||h.call(c,r,s)}),d(S,"lodInfos",new Map),d(S,"previouslyLoaded",new Map),d(S,"lowresCache",new Map);class Pe{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 N=j("debugprogressive"),Be=j("noprogressive"),de=Symbol("Needle:LODSManager"),ie=Symbol("Needle:LODState"),U=Symbol("Needle:CurrentLOD"),R={mesh_lod:-1,texture_lod:-1},B=class{constructor(e){d(this,"renderer");d(this,"projectionScreenMatrix",new p.Matrix4);d(this,"cameraFrustrum",new p.Frustum);d(this,"targetTriangleDensity",2e5);d(this,"updateInterval",0);d(this,"pause",!1);d(this,"_frame",0);d(this,"_originalRender");d(this,"_sphere",new p.Sphere);d(this,"_tempBox",new p.Box3);d(this,"_tempBox2",new p.Box3);d(this,"tempMatrix",new p.Matrix4);d(this,"_tempWorldPosition",new p.Vector3);d(this,"_tempBoxSize",new p.Vector3);d(this,"_tempBox2Size",new p.Vector3);this.renderer=e}static getObjectLODState(e){return e[ie]}static addPlugin(e){F.push(e)}static removePlugin(e){const t=F.indexOf(e);t>=0&&F.splice(t,1)}static get(e){return e[de]?e[de]:new B(e)}get plugins(){return F}enable(){if(this._originalRender)return;let e=0;this._originalRender=this.renderer.render;const t=this;ce(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,h;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(Be||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"||((h=u.geometry)==null?void 0:h.type)==="BufferGeometry")&&(u.material.name==="SphericalGaussianBlur"||u.material.name=="BackgroundCubeMaterial"||u.material.name==="CubemapFromEquirect"||u.material.name==="EquirectangularToCubeUV")){N&&(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 y=u.object;(y instanceof p.Mesh||y.isMesh)&&this.updateLODs(e,t,y,c,i)}const L=o.transparent;for(const u of L){const y=u.object;(y instanceof p.Mesh||y.isMesh)&&this.updateLODs(e,t,y,c,i)}}}updateLODs(e,t,r,i,o){var a,h;r.userData||(r.userData={});let s=r[ie];if(s||(s=new Ce,r[ie]=s),s.frames++<2)return;for(const c of F)(a=c.onBeforeUpdateLOD)==null||a.call(c,this.renderer,e,t,r);this.calculateLodLevel(t,r,s,i,R),R.mesh_lod=Math.round(R.mesh_lod),R.texture_lod=Math.round(R.texture_lod),R.mesh_lod>=0&&this.loadProgressiveMeshes(r,R.mesh_lod);let n=R.texture_lod;if(r.material&&n>=0){const c=r["DEBUG:LOD"];c!=null&&(n=c),this.loadProgressiveTextures(r.material,n)}for(const c of F)(h=c.onAfterUpdatedLOD)==null||h.call(c,this.renderer,e,t,r,R);s.lastLodLevel_Mesh=R.mesh_lod,s.lastLodLevel_Texture=R.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 w;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(N&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const h=S.getMeshLODInformation(t.geometry),c=h==null?void 0:h.lods,L=c&&c.length>0,u=S.getMaterialMinMaxLODsCount(t.material),y=(u==null?void 0:u.min_count)!=1/0&&u.min_count>0&&u.max_count>0;if(!L&&!y){o.mesh_lod=0,o.texture_lod=0;return}if(L||(a=!0,n=0),!((w=this.cameraFrustrum)!=null&&w.intersectsObject(t))){o.mesh_lod=99,o.texture_lod=99;return}let m=t.geometry.boundingBox;if(t.type==="SkinnedMesh"){const _=t;_.boundingBox||_.computeBoundingBox(),m=_.boundingBox}if(m&&e.isPerspectiveCamera){const _=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 g=e.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(g)){o.mesh_lod=0,o.texture_lod=0;return}}if(this._tempBox.copy(m),t.type==="SkinnedMesh"?t.parent&&this._tempBox.applyMatrix4(t.parent.matrixWorld):this._tempBox.applyMatrix4(t.matrixWorld),B.isInside(this._tempBox,this.projectionScreenMatrix)){o.mesh_lod=0,o.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&_.fov>70){const g=this._tempBox.min,f=this._tempBox.max;let M=g.x,T=g.y,b=f.x,G=f.y;const $=2,te=1.5,H=(g.x+f.x)*.5,J=(g.y+f.y)*.5;M=(M-H)*$+H,T=(T-J)*$+J,b=(b-H)*$+H,G=(G-J)*$+J;const ye=M<0&&b>0?0:Math.min(Math.abs(g.x),Math.abs(f.x)),xe=T<0&&G>0?0:Math.min(Math.abs(g.y),Math.abs(f.y)),re=Math.max(ye,xe);r.lastCentrality=(te-re)*(te-re)*(te-re)}else r.lastCentrality=1;const D=this._tempBox.getSize(this._tempBoxSize);D.multiplyScalar(.5),screen.availHeight>0&&D.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),D.x*=_.aspect;const O=e.matrixWorldInverse,A=this._tempBox2;A.copy(m),A.applyMatrix4(t.matrixWorld),A.applyMatrix4(O);const P=A.getSize(this._tempBox2Size),Y=Math.max(P.x,P.y);if(Math.max(D.x,D.y)!=0&&Y!=0&&(D.z=P.z/Math.max(P.x,P.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,N&&B.debugDrawLine){const g=this.tempMatrix.copy(this.projectionScreenMatrix);g.invert();const f=B.corner0,M=B.corner1,T=B.corner2,b=B.corner3;f.copy(this._tempBox.min),M.copy(this._tempBox.max),M.x=f.x,T.copy(this._tempBox.max),T.y=f.y,b.copy(this._tempBox.max);const G=(f.z+b.z)*.5;f.z=M.z=T.z=b.z=G,f.applyMatrix4(g),M.applyMatrix4(g),T.applyMatrix4(g),b.applyMatrix4(g),B.debugDrawLine(f,M,255),B.debugDrawLine(f,T,255),B.debugDrawLine(M,b,255),B.debugDrawLine(T,b,255)}let z=999;if(c&&r.lastScreenCoverage>0){for(let g=0;g<c.length;g++)if(c[g].density/r.lastScreenCoverage<i){z=g;break}}z<n&&(n=z,a=!0)}if(a?o.mesh_lod=n:o.mesh_lod=r.lastLodLevel_Mesh,N&&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(y)if(r.lastLodLevel_Texture<0){if(o.texture_lod=u.max_count-1,N){const _=u.lods[u.max_count-1];N&&console.log(`First Texture LOD ${o.texture_lod} (${_.max_height}px) - ${t.name}`)}}else{const _=r.lastScreenCoverage*1.5,O=this.renderer.domElement.clientHeight/window.devicePixelRatio*_;for(let A=u.lods.length-1;A>=0;A--){const P=u.lods[A];if(!(Te()&&P.max_height>4096)&&P.max_height>O){o.texture_lod=A,o.texture_lod<r.lastLodLevel_Texture&&N&&console.log(`Texture LOD changed: ${r.lastLodLevel_Texture} → ${o.texture_lod} (${P.max_height}px: ${(100*r.lastScreenCoverage).toFixed(2)} % = ${O.toFixed(0)}px) - ${t.name}`);break}}}else o.texture_lod=0}};let C=B;d(C,"debugDrawLine"),d(C,"corner0",new p.Vector3),d(C,"corner1",new p.Vector3),d(C,"corner2",new p.Vector3),d(C,"corner3",new p.Vector3),d(C,"_tempPtInside",new p.Vector3);class Ce{constructor(){d(this,"frames",0);d(this,"lastLodLevel_Mesh",-1);d(this,"lastLodLevel_Texture",-1);d(this,"lastScreenCoverage",0);d(this,"lastScreenspaceVolume",new p.Vector3);d(this,"lastCentrality",0)}}const he=Symbol("NEEDLE_mesh_lod"),Q=Symbol("NEEDLE_texture_lod");function pe(l){if(!l)return null;let e=null,t=null;for(let r=l;r!=null;r=Object.getPrototypeOf(r)){const i=Object.getOwnPropertySymbols(r),o=i.find(n=>n.toString()=="Symbol(renderer)"),s=i.find(n=>n.toString()=="Symbol(scene)");!e&&o!=null&&(e=l[o].threeRenderer),!t&&s!=null&&(t=l[s])}if(e){const r=C.get(e);if(C.addPlugin(new Re(l)),r.enable(),t){const i=t.camera||t.traverse(o=>o.type=="PerspectiveCamera")[0];i&&e.render(t,i)}return()=>{r.disable()}}return null}class Re{constructor(e){d(this,"modelviewer");d(this,"_didWarnAboutMissingUrl",!1);this.modelviewer=e}onBeforeUpdateLOD(e,t,r,i){this.tryParseMeshLOD(t,i),this.tryParseTextureLOD(t,i)}getUrl(){let e=this.modelviewer.getAttribute("src");return e||(e=this.modelviewer.src),e||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",this.modelviewer),this._didWarnAboutMissingUrl=!0),e}tryGetCurrentGLTF(e){return e._currentGLTF}tryParseTextureLOD(e,t){if(t[Q]==!0)return;t[Q]=!0;const r=this.tryGetCurrentGLTF(e),i=this.getUrl();if(i&&r&&t.material){let o=function(n){var h,c,L;if(n[Q]==!0)return;n[Q]=!0,n.userData&&(n.userData.LOD=-1);const a=Object.keys(n);for(let u=0;u<a.length;u++){const y=a[u],m=n[y];if((m==null?void 0:m.isTexture)===!0){const w=(c=(h=m.userData)==null?void 0:h.associations)==null?void 0:c.textures,_=r.parser.json.textures[w];if(!_){console.warn("Texture data not found for texture index "+w);continue}if((L=_==null?void 0:_.extensions)!=null&&L[E]){const D=_.extensions[E];D&&i&&S.registerTexture(i,m,D.lods.length,w,D)}}}};const s=t.material;if(Array.isArray(s))for(const n of s)o(n);else o(s)}}tryParseMeshLOD(e,t){var o,s;if(t[he]==!0)return;t[he]=!0;const r=this.getUrl();if(!r)return;const i=(s=(o=t.userData)==null?void 0:o.gltfExtensions)==null?void 0:s[E];if(i&&r){const n=t.uuid;S.registerMesh(r,n,t,0,i.lods.length,i)}}}document.addEventListener("DOMContentLoaded",()=>{pe(document.querySelector("model-viewer"))});function Ee(l,e,t,r){ce(e),ue(t),t.register(o=>new S(o,l));const i=C.get(e);return(r==null?void 0:r.enableLODsManager)!==!1&&i.enable(),i}exports.EXTENSION_NAME=E;exports.LODsManager=C;exports.NEEDLE_progressive=S;exports.addDracoAndKTX2Loaders=ue;exports.createLoaders=ce;exports.getRaycastMesh=ee;exports.patchModelViewer=pe;exports.setDracoDecoderLocation=Oe;exports.setKTX2TranscoderLocation=ve;exports.setRaycastMesh=ge;exports.useNeedleProgressive=Ee;exports.useRaycastMeshes=be;
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 v=w;h(v,"registerTexture",(e,t,r,i,o)=>{if(L&&console.log("> Progressive: register texture",i,t.name,t.uuid,t,o),!t){L&&console.error("gltf-progressive: Register texture without texture");return}t.source&&(t.source[oe]=o);const s=o.guid;w.assignLODInformation(e,t,s,r,i,void 0),w.lodInfos.set(s,o),w.lowresCache.set(s,t)}),h(v,"registerMesh",(e,t,r,i,o,s)=>{var d;L&&console.log("> Progressive: register mesh",o,r.name,s,r.uuid,r);const n=r.geometry;if(!n){L&&console.warn("gltf-progressive: Register mesh without geometry");return}n.userData||(n.userData={}),w.assignLODInformation(e,n,t,i,o,s.density),w.lodInfos.set(t,s);let a=w.lowresCache.get(t);a?a.push(r.geometry):a=[r.geometry],w.lowresCache.set(t,a),i>0&&!te(r)&&Le(r,n);for(const c of $)(d=c.onRegisteredNewMesh)==null||d.call(c,r,s)}),h(v,"lodInfos",new Map),h(v,"previouslyLoaded",new Map),h(v,"lowresCache",new Map);class Be{constructor(e,t,r,i,o){h(this,"url");h(this,"key");h(this,"level");h(this,"index");h(this,"density");this.url=e,this.key=t,this.level=r,i!=null&&(this.index=i),o!=null&&(this.density=o)}}const N=H("debugprogressive"),ke=H("noprogressive"),ie=Symbol("Needle:LODSManager"),ne=Symbol("Needle:LODState"),z=Symbol("Needle:CurrentLOD"),k={mesh_lod:-1,texture_lod:-1},C=class{constructor(e,t){h(this,"context");h(this,"renderer");h(this,"projectionScreenMatrix",new p.Matrix4);h(this,"cameraFrustrum",new p.Frustum);h(this,"targetTriangleDensity",2e5);h(this,"updateInterval",0);h(this,"pause",!1);h(this,"_frame",0);h(this,"_originalRender");h(this,"_sphere",new p.Sphere);h(this,"_tempBox",new p.Box3);h(this,"_tempBox2",new p.Box3);h(this,"tempMatrix",new p.Matrix4);h(this,"_tempWorldPosition",new p.Vector3);h(this,"_tempBoxSize",new p.Vector3);h(this,"_tempBox2Size",new p.Vector3);this.renderer=e,this.context={...t}}static getObjectLODState(e){return e[ne]}static addPlugin(e){$.push(e)}static removePlugin(e){const t=$.indexOf(e);t>=0&&$.splice(t,1)}static get(e,t){if(e[ie])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),e[ie];const r=new C(e,{engine:"unknown",...t});return e[ie]=r,r}get plugins(){return $}enable(){if(this._originalRender)return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let e=0;this._originalRender=this.renderer.render;const t=this;he(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,d;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(ke||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 f of s){if(f.material&&(((a=f.geometry)==null?void 0:a.type)==="BoxGeometry"||((d=f.geometry)==null?void 0:d.type)==="BufferGeometry")&&(f.material.name==="SphericalGaussianBlur"||f.material.name=="BackgroundCubeMaterial"||f.material.name==="CubemapFromEquirect"||f.material.name==="EquirectangularToCubeUV")){N&&(f.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(f.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",f,f.material.name,f.material.type)));continue}switch(f.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}const x=f.object;(x instanceof p.Mesh||x.isMesh)&&this.updateLODs(e,t,x,c,i)}const m=o.transparent;for(const f of m){const x=f.object;(x instanceof p.Mesh||x.isMesh)&&this.updateLODs(e,t,x,c,i)}}}updateLODs(e,t,r,i,o){var a,d;r.userData||(r.userData={});let s=r[ne];if(s||(s=new Ie,r[ne]=s),s.frames++<2)return;for(const c of $)(a=c.onBeforeUpdateLOD)==null||a.call(c,this.renderer,e,t,r);this.calculateLodLevel(t,r,s,i,k),k.mesh_lod=Math.round(k.mesh_lod),k.texture_lod=Math.round(k.texture_lod),k.mesh_lod>=0&&this.loadProgressiveMeshes(r,k.mesh_lod);let n=k.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,k);s.lastLodLevel_Mesh=k.mesh_lod,s.lastLodLevel_Texture=k.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[z]===void 0||t<e[z])&&(r=!0),r&&(e[z]=t,v.assignTextureLOD(e,t))}loadProgressiveMeshes(e,t){if(!e)return Promise.resolve(null);if(e[z]!==t){e[z]=t;const r=e.geometry;return v.assignMeshLOD(e,t).then(i=>(i&&e[z]==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 I;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(N&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const d=v.getMeshLODInformation(t.geometry),c=d==null?void 0:d.lods,m=c&&c.length>0,f=v.getMaterialMinMaxLODsCount(t.material),x=(f==null?void 0:f.min_count)!=1/0&&f.min_count>0&&f.max_count>0;if(!m&&!x){o.mesh_lod=0,o.texture_lod=0;return}if(m||(a=!0,n=0),!((I=this.cameraFrustrum)!=null&&I.intersectsObject(t))){o.mesh_lod=99,o.texture_lod=99;return}const D=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let M=t.geometry.boundingBox;if(t.type==="SkinnedMesh"){const _=t;_.boundingBox||_.computeBoundingBox(),M=_.boundingBox}if(M&&e.isPerspectiveCamera){const _=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 u=e.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(u)){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&&_.fov>70){const u=this._tempBox.min,y=this._tempBox.max;let O=u.x,S=u.y,P=y.x,F=y.y;const J=2,re=1.5,Q=(u.x+y.x)*.5,Z=(u.y+y.y)*.5;O=(O-Q)*J+Q,S=(S-Z)*J+Z,P=(P-Q)*J+Q,F=(F-Z)*J+Z;const Me=O<0&&P>0?0:Math.min(Math.abs(u.x),Math.abs(y.x)),De=S<0&&F>0?0:Math.min(Math.abs(u.y),Math.abs(y.y)),se=Math.max(Me,De);r.lastCentrality=(re-se)*(re-se)*(re-se)}else r.lastCentrality=1;const g=this._tempBox.getSize(this._tempBoxSize);g.multiplyScalar(.5),screen.availHeight>0&&D>0&&g.multiplyScalar(D/screen.availHeight),g.x*=_.aspect;const V=e.matrixWorldInverse,R=this._tempBox2;R.copy(M),R.applyMatrix4(t.matrixWorld),R.applyMatrix4(V);const b=R.getSize(this._tempBox2Size),T=Math.max(b.x,b.y);if(Math.max(g.x,g.y)!=0&&T!=0&&(g.z=b.z/Math.max(b.x,b.y)*Math.max(g.x,g.y)),r.lastScreenCoverage=Math.max(g.x,g.y,g.z),r.lastScreenspaceVolume.copy(g),r.lastScreenCoverage*=r.lastCentrality,N&&C.debugDrawLine){const u=this.tempMatrix.copy(this.projectionScreenMatrix);u.invert();const y=C.corner0,O=C.corner1,S=C.corner2,P=C.corner3;y.copy(this._tempBox.min),O.copy(this._tempBox.max),O.x=y.x,S.copy(this._tempBox.max),S.y=y.y,P.copy(this._tempBox.max);const F=(y.z+P.z)*.5;y.z=O.z=S.z=P.z=F,y.applyMatrix4(u),O.applyMatrix4(u),S.applyMatrix4(u),P.applyMatrix4(u),C.debugDrawLine(y,O,255),C.debugDrawLine(y,S,255),C.debugDrawLine(O,P,255),C.debugDrawLine(S,P,255)}let B=999;if(c&&r.lastScreenCoverage>0){for(let u=0;u<c.length;u++)if(c[u].density/r.lastScreenCoverage<i){B=u;break}}B<n&&(n=B,a=!0)}if(a?o.mesh_lod=n:o.mesh_lod=r.lastLodLevel_Mesh,N&&o.mesh_lod!=r.lastLodLevel_Mesh){const g=c==null?void 0:c[o.mesh_lod];g&&console.log(`Mesh LOD changed: ${r.lastLodLevel_Mesh} → ${o.mesh_lod} (${g.density.toFixed(0)}) - ${t.name}`)}if(x)if(r.lastLodLevel_Texture<0){if(o.texture_lod=f.max_count-1,N){const _=f.lods[f.max_count-1];N&&console.log(`First Texture LOD ${o.texture_lod} (${_.max_height}px) - ${t.name}`)}}else{const _=r.lastScreenspaceVolume.x+r.lastScreenspaceVolume.y+r.lastScreenspaceVolume.z,g=r.lastScreenCoverage*2,R=D/window.devicePixelRatio*g;for(let b=f.lods.length-1;b>=0;b--){let T=f.lods[b];if(!(Ce()&&T.max_height>4096)&&T.max_height>R){if(o.texture_lod=b,o.texture_lod<r.lastLodLevel_Texture){const U=T.max_height;N&&console.log(`Texture LOD changed: ${r.lastLodLevel_Texture} → ${o.texture_lod} = ${U}px
6
+ Screensize: ${R.toFixed(0)}px, Coverage: ${(100*r.lastScreenCoverage).toFixed(2)}%, Volume ${_.toFixed(1)}
7
+ ${t.name}`)}break}}}else o.texture_lod=0}};let E=C;h(E,"debugDrawLine"),h(E,"corner0",new p.Vector3),h(E,"corner1",new p.Vector3),h(E,"corner2",new p.Vector3),h(E,"corner3",new p.Vector3),h(E,"_tempPtInside",new p.Vector3);class Ie{constructor(){h(this,"frames",0);h(this,"lastLodLevel_Mesh",-1);h(this,"lastLodLevel_Texture",-1);h(this,"lastScreenCoverage",0);h(this,"lastScreenspaceVolume",new p.Vector3);h(this,"lastCentrality",0)}}const ye=Symbol("NEEDLE_mesh_lod"),j=Symbol("NEEDLE_texture_lod");function me(){document.removeEventListener("DOMContentLoaded",ae),document.addEventListener("DOMContentLoaded",ae),ae()}function ae(){document.querySelectorAll("model-viewer").forEach((e,t)=>{Ge(e,t)})}const xe=new WeakSet;function Ge(l,e){if(!l||xe.has(l))return null;xe.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)"),d=s.find(c=>c.toString()=="Symbol(needsRender)");!t&&n!=null&&(t=l[n].threeRenderer),!r&&a!=null&&(r=l[a]),!i&&d!=null&&(i=l[d])}if(t&&r){console.debug("[gltf-progressive] setup model-viewer");const o=E.get(t,{engine:"model-viewer"});if(E.addPlugin(new Fe),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 Fe{constructor(){h(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[j]==!0)return;t[j]=!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,m,f;if(a[j]==!0)return;a[j]=!0,a.userData&&(a.userData.LOD=-1);const d=Object.keys(a);for(let x=0;x<d.length;x++){const D=d[x],M=a[D];if((M==null?void 0:M.isTexture)===!0){const I=(m=(c=M.userData)==null?void 0:c.associations)==null?void 0:m.textures;if(I==null)continue;const _=r.parser.json.textures[I];if(!_){console.warn("Texture data not found for texture index "+I);continue}if((f=_==null?void 0:_.extensions)!=null&&f[G]){const g=_.extensions[G];g&&o&&v.registerTexture(o,M,g.lods.length,I,g)}}}};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[ye]==!0)return;t[ye]=!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;v.registerMesh(i,a,t,0,o.lods.length,o)}}}me();function $e(l,e,t,r){he(e),ge(t),t.register(o=>new v(o,l));const i=E.get(e);return(r==null?void 0:r.enableLODsManager)!==!1&&i.enable(),i}exports.EXTENSION_NAME=G;exports.LODsManager=E;exports.NEEDLE_progressive=v;exports.VERSION=fe;exports.addDracoAndKTX2Loaders=ge;exports.createLoaders=he;exports.getRaycastMesh=te;exports.patchModelViewer=me;exports.setDracoDecoderLocation=be;exports.setKTX2TranscoderLocation=Ae;exports.setRaycastMesh=Le;exports.useNeedleProgressive=$e;exports.useRaycastMeshes=Re;
package/lib/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export { version as VERSION } from "./version.js";
1
2
  export * from "./extension.js";
2
3
  export * from "./plugins/index.js";
3
4
  export { LODsManager } from "./lods_manager.js";
package/lib/index.js CHANGED
@@ -1,13 +1,12 @@
1
+ export { version as VERSION } from "./version.js";
1
2
  export * from "./extension.js";
2
3
  export * from "./plugins/index.js";
3
4
  export { LODsManager } from "./lods_manager.js";
4
5
  export { setDracoDecoderLocation, setKTX2TranscoderLocation, createLoaders, addDracoAndKTX2Loaders } from "./loaders.js";
5
6
  export * from "./utils.js";
7
+ /** Modelviewer */
6
8
  import { patchModelViewer } from "./plugins/modelviewer.js";
7
- // Query once for model viewer. If a user does not have model-viewer in their page, this will return null.
8
- document.addEventListener("DOMContentLoaded", () => {
9
- patchModelViewer(document.querySelector("model-viewer"));
10
- });
9
+ patchModelViewer();
11
10
  import { addDracoAndKTX2Loaders, createLoaders } from "./loaders.js";
12
11
  import { NEEDLE_progressive } from "./extension.js";
13
12
  import { LODsManager } from "./lods_manager.js";
@@ -1,5 +1,8 @@
1
1
  import { Frustum, Matrix4, Object3D, Vector3, WebGLRenderer } from "three";
2
2
  import { NEEDLE_progressive_plugin } from "./plugins/plugin.js";
3
+ export type LODManagerContext = {
4
+ engine: "three" | "needle-engine" | "model-viewer" | "react-three-fiber" | "unknown";
5
+ };
3
6
  export declare type LOD_Results = {
4
7
  mesh_lod: number;
5
8
  texture_lod: number;
@@ -46,7 +49,8 @@ export declare class LODsManager {
46
49
  * @param renderer The renderer to get the LODsManager for.
47
50
  * @returns The LODsManager instance.
48
51
  */
49
- static get(renderer: WebGLRenderer): LODsManager;
52
+ static get(renderer: WebGLRenderer, context?: LODManagerContext): LODsManager;
53
+ private readonly context;
50
54
  readonly renderer: WebGLRenderer;
51
55
  readonly projectionScreenMatrix: Matrix4;
52
56
  readonly cameraFrustrum: Frustum;
@@ -59,13 +59,19 @@ export class LODsManager {
59
59
  * @param renderer The renderer to get the LODsManager for.
60
60
  * @returns The LODsManager instance.
61
61
  */
62
- static get(renderer) {
62
+ static get(renderer, context) {
63
63
  if (renderer[$lodsManager]) {
64
+ console.debug("[gltf-progressive] LODsManager already exists for this renderer");
64
65
  return renderer[$lodsManager];
65
66
  }
66
- const lodsManager = new LODsManager(renderer);
67
+ const lodsManager = new LODsManager(renderer, {
68
+ engine: "unknown",
69
+ ...context,
70
+ });
71
+ renderer[$lodsManager] = lodsManager;
67
72
  return lodsManager;
68
73
  }
74
+ context;
69
75
  renderer;
70
76
  projectionScreenMatrix = new Matrix4();
71
77
  cameraFrustrum = new Frustum();
@@ -85,8 +91,9 @@ export class LODsManager {
85
91
  */
86
92
  pause = false;
87
93
  // readonly plugins: NEEDLE_progressive_plugin[] = [];
88
- constructor(renderer) {
94
+ constructor(renderer, context) {
89
95
  this.renderer = renderer;
96
+ this.context = { ...context };
90
97
  }
91
98
  _frame = 0;
92
99
  _originalRender;
@@ -96,6 +103,7 @@ export class LODsManager {
96
103
  enable() {
97
104
  if (this._originalRender)
98
105
  return;
106
+ console.debug("[gltf-progressive] Enabling LODsManager for renderer");
99
107
  let stack = 0;
100
108
  // Save the original render method
101
109
  this._originalRender = this.renderer.render;
@@ -364,11 +372,13 @@ export class LODsManager {
364
372
  result.texture_lod = 99;
365
373
  return;
366
374
  }
375
+ const canvasHeight = this.renderer.domElement.clientHeight || this.renderer.domElement.height;
367
376
  let boundingBox = mesh.geometry.boundingBox;
368
377
  if (mesh.type === "SkinnedMesh") {
369
378
  const skinnedMesh = mesh;
370
- if (!skinnedMesh.boundingBox)
379
+ if (!skinnedMesh.boundingBox) {
371
380
  skinnedMesh.computeBoundingBox();
381
+ }
372
382
  boundingBox = skinnedMesh.boundingBox;
373
383
  }
374
384
  if (boundingBox && camera.isPerspectiveCamera) {
@@ -388,14 +398,7 @@ export class LODsManager {
388
398
  }
389
399
  // calculate size on screen
390
400
  this._tempBox.copy(boundingBox);
391
- // For skinned meshes we need to ignore the transformation of the mesh itself since it's controlled by the bones
392
- if (mesh.type === "SkinnedMesh") {
393
- if (mesh.parent)
394
- this._tempBox.applyMatrix4(mesh.parent.matrixWorld);
395
- }
396
- else {
397
- this._tempBox.applyMatrix4(mesh.matrixWorld);
398
- }
401
+ this._tempBox.applyMatrix4(mesh.matrixWorld);
399
402
  // Converting into projection space has the disadvantage that objects further to the side
400
403
  // will have a much larger coverage, especially with high-field-of-view situations like in VR.
401
404
  // Alternatively, we could attempt to calculate angular coverage (some kind of polar coordinates maybe?)
@@ -439,8 +442,11 @@ export class LODsManager {
439
442
  }
440
443
  const boxSize = this._tempBox.getSize(this._tempBoxSize);
441
444
  boxSize.multiplyScalar(0.5); // goes from -1..1, we want -0.5..0.5 for coverage in percent
442
- if (screen.availHeight > 0)
443
- boxSize.multiplyScalar(this.renderer.domElement.clientHeight / screen.availHeight); // correct for size of context on screen
445
+ if (screen.availHeight > 0) {
446
+ // correct for size of context on screen
447
+ if (canvasHeight > 0)
448
+ boxSize.multiplyScalar(canvasHeight / screen.availHeight);
449
+ }
444
450
  boxSize.x *= cam.aspect;
445
451
  const matView = camera.matrixWorldInverse;
446
452
  const box2 = this._tempBox2;
@@ -528,18 +534,20 @@ export class LODsManager {
528
534
  }
529
535
  }
530
536
  else {
531
- const factor = state.lastScreenCoverage * 1.5;
532
- const screenSize = this.renderer.domElement.clientHeight / window.devicePixelRatio;
537
+ const volume = state.lastScreenspaceVolume.x + state.lastScreenspaceVolume.y + state.lastScreenspaceVolume.z;
538
+ const factor = state.lastScreenCoverage * 2;
539
+ const screenSize = canvasHeight / window.devicePixelRatio;
533
540
  const pixelSizeOnScreen = screenSize * factor;
534
541
  for (let i = texture_lods_minmax.lods.length - 1; i >= 0; i--) {
535
- const lod = texture_lods_minmax.lods[i];
542
+ let lod = texture_lods_minmax.lods[i];
536
543
  if (isMobileDevice() && lod.max_height > 4096)
537
544
  continue; // skip 8k textures on mobile devices (for now)
538
545
  if (lod.max_height > pixelSizeOnScreen) {
539
546
  result.texture_lod = i;
540
547
  if (result.texture_lod < state.lastLodLevel_Texture) {
548
+ const lod_pixel_height = lod.max_height;
541
549
  if (debugProgressiveLoading)
542
- console.log(`Texture LOD changed: ${state.lastLodLevel_Texture} → ${result.texture_lod} (${lod.max_height}px: ${(100 * state.lastScreenCoverage).toFixed(2)} % = ${pixelSizeOnScreen.toFixed(0)}px) - ${mesh.name}`);
550
+ console.log(`Texture LOD changed: ${state.lastLodLevel_Texture} → ${result.texture_lod} = ${lod_pixel_height}px \nScreensize: ${pixelSizeOnScreen.toFixed(0)}px, Coverage: ${(100 * state.lastScreenCoverage).toFixed(2)}%, Volume ${volume.toFixed(1)} \n${mesh.name}`);
543
551
  }
544
552
  break;
545
553
  }
@@ -1,4 +1 @@
1
- /** Patch modelviewer to support NEEDLE progressive system
2
- * @returns a function to remove the patch
3
- */
4
- export declare function patchModelViewer(modelviewer: HTMLElement): (() => void) | null;
1
+ export declare function patchModelViewer(): void;
@@ -2,33 +2,67 @@ 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
+ export function patchModelViewer() {
6
+ document.removeEventListener("DOMContentLoaded", searchModelViewers);
7
+ document.addEventListener("DOMContentLoaded", searchModelViewers);
8
+ searchModelViewers();
9
+ }
10
+ function searchModelViewers() {
11
+ // Query once for model viewer. If a user does not have model-viewer in their page, this will return null.
12
+ const modelviewers = document.querySelectorAll("model-viewer");
13
+ modelviewers.forEach((modelviewer, index) => {
14
+ _patchModelViewer(modelviewer, index);
15
+ });
16
+ }
17
+ const foundModelViewers = new WeakSet();
5
18
  /** Patch modelviewer to support NEEDLE progressive system
6
19
  * @returns a function to remove the patch
7
20
  */
8
- export function patchModelViewer(modelviewer) {
21
+ function _patchModelViewer(modelviewer, index) {
9
22
  if (!modelviewer)
10
23
  return null;
24
+ if (foundModelViewers.has(modelviewer))
25
+ return null;
26
+ foundModelViewers.add(modelviewer);
27
+ console.debug("[gltf-progressive] found model-viewer..." + index);
28
+ // Find the necessary internal methods and properties. We need access to the scene, renderer
11
29
  let renderer = null;
12
30
  let scene = null;
31
+ let needsRender = null; // < used to force render updates for a few frames
13
32
  for (let p = modelviewer; p != null; p = Object.getPrototypeOf(p)) {
14
33
  const privateAPI = Object.getOwnPropertySymbols(p);
15
34
  const rendererSymbol = privateAPI.find((value) => value.toString() == 'Symbol(renderer)');
16
35
  const sceneSymbol = privateAPI.find((value) => value.toString() == 'Symbol(scene)');
36
+ const needsRenderSymbol = privateAPI.find((value) => value.toString() == 'Symbol(needsRender)');
17
37
  if (!renderer && rendererSymbol != null) {
18
38
  renderer = modelviewer[rendererSymbol].threeRenderer;
19
39
  }
20
40
  if (!scene && sceneSymbol != null) {
21
41
  scene = modelviewer[sceneSymbol];
22
42
  }
43
+ if (!needsRender && needsRenderSymbol != null) {
44
+ needsRender = modelviewer[needsRenderSymbol];
45
+ }
23
46
  }
24
- if (renderer) {
25
- const lod = LODsManager.get(renderer);
26
- LODsManager.addPlugin(new RegisterModelviewerDataPlugin(modelviewer));
47
+ if (renderer && scene) {
48
+ console.debug("[gltf-progressive] setup model-viewer");
49
+ const lod = LODsManager.get(renderer, { engine: "model-viewer" });
50
+ LODsManager.addPlugin(new RegisterModelviewerDataPlugin());
27
51
  lod.enable();
28
52
  if (scene) {
29
- const camera = scene["camera"] || scene.traverse((o) => o.type == "PerspectiveCamera")[0];
30
- if (camera) {
31
- renderer.render(scene, camera);
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
+ */
57
+ if (needsRender) {
58
+ let forcedFrames = 0;
59
+ let interval = setInterval(() => {
60
+ if (forcedFrames++ > 10) {
61
+ clearInterval(interval);
62
+ return;
63
+ }
64
+ needsRender?.call(modelviewer);
65
+ }, 150);
32
66
  }
33
67
  }
34
68
  return () => {
@@ -41,24 +75,23 @@ export function patchModelViewer(modelviewer) {
41
75
  * LODs manager plugin that registers LOD data to the NEEDLE progressive system
42
76
  */
43
77
  class RegisterModelviewerDataPlugin {
44
- modelviewer;
45
78
  _didWarnAboutMissingUrl = false;
46
- constructor(modelviewer) {
47
- this.modelviewer = modelviewer;
48
- }
49
79
  onBeforeUpdateLOD(_renderer, scene, _camera, object) {
50
80
  this.tryParseMeshLOD(scene, object);
51
81
  this.tryParseTextureLOD(scene, object);
52
82
  }
53
- getUrl() {
54
- let url = this.modelviewer.getAttribute("src");
83
+ getUrl(element) {
84
+ if (!element) {
85
+ return null;
86
+ }
87
+ let url = element.getAttribute("src");
55
88
  // fallback in case the attribute is not set but the src property is
56
89
  if (!url) {
57
- url = this.modelviewer["src"];
90
+ url = element["src"];
58
91
  }
59
92
  if (!url) {
60
93
  if (!this._didWarnAboutMissingUrl)
61
- console.warn("No url found in modelviewer", this.modelviewer);
94
+ console.warn("No url found in modelviewer", element);
62
95
  this._didWarnAboutMissingUrl = true;
63
96
  }
64
97
  return url;
@@ -66,12 +99,16 @@ class RegisterModelviewerDataPlugin {
66
99
  tryGetCurrentGLTF(scene) {
67
100
  return scene._currentGLTF;
68
101
  }
102
+ tryGetCurrentModelViewer(scene) {
103
+ return scene.element;
104
+ }
69
105
  tryParseTextureLOD(scene, object) {
70
106
  if (object[$textureLODSymbol] == true)
71
107
  return;
72
108
  object[$textureLODSymbol] = true;
73
109
  const currentGLTF = this.tryGetCurrentGLTF(scene);
74
- const url = this.getUrl();
110
+ const element = this.tryGetCurrentModelViewer(scene);
111
+ const url = this.getUrl(element);
75
112
  if (!url) {
76
113
  return;
77
114
  }
@@ -96,6 +133,8 @@ class RegisterModelviewerDataPlugin {
96
133
  const value = mat[key];
97
134
  if (value?.isTexture === true) {
98
135
  const textureIndex = value.userData?.associations?.textures;
136
+ if (textureIndex == null)
137
+ continue;
99
138
  const textureData = currentGLTF.parser.json.textures[textureIndex];
100
139
  if (!textureData) {
101
140
  console.warn("Texture data not found for texture index " + textureIndex);
@@ -113,11 +152,12 @@ class RegisterModelviewerDataPlugin {
113
152
  }
114
153
  }
115
154
  }
116
- tryParseMeshLOD(_scene, object) {
155
+ tryParseMeshLOD(scene, object) {
117
156
  if (object[$meshLODSymbol] == true)
118
157
  return;
119
158
  object[$meshLODSymbol] = true;
120
- const url = this.getUrl();
159
+ const element = this.tryGetCurrentModelViewer(scene);
160
+ const url = this.getUrl(element);
121
161
  if (!url) {
122
162
  return;
123
163
  }