@needle-tools/gltf-progressive 2.1.6-next.c9b2e8b → 2.1.6-next.fa4044e

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.
Files changed (47) hide show
  1. package/examples/react-three-fiber/src/App.tsx +38 -0
  2. package/examples/react-three-fiber/src/index.tsx +12 -0
  3. package/examples/react-three-fiber/src/styles.css +16 -0
  4. package/examples/react-three-fiber/tsconfig.json +22 -0
  5. package/gltf-progressive.js +1098 -0
  6. package/gltf-progressive.min.js +8 -0
  7. package/gltf-progressive.umd.cjs +8 -0
  8. package/{dist/lib → lib}/extension.d.ts +10 -6
  9. package/{dist/lib → lib}/extension.js +20 -94
  10. package/lib/lods.debug.d.ts +4 -0
  11. package/lib/lods.debug.js +41 -0
  12. package/{dist/lib → lib}/lods_manager.d.ts +6 -1
  13. package/{dist/lib → lib}/lods_manager.js +26 -10
  14. package/{dist/lib → lib}/plugins/plugin.d.ts +2 -2
  15. package/{dist/lib → lib}/version.js +1 -1
  16. package/package.json +14 -17
  17. package/.github/workflows/publish.yml +0 -47
  18. package/dist/CHANGELOG.md +0 -211
  19. package/dist/README.md +0 -129
  20. package/dist/examples/modelviewer-multiple.html +0 -126
  21. package/dist/examples/modelviewer.html +0 -34
  22. package/dist/examples/react-three-fiber/.prettierrc +0 -10
  23. package/dist/examples/react-three-fiber/favicon.png +0 -0
  24. package/dist/examples/react-three-fiber/index.html +0 -24
  25. package/dist/examples/react-three-fiber/package-lock.json +0 -4023
  26. package/dist/examples/react-three-fiber/package.json +0 -34
  27. package/dist/examples/react-three-fiber/vite.config.js +0 -39
  28. package/dist/examples/threejs/index.html +0 -52
  29. package/dist/examples/threejs/main.js +0 -181
  30. package/dist/gltf-progressive.js +0 -1107
  31. package/dist/gltf-progressive.min.js +0 -8
  32. package/dist/gltf-progressive.umd.cjs +0 -8
  33. package/dist/package.json +0 -65
  34. /package/{dist/lib → lib}/index.d.ts +0 -0
  35. /package/{dist/lib → lib}/index.js +0 -0
  36. /package/{dist/lib → lib}/loaders.d.ts +0 -0
  37. /package/{dist/lib → lib}/loaders.js +0 -0
  38. /package/{dist/lib → lib}/plugins/index.d.ts +0 -0
  39. /package/{dist/lib → lib}/plugins/index.js +0 -0
  40. /package/{dist/lib → lib}/plugins/modelviewer.d.ts +0 -0
  41. /package/{dist/lib → lib}/plugins/modelviewer.js +0 -0
  42. /package/{dist/lib → lib}/plugins/plugin.js +0 -0
  43. /package/{dist/lib → lib}/utils.d.ts +0 -0
  44. /package/{dist/lib → lib}/utils.internal.d.ts +0 -0
  45. /package/{dist/lib → lib}/utils.internal.js +0 -0
  46. /package/{dist/lib → lib}/utils.js +0 -0
  47. /package/{dist/lib → lib}/version.d.ts +0 -0
@@ -0,0 +1,8 @@
1
+ var He=Object.defineProperty,Ye=(t,e,s)=>e in t?He(t,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):t[e]=s,d=(t,e,s)=>(Ye(t,typeof e!="symbol"?e+"":e,s),s),Ee=(t,e,s)=>{if(!e.has(t))throw TypeError("Cannot "+s)},v=(t,e,s)=>(Ee(t,e,"read from private field"),s?s.call(t):e.get(t)),H=(t,e,s)=>{if(e.has(t))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(t):e.set(t,s)},F=(t,e,s,n)=>(Ee(t,e,"write to private field"),n?n.call(t,s):e.set(t,s),s);import{BufferGeometry as ue,Mesh as Y,Texture as se,TextureLoader as Je,Matrix4 as Pe,Clock as Qe,MeshStandardMaterial as Ze,Sphere as et,Box3 as Ie,Vector3 as z}from"three";import{GLTFLoader as xe}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as tt}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as st}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as rt}from"three/examples/jsm/loaders/KTX2Loader.js";const Ce="";globalThis.GLTF_PROGRESSIVE_VERSION=Ce,console.debug("[gltf-progressive] version -");let $="https://www.gstatic.com/draco/versioned/decoders/1.5.7/",Q="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";const ot=$,nt=Q,Be=new URL($+"draco_decoder.js");Be.searchParams.append("range","true"),fetch(Be,{method:"GET",headers:{Range:"bytes=0-1"}}).catch(t=>{console.debug(`Failed to fetch remote Draco decoder from ${$} (offline: ${typeof navigator<"u"?navigator.onLine:"unknown"})`),$===ot&&ke("./include/draco/"),Q===nt&&Re("./include/ktx2/")}).finally(()=>{je()});function ke(t){$=t,B&&B[ye]!=$?(console.debug("Updating Draco decoder path to "+t),B[ye]=$,B.setDecoderPath($),B.preload()):console.debug("Setting Draco decoder path to "+t)}function Re(t){Q=t,G&&G.transcoderPath!=Q?(console.debug("Updating KTX2 transcoder path to "+t),G.setTranscoderPath(Q),G.init()):console.debug("Setting KTX2 transcoder path to "+t)}const ye=Symbol("dracoDecoderPath");let B,ce,G;function je(){B||(B=new st,B[ye]=$,B.setDecoderPath($),B.setDecoderConfig({type:"js"}),B.preload()),G||(G=new rt,G.setTranscoderPath(Q),G.init()),ce||(ce=tt)}function Le(t){return je(),t?G.detectSupport(t):t!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:B,ktx2Loader:G,meshoptDecoder:ce}}function De(t){t.dracoLoader||t.setDRACOLoader(B),t.ktx2Loader||t.setKTX2Loader(G),t.meshoptDecoder||t.setMeshoptDecoder(ce)}const Me=new WeakMap;function we(t,e){let s=Me.get(t);s?s=Object.assign(s,e):s=e,Me.set(t,s)}const Ge=xe.prototype.load;function it(...t){const e=Me.get(this);let s=t[0];const n=new URL(s,window.location.href);if(n.hostname.endsWith("needle.tools")){const r=e?.progressive!==void 0?e.progressive:!0,o=e!=null&&e.usecase?e.usecase:"default";r?this.requestHeader.Accept=`*/*;progressive=allowed;usecase=${o}`:this.requestHeader.Accept=`*/*;usecase=${o}`,s=n.toString()}return t[0]=s,Ge?.call(this,...t)}xe.prototype.load=it,re("debugprogressive");function re(t){if(typeof window>"u")return!1;const e=new URL(window.location.href).searchParams.get(t);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function at(t,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||t===void 0)return e;const s=t.lastIndexOf("/");if(s>=0){const n=t.substring(0,s+1);for(;n.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return n+e}return e}let de;function lt(){return de!==void 0||(de=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),re("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",de)),de}const ut=typeof window>"u"&&typeof document>"u",_e=Symbol("needle:raycast-mesh");function Z(t){return t?.[_e]instanceof ue?t[_e]:null}function Ne(t,e){if((t.type==="Mesh"||t.type==="SkinnedMesh")&&!Z(t)){const s=ct(e);s.userData={isRaycastMesh:!0},t[_e]=s}}function $e(t=!0){if(t){if(oe)return;const e=oe=Y.prototype.raycast;Y.prototype.raycast=function(s,n){const r=this,o=Z(r);let i;o&&r.isMesh&&(i=r.geometry,r.geometry=o),e.call(this,s,n),i&&(r.geometry=i)}}else{if(!oe)return;Y.prototype.raycast=oe,oe=null}}let oe=null;function ct(t){const e=new ue;for(const s in t.attributes)e.setAttribute(s,t.getAttribute(s));return e.setIndex(t.getIndex()),e}const V=new Array,L=re("debugprogressive");let he,J=-1;if(L){let t=function(){J+=1,J>=e&&(J=-1),console.log(`Toggle LOD level [${J}]`)},e=6;window.addEventListener("keyup",s=>{s.key==="p"&&t(),s.key==="w"&&(he=!he,console.log(`Toggle wireframe [${he}]`));const n=parseInt(s.key);!isNaN(n)&&n>=0&&(J=n,console.log(`Set LOD level to [${J}]`))})}function We(t){if(L)if(Array.isArray(t))for(const e of t)We(e);else t&&"wireframe"in t&&(t.wireframe=he===!0)}const W="NEEDLE_progressive",be=Symbol("needle-progressive-texture"),w=class{constructor(t,e){d(this,"parser"),d(this,"url"),d(this,"_isLoadingMesh"),d(this,"loadMesh",s=>{var n,r;if(this._isLoadingMesh)return null;const o=(r=(n=this.parser.json.meshes[s])==null?void 0:n.extensions)==null?void 0:r[W];return o?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",s).then(i=>{var l;return this._isLoadingMesh=!1,i&&w.registerMesh(this.url,o.guid,i,(l=o.lods)==null?void 0:l.length,0,o),i})):null}),L&&console.log("Progressive extension registered for",e),this.parser=t,this.url=e}get name(){return W}static getMeshLODExtension(t){const e=this.getAssignedLODInformation(t);return e!=null&&e.key?this.lodInfos.get(e.key):null}static getPrimitiveIndex(t){var e;return((e=this.getAssignedLODInformation(t))==null?void 0:e.index)??-1}static getMaterialMinMaxLODsCount(t,e){const s=this,n="LODS:minmax",r=t[n];if(r!=null)return r;if(e||(e={min_count:1/0,max_count:0,lods:[]}),Array.isArray(t)){for(const i of t)this.getMaterialMinMaxLODsCount(i,e);return t[n]=e,e}if(L==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const i=t;for(const l of Object.keys(i.uniforms)){const u=i.uniforms[l].value;u?.isTexture===!0&&o(u,e)}}else if(t.isMaterial)for(const i of Object.keys(t)){const l=t[i];l?.isTexture===!0&&o(l,e)}return t[n]=e,e;function o(i,l){const u=s.getAssignedLODInformation(i);if(u){const a=s.lodInfos.get(u.key);if(a&&a.lods){l.min_count=Math.min(l.min_count,a.lods.length),l.max_count=Math.max(l.max_count,a.lods.length);for(let h=0;h<a.lods.length;h++){const x=a.lods[h];x.width&&(l.lods[h]=l.lods[h]||{min_height:1/0,max_height:0},l.lods[h].min_height=Math.min(l.lods[h].min_height,x.height),l.lods[h].max_height=Math.max(l.lods[h].max_height,x.height))}}}}}static hasLODLevelAvailable(t,e){var s;if(Array.isArray(t)){for(const o of t)if(this.hasLODLevelAvailable(o,e))return!0;return!1}if(t.isMaterial===!0){for(const o of Object.keys(t)){const i=t[o];if(i&&i.isTexture&&this.hasLODLevelAvailable(i,e))return!0}return!1}else if(t.isGroup===!0){for(const o of t.children)if(o.isMesh===!0&&this.hasLODLevelAvailable(o,e))return!0}let n,r;if(t.isMesh?n=t.geometry:(t.isBufferGeometry||t.isTexture)&&(n=t),n&&(s=n?.userData)!=null&&s.LODS){const o=n.userData.LODS;if(r=this.lodInfos.get(o.key),e===void 0)return r!=null;if(r)return Array.isArray(r.lods)?e<r.lods.length:e===0}return!1}static assignMeshLOD(t,e){var s;if(!t)return Promise.resolve(null);if(t instanceof Y||t.isMesh===!0){const n=t.geometry,r=this.getAssignedLODInformation(n);if(!r)return Promise.resolve(null);for(const o of V)(s=o.onBeforeGetLODMesh)==null||s.call(o,t,e);return t["LOD:requested level"]=e,w.getOrLoadLOD(n,e).then(o=>{if(Array.isArray(o)){const i=r.index||0;o=o[i]}return t["LOD:requested level"]===e&&(delete t["LOD:requested level"],o&&n!=o&&(o?.isBufferGeometry?t.geometry=o:L&&console.error("Invalid LOD geometry",o))),o}).catch(o=>(console.error("Error loading mesh LOD",t,o),null))}else L&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",t);return Promise.resolve(null)}static assignTextureLOD(t,e=0){if(!t)return Promise.resolve(null);if(t.isMesh===!0){const s=t;if(Array.isArray(s.material)){const n=new Array;for(const r of s.material){const o=this.assignTextureLOD(r,e);n.push(o)}return Promise.all(n).then(r=>{const o=new Array;for(const i of r)Array.isArray(i)&&o.push(...i);return o})}else return this.assignTextureLOD(s.material,e)}if(t.isMaterial===!0){const s=t,n=[],r=new Array;if(s.uniforms&&(s.isRawShaderMaterial||s.isShaderMaterial===!0)){const o=s;for(const i of Object.keys(o.uniforms)){const l=o.uniforms[i].value;if(l?.isTexture===!0){const u=this.assignTextureLODForSlot(l,e,s,i).then(a=>(a&&o.uniforms[i].value!=a&&(o.uniforms[i].value=a,o.uniformsNeedUpdate=!0),a));n.push(u),r.push(i)}}}else for(const o of Object.keys(s)){const i=s[o];if(i?.isTexture===!0){const l=this.assignTextureLODForSlot(i,e,s,o);n.push(l),r.push(o)}}return Promise.all(n).then(o=>{const i=new Array;for(let l=0;l<o.length;l++){const u=o[l],a=r[l];u&&u.isTexture===!0?i.push({material:s,slot:a,texture:u,level:e}):i.push({material:s,slot:a,texture:null,level:e})}return i})}if(t instanceof se||t.isTexture===!0){const s=t;return this.assignTextureLODForSlot(s,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,s,n){return t?.isTexture!==!0?Promise.resolve(null):n==="glyphMap"?Promise.resolve(t):w.getOrLoadLOD(t,e).then(r=>{if(Array.isArray(r))return null;if(r?.isTexture===!0){if(r!=t&&s&&n){const o=s[n];if(o&&!L){const i=this.getAssignedLODInformation(o);if(i&&i?.level<e)return L==="verbose"&&console.warn("Assigned texture level is already higher: ",i.level,e,s,o,r),null}s[n]=r}return r}else L=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(r=>(console.error("Error loading LOD",t,r),null))}afterRoot(t){var e,s;return L&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((n,r)=>{var o;if(n!=null&&n.extensions){const i=n?.extensions[W];if(i){if(!i.lods){L&&console.warn("Texture has no LODs",i);return}let l=!1;for(const u of this.parser.associations.keys())if(u.isTexture===!0){const a=this.parser.associations.get(u);a?.textures===r&&(l=!0,w.registerTexture(this.url,u,(o=i.lods)==null?void 0:o.length,r,i))}l||this.parser.getDependency("texture",r).then(u=>{var a;u&&w.registerTexture(this.url,u,(a=i.lods)==null?void 0:a.length,r,i)})}}}),(s=this.parser.json.meshes)==null||s.forEach((n,r)=>{if(n!=null&&n.extensions){const o=n?.extensions[W];if(o&&o.lods){for(const i of this.parser.associations.keys())if(i.isMesh){const l=this.parser.associations.get(i);l?.meshes===r&&w.registerMesh(this.url,o.guid,i,o.lods.length,l.primitives,o)}}}}),null}static async getOrLoadLOD(t,e){var s,n,r,o;const i=L=="verbose",l=t.userData.LODS;if(!l)return null;const u=l?.key;let a;if(t.isTexture===!0){const h=t;h.source&&h.source[be]&&(a=h.source[be])}if(a||(a=w.lodInfos.get(u)),a){if(e>0){let m=!1;const M=Array.isArray(a.lods);if(M&&e>=a.lods.length?m=!0:M||(m=!0),m)return this.lowresCache.get(u)}const h=Array.isArray(a.lods)?(s=a.lods[e])==null?void 0:s.path:a.lods;if(!h)return L&&!a["missing:uri"]&&(a["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,a)),null;const x=at(l.url,h);if(x.endsWith(".glb")||x.endsWith(".gltf")){if(!a.guid)return console.warn("missing pointer for glb/gltf texture",a),null;const m=x+"_"+a.guid,M=this.previouslyLoaded.get(m);if(M!==void 0){i&&console.log(`LOD ${e} was already loading/loaded: ${m}`);let y=await M.catch(f=>(console.error(`Error loading LOD ${e} from ${x}
2
+ `,f),null)),p=!1;if(y==null||(y instanceof se&&t instanceof se?(n=y.image)!=null&&n.data||(r=y.source)!=null&&r.data?y=this.copySettings(t,y):(p=!0,this.previouslyLoaded.delete(m)):y instanceof ue&&t instanceof ue&&((o=y.attributes.position)!=null&&o.array||(p=!0,this.previouslyLoaded.delete(m)))),!p)return y}const b=a,R=new Promise(async(y,p)=>{const f=new xe;De(f),L&&(await new Promise(D=>setTimeout(D,1e3)),i&&console.warn("Start loading (delayed) "+x,b.guid));let U=x;if(b&&Array.isArray(b.lods)){const D=b.lods[e];D.hash&&(U+="?v="+D.hash)}const _=await f.loadAsync(U).catch(D=>(console.error(`Error loading LOD ${e} from ${x}
3
+ `,D),null));if(!_)return null;const j=_.parser;i&&console.log("Loading finished "+x,b.guid);let O=0;if(_.parser.json.textures){let D=!1;for(const c of _.parser.json.textures){if(c!=null&&c.extensions){const g=c?.extensions[W];if(g!=null&&g.guid&&g.guid===b.guid){D=!0;break}}O++}if(D){let c=await j.getDependency("texture",O);return c&&w.assignLODInformation(l.url,c,u,e,void 0),i&&console.log('change "'+t.name+'" \u2192 "'+c.name+'"',x,O,c,m),t instanceof se&&(c=this.copySettings(t,c)),c&&(c.guid=b.guid),y(c)}else L&&console.warn("Could not find texture with guid",b.guid,_.parser.json)}if(O=0,_.parser.json.meshes){let D=!1;for(const c of _.parser.json.meshes){if(c!=null&&c.extensions){const g=c?.extensions[W];if(g!=null&&g.guid&&g.guid===b.guid){D=!0;break}}O++}if(D){const c=await j.getDependency("mesh",O);if(i&&console.log(`Loaded Mesh "${c.name}"`,x,O,c,m),c.isMesh===!0){const g=c.geometry;return w.assignLODInformation(l.url,g,u,e,0),y(g)}else{const g=new Array;for(let S=0;S<c.children.length;S++){const I=c.children[S];if(I.isMesh===!0){const C=I.geometry;w.assignLODInformation(l.url,C,u,e,S),g.push(C)}}return y(g)}}else L&&console.warn("Could not find mesh with guid",b.guid,_.parser.json)}return y(null)});return this.previouslyLoaded.set(m,R),await R}else if(t instanceof se){i&&console.log("Load texture from uri: "+x);const m=await new Je().loadAsync(x);return m?(m.guid=a.guid,m.flipY=!1,m.needsUpdate=!0,m.colorSpace=t.colorSpace,i&&console.log(a,m)):L&&console.warn("failed loading",x),m}}else L&&console.warn(`Can not load LOD ${e}: no LOD info found for "${u}" ${t.name}`,t.type);return null}static assignLODInformation(t,e,s,n,r){if(!e)return;e.userData||(e.userData={});const o=new dt(t,s,n,r);e.userData.LODS=o}static getAssignedLODInformation(t){var e;return((e=t?.userData)==null?void 0:e.LODS)||null}static copySettings(t,e){return e?(L&&console.warn(`Copy texture settings
4
+ `,t.uuid,`
5
+ `,e.uuid),e=e.clone(),e.offset=t.offset,e.repeat=t.repeat,e.colorSpace=t.colorSpace,e.magFilter=t.magFilter,e.minFilter=t.minFilter,e.wrapS=t.wrapS,e.wrapT=t.wrapT,e.flipY=t.flipY,e.anisotropy=t.anisotropy,e.mipmaps||(e.generateMipmaps=t.generateMipmaps),e):t}};let T=w;d(T,"registerTexture",(t,e,s,n,r)=>{if(L&&console.log("> Progressive: register texture",n,e.name,e.uuid,e,r),!e){L&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[be]=r);const o=r.guid;w.assignLODInformation(t,e,o,s,n),w.lodInfos.set(o,r),w.lowresCache.set(o,e)}),d(T,"registerMesh",(t,e,s,n,r,o)=>{var i;const l=s.geometry;if(!l){L&&console.warn("gltf-progressive: Register mesh without geometry");return}l.userData||(l.userData={}),L&&console.log("> Progressive: register mesh "+s.name,{index:r,uuid:s.uuid},o,s),w.assignLODInformation(t,l,e,n,r),w.lodInfos.set(e,o);let u=w.lowresCache.get(e);u?u.push(s.geometry):u=[s.geometry],w.lowresCache.set(e,u),n>0&&!Z(s)&&Ne(s,l);for(const a of V)(i=a.onRegisteredNewMesh)==null||i.call(a,s,o)}),d(T,"lodInfos",new Map),d(T,"previouslyLoaded",new Map),d(T,"lowresCache",new Map);class dt{constructor(e,s,n,r){d(this,"url"),d(this,"key"),d(this,"level"),d(this,"index"),this.url=e,this.key=s,this.level=n,r!=null&&(this.index=r)}}const N=re("debugprogressive"),ht=re("noprogressive"),Oe=Symbol("Needle:LODSManager"),Se=Symbol("Needle:LODState"),q=Symbol("Needle:CurrentLOD"),A={mesh_lod:-1,texture_lod:-1};var E,X,Te,ee,ne,ge,K;const P=class{constructor(t,e){d(this,"context"),d(this,"renderer"),d(this,"projectionScreenMatrix",new Pe),d(this,"targetTriangleDensity",2e5),d(this,"skinnedMeshAutoUpdateBoundsInterval",30),d(this,"updateInterval","auto"),H(this,E,1),d(this,"pause",!1),d(this,"manual",!1),d(this,"_lodchangedlisteners",[]),H(this,X,void 0),H(this,Te,new Qe),H(this,ee,0),H(this,ne,0),H(this,ge,0),H(this,K,0),d(this,"_fpsBuffer",[60,60,60,60,60]),d(this,"_sphere",new et),d(this,"_tempBox",new Ie),d(this,"_tempBox2",new Ie),d(this,"tempMatrix",new Pe),d(this,"_tempWorldPosition",new z),d(this,"_tempBoxSize",new z),d(this,"_tempBox2Size",new z),this.renderer=t,this.context={...e}}static getObjectLODState(t){return t[Se]}static addPlugin(t){V.push(t)}static removePlugin(t){const e=V.indexOf(t);e>=0&&V.splice(e,1)}static get(t,e){if(t[Oe])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[Oe];const s=new P(t,{engine:"unknown",...e});return t[Oe]=s,s}get plugins(){return V}addEventListener(t,e){t==="changed"&&this._lodchangedlisteners.push(e)}removeEventListener(t,e){if(t==="changed"){const s=this._lodchangedlisteners.indexOf(e);s>=0&&this._lodchangedlisteners.splice(s,1)}}enable(){if(v(this,X))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let t=0;F(this,X,this.renderer.render);const e=this;Le(this.renderer),this.renderer.render=function(s,n){const r=e.renderer.getRenderTarget();(r==null||"isXRRenderTarget"in r&&r.isXRRenderTarget)&&(t=0,F(e,ee,v(e,ee)+1),F(e,ne,v(e,Te).getDelta()),F(e,ge,v(e,ge)+v(e,ne)),e._fpsBuffer.shift(),e._fpsBuffer.push(1/v(e,ne)),F(e,K,e._fpsBuffer.reduce((i,l)=>i+l)/e._fpsBuffer.length),N&&v(e,ee)%200===0&&console.log("FPS",Math.round(v(e,K)),"Interval:",v(e,E)));const o=t++;v(e,X).call(this,s,n),e.onAfterRender(s,n,o)}}disable(){v(this,X)&&(console.debug("[gltf-progressive] Disabling LODsManager for renderer"),this.renderer.render=v(this,X),F(this,X,void 0))}update(t,e){this.internalUpdate(t,e)}onAfterRender(t,e,s){if(this.pause)return;const n=this.renderer.renderLists.get(t,0).opaque;let r=!0;if(n.length===1){const o=n[0].material;(o.name==="EffectMaterial"||o.name==="CopyShader")&&(r=!1)}if((e.parent&&e.parent.type==="CubeCamera"||s>=1&&e.type==="OrthographicCamera")&&(r=!1),r){if(ht||(this.updateInterval==="auto"?v(this,K)<40&&v(this,E)<10?(F(this,E,v(this,E)+1),N&&console.warn("\u2193 Reducing LOD updates",v(this,E),v(this,K).toFixed(0))):v(this,K)>=60&&v(this,E)>1&&(F(this,E,v(this,E)-1),N&&console.warn("\u2191 Increasing LOD updates",v(this,E),v(this,K).toFixed(0))):F(this,E,this.updateInterval),v(this,E)>0&&v(this,ee)%v(this,E)!=0))return;this.internalUpdate(t,e)}}internalUpdate(t,e){var s,n;const r=this.renderer.renderLists.get(t,0),o=r.opaque;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse);const i=this.targetTriangleDensity;for(const a of o){if(a.material&&(((s=a.geometry)==null?void 0:s.type)==="BoxGeometry"||((n=a.geometry)==null?void 0:n.type)==="BufferGeometry")&&(a.material.name==="SphericalGaussianBlur"||a.material.name=="BackgroundCubeMaterial"||a.material.name==="CubemapFromEquirect"||a.material.name==="EquirectangularToCubeUV")){N&&(a.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(a.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",a,a.material.name,a.material.type)));continue}switch(a.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}if(N==="color"&&a.material&&!a.object.progressive_debug_color){a.object.progressive_debug_color=!0;const x=Math.random()*16777215,m=new Ze({color:x});a.object.material=m}const h=a.object;(h instanceof Y||h.isMesh)&&this.updateLODs(t,e,h,i)}const l=r.transparent;for(const a of l){const h=a.object;(h instanceof Y||h.isMesh)&&this.updateLODs(t,e,h,i)}const u=r.transmissive;for(const a of u){const h=a.object;(h instanceof Y||h.isMesh)&&this.updateLODs(t,e,h,i)}}updateLODs(t,e,s,n){var r,o;s.userData||(s.userData={});let i=s[Se];if(i||(i=new gt,s[Se]=i),i.frames++<2)return;for(const u of V)(r=u.onBeforeUpdateLOD)==null||r.call(u,this.renderer,t,e,s);const l=P.overrideGlobalLodLevel!==void 0?P.overrideGlobalLodLevel:J;l>=0?(A.mesh_lod=l,A.texture_lod=l):(this.calculateLodLevel(e,s,i,n,A),A.mesh_lod=Math.round(A.mesh_lod),A.texture_lod=Math.round(A.texture_lod)),A.mesh_lod>=0&&this.loadProgressiveMeshes(s,A.mesh_lod),s.material&&A.texture_lod>=0&&this.loadProgressiveTextures(s.material,A.texture_lod),L&&s.material&&!s.isGizmo&&We(s.material);for(const u of V)(o=u.onAfterUpdatedLOD)==null||o.call(u,this.renderer,t,e,s,A);i.lastLodLevel_Mesh=A.mesh_lod,i.lastLodLevel_Texture=A.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const r of t)this.loadProgressiveTextures(r,e);return}let s=!1;(t[q]===void 0||e<t[q])&&(s=!0);const n=t["DEBUG:LOD"];n!=null&&(s=t[q]!=n,e=n),s&&(t[q]=e,T.assignTextureLOD(t,e).then(r=>{this._lodchangedlisteners.forEach(o=>o({type:"texture",level:e,object:t}))}))}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);let s=t[q]!==e;const n=t["DEBUG:LOD"];if(n!=null&&(s=t[q]!=n,e=n),s){t[q]=e;const r=t.geometry;return T.assignMeshLOD(t,e).then(o=>(o&&t[q]==e&&r!=t.geometry&&this._lodchangedlisteners.forEach(i=>i({type:"mesh",level:e,object:t})),o))}return Promise.resolve(null)}static isInside(t,e){const s=t.min,n=t.max,r=(s.x+n.x)*.5,o=(s.y+n.y)*.5;return this._tempPtInside.set(r,o,s.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,s,n,r){var o,i,l;if(!e){r.mesh_lod=-1,r.texture_lod=-1;return}if(!t){r.mesh_lod=-1,r.texture_lod=-1;return}let u=10+1,a=!1;if(N&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const h=(o=T.getMeshLODExtension(e.geometry))==null?void 0:o.lods,x=T.getPrimitiveIndex(e.geometry),m=h&&h.length>0,M=T.getMaterialMinMaxLODsCount(e.material),b=M?.min_count!=1/0&&M.min_count>0&&M.max_count>0;if(!m&&!b){r.mesh_lod=0,r.texture_lod=0;return}m||(a=!0,u=0);const R=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let y=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const p=e;if(!p.boundingBox)p.computeBoundingBox();else if(this.skinnedMeshAutoUpdateBoundsInterval>0&&s.frames%this.skinnedMeshAutoUpdateBoundsInterval===0){const f=Z(p),U=p.geometry;f&&(p.geometry=f),p.computeBoundingBox(),p.geometry=U}y=p.boundingBox}if(y){const p=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 c=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(c)){r.mesh_lod=0,r.texture_lod=0;return}}if(this._tempBox.copy(y),this._tempBox.applyMatrix4(e.matrixWorld),p.isPerspectiveCamera&&P.isInside(this._tempBox,this.projectionScreenMatrix)){r.mesh_lod=0,r.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&p.isPerspectiveCamera&&p.fov>70){const c=this._tempBox.min,g=this._tempBox.max;let S=c.x,I=c.y,C=g.x,te=g.y;const ie=2,pe=1.5,ae=(c.x+g.x)*.5,le=(c.y+g.y)*.5;S=(S-ae)*ie+ae,I=(I-le)*ie+le,C=(C-ae)*ie+ae,te=(te-le)*ie+le;const Xe=S<0&&C>0?0:Math.min(Math.abs(c.x),Math.abs(g.x)),Ke=I<0&&te>0?0:Math.min(Math.abs(c.y),Math.abs(g.y)),ve=Math.max(Xe,Ke);s.lastCentrality=(pe-ve)*(pe-ve)*(pe-ve)}else s.lastCentrality=1;const f=this._tempBox.getSize(this._tempBoxSize);f.multiplyScalar(.5),screen.availHeight>0&&R>0&&f.multiplyScalar(R/screen.availHeight),t.isPerspectiveCamera?f.x*=t.aspect:t.isOrthographicCamera;const U=t.matrixWorldInverse,_=this._tempBox2;_.copy(y),_.applyMatrix4(e.matrixWorld),_.applyMatrix4(U);const j=_.getSize(this._tempBox2Size),O=Math.max(j.x,j.y);if(Math.max(f.x,f.y)!=0&&O!=0&&(f.z=j.z/Math.max(j.x,j.y)*Math.max(f.x,f.y)),s.lastScreenCoverage=Math.max(f.x,f.y,f.z),s.lastScreenspaceVolume.copy(f),s.lastScreenCoverage*=s.lastCentrality,N&&P.debugDrawLine){const c=this.tempMatrix.copy(this.projectionScreenMatrix);c.invert();const g=P.corner0,S=P.corner1,I=P.corner2,C=P.corner3;g.copy(this._tempBox.min),S.copy(this._tempBox.max),S.x=g.x,I.copy(this._tempBox.max),I.y=g.y,C.copy(this._tempBox.max);const te=(g.z+C.z)*.5;g.z=S.z=I.z=C.z=te,g.applyMatrix4(c),S.applyMatrix4(c),I.applyMatrix4(c),C.applyMatrix4(c),P.debugDrawLine(g,S,255),P.debugDrawLine(g,I,255),P.debugDrawLine(S,C,255),P.debugDrawLine(I,C,255)}let D=999;if(h&&s.lastScreenCoverage>0)for(let c=0;c<h.length;c++){const g=h[c];if((((i=g.densities)==null?void 0:i[x])||g.density||1e-5)/s.lastScreenCoverage<n){D=c;break}}D<u&&(u=D,a=!0)}if(a?r.mesh_lod=u:r.mesh_lod=s.lastLodLevel_Mesh,N&&r.mesh_lod!=s.lastLodLevel_Mesh){const p=h?.[r.mesh_lod];p&&console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} \u2192 ${r.mesh_lod} (${p.density.toFixed(0)}) - ${e.name}`)}if(b){const p="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(s.lastLodLevel_Texture<0){if(r.texture_lod=M.max_count-1,N){const f=M.lods[M.max_count-1];N&&console.log(`First Texture LOD ${r.texture_lod} (${f.max_height}px) - ${e.name}`)}}else{const f=s.lastScreenspaceVolume.x+s.lastScreenspaceVolume.y+s.lastScreenspaceVolume.z;let U=s.lastScreenCoverage*4;((l=this.context)==null?void 0:l.engine)==="model-viewer"&&(U*=1.5);const _=R/window.devicePixelRatio*U;let j=!1;for(let O=M.lods.length-1;O>=0;O--){const D=M.lods[O];if(!(p&&D.max_height>=2048)&&!(lt()&&D.max_height>4096)&&(D.max_height>_||!j&&O===0)){if(j=!0,r.texture_lod=O,r.texture_lod<s.lastLodLevel_Texture){const c=D.max_height;N&&console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} \u2192 ${r.texture_lod} = ${c}px
6
+ Screensize: ${_.toFixed(0)}px, Coverage: ${(100*s.lastScreenCoverage).toFixed(2)}%, Volume ${f.toFixed(1)}
7
+ ${e.name}`)}break}}}}else r.texture_lod=0}};let k=P;E=new WeakMap,X=new WeakMap,Te=new WeakMap,ee=new WeakMap,ne=new WeakMap,ge=new WeakMap,K=new WeakMap,d(k,"debugDrawLine"),d(k,"overrideGlobalLodLevel"),d(k,"corner0",new z),d(k,"corner1",new z),d(k,"corner2",new z),d(k,"corner3",new z),d(k,"_tempPtInside",new z);class gt{constructor(){d(this,"frames",0),d(this,"lastLodLevel_Mesh",-1),d(this,"lastLodLevel_Texture",-1),d(this,"lastScreenCoverage",0),d(this,"lastScreenspaceVolume",new z),d(this,"lastCentrality",0)}}const Ue=Symbol("NEEDLE_mesh_lod"),fe=Symbol("NEEDLE_texture_lod");let me=null;function Ae(){const t=ft();t&&(t.mapURLs(function(e){return Fe(),e}),Fe(),me?.disconnect(),me=new MutationObserver(e=>{e.forEach(s=>{s.addedNodes.forEach(n=>{n instanceof HTMLElement&&n.tagName.toLowerCase()==="model-viewer"&&Ve(n)})})}),me.observe(document,{childList:!0,subtree:!0}))}function ft(){return typeof customElements>"u"?null:customElements.get("model-viewer")||(customElements.whenDefined("model-viewer").then(()=>{console.debug("[gltf-progressive] model-viewer defined"),Ae()}),null)}function Fe(){typeof document>"u"||document.querySelectorAll("model-viewer").forEach(t=>{Ve(t)})}const ze=new WeakSet;let mt=0;function Ve(t){if(!t||ze.has(t))return null;ze.add(t),console.debug("[gltf-progressive] found new model-viewer..."+ ++mt+`
8
+ `,t.getAttribute("src"));let e=null,s=null,n=null;for(let r=t;r!=null;r=Object.getPrototypeOf(r)){const o=Object.getOwnPropertySymbols(r),i=o.find(a=>a.toString()=="Symbol(renderer)"),l=o.find(a=>a.toString()=="Symbol(scene)"),u=o.find(a=>a.toString()=="Symbol(needsRender)");!e&&i!=null&&(e=t[i].threeRenderer),!s&&l!=null&&(s=t[l]),!n&&u!=null&&(n=t[u])}if(e&&s){let r=function(){if(n){let i=0,l=setInterval(()=>{if(i++>5){clearInterval(l);return}n?.call(t)},300)}};console.debug("[gltf-progressive] setup model-viewer");const o=k.get(e,{engine:"model-viewer"});return k.addPlugin(new pt),o.enable(),o.addEventListener("changed",()=>{n?.call(t)}),t.addEventListener("model-visibility",i=>{i.detail.visible&&n?.call(t)}),t.addEventListener("load",()=>{r()}),()=>{o.disable()}}return null}class pt{constructor(){d(this,"_didWarnAboutMissingUrl",!1)}onBeforeUpdateLOD(e,s,n,r){this.tryParseMeshLOD(s,r),this.tryParseTextureLOD(s,r)}getUrl(e){if(!e)return null;let s=e.getAttribute("src");return s||(s=e.src),s||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",e),this._didWarnAboutMissingUrl=!0),s}tryGetCurrentGLTF(e){return e._currentGLTF}tryGetCurrentModelViewer(e){return e.element}tryParseTextureLOD(e,s){if(s[fe]==!0)return;s[fe]=!0;const n=this.tryGetCurrentGLTF(e),r=this.tryGetCurrentModelViewer(e),o=this.getUrl(r);if(o&&n&&s.material){let i=function(u){var a,h,x;if(u[fe]==!0)return;u[fe]=!0,u.userData&&(u.userData.LOD=-1);const m=Object.keys(u);for(let M=0;M<m.length;M++){const b=m[M],R=u[b];if(R?.isTexture===!0){const y=(h=(a=R.userData)==null?void 0:a.associations)==null?void 0:h.textures;if(y==null)continue;const p=n.parser.json.textures[y];if(!p){console.warn("Texture data not found for texture index "+y);continue}if((x=p?.extensions)!=null&&x[W]){const f=p.extensions[W];f&&o&&T.registerTexture(o,R,f.lods.length,y,f)}}}};const l=s.material;if(Array.isArray(l))for(const u of l)i(u);else i(l)}}tryParseMeshLOD(e,s){var n,r;if(s[Ue]==!0)return;s[Ue]=!0;const o=this.tryGetCurrentModelViewer(e),i=this.getUrl(o);if(!i)return;const l=(r=(n=s.userData)==null?void 0:n.gltfExtensions)==null?void 0:r[W];if(l&&i){const u=s.uuid;T.registerMesh(i,u,s,0,l.lods.length,l)}}}function qe(t,e,s,n){Le(e),De(s),we(s,{progressive:!0,...n?.hints}),s.register(o=>new T(o,t));const r=k.get(e);return n?.enableLODsManager!==!1&&r.enable(),r}if(Ae(),!ut){const t={gltfProgressive:{useNeedleProgressive:qe,LODsManager:k,configureLoader:we,getRaycastMesh:Z,useRaycastMeshes:$e}};if(!globalThis.Needle)globalThis.Needle=t;else for(const e in t)globalThis.Needle[e]=t[e]}export{W as EXTENSION_NAME,k as LODsManager,T as NEEDLE_progressive,Ce as VERSION,De as addDracoAndKTX2Loaders,we as configureLoader,Le as createLoaders,Z as getRaycastMesh,Ae as patchModelViewer,Ne as registerRaycastMesh,ke as setDracoDecoderLocation,Re as setKTX2TranscoderLocation,qe as useNeedleProgressive,$e as useRaycastMeshes};
@@ -0,0 +1,8 @@
1
+ "use strict";var Ye=Object.defineProperty;var He=(n,t,e)=>t in n?Ye(n,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):n[t]=e;var d=(n,t,e)=>(He(n,typeof t!="symbol"?t+"":t,e),e),Ce=(n,t,e)=>{if(!t.has(n))throw TypeError("Cannot "+e)};var L=(n,t,e)=>(Ce(n,t,"read from private field"),e?e.call(n):t.get(n)),J=(n,t,e)=>{if(t.has(n))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(n):t.set(n,e)},W=(n,t,e,r)=>(Ce(n,t,"write to private field"),r?r.call(n,e):t.set(n,e),e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const p=require("three"),Se=require("three/examples/jsm/loaders/GLTFLoader.js"),je=require("three/examples/jsm/libs/meshopt_decoder.module.js"),Je=require("three/examples/jsm/loaders/DRACOLoader.js"),Qe=require("three/examples/jsm/loaders/KTX2Loader.js"),Ge="";globalThis.GLTF_PROGRESSIVE_VERSION=Ge;console.debug("[gltf-progressive] version -");let X="https://www.gstatic.com/draco/versioned/decoders/1.5.7/",te="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";const Ze=X,et=te,ke=new URL(X+"draco_decoder.js");ke.searchParams.append("range","true");fetch(ke,{method:"GET",headers:{Range:"bytes=0-1"}}).catch(n=>{console.debug(`Failed to fetch remote Draco decoder from ${X} (offline: ${typeof navigator<"u"?navigator.onLine:"unknown"})`),X===Ze&&$e("./include/draco/"),te===et&&Fe("./include/ktx2/")}).finally(()=>{Ne()});function $e(n){X=n,G&&G[_e]!=X?(console.debug("Updating Draco decoder path to "+n),G[_e]=X,G.setDecoderPath(X),G.preload()):console.debug("Setting Draco decoder path to "+n)}function Fe(n){te=n,U&&U.transcoderPath!=te?(console.debug("Updating KTX2 transcoder path to "+n),U.setTranscoderPath(te),U.init()):console.debug("Setting KTX2 transcoder path to "+n)}const _e=Symbol("dracoDecoderPath");let G,pe,U;function Ne(){G||(G=new Je.DRACOLoader,G[_e]=X,G.setDecoderPath(X),G.setDecoderConfig({type:"js"}),G.preload()),U||(U=new Qe.KTX2Loader,U.setTranscoderPath(te),U.init()),pe||(pe=je.MeshoptDecoder)}function Te(n){return Ne(),n?U.detectSupport(n):n!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:G,ktx2Loader:U,meshoptDecoder:pe}}function Ae(n){n.dracoLoader||n.setDRACOLoader(G),n.ktx2Loader||n.setKTX2Loader(U),n.meshoptDecoder||n.setMeshoptDecoder(pe)}const Oe=new WeakMap;function Pe(n,t){let e=Oe.get(n);e?e=Object.assign(e,t):e=t,Oe.set(n,e)}const Me=Se.GLTFLoader.prototype.load;function tt(...n){const t=Oe.get(this);let e=n[0];const r=new URL(e,window.location.href);if(r.hostname.endsWith("needle.tools")){const o=(t==null?void 0:t.progressive)!==void 0?t.progressive:!0,s=t!=null&&t.usecase?t.usecase:"default";o?this.requestHeader.Accept=`*/*;progressive=allowed;usecase=${s}`:this.requestHeader.Accept=`*/*;usecase=${s}`,e=r.toString()}return n[0]=e,Me==null?void 0:Me.call(this,...n)}Se.GLTFLoader.prototype.load=tt;ce("debugprogressive");function ce(n){if(typeof window>"u")return!1;const e=new URL(window.location.href).searchParams.get(n);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function rt(n,t){if(t===void 0||t.startsWith("./")||t.startsWith("http")||n===void 0)return t;const e=n.lastIndexOf("/");if(e>=0){const r=n.substring(0,e+1);for(;r.endsWith("/")&&t.startsWith("/");)t=t.substring(1);return r+t}return t}let ne;function st(){return ne!==void 0||(ne=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),ce("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",ne)),ne}const ot=typeof window>"u"&&typeof document>"u",be=Symbol("needle:raycast-mesh");function oe(n){return(n==null?void 0:n[be])instanceof p.BufferGeometry?n[be]:null}function Ue(n,t){if((n.type==="Mesh"||n.type==="SkinnedMesh")&&!oe(n)){const r=it(t);r.userData={isRaycastMesh:!0},n[be]=r}}function Ve(n=!0){if(n){if(ae)return;const t=ae=p.Mesh.prototype.raycast;p.Mesh.prototype.raycast=function(e,r){const i=this,o=oe(i);let s;o&&i.isMesh&&(s=i.geometry,i.geometry=o),t.call(this,e,r),s&&(i.geometry=s)}}else{if(!ae)return;p.Mesh.prototype.raycast=ae,ae=null}}let ae=null;function it(n){const t=new p.BufferGeometry;for(const e in n.attributes)t.setAttribute(e,n.getAttribute(e));return t.setIndex(n.getIndex()),t}const Z=new Array,x=ce("debugprogressive");let ge,ee=-1;if(x){let n=function(){ee+=1,ee>=t&&(ee=-1),console.log(`Toggle LOD level [${ee}]`)},t=6;window.addEventListener("keyup",e=>{e.key==="p"&&n(),e.key==="w"&&(ge=!ge,console.log(`Toggle wireframe [${ge}]`));const r=parseInt(e.key);!isNaN(r)&&r>=0&&(ee=r,console.log(`Set LOD level to [${ee}]`))})}function ze(n){if(x)if(Array.isArray(n))for(const t of n)ze(t);else n&&"wireframe"in n&&(n.wireframe=ge===!0)}const q="NEEDLE_progressive",De=Symbol("needle-progressive-texture"),S=class{constructor(t,e){d(this,"parser");d(this,"url");d(this,"_isLoadingMesh");d(this,"loadMesh",t=>{var r,i;if(this._isLoadingMesh)return null;const e=(i=(r=this.parser.json.meshes[t])==null?void 0:r.extensions)==null?void 0:i[q];return e?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",t).then(o=>{var s;return this._isLoadingMesh=!1,o&&S.registerMesh(this.url,e.guid,o,(s=e.lods)==null?void 0:s.length,0,e),o})):null});x&&console.log("Progressive extension registered for",e),this.parser=t,this.url=e}get name(){return q}static getMeshLODExtension(t){const e=this.getAssignedLODInformation(t);return e!=null&&e.key?this.lodInfos.get(e.key):null}static getPrimitiveIndex(t){var r;const e=(r=this.getAssignedLODInformation(t))==null?void 0:r.index;return e??-1}static getMaterialMinMaxLODsCount(t,e){const r=this,i="LODS:minmax",o=t[i];if(o!=null)return o;if(e||(e={min_count:1/0,max_count:0,lods:[]}),Array.isArray(t)){for(const a of t)this.getMaterialMinMaxLODsCount(a,e);return t[i]=e,e}if(x==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const a=t;for(const l of Object.keys(a.uniforms)){const u=a.uniforms[l].value;(u==null?void 0:u.isTexture)===!0&&s(u,e)}}else if(t.isMaterial)for(const a of Object.keys(t)){const l=t[a];(l==null?void 0:l.isTexture)===!0&&s(l,e)}return t[i]=e,e;function s(a,l){const u=r.getAssignedLODInformation(a);if(u){const c=r.lodInfos.get(u.key);if(c&&c.lods){l.min_count=Math.min(l.min_count,c.lods.length),l.max_count=Math.max(l.max_count,c.lods.length);for(let h=0;h<c.lods.length;h++){const g=c.lods[h];g.width&&(l.lods[h]=l.lods[h]||{min_height:1/0,max_height:0},l.lods[h].min_height=Math.min(l.lods[h].min_height,g.height),l.lods[h].max_height=Math.max(l.lods[h].max_height,g.height))}}}}}static hasLODLevelAvailable(t,e){var o;if(Array.isArray(t)){for(const s of t)if(this.hasLODLevelAvailable(s,e))return!0;return!1}if(t.isMaterial===!0){for(const s of Object.keys(t)){const a=t[s];if(a&&a.isTexture&&this.hasLODLevelAvailable(a,e))return!0}return!1}else if(t.isGroup===!0){for(const s of t.children)if(s.isMesh===!0&&this.hasLODLevelAvailable(s,e))return!0}let r,i;if(t.isMesh?r=t.geometry:(t.isBufferGeometry||t.isTexture)&&(r=t),r&&(o=r==null?void 0:r.userData)!=null&&o.LODS){const s=r.userData.LODS;if(i=this.lodInfos.get(s.key),e===void 0)return i!=null;if(i)return Array.isArray(i.lods)?e<i.lods.length:e===0}return!1}static assignMeshLOD(t,e){var r;if(!t)return Promise.resolve(null);if(t instanceof p.Mesh||t.isMesh===!0){const i=t.geometry,o=this.getAssignedLODInformation(i);if(!o)return Promise.resolve(null);for(const s of Z)(r=s.onBeforeGetLODMesh)==null||r.call(s,t,e);return t["LOD:requested level"]=e,S.getOrLoadLOD(i,e).then(s=>{if(Array.isArray(s)){const a=o.index||0;s=s[a]}return t["LOD:requested level"]===e&&(delete t["LOD:requested level"],s&&i!=s&&((s==null?void 0:s.isBufferGeometry)?t.geometry=s:x&&console.error("Invalid LOD geometry",s))),s}).catch(s=>(console.error("Error loading mesh LOD",t,s),null))}else x&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",t);return Promise.resolve(null)}static assignTextureLOD(t,e=0){if(!t)return Promise.resolve(null);if(t.isMesh===!0){const r=t;if(Array.isArray(r.material)){const i=new Array;for(const o of r.material){const s=this.assignTextureLOD(o,e);i.push(s)}return Promise.all(i).then(o=>{const s=new Array;for(const a of o)Array.isArray(a)&&s.push(...a);return s})}else return this.assignTextureLOD(r.material,e)}if(t.isMaterial===!0){const r=t,i=[],o=new Array;if(r.uniforms&&(r.isRawShaderMaterial||r.isShaderMaterial===!0)){const s=r;for(const a of Object.keys(s.uniforms)){const l=s.uniforms[a].value;if((l==null?void 0:l.isTexture)===!0){const u=this.assignTextureLODForSlot(l,e,r,a).then(c=>(c&&s.uniforms[a].value!=c&&(s.uniforms[a].value=c,s.uniformsNeedUpdate=!0),c));i.push(u),o.push(a)}}}else for(const s of Object.keys(r)){const a=r[s];if((a==null?void 0:a.isTexture)===!0){const l=this.assignTextureLODForSlot(a,e,r,s);i.push(l),o.push(s)}}return Promise.all(i).then(s=>{const a=new Array;for(let l=0;l<s.length;l++){const u=s[l],c=o[l];u&&u.isTexture===!0?a.push({material:r,slot:c,texture:u,level:e}):a.push({material:r,slot:c,texture:null,level:e})}return a})}if(t instanceof p.Texture||t.isTexture===!0){const r=t;return this.assignTextureLODForSlot(r,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,r,i){return(t==null?void 0:t.isTexture)!==!0?Promise.resolve(null):i==="glyphMap"?Promise.resolve(t):S.getOrLoadLOD(t,e).then(o=>{if(Array.isArray(o))return null;if((o==null?void 0:o.isTexture)===!0){if(o!=t&&r&&i){const s=r[i];if(s&&!x){const a=this.getAssignedLODInformation(s);if(a&&(a==null?void 0:a.level)<e)return x==="verbose"&&console.warn("Assigned texture level is already higher: ",a.level,e,r,s,o),null}r[i]=o}return o}else x=="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 x&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((i,o)=>{var s;if(i!=null&&i.extensions){const a=i==null?void 0:i.extensions[q];if(a){if(!a.lods){x&&console.warn("Texture has no LODs",a);return}let l=!1;for(const u of this.parser.associations.keys())if(u.isTexture===!0){const c=this.parser.associations.get(u);(c==null?void 0:c.textures)===o&&(l=!0,S.registerTexture(this.url,u,(s=a.lods)==null?void 0:s.length,o,a))}l||this.parser.getDependency("texture",o).then(u=>{var c;u&&S.registerTexture(this.url,u,(c=a.lods)==null?void 0:c.length,o,a)})}}}),(r=this.parser.json.meshes)==null||r.forEach((i,o)=>{if(i!=null&&i.extensions){const s=i==null?void 0:i.extensions[q];if(s&&s.lods){for(const a of this.parser.associations.keys())if(a.isMesh){const l=this.parser.associations.get(a);(l==null?void 0:l.meshes)===o&&S.registerMesh(this.url,s.guid,a,s.lods.length,l.primitives,s)}}}}),null}static async getOrLoadLOD(t,e){var a,l,u,c;const r=x=="verbose",i=t.userData.LODS;if(!i)return null;const o=i==null?void 0:i.key;let s;if(t.isTexture===!0){const h=t;h.source&&h.source[De]&&(s=h.source[De])}if(s||(s=S.lodInfos.get(o)),s){if(e>0){let D=!1;const O=Array.isArray(s.lods);if(O&&e>=s.lods.length?D=!0:O||(D=!0),D)return this.lowresCache.get(o)}const h=Array.isArray(s.lods)?(a=s.lods[e])==null?void 0:a.path:s.lods;if(!h)return x&&!s["missing:uri"]&&(s["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,s)),null;const g=rt(i.url,h);if(g.endsWith(".glb")||g.endsWith(".gltf")){if(!s.guid)return console.warn("missing pointer for glb/gltf texture",s),null;const D=g+"_"+s.guid,O=this.previouslyLoaded.get(D);if(O!==void 0){r&&console.log(`LOD ${e} was already loading/loaded: ${D}`);let v=await O.catch(y=>(console.error(`Error loading LOD ${e} from ${g}
2
+ `,y),null)),_=!1;if(v==null||(v instanceof p.Texture&&t instanceof p.Texture?(l=v.image)!=null&&l.data||(u=v.source)!=null&&u.data?v=this.copySettings(t,v):(_=!0,this.previouslyLoaded.delete(D)):v instanceof p.BufferGeometry&&t instanceof p.BufferGeometry&&((c=v.attributes.position)!=null&&c.array||(_=!0,this.previouslyLoaded.delete(D)))),!_)return v}const M=s,V=new Promise(async(v,_)=>{const y=new Se.GLTFLoader;Ae(y),x&&(await new Promise(b=>setTimeout(b,1e3)),r&&console.warn("Start loading (delayed) "+g,M.guid));let Y=g;if(M&&Array.isArray(M.lods)){const b=M.lods[e];b.hash&&(Y+="?v="+b.hash)}const E=await y.loadAsync(Y).catch(b=>(console.error(`Error loading LOD ${e} from ${g}
3
+ `,b),null));if(!E)return null;const $=E.parser;r&&console.log("Loading finished "+g,M.guid);let k=0;if(E.parser.json.textures){let b=!1;for(const f of E.parser.json.textures){if(f!=null&&f.extensions){const T=f==null?void 0:f.extensions[q];if(T!=null&&T.guid&&T.guid===M.guid){b=!0;break}}k++}if(b){let f=await $.getDependency("texture",k);return f&&S.assignLODInformation(i.url,f,o,e,void 0),r&&console.log('change "'+t.name+'" → "'+f.name+'"',g,k,f,D),t instanceof p.Texture&&(f=this.copySettings(t,f)),f&&(f.guid=M.guid),v(f)}else x&&console.warn("Could not find texture with guid",M.guid,E.parser.json)}if(k=0,E.parser.json.meshes){let b=!1;for(const f of E.parser.json.meshes){if(f!=null&&f.extensions){const T=f==null?void 0:f.extensions[q];if(T!=null&&T.guid&&T.guid===M.guid){b=!0;break}}k++}if(b){const f=await $.getDependency("mesh",k);if(r&&console.log(`Loaded Mesh "${f.name}"`,g,k,f,D),f.isMesh===!0){const T=f.geometry;return S.assignLODInformation(i.url,T,o,e,0),v(T)}else{const T=new Array;for(let m=0;m<f.children.length;m++){const w=f.children[m];if(w.isMesh===!0){const C=w.geometry;S.assignLODInformation(i.url,C,o,e,m),T.push(C)}}return v(T)}}else x&&console.warn("Could not find mesh with guid",M.guid,E.parser.json)}return v(null)});return this.previouslyLoaded.set(D,V),await V}else if(t instanceof p.Texture){r&&console.log("Load texture from uri: "+g);const O=await new p.TextureLoader().loadAsync(g);return O?(O.guid=s.guid,O.flipY=!1,O.needsUpdate=!0,O.colorSpace=t.colorSpace,r&&console.log(s,O)):x&&console.warn("failed loading",g),O}}else x&&console.warn(`Can not load LOD ${e}: no LOD info found for "${o}" ${t.name}`,t.type);return null}static assignLODInformation(t,e,r,i,o){if(!e)return;e.userData||(e.userData={});const s=new nt(t,r,i,o);e.userData.LODS=s}static getAssignedLODInformation(t){var e;return((e=t==null?void 0:t.userData)==null?void 0:e.LODS)||null}static copySettings(t,e){return e?(x&&console.warn(`Copy texture settings
4
+ `,t.uuid,`
5
+ `,e.uuid),e=e.clone(),e.offset=t.offset,e.repeat=t.repeat,e.colorSpace=t.colorSpace,e.magFilter=t.magFilter,e.minFilter=t.minFilter,e.wrapS=t.wrapS,e.wrapT=t.wrapT,e.flipY=t.flipY,e.anisotropy=t.anisotropy,e.mipmaps||(e.generateMipmaps=t.generateMipmaps),e):t}};let A=S;d(A,"registerTexture",(t,e,r,i,o)=>{if(x&&console.log("> Progressive: register texture",i,e.name,e.uuid,e,o),!e){x&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[De]=o);const s=o.guid;S.assignLODInformation(t,e,s,r,i),S.lodInfos.set(s,o),S.lowresCache.set(s,e)}),d(A,"registerMesh",(t,e,r,i,o,s)=>{var u;const a=r.geometry;if(!a){x&&console.warn("gltf-progressive: Register mesh without geometry");return}a.userData||(a.userData={}),x&&console.log("> Progressive: register mesh "+r.name,{index:o,uuid:r.uuid},s,r),S.assignLODInformation(t,a,e,i,o),S.lodInfos.set(e,s);let l=S.lowresCache.get(e);l?l.push(r.geometry):l=[r.geometry],S.lowresCache.set(e,l),i>0&&!oe(r)&&Ue(r,a);for(const c of Z)(u=c.onRegisteredNewMesh)==null||u.call(c,r,s)}),d(A,"lodInfos",new Map),d(A,"previouslyLoaded",new Map),d(A,"lowresCache",new Map);class nt{constructor(t,e,r,i){d(this,"url");d(this,"key");d(this,"level");d(this,"index");this.url=t,this.key=e,this.level=r,i!=null&&(this.index=i)}}const N=ce("debugprogressive"),at=ce("noprogressive"),ve=Symbol("Needle:LODSManager"),we=Symbol("Needle:LODState"),Q=Symbol("Needle:CurrentLOD"),B={mesh_lod:-1,texture_lod:-1};var I,H,ye,re,se,Le,j;const P=class{constructor(t,e){d(this,"context");d(this,"renderer");d(this,"projectionScreenMatrix",new p.Matrix4);d(this,"targetTriangleDensity",2e5);d(this,"skinnedMeshAutoUpdateBoundsInterval",30);d(this,"updateInterval","auto");J(this,I,1);d(this,"pause",!1);d(this,"manual",!1);d(this,"_lodchangedlisteners",[]);J(this,H,void 0);J(this,ye,new p.Clock);J(this,re,0);J(this,se,0);J(this,Le,0);J(this,j,0);d(this,"_fpsBuffer",[60,60,60,60,60]);d(this,"_sphere",new p.Sphere);d(this,"_tempBox",new p.Box3);d(this,"_tempBox2",new p.Box3);d(this,"tempMatrix",new p.Matrix4);d(this,"_tempWorldPosition",new p.Vector3);d(this,"_tempBoxSize",new p.Vector3);d(this,"_tempBox2Size",new p.Vector3);this.renderer=t,this.context={...e}}static getObjectLODState(t){return t[we]}static addPlugin(t){Z.push(t)}static removePlugin(t){const e=Z.indexOf(t);e>=0&&Z.splice(e,1)}static get(t,e){if(t[ve])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[ve];const r=new P(t,{engine:"unknown",...e});return t[ve]=r,r}get plugins(){return Z}addEventListener(t,e){t==="changed"&&this._lodchangedlisteners.push(e)}removeEventListener(t,e){if(t==="changed"){const r=this._lodchangedlisteners.indexOf(e);r>=0&&this._lodchangedlisteners.splice(r,1)}}enable(){if(L(this,H))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let t=0;W(this,H,this.renderer.render);const e=this;Te(this.renderer),this.renderer.render=function(r,i){const o=e.renderer.getRenderTarget();(o==null||"isXRRenderTarget"in o&&o.isXRRenderTarget)&&(t=0,W(e,re,L(e,re)+1),W(e,se,L(e,ye).getDelta()),W(e,Le,L(e,Le)+L(e,se)),e._fpsBuffer.shift(),e._fpsBuffer.push(1/L(e,se)),W(e,j,e._fpsBuffer.reduce((a,l)=>a+l)/e._fpsBuffer.length),N&&L(e,re)%200===0&&console.log("FPS",Math.round(L(e,j)),"Interval:",L(e,I)));const s=t++;L(e,H).call(this,r,i),e.onAfterRender(r,i,s)}}disable(){L(this,H)&&(console.debug("[gltf-progressive] Disabling LODsManager for renderer"),this.renderer.render=L(this,H),W(this,H,void 0))}update(t,e){this.internalUpdate(t,e)}onAfterRender(t,e,r){if(this.pause)return;const o=this.renderer.renderLists.get(t,0).opaque;let s=!0;if(o.length===1){const a=o[0].material;(a.name==="EffectMaterial"||a.name==="CopyShader")&&(s=!1)}if((e.parent&&e.parent.type==="CubeCamera"||r>=1&&e.type==="OrthographicCamera")&&(s=!1),s){if(at||(this.updateInterval==="auto"?L(this,j)<40&&L(this,I)<10?(W(this,I,L(this,I)+1),N&&console.warn("↓ Reducing LOD updates",L(this,I),L(this,j).toFixed(0))):L(this,j)>=60&&L(this,I)>1&&(W(this,I,L(this,I)-1),N&&console.warn("↑ Increasing LOD updates",L(this,I),L(this,j).toFixed(0))):W(this,I,this.updateInterval),L(this,I)>0&&L(this,re)%L(this,I)!=0))return;this.internalUpdate(t,e)}}internalUpdate(t,e){var l,u;const r=this.renderer.renderLists.get(t,0),i=r.opaque;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse);const o=this.targetTriangleDensity;for(const c of i){if(c.material&&(((l=c.geometry)==null?void 0:l.type)==="BoxGeometry"||((u=c.geometry)==null?void 0:u.type)==="BufferGeometry")&&(c.material.name==="SphericalGaussianBlur"||c.material.name=="BackgroundCubeMaterial"||c.material.name==="CubemapFromEquirect"||c.material.name==="EquirectangularToCubeUV")){N&&(c.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(c.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",c,c.material.name,c.material.type)));continue}switch(c.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}if(N==="color"&&c.material&&!c.object.progressive_debug_color){c.object.progressive_debug_color=!0;const g=Math.random()*16777215,D=new p.MeshStandardMaterial({color:g});c.object.material=D}const h=c.object;(h instanceof p.Mesh||h.isMesh)&&this.updateLODs(t,e,h,o)}const s=r.transparent;for(const c of s){const h=c.object;(h instanceof p.Mesh||h.isMesh)&&this.updateLODs(t,e,h,o)}const a=r.transmissive;for(const c of a){const h=c.object;(h instanceof p.Mesh||h.isMesh)&&this.updateLODs(t,e,h,o)}}updateLODs(t,e,r,i){var a,l;r.userData||(r.userData={});let o=r[we];if(o||(o=new lt,r[we]=o),o.frames++<2)return;for(const u of Z)(a=u.onBeforeUpdateLOD)==null||a.call(u,this.renderer,t,e,r);const s=P.overrideGlobalLodLevel!==void 0?P.overrideGlobalLodLevel:ee;s>=0?(B.mesh_lod=s,B.texture_lod=s):(this.calculateLodLevel(e,r,o,i,B),B.mesh_lod=Math.round(B.mesh_lod),B.texture_lod=Math.round(B.texture_lod)),B.mesh_lod>=0&&this.loadProgressiveMeshes(r,B.mesh_lod),r.material&&B.texture_lod>=0&&this.loadProgressiveTextures(r.material,B.texture_lod),x&&r.material&&!r.isGizmo&&ze(r.material);for(const u of Z)(l=u.onAfterUpdatedLOD)==null||l.call(u,this.renderer,t,e,r,B);o.lastLodLevel_Mesh=B.mesh_lod,o.lastLodLevel_Texture=B.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const o of t)this.loadProgressiveTextures(o,e);return}let r=!1;(t[Q]===void 0||e<t[Q])&&(r=!0);const i=t["DEBUG:LOD"];i!=null&&(r=t[Q]!=i,e=i),r&&(t[Q]=e,A.assignTextureLOD(t,e).then(o=>{this._lodchangedlisteners.forEach(s=>s({type:"texture",level:e,object:t}))}))}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);let r=t[Q]!==e;const i=t["DEBUG:LOD"];if(i!=null&&(r=t[Q]!=i,e=i),r){t[Q]=e;const o=t.geometry;return A.assignMeshLOD(t,e).then(s=>(s&&t[Q]==e&&o!=t.geometry&&this._lodchangedlisteners.forEach(a=>a({type:"mesh",level:e,object:t})),s))}return Promise.resolve(null)}static isInside(t,e){const r=t.min,i=t.max,o=(r.x+i.x)*.5,s=(r.y+i.y)*.5;return this._tempPtInside.set(o,s,r.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,r,i,o){var V,K,v;if(!e){o.mesh_lod=-1,o.texture_lod=-1;return}if(!t){o.mesh_lod=-1,o.texture_lod=-1;return}let a=10+1,l=!1;if(N&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const u=(V=A.getMeshLODExtension(e.geometry))==null?void 0:V.lods,c=A.getPrimitiveIndex(e.geometry),h=u&&u.length>0,g=A.getMaterialMinMaxLODsCount(e.material),D=(g==null?void 0:g.min_count)!=1/0&&g.min_count>0&&g.max_count>0;if(!h&&!D){o.mesh_lod=0,o.texture_lod=0;return}h||(l=!0,a=0);const O=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let M=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const _=e;if(!_.boundingBox)_.computeBoundingBox();else if(this.skinnedMeshAutoUpdateBoundsInterval>0&&r.frames%this.skinnedMeshAutoUpdateBoundsInterval===0){const y=oe(_),Y=_.geometry;y&&(_.geometry=y),_.computeBoundingBox(),_.geometry=Y}M=_.boundingBox}if(M){const _=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)){o.mesh_lod=0,o.texture_lod=0;return}}if(this._tempBox.copy(M),this._tempBox.applyMatrix4(e.matrixWorld),_.isPerspectiveCamera&&P.isInside(this._tempBox,this.projectionScreenMatrix)){o.mesh_lod=0,o.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&_.isPerspectiveCamera&&_.fov>70){const m=this._tempBox.min,w=this._tempBox.max;let C=m.x,F=m.y,z=w.x,ie=w.y;const ue=2,me=1.5,de=(m.x+w.x)*.5,fe=(m.y+w.y)*.5;C=(C-de)*ue+de,F=(F-fe)*ue+fe,z=(z-de)*ue+de,ie=(ie-fe)*ue+fe;const Xe=C<0&&z>0?0:Math.min(Math.abs(m.x),Math.abs(w.x)),Ke=F<0&&ie>0?0:Math.min(Math.abs(m.y),Math.abs(w.y)),xe=Math.max(Xe,Ke);r.lastCentrality=(me-xe)*(me-xe)*(me-xe)}else r.lastCentrality=1;const y=this._tempBox.getSize(this._tempBoxSize);y.multiplyScalar(.5),screen.availHeight>0&&O>0&&y.multiplyScalar(O/screen.availHeight),t.isPerspectiveCamera?y.x*=t.aspect:t.isOrthographicCamera;const Y=t.matrixWorldInverse,E=this._tempBox2;E.copy(M),E.applyMatrix4(e.matrixWorld),E.applyMatrix4(Y);const $=E.getSize(this._tempBox2Size),k=Math.max($.x,$.y);if(Math.max(y.x,y.y)!=0&&k!=0&&(y.z=$.z/Math.max($.x,$.y)*Math.max(y.x,y.y)),r.lastScreenCoverage=Math.max(y.x,y.y,y.z),r.lastScreenspaceVolume.copy(y),r.lastScreenCoverage*=r.lastCentrality,N&&P.debugDrawLine){const m=this.tempMatrix.copy(this.projectionScreenMatrix);m.invert();const w=P.corner0,C=P.corner1,F=P.corner2,z=P.corner3;w.copy(this._tempBox.min),C.copy(this._tempBox.max),C.x=w.x,F.copy(this._tempBox.max),F.y=w.y,z.copy(this._tempBox.max);const ie=(w.z+z.z)*.5;w.z=C.z=F.z=z.z=ie,w.applyMatrix4(m),C.applyMatrix4(m),F.applyMatrix4(m),z.applyMatrix4(m),P.debugDrawLine(w,C,255),P.debugDrawLine(w,F,255),P.debugDrawLine(C,z,255),P.debugDrawLine(F,z,255)}let f=999;if(u&&r.lastScreenCoverage>0)for(let m=0;m<u.length;m++){const w=u[m];if((((K=w.densities)==null?void 0:K[c])||w.density||1e-5)/r.lastScreenCoverage<i){f=m;break}}f<a&&(a=f,l=!0)}if(l?o.mesh_lod=a:o.mesh_lod=r.lastLodLevel_Mesh,N&&o.mesh_lod!=r.lastLodLevel_Mesh){const y=u==null?void 0:u[o.mesh_lod];y&&console.log(`Mesh LOD changed: ${r.lastLodLevel_Mesh} → ${o.mesh_lod} (${y.density.toFixed(0)}) - ${e.name}`)}if(D){const _="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(r.lastLodLevel_Texture<0){if(o.texture_lod=g.max_count-1,N){const y=g.lods[g.max_count-1];N&&console.log(`First Texture LOD ${o.texture_lod} (${y.max_height}px) - ${e.name}`)}}else{const y=r.lastScreenspaceVolume.x+r.lastScreenspaceVolume.y+r.lastScreenspaceVolume.z;let Y=r.lastScreenCoverage*4;((v=this.context)==null?void 0:v.engine)==="model-viewer"&&(Y*=1.5);const $=O/window.devicePixelRatio*Y;let k=!1;for(let b=g.lods.length-1;b>=0;b--){const f=g.lods[b];if(!(_&&f.max_height>=2048)&&!(st()&&f.max_height>4096)&&(f.max_height>$||!k&&b===0)){if(k=!0,o.texture_lod=b,o.texture_lod<r.lastLodLevel_Texture){const T=f.max_height;N&&console.log(`Texture LOD changed: ${r.lastLodLevel_Texture} → ${o.texture_lod} = ${T}px
6
+ Screensize: ${$.toFixed(0)}px, Coverage: ${(100*r.lastScreenCoverage).toFixed(2)}%, Volume ${y.toFixed(1)}
7
+ ${e.name}`)}break}}}}else o.texture_lod=0}};let R=P;I=new WeakMap,H=new WeakMap,ye=new WeakMap,re=new WeakMap,se=new WeakMap,Le=new WeakMap,j=new WeakMap,d(R,"debugDrawLine"),d(R,"overrideGlobalLodLevel"),d(R,"corner0",new p.Vector3),d(R,"corner1",new p.Vector3),d(R,"corner2",new p.Vector3),d(R,"corner3",new p.Vector3),d(R,"_tempPtInside",new p.Vector3);class lt{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 Be=Symbol("NEEDLE_mesh_lod"),he=Symbol("NEEDLE_texture_lod");let le=null;function Ee(){const n=ct();n&&(n.mapURLs(function(t){return Re(),t}),Re(),le==null||le.disconnect(),le=new MutationObserver(t=>{t.forEach(e=>{e.addedNodes.forEach(r=>{r instanceof HTMLElement&&r.tagName.toLowerCase()==="model-viewer"&&We(r)})})}),le.observe(document,{childList:!0,subtree:!0}))}function ct(){if(typeof customElements>"u")return null;const n=customElements.get("model-viewer");return n||(customElements.whenDefined("model-viewer").then(()=>{console.debug("[gltf-progressive] model-viewer defined"),Ee()}),null)}function Re(){if(typeof document>"u")return;document.querySelectorAll("model-viewer").forEach(t=>{We(t)})}const Ie=new WeakSet;let ut=0;function We(n){if(!n||Ie.has(n))return null;Ie.add(n),console.debug("[gltf-progressive] found new model-viewer..."+ ++ut+`
8
+ `,n.getAttribute("src"));let t=null,e=null,r=null;for(let i=n;i!=null;i=Object.getPrototypeOf(i)){const o=Object.getOwnPropertySymbols(i),s=o.find(u=>u.toString()=="Symbol(renderer)"),a=o.find(u=>u.toString()=="Symbol(scene)"),l=o.find(u=>u.toString()=="Symbol(needsRender)");!t&&s!=null&&(t=n[s].threeRenderer),!e&&a!=null&&(e=n[a]),!r&&l!=null&&(r=n[l])}if(t&&e){let i=function(){if(r){let s=0,a=setInterval(()=>{if(s++>5){clearInterval(a);return}r==null||r.call(n)},300)}};console.debug("[gltf-progressive] setup model-viewer");const o=R.get(t,{engine:"model-viewer"});return R.addPlugin(new dt),o.enable(),o.addEventListener("changed",()=>{r==null||r.call(n)}),n.addEventListener("model-visibility",s=>{s.detail.visible&&(r==null||r.call(n))}),n.addEventListener("load",()=>{i()}),()=>{o.disable()}}return null}class dt{constructor(){d(this,"_didWarnAboutMissingUrl",!1)}onBeforeUpdateLOD(t,e,r,i){this.tryParseMeshLOD(e,i),this.tryParseTextureLOD(e,i)}getUrl(t){if(!t)return null;let e=t.getAttribute("src");return e||(e=t.src),e||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",t),this._didWarnAboutMissingUrl=!0),e}tryGetCurrentGLTF(t){return t._currentGLTF}tryGetCurrentModelViewer(t){return t.element}tryParseTextureLOD(t,e){if(e[he]==!0)return;e[he]=!0;const r=this.tryGetCurrentGLTF(t),i=this.tryGetCurrentModelViewer(t),o=this.getUrl(i);if(o&&r&&e.material){let s=function(l){var c,h,g;if(l[he]==!0)return;l[he]=!0,l.userData&&(l.userData.LOD=-1);const u=Object.keys(l);for(let D=0;D<u.length;D++){const O=u[D],M=l[O];if((M==null?void 0:M.isTexture)===!0){const V=(h=(c=M.userData)==null?void 0:c.associations)==null?void 0:h.textures;if(V==null)continue;const K=r.parser.json.textures[V];if(!K){console.warn("Texture data not found for texture index "+V);continue}if((g=K==null?void 0:K.extensions)!=null&&g[q]){const v=K.extensions[q];v&&o&&A.registerTexture(o,M,v.lods.length,V,v)}}}};const a=e.material;if(Array.isArray(a))for(const l of a)s(l);else s(a)}}tryParseMeshLOD(t,e){var s,a;if(e[Be]==!0)return;e[Be]=!0;const r=this.tryGetCurrentModelViewer(t),i=this.getUrl(r);if(!i)return;const o=(a=(s=e.userData)==null?void 0:s.gltfExtensions)==null?void 0:a[q];if(o&&i){const l=e.uuid;A.registerMesh(i,l,e,0,o.lods.length,o)}}}function qe(n,t,e,r){Te(t),Ae(e),Pe(e,{progressive:!0,...r==null?void 0:r.hints}),e.register(o=>new A(o,n));const i=R.get(t);return(r==null?void 0:r.enableLODsManager)!==!1&&i.enable(),i}Ee();if(!ot){const n={gltfProgressive:{useNeedleProgressive:qe,LODsManager:R,configureLoader:Pe,getRaycastMesh:oe,useRaycastMeshes:Ve}};if(!globalThis.Needle)globalThis.Needle=n;else for(const t in n)globalThis.Needle[t]=n[t]}exports.EXTENSION_NAME=q;exports.LODsManager=R;exports.NEEDLE_progressive=A;exports.VERSION=Ge;exports.addDracoAndKTX2Loaders=Ae;exports.configureLoader=Pe;exports.createLoaders=Te;exports.getRaycastMesh=oe;exports.patchModelViewer=Ee;exports.registerRaycastMesh=Ue;exports.setDracoDecoderLocation=$e;exports.setKTX2TranscoderLocation=Fe;exports.useNeedleProgressive=qe;exports.useRaycastMeshes=Ve;
@@ -6,22 +6,25 @@ declare type NEEDLE_progressive_model_LOD = {
6
6
  hash?: string;
7
7
  };
8
8
  /** This is the data structure we have in the NEEDLE_progressive extension */
9
- declare type NEEDLE_progressive_model = {
9
+ declare type NEEDLE_progressive_ext = {
10
10
  guid: string;
11
11
  lods: Array<NEEDLE_progressive_model_LOD>;
12
12
  };
13
- export declare type NEEDLE_progressive_texture_model = NEEDLE_progressive_model & {
13
+ export declare type NEEDLE_ext_progressive_texture = NEEDLE_progressive_ext & {
14
14
  lods: Array<NEEDLE_progressive_model_LOD & {
15
15
  width: number;
16
16
  height: number;
17
17
  }>;
18
18
  };
19
- export declare type NEEDLE_progressive_mesh_model = NEEDLE_progressive_model & {
19
+ export declare type NEEDLE_ext_progressive_mesh = NEEDLE_progressive_ext & {
20
+ /** @deprecated Removed */
20
21
  density: number;
21
22
  lods: Array<NEEDLE_progressive_model_LOD & {
23
+ /** @deprecated Use densities with the primitive index */
22
24
  density: number;
23
25
  indexCount: number;
24
26
  vertexCount: number;
27
+ densities: number[] | undefined;
25
28
  }>;
26
29
  };
27
30
  /**
@@ -64,7 +67,8 @@ declare type TextureLODsMinMaxInfo = {
64
67
  export declare class NEEDLE_progressive implements GLTFLoaderPlugin {
65
68
  /** The name of the extension */
66
69
  get name(): string;
67
- static getMeshLODInformation(geo: BufferGeometry): NEEDLE_progressive_mesh_model | null;
70
+ static getMeshLODExtension(geo: BufferGeometry): NEEDLE_ext_progressive_mesh | null;
71
+ static getPrimitiveIndex(geo: BufferGeometry): number;
68
72
  static getMaterialMinMaxLODsCount(material: Material | Material[], minmax?: TextureLODsMinMaxInfo): TextureLODsMinMaxInfo;
69
73
  /** Check if a LOD level is available for a mesh or a texture
70
74
  * @param obj the mesh or texture to check
@@ -107,11 +111,11 @@ export declare class NEEDLE_progressive implements GLTFLoaderPlugin {
107
111
  /**
108
112
  * Register a texture with LOD information
109
113
  */
110
- static registerTexture: (url: string, tex: Texture, level: number, index: number, ext: NEEDLE_progressive_texture_model) => void;
114
+ static registerTexture: (url: string, tex: Texture, level: number, index: number, ext: NEEDLE_ext_progressive_texture) => void;
111
115
  /**
112
116
  * Register a mesh with LOD information
113
117
  */
114
- static registerMesh: (url: string, key: string, mesh: Mesh, level: number, index: number | undefined, ext: NEEDLE_progressive_mesh_model) => void;
118
+ static registerMesh: (url: string, key: string, mesh: Mesh, level: number, index: number, ext: NEEDLE_ext_progressive_mesh) => void;
115
119
  /** A map of key = asset uuid and value = LOD information */
116
120
  private static readonly lodInfos;
117
121
  /** cache of already loaded mesh lods */
@@ -1,80 +1,15 @@
1
1
  import { BufferGeometry, Mesh, Texture, TextureLoader } from "three";
2
2
  import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
3
3
  import { addDracoAndKTX2Loaders } from "./loaders.js";
4
- import { getParam, resolveUrl } from "./utils.internal.js";
4
+ import { resolveUrl } from "./utils.internal.js";
5
5
  import { getRaycastMesh, registerRaycastMesh } from "./utils.js";
6
6
  // All of this has to be removed
7
7
  // import { getRaycastMesh, setRaycastMesh } from "../../engine_physics.js";
8
8
  // import { PromiseAllWithErrors, resolveUrl } from "../../engine_utils.js";
9
9
  import { plugins } from "./plugins/plugin.js";
10
+ import { debug } from "./lods.debug.js";
10
11
  export const EXTENSION_NAME = "NEEDLE_progressive";
11
- const debug = getParam("debugprogressive");
12
12
  const $progressiveTextureExtension = Symbol("needle-progressive-texture");
13
- const debug_toggle_maps = new Map();
14
- const debug_materials = new Set();
15
- if (debug) {
16
- let currentDebugLodLevel = -1;
17
- let maxLevel = 2;
18
- let wireframe = false;
19
- function debugToggleProgressive() {
20
- currentDebugLodLevel += 1;
21
- console.log("Toggle LOD level", currentDebugLodLevel, debug_toggle_maps);
22
- debug_toggle_maps.forEach((arr, obj) => {
23
- for (const key of arr.keys) {
24
- const cur = obj[key];
25
- // if it's null or undefined we skip it
26
- if (cur == null) {
27
- continue;
28
- }
29
- if (cur.isBufferGeometry === true) {
30
- const info = NEEDLE_progressive.getMeshLODInformation(cur);
31
- const level = !info ? 0 : Math.min(currentDebugLodLevel, info.lods.length);
32
- obj["DEBUG:LOD"] = level;
33
- // NEEDLE_progressive.assignMeshLOD(obj as Mesh, level);
34
- if (info)
35
- maxLevel = Math.max(maxLevel, info.lods.length - 1);
36
- }
37
- else if (obj.isMaterial === true) {
38
- obj["DEBUG:LOD"] = currentDebugLodLevel;
39
- // NEEDLE_progressive.assignTextureLOD(obj as Material, currentDebugLodLevel);
40
- }
41
- }
42
- });
43
- if (currentDebugLodLevel >= maxLevel) {
44
- currentDebugLodLevel = -1;
45
- }
46
- }
47
- window.addEventListener("keyup", evt => {
48
- if (evt.key === "p")
49
- debugToggleProgressive();
50
- if (evt.key === "w") {
51
- wireframe = !wireframe;
52
- if (debug_materials) {
53
- debug_materials.forEach(mat => {
54
- // we don't want to change the skybox material
55
- if (mat.name == "BackgroundCubeMaterial")
56
- return;
57
- if (mat["glyphMap"] != undefined)
58
- return;
59
- if ("wireframe" in mat) {
60
- mat.wireframe = wireframe;
61
- }
62
- });
63
- }
64
- }
65
- });
66
- }
67
- function registerDebug(obj, key, sourceId) {
68
- if (!debug)
69
- return;
70
- if (!debug_toggle_maps.has(obj)) {
71
- debug_toggle_maps.set(obj, { keys: [], sourceId });
72
- }
73
- const existing = debug_toggle_maps.get(obj);
74
- if (existing?.keys?.includes(key) == false) {
75
- existing.keys.push(key);
76
- }
77
- }
78
13
  /**
79
14
  * The NEEDLE_progressive extension for the GLTFLoader is responsible for loading progressive LODs for meshes and textures.
80
15
  * This extension can be used to load different resolutions of a mesh or texture at runtime (e.g. for LODs or progressive textures).
@@ -95,13 +30,19 @@ export class NEEDLE_progressive {
95
30
  get name() {
96
31
  return EXTENSION_NAME;
97
32
  }
98
- static getMeshLODInformation(geo) {
33
+ static getMeshLODExtension(geo) {
99
34
  const info = this.getAssignedLODInformation(geo);
100
35
  if (info?.key) {
101
36
  return this.lodInfos.get(info.key);
102
37
  }
103
38
  return null;
104
39
  }
40
+ static getPrimitiveIndex(geo) {
41
+ const index = this.getAssignedLODInformation(geo)?.index;
42
+ if (index === undefined || index === null)
43
+ return -1;
44
+ return index;
45
+ }
105
46
  static getMaterialMinMaxLODsCount(material, minmax) {
106
47
  const self = this;
107
48
  // we can cache this material min max data because it wont change at runtime
@@ -261,8 +202,6 @@ export class NEEDLE_progressive {
261
202
  // if (debug == "verbose") console.log("Progressive Mesh " + mesh.name + " loaded", currentGeometry, "→", geo, "\n", mesh)
262
203
  if (isGeometry) {
263
204
  mesh.geometry = geo;
264
- if (debug)
265
- registerDebug(mesh, "geometry", lodinfo.url);
266
205
  }
267
206
  else if (debug) {
268
207
  console.error("Invalid LOD geometry", geo);
@@ -311,8 +250,6 @@ export class NEEDLE_progressive {
311
250
  const material = materialOrTexture;
312
251
  const promises = [];
313
252
  const slots = new Array();
314
- if (debug)
315
- debug_materials.add(material);
316
253
  // Handle custom shaders / uniforms progressive textures. This includes support for VRM shaders
317
254
  if (material.uniforms && (material.isRawShaderMaterial || material.isShaderMaterial === true)) {
318
255
  // iterate uniforms of custom shaders
@@ -391,13 +328,6 @@ export class NEEDLE_progressive {
391
328
  }
392
329
  material[slot] = tex;
393
330
  }
394
- if (debug && slot && material) {
395
- const lodinfo = this.getAssignedLODInformation(current);
396
- if (lodinfo)
397
- registerDebug(material, slot, lodinfo.url);
398
- else
399
- console.warn("No LOD info for texture", current);
400
- }
401
331
  // check if the old texture is still used by other objects
402
332
  // if not we dispose it...
403
333
  // this could also be handled elsewhere and not be done immediately
@@ -440,7 +370,7 @@ export class NEEDLE_progressive {
440
370
  return this.parser.getDependency("mesh", meshIndex).then(mesh => {
441
371
  this._isLoadingMesh = false;
442
372
  if (mesh) {
443
- NEEDLE_progressive.registerMesh(this.url, ext.guid, mesh, ext.lods?.length, undefined, ext);
373
+ NEEDLE_progressive.registerMesh(this.url, ext.guid, mesh, ext.lods?.length, 0, ext);
444
374
  }
445
375
  return mesh;
446
376
  });
@@ -522,7 +452,7 @@ export class NEEDLE_progressive {
522
452
  if (tex.source)
523
453
  tex.source[$progressiveTextureExtension] = ext;
524
454
  const LODKEY = ext.guid;
525
- NEEDLE_progressive.assignLODInformation(url, tex, LODKEY, level, index, undefined);
455
+ NEEDLE_progressive.assignLODInformation(url, tex, LODKEY, level, index);
526
456
  NEEDLE_progressive.lodInfos.set(LODKEY, ext);
527
457
  NEEDLE_progressive.lowresCache.set(LODKEY, tex);
528
458
  };
@@ -530,8 +460,6 @@ export class NEEDLE_progressive {
530
460
  * Register a mesh with LOD information
531
461
  */
532
462
  static registerMesh = (url, key, mesh, level, index, ext) => {
533
- if (debug)
534
- console.log("> Progressive: register mesh", index, mesh.name, ext, mesh.uuid, mesh);
535
463
  const geometry = mesh.geometry;
536
464
  if (!geometry) {
537
465
  if (debug)
@@ -540,7 +468,9 @@ export class NEEDLE_progressive {
540
468
  }
541
469
  if (!geometry.userData)
542
470
  geometry.userData = {};
543
- NEEDLE_progressive.assignLODInformation(url, geometry, key, level, index, ext.density);
471
+ if (debug)
472
+ console.log("> Progressive: register mesh " + mesh.name, { index, uuid: mesh.uuid }, ext, mesh);
473
+ NEEDLE_progressive.assignLODInformation(url, geometry, key, level, index);
544
474
  NEEDLE_progressive.lodInfos.set(key, ext);
545
475
  let existing = NEEDLE_progressive.lowresCache.get(key);
546
476
  if (existing)
@@ -695,7 +625,7 @@ export class NEEDLE_progressive {
695
625
  if (found) {
696
626
  let tex = await parser.getDependency("texture", index);
697
627
  if (tex) {
698
- NEEDLE_progressive.assignLODInformation(LOD.url, tex, LODKEY, level, undefined, undefined);
628
+ NEEDLE_progressive.assignLODInformation(LOD.url, tex, LODKEY, level, undefined);
699
629
  }
700
630
  if (debugverbose)
701
631
  console.log("change \"" + current.name + "\" → \"" + tex.name + "\"", lod_url, index, tex, KEY);
@@ -733,7 +663,7 @@ export class NEEDLE_progressive {
733
663
  console.log(`Loaded Mesh \"${mesh.name}\"`, lod_url, index, mesh, KEY);
734
664
  if (mesh.isMesh === true) {
735
665
  const geo = mesh.geometry;
736
- NEEDLE_progressive.assignLODInformation(LOD.url, geo, LODKEY, level, undefined, meshExt.density);
666
+ NEEDLE_progressive.assignLODInformation(LOD.url, geo, LODKEY, level, 0);
737
667
  return resolve(geo);
738
668
  }
739
669
  else {
@@ -742,7 +672,7 @@ export class NEEDLE_progressive {
742
672
  const child = mesh.children[i];
743
673
  if (child.isMesh === true) {
744
674
  const geo = child.geometry;
745
- NEEDLE_progressive.assignLODInformation(LOD.url, geo, LODKEY, level, i, meshExt.density);
675
+ NEEDLE_progressive.assignLODInformation(LOD.url, geo, LODKEY, level, i);
746
676
  geometries.push(geo);
747
677
  }
748
678
  }
@@ -786,12 +716,12 @@ export class NEEDLE_progressive {
786
716
  }
787
717
  return null;
788
718
  }
789
- static assignLODInformation(url, res, key, level, index, density) {
719
+ static assignLODInformation(url, res, key, level, index) {
790
720
  if (!res)
791
721
  return;
792
722
  if (!res.userData)
793
723
  res.userData = {};
794
- const info = new LODInformation(url, key, level, index, density);
724
+ const info = new LODInformation(url, key, level, index);
795
725
  res.userData.LODS = info;
796
726
  }
797
727
  static getAssignedLODInformation(res) {
@@ -848,16 +778,12 @@ class LODInformation {
848
778
  level;
849
779
  /** For multi objects (e.g. a group of meshes) this is the index of the object */
850
780
  index;
851
- /** the mesh density */
852
- density;
853
- constructor(url, key, level, index, density) {
781
+ constructor(url, key, level, index) {
854
782
  this.url = url;
855
783
  this.key = key;
856
784
  this.level = level;
857
785
  if (index != undefined)
858
786
  this.index = index;
859
- if (density != undefined)
860
- this.density = density;
861
787
  }
862
788
  }
863
789
  ;
@@ -0,0 +1,4 @@
1
+ import { Material } from "three";
2
+ export declare const debug: string | boolean;
3
+ export declare let debug_OverrideLodLevel: number;
4
+ export declare function applyDebugSettings(material: Material | Array<Material>): void;
@@ -0,0 +1,41 @@
1
+ import { getParam } from "./utils.internal.js";
2
+ export const debug = getParam("debugprogressive");
3
+ let debug_RenderWireframe;
4
+ export let debug_OverrideLodLevel = -1; // -1 is automatic
5
+ if (debug) {
6
+ let maxLevel = 6;
7
+ function debugToggleProgressive() {
8
+ debug_OverrideLodLevel += 1;
9
+ if (debug_OverrideLodLevel >= maxLevel) {
10
+ debug_OverrideLodLevel = -1;
11
+ }
12
+ console.log(`Toggle LOD level [${debug_OverrideLodLevel}]`);
13
+ }
14
+ window.addEventListener("keyup", evt => {
15
+ if (evt.key === "p")
16
+ debugToggleProgressive();
17
+ if (evt.key === "w") {
18
+ debug_RenderWireframe = !debug_RenderWireframe;
19
+ console.log(`Toggle wireframe [${debug_RenderWireframe}]`);
20
+ }
21
+ const pressedNumber = parseInt(evt.key);
22
+ if (!isNaN(pressedNumber) && pressedNumber >= 0) {
23
+ debug_OverrideLodLevel = pressedNumber;
24
+ console.log(`Set LOD level to [${debug_OverrideLodLevel}]`);
25
+ }
26
+ });
27
+ }
28
+ export function applyDebugSettings(material) {
29
+ if (!debug)
30
+ return;
31
+ if (Array.isArray(material)) {
32
+ for (const mat of material) {
33
+ applyDebugSettings(mat);
34
+ }
35
+ }
36
+ else if (material) {
37
+ if ("wireframe" in material) {
38
+ material.wireframe = debug_RenderWireframe === true;
39
+ }
40
+ }
41
+ }
@@ -43,9 +43,14 @@ declare type LODChangedEventListener = (args: {
43
43
  */
44
44
  export declare class LODsManager {
45
45
  #private;
46
- /** Assign a function to draw debug lines for the LODs. This function will be called with the start and end position of the line and the color of the line when the `debugprogressive` query parameter is set.
46
+ /**
47
+ * Assign a function to draw debug lines for the LODs. This function will be called with the start and end position of the line and the color of the line when the `debugprogressive` query parameter is set.
47
48
  */
48
49
  static debugDrawLine?: (a: Vector3, b: Vector3, color: number) => void;
50
+ /**
51
+ * Force override the LOD level for all objects in the scene
52
+ */
53
+ static overrideGlobalLodLevel?: number;
49
54
  /** @internal */
50
55
  static getObjectLODState(object: Object3D): LOD_state | undefined;
51
56
  static addPlugin(plugin: NEEDLE_progressive_plugin): void;
@@ -4,6 +4,7 @@ import { createLoaders } from "./loaders.js";
4
4
  import { getParam, isMobileDevice } from "./utils.internal.js";
5
5
  import { plugins } from "./plugins/plugin.js";
6
6
  import { getRaycastMesh } from "./utils.js";
7
+ import { applyDebugSettings, debug, debug_OverrideLodLevel } from "./lods.debug.js";
7
8
  const debugProgressiveLoading = getParam("debugprogressive");
8
9
  const suppressProgressiveLoading = getParam("noprogressive");
9
10
  const $lodsManager = Symbol("Needle:LODSManager");
@@ -40,9 +41,14 @@ const levels = { mesh_lod: -1, texture_lod: -1 };
40
41
  * ```
41
42
  */
42
43
  export class LODsManager {
43
- /** Assign a function to draw debug lines for the LODs. This function will be called with the start and end position of the line and the color of the line when the `debugprogressive` query parameter is set.
44
+ /**
45
+ * Assign a function to draw debug lines for the LODs. This function will be called with the start and end position of the line and the color of the line when the `debugprogressive` query parameter is set.
44
46
  */
45
47
  static debugDrawLine;
48
+ /**
49
+ * Force override the LOD level for all objects in the scene
50
+ */
51
+ static overrideGlobalLodLevel;
46
52
  /** @internal */
47
53
  static getObjectLODState(object) {
48
54
  return object[$lodstate];
@@ -305,17 +311,26 @@ export class LODsManager {
305
311
  for (const plugin of plugins) {
306
312
  plugin.onBeforeUpdateLOD?.(this.renderer, scene, camera, object);
307
313
  }
308
- this.calculateLodLevel(camera, object, state, desiredDensity, levels);
309
- levels.mesh_lod = Math.round(levels.mesh_lod);
310
- levels.texture_lod = Math.round(levels.texture_lod);
314
+ const debugLodLevel = LODsManager.overrideGlobalLodLevel !== undefined ? LODsManager.overrideGlobalLodLevel : debug_OverrideLodLevel;
315
+ if (debugLodLevel >= 0) {
316
+ levels.mesh_lod = debugLodLevel;
317
+ levels.texture_lod = debugLodLevel;
318
+ }
319
+ else {
320
+ this.calculateLodLevel(camera, object, state, desiredDensity, levels);
321
+ levels.mesh_lod = Math.round(levels.mesh_lod);
322
+ levels.texture_lod = Math.round(levels.texture_lod);
323
+ }
311
324
  // we currently only support auto LOD changes for meshes
312
325
  if (levels.mesh_lod >= 0) {
313
326
  this.loadProgressiveMeshes(object, levels.mesh_lod);
314
327
  }
315
328
  // TODO: we currently can not switch texture lods because we need better caching for the textures internally (see copySettings in progressive + NE-4431)
316
- let textureLOD = levels.texture_lod;
317
- if (object.material && textureLOD >= 0) {
318
- this.loadProgressiveTextures(object.material, textureLOD);
329
+ if (object.material && levels.texture_lod >= 0) {
330
+ this.loadProgressiveTextures(object.material, levels.texture_lod);
331
+ }
332
+ if (debug && object.material && !object["isGizmo"]) {
333
+ applyDebugSettings(object.material);
319
334
  }
320
335
  for (const plugin of plugins) {
321
336
  plugin.onAfterUpdatedLOD?.(this.renderer, scene, camera, object, levels);
@@ -435,8 +450,8 @@ export class LODsManager {
435
450
  return mesh["DEBUG:LOD"];
436
451
  }
437
452
  // The mesh info contains also the density for all available LOD level so we can use this for selecting which level to show
438
- const mesh_lods_info = NEEDLE_progressive.getMeshLODInformation(mesh.geometry);
439
- const mesh_lods = mesh_lods_info?.lods;
453
+ const mesh_lods = NEEDLE_progressive.getMeshLODExtension(mesh.geometry)?.lods;
454
+ const primitive_index = NEEDLE_progressive.getPrimitiveIndex(mesh.geometry);
440
455
  const has_mesh_lods = mesh_lods && mesh_lods.length > 0;
441
456
  const texture_lods_minmax = NEEDLE_progressive.getMaterialMinMaxLODsCount(mesh.material);
442
457
  const has_texture_lods = texture_lods_minmax?.min_count != Infinity && texture_lods_minmax.min_count > 0 && texture_lods_minmax.max_count > 0;
@@ -590,7 +605,8 @@ export class LODsManager {
590
605
  // const framerate = this.context.time.smoothedFps;
591
606
  if (mesh_lods && state.lastScreenCoverage > 0) {
592
607
  for (let l = 0; l < mesh_lods.length; l++) {
593
- const densityForThisLevel = mesh_lods[l].density;
608
+ const lod = mesh_lods[l];
609
+ const densityForThisLevel = lod.densities?.[primitive_index] || lod.density || .00001;
594
610
  const resultingDensity = densityForThisLevel / state.lastScreenCoverage;
595
611
  if (resultingDensity < desiredDensity) {
596
612
  expectedLevel = l;
@@ -1,5 +1,5 @@
1
1
  import { WebGLRenderer, Scene, Camera, Mesh } from 'three';
2
- import { NEEDLE_progressive_mesh_model } from '../extension.js';
2
+ import { NEEDLE_ext_progressive_mesh } from '../extension.js';
3
3
  /**
4
4
  * This interface is used to define a plugin for the progressive extension. It can be registered using the `registerPlugin` function.
5
5
  */
@@ -12,7 +12,7 @@ export interface NEEDLE_progressive_plugin {
12
12
  texture_lod: number;
13
13
  }): void;
14
14
  /** Called when a new mesh is registered */
15
- onRegisteredNewMesh?(mesh: Mesh, ext: NEEDLE_progressive_mesh_model): void;
15
+ onRegisteredNewMesh?(mesh: Mesh, ext: NEEDLE_ext_progressive_mesh): void;
16
16
  /** Called before the LOD mesh is fetched */
17
17
  onBeforeGetLODMesh?(mesh: Mesh, level: number): void;
18
18
  }
@@ -1,4 +1,4 @@
1
1
  // replaced at build time
2
- export const version = "2.1.6-next.c9b2e8b";
2
+ export const version = "2.1.6";
3
3
  globalThis["GLTF_PROGRESSIVE_VERSION"] = version;
4
4
  console.debug(`[gltf-progressive] version ${version || "-"}`);