@needle-tools/engine
Version:
Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in
9 lines (8 loc) • 29.3 kB
JavaScript
"use strict";const g=require("./three.umd.cjs"),Z=require("./three-examples.umd.cjs"),Fe="";globalThis.GLTF_PROGRESSIVE_VERSION=Fe;console.debug("[gltf-progressive] version -");let F="https://www.gstatic.com/draco/versioned/decoders/1.5.7/",j="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";const Ue=F,Ve=j,Pe=new URL(F+"draco_decoder.js");Pe.searchParams.append("range","true");fetch(Pe,{method:"GET",headers:{Range:"bytes=0-1"}}).catch(t=>{console.debug(`Failed to fetch remote Draco decoder from ${F} (offline: ${typeof navigator<"u"?navigator.onLine:"unknown"})`),F===Ue&&Ce("./include/draco/"),j===Ve&&Be("./include/ktx2/")}).finally(()=>{ke()});function Ce(t){F=t,C&&C[me]!=F?(console.debug("Updating Draco decoder path to "+t),C[me]=F,C.setDecoderPath(F),C.preload()):console.debug("Setting Draco decoder path to "+t)}function Be(t){j=t,$&&$.transcoderPath!=j?(console.debug("Updating KTX2 transcoder path to "+t),$.setTranscoderPath(j),$.init()):console.debug("Setting KTX2 transcoder path to "+t)}const me=Symbol("dracoDecoderPath");let C,de,$;function ke(){C||(C=new Z.DRACOLoader,C[me]=F,C.setDecoderPath(F),C.setDecoderConfig({type:"js"}),C.preload()),$||($=new Z.KTX2Loader,$.setTranscoderPath(j),$.init()),de||(de=Z.MeshoptDecoder)}function we(t){return ke(),t?$.detectSupport(t):t!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:C,ktx2Loader:$,meshoptDecoder:de}}function Oe(t){t.dracoLoader||t.setDRACOLoader(C),t.ktx2Loader||t.setKTX2Loader($),t.meshoptDecoder||t.setMeshoptDecoder(de)}const xe=new WeakMap;function Se(t,e){let s=xe.get(t);s?s=Object.assign(s,e):s=e,xe.set(t,s)}const pe=Z.GLTFLoader.prototype.load;function We(...t){const e=xe.get(this);let s=t[0];const o=new URL(s,window.location.href);if(o.hostname.endsWith("needle.tools")){const r=(e==null?void 0:e.progressive)!==void 0?e.progressive:!0,n=e!=null&&e.usecase?e.usecase:"default";r?this.requestHeader.Accept=`*/*;progressive=allowed;usecase=${n}`:this.requestHeader.Accept=`*/*;usecase=${n}`,s=o.toString()}return t[0]=s,pe==null?void 0:pe.call(this,...t)}Z.GLTFLoader.prototype.load=We;ne("debugprogressive");function ne(t){if(typeof window>"u")return!1;const s=new URL(window.location.href).searchParams.get(t);return s==null||s==="0"||s==="false"?!1:s===""?!0:s}function ze(t,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||t===void 0)return e;const s=t.lastIndexOf("/");if(s>=0){const o=t.substring(0,s+1);for(;o.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return o+e}return e}let te;function Xe(){return te!==void 0||(te=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),ne("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",te)),te}const qe=typeof window>"u"&&typeof document>"u",De=Symbol("needle:raycast-mesh");function ee(t){return(t==null?void 0:t[De])instanceof g.BufferGeometry?t[De]:null}function Ke(t,e){if((t.type==="Mesh"||t.type==="SkinnedMesh")&&!ee(t)){const o=He(e);o.userData={isRaycastMesh:!0},t[De]=o}}function Ye(t=!0){if(t){if(se)return;const e=se=g.Mesh.prototype.raycast;g.Mesh.prototype.raycast=function(s,o){const i=this,r=ee(i);let n;r&&i.isMesh&&(n=i.geometry,i.geometry=r),e.call(this,s,o),n&&(i.geometry=n)}}else{if(!se)return;g.Mesh.prototype.raycast=se,se=null}}let se=null;function He(t){const e=new g.BufferGeometry;for(const s in t.attributes)e.setAttribute(s,t.getAttribute(s));return e.setIndex(t.getIndex()),e}const H=new Array,z="NEEDLE_progressive",y=ne("debugprogressive"),Me=Symbol("needle-progressive-texture"),oe=new Map,_e=new Set;if(y){let t=function(){e+=1,console.log("Toggle LOD level",e,oe),oe.forEach((i,r)=>{for(const n of i.keys){const a=r[n];if(a!=null)if(a.isBufferGeometry===!0){const c=E.getMeshLODInformation(a),l=c?Math.min(e,c.lods.length):0;r["DEBUG:LOD"]=l,c&&(s=Math.max(s,c.lods.length-1))}else r.isMaterial===!0&&(r["DEBUG:LOD"]=e)}}),e>=s&&(e=-1)},e=-1,s=2,o=!1;window.addEventListener("keyup",i=>{i.key==="p"&&t(),i.key==="w"&&(o=!o,_e&&_e.forEach(r=>{r.name!="BackgroundCubeMaterial"&&r.glyphMap==null&&"wireframe"in r&&(r.wireframe=o)}))})}function be(t,e,s){var i;if(!y)return;oe.has(t)||oe.set(t,{keys:[],sourceId:s});const o=oe.get(t);((i=o==null?void 0:o.keys)==null?void 0:i.includes(e))==!1&&o.keys.push(e)}const _=class{constructor(t,e){this.loadMesh=s=>{var i,r;if(this._isLoadingMesh)return null;const o=(r=(i=this.parser.json.meshes[s])==null?void 0:i.extensions)==null?void 0:r[z];return o?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",s).then(n=>{var a;return this._isLoadingMesh=!1,n&&_.registerMesh(this.url,o.guid,n,(a=o.lods)==null?void 0:a.length,void 0,o),n})):null},y&&console.log("Progressive extension registered for",e),this.parser=t,this.url=e}get name(){return z}static getMeshLODInformation(t){const e=this.getAssignedLODInformation(t);return e!=null&&e.key?this.lodInfos.get(e.key):null}static getMaterialMinMaxLODsCount(t,e){const s=this,o="LODS:minmax",i=t[o];if(i!=null)return i;if(e||(e={min_count:1/0,max_count:0,lods:[]}),Array.isArray(t)){for(const n of t)this.getMaterialMinMaxLODsCount(n,e);return t[o]=e,e}if(y==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const n=t;for(const a of Object.keys(n.uniforms)){const c=n.uniforms[a].value;(c==null?void 0:c.isTexture)===!0&&r(c,e)}}else if(t.isMaterial)for(const n of Object.keys(t)){const a=t[n];(a==null?void 0:a.isTexture)===!0&&r(a,e)}return t[o]=e,e;function r(n,a){const c=s.getAssignedLODInformation(n);if(c){const l=s.lodInfos.get(c.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 d=0;d<l.lods.length;d++){const h=l.lods[d];h.width&&(a.lods[d]=a.lods[d]||{min_height:1/0,max_height:0},a.lods[d].min_height=Math.min(a.lods[d].min_height,h.height),a.lods[d].max_height=Math.max(a.lods[d].max_height,h.height))}}}}}static hasLODLevelAvailable(t,e){var i;if(Array.isArray(t)){for(const r of t)if(this.hasLODLevelAvailable(r,e))return!0;return!1}if(t.isMaterial===!0){for(const r of Object.keys(t)){const n=t[r];if(n&&n.isTexture&&this.hasLODLevelAvailable(n,e))return!0}return!1}else if(t.isGroup===!0){for(const r of t.children)if(r.isMesh===!0&&this.hasLODLevelAvailable(r,e))return!0}let s,o;if(t.isMesh?s=t.geometry:(t.isBufferGeometry||t.isTexture)&&(s=t),s&&(i=s==null?void 0:s.userData)!=null&&i.LODS){const r=s.userData.LODS;if(o=this.lodInfos.get(r.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 s;if(!t)return Promise.resolve(null);if(t instanceof g.Mesh||t.isMesh===!0){const o=t.geometry,i=this.getAssignedLODInformation(o);if(!i)return Promise.resolve(null);for(const r of H)(s=r.onBeforeGetLODMesh)==null||s.call(r,t,e);return t["LOD:requested level"]=e,_.getOrLoadLOD(o,e).then(r=>{if(Array.isArray(r)){const n=i.index||0;r=r[n]}return t["LOD:requested level"]===e&&(delete t["LOD:requested level"],r&&o!=r&&((r==null?void 0:r.isBufferGeometry)?(t.geometry=r,y&&be(t,"geometry",i.url)):y&&console.error("Invalid LOD geometry",r))),r}).catch(r=>(console.error("Error loading mesh LOD",t,r),null))}else y&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",t);return Promise.resolve(null)}static assignTextureLOD(t,e=0){if(!t)return Promise.resolve(null);if(t.isMesh===!0){const s=t;if(Array.isArray(s.material)){const o=new Array;for(const i of s.material){const r=this.assignTextureLOD(i,e);o.push(r)}return Promise.all(o).then(i=>{const r=new Array;for(const n of i)Array.isArray(n)&&r.push(...n);return r})}else return this.assignTextureLOD(s.material,e)}if(t.isMaterial===!0){const s=t,o=[],i=new Array;if(y&&_e.add(s),s.uniforms&&(s.isRawShaderMaterial||s.isShaderMaterial===!0)){const r=s;for(const n of Object.keys(r.uniforms)){const a=r.uniforms[n].value;if((a==null?void 0:a.isTexture)===!0){const c=this.assignTextureLODForSlot(a,e,s,n).then(l=>(l&&r.uniforms[n].value!=l&&(r.uniforms[n].value=l,r.uniformsNeedUpdate=!0),l));o.push(c),i.push(n)}}}else for(const r of Object.keys(s)){const n=s[r];if((n==null?void 0:n.isTexture)===!0){const a=this.assignTextureLODForSlot(n,e,s,r);o.push(a),i.push(r)}}return Promise.all(o).then(r=>{const n=new Array;for(let a=0;a<r.length;a++){const c=r[a],l=i[a];c&&c.isTexture===!0?n.push({material:s,slot:l,texture:c,level:e}):n.push({material:s,slot:l,texture:null,level:e})}return n})}if(t instanceof g.Texture||t.isTexture===!0){const s=t;return this.assignTextureLODForSlot(s,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,s,o){return(t==null?void 0:t.isTexture)!==!0?Promise.resolve(null):o==="glyphMap"?Promise.resolve(t):_.getOrLoadLOD(t,e).then(i=>{if(Array.isArray(i))return null;if((i==null?void 0:i.isTexture)===!0){if(i!=t){if(s&&o){const r=s[o];if(r&&!y){const n=this.getAssignedLODInformation(r);if(n&&(n==null?void 0:n.level)<e)return y==="verbose"&&console.warn("Assigned texture level is already higher: ",n.level,e,s,r,i),null}s[o]=i}if(y&&o&&s){const r=this.getAssignedLODInformation(t);r?be(s,o,r.url):console.warn("No LOD info for texture",t)}}return i}else y=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(i=>(console.error("Error loading LOD",t,i),null))}afterRoot(t){var e,s;return y&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((o,i)=>{var r;if(o!=null&&o.extensions){const n=o==null?void 0:o.extensions[z];if(n){if(!n.lods){y&&console.warn("Texture has no LODs",n);return}let a=!1;for(const c of this.parser.associations.keys())if(c.isTexture===!0){const l=this.parser.associations.get(c);(l==null?void 0:l.textures)===i&&(a=!0,_.registerTexture(this.url,c,(r=n.lods)==null?void 0:r.length,i,n))}a||this.parser.getDependency("texture",i).then(c=>{var l;c&&_.registerTexture(this.url,c,(l=n.lods)==null?void 0:l.length,i,n)})}}}),(s=this.parser.json.meshes)==null||s.forEach((o,i)=>{if(o!=null&&o.extensions){const r=o==null?void 0:o.extensions[z];if(r&&r.lods){for(const n of this.parser.associations.keys())if(n.isMesh){const a=this.parser.associations.get(n);(a==null?void 0:a.meshes)===i&&_.registerMesh(this.url,r.guid,n,r.lods.length,a.primitives,r)}}}}),null}static async getOrLoadLOD(t,e){var n,a,c,l;const s=y=="verbose",o=t.userData.LODS;if(!o)return null;const i=o==null?void 0:o.key;let r;if(t.isTexture===!0){const d=t;d.source&&d.source[Me]&&(r=d.source[Me])}if(r||(r=_.lodInfos.get(i)),r){if(e>0){let D=!1;const m=Array.isArray(r.lods);if(m&&e>=r.lods.length?D=!0:m||(D=!0),D)return this.lowresCache.get(i)}const d=Array.isArray(r.lods)?(n=r.lods[e])==null?void 0:n.path:r.lods;if(!d)return y&&!r["missing:uri"]&&(r["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,r)),null;const h=ze(o.url,d);if(h.endsWith(".glb")||h.endsWith(".gltf")){if(!r.guid)return console.warn("missing pointer for glb/gltf texture",r),null;const D=h+"_"+r.guid,m=this.previouslyLoaded.get(D);if(m!==void 0){s&&console.log(`LOD ${e} was already loading/loaded: ${D}`);let f=await m.catch(N=>(console.error(`Error loading LOD ${e} from ${h}
`,N),null)),O=!1;if(f==null||(f instanceof g.Texture&&t instanceof g.Texture?(a=f.image)!=null&&a.data||(c=f.source)!=null&&c.data?f=this.copySettings(t,f):(O=!0,this.previouslyLoaded.delete(D)):f instanceof g.BufferGeometry&&t instanceof g.BufferGeometry&&((l=f.attributes.position)!=null&&l.array||(O=!0,this.previouslyLoaded.delete(D)))),!O)return f}const M=r,k=new Promise(async(f,O)=>{const N=new Z.GLTFLoader;Oe(N),y&&(await new Promise(S=>setTimeout(S,1e3)),s&&console.warn("Start loading (delayed) "+h,M.guid));let R=h;if(M&&Array.isArray(M.lods)){const S=M.lods[e];S.hash&&(R+="?v="+S.hash)}const A=await N.loadAsync(R).catch(S=>(console.error(`Error loading LOD ${e} from ${h}
`,S),null));if(!A)return null;const V=A.parser;s&&console.log("Loading finished "+h,M.guid);let w=0;if(A.parser.json.textures){let S=!1;for(const u of A.parser.json.textures){if(u!=null&&u.extensions){const p=u==null?void 0:u.extensions[z];if(p!=null&&p.guid&&p.guid===M.guid){S=!0;break}}w++}if(S){let u=await V.getDependency("texture",w);return u&&_.assignLODInformation(o.url,u,i,e,void 0,void 0),s&&console.log('change "'+t.name+'" → "'+u.name+'"',h,w,u,D),t instanceof g.Texture&&(u=this.copySettings(t,u)),u&&(u.guid=M.guid),f(u)}else y&&console.warn("Could not find texture with guid",M.guid,A.parser.json)}if(w=0,A.parser.json.meshes){let S=!1;for(const u of A.parser.json.meshes){if(u!=null&&u.extensions){const p=u==null?void 0:u.extensions[z];if(p!=null&&p.guid&&p.guid===M.guid){S=!0;break}}w++}if(S){const u=await V.getDependency("mesh",w),p=M;if(s&&console.log(`Loaded Mesh "${u.name}"`,h,w,u,D),u.isMesh===!0){const v=u.geometry;return _.assignLODInformation(o.url,v,i,e,void 0,p.density),f(v)}else{const v=new Array;for(let b=0;b<u.children.length;b++){const P=u.children[b];if(P.isMesh===!0){const X=P.geometry;_.assignLODInformation(o.url,X,i,e,b,p.density),v.push(X)}}return f(v)}}else y&&console.warn("Could not find mesh with guid",M.guid,A.parser.json)}return f(null)});return this.previouslyLoaded.set(D,k),await k}else if(t instanceof g.Texture){s&&console.log("Load texture from uri: "+h);const m=await new g.TextureLoader().loadAsync(h);return m?(m.guid=r.guid,m.flipY=!1,m.needsUpdate=!0,m.colorSpace=t.colorSpace,s&&console.log(r,m)):y&&console.warn("failed loading",h),m}}else y&&console.warn(`Can not load LOD ${e}: no LOD info found for "${i}" ${t.name}`,t.type);return null}static assignLODInformation(t,e,s,o,i,r){if(!e)return;e.userData||(e.userData={});const n=new Je(t,s,o,i,r);e.userData.LODS=n}static getAssignedLODInformation(t){var e;return((e=t==null?void 0:t.userData)==null?void 0:e.LODS)||null}static copySettings(t,e){return e?(y&&console.warn(`Copy texture settings
`,t.uuid,`
`,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 E=_;E.registerTexture=(t,e,s,o,i)=>{if(y&&console.log("> Progressive: register texture",o,e.name,e.uuid,e,i),!e){y&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[Me]=i);const r=i.guid;_.assignLODInformation(t,e,r,s,o,void 0),_.lodInfos.set(r,i),_.lowresCache.set(r,e)};E.registerMesh=(t,e,s,o,i,r)=>{var c;y&&console.log("> Progressive: register mesh",i,s.name,r,s.uuid,s);const n=s.geometry;if(!n){y&&console.warn("gltf-progressive: Register mesh without geometry");return}n.userData||(n.userData={}),_.assignLODInformation(t,n,e,o,i,r.density),_.lodInfos.set(e,r);let a=_.lowresCache.get(e);a?a.push(s.geometry):a=[s.geometry],_.lowresCache.set(e,a),o>0&&!ee(s)&&Ke(s,n);for(const l of H)(c=l.onRegisteredNewMesh)==null||c.call(l,s,r)};E.lodInfos=new Map;E.previouslyLoaded=new Map;E.lowresCache=new Map;class Je{constructor(e,s,o,i,r){this.url=e,this.key=s,this.level=o,i!=null&&(this.index=i),r!=null&&(this.density=r)}}var Re=(t,e,s)=>{if(!e.has(t))throw TypeError("Cannot "+s)},L=(t,e,s)=>(Re(t,e,"read from private field"),s?s.call(t):e.get(t)),J=(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)},W=(t,e,s,o)=>(Re(t,e,"write to private field"),o?o.call(t,s):e.set(t,s),s),T,K,ve,Q,ie,fe,Y;const G=ne("debugprogressive"),Qe=ne("noprogressive"),ye=Symbol("Needle:LODSManager"),Le=Symbol("Needle:LODState"),q=Symbol("Needle:CurrentLOD"),I={mesh_lod:-1,texture_lod:-1},B=class{constructor(t,e){this.projectionScreenMatrix=new g.Matrix4,this.targetTriangleDensity=2e5,this.updateInterval="auto",J(this,T,1),this.pause=!1,this.manual=!1,this._lodchangedlisteners=[],J(this,K,void 0),J(this,ve,new g.Clock),J(this,Q,0),J(this,ie,0),J(this,fe,0),J(this,Y,0),this._fpsBuffer=[60,60,60,60,60],this._sphere=new g.Sphere,this._tempBox=new g.Box3,this._tempBox2=new g.Box3,this.tempMatrix=new g.Matrix4,this._tempWorldPosition=new g.Vector3,this._tempBoxSize=new g.Vector3,this._tempBox2Size=new g.Vector3,this.renderer=t,this.context={...e}}static getObjectLODState(t){return t[Le]}static addPlugin(t){H.push(t)}static removePlugin(t){const e=H.indexOf(t);e>=0&&H.splice(e,1)}static get(t,e){if(t[ye])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[ye];const s=new B(t,{engine:"unknown",...e});return t[ye]=s,s}get plugins(){return H}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(L(this,K))return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let t=0;W(this,K,this.renderer.render);const e=this;we(this.renderer),this.renderer.render=function(s,o){const i=e.renderer.getRenderTarget();(i==null||"isXRRenderTarget"in i&&i.isXRRenderTarget)&&(t=0,W(e,Q,L(e,Q)+1),W(e,ie,L(e,ve).getDelta()),W(e,fe,L(e,fe)+L(e,ie)),e._fpsBuffer.shift(),e._fpsBuffer.push(1/L(e,ie)),W(e,Y,e._fpsBuffer.reduce((n,a)=>n+a)/e._fpsBuffer.length),G&&L(e,Q)%200===0&&console.log("FPS",Math.round(L(e,Y)),"Interval:",L(e,T)));const r=t++;L(e,K).call(this,s,o),e.onAfterRender(s,o,r)}}disable(){L(this,K)&&(console.debug("[gltf-progressive] Disabling LODsManager for renderer"),this.renderer.render=L(this,K),W(this,K,void 0))}update(t,e){this.internalUpdate(t,e)}onAfterRender(t,e,s){if(this.pause)return;const i=this.renderer.renderLists.get(t,0).opaque;let r=!0;if(i.length===1){const n=i[0].material;(n.name==="EffectMaterial"||n.name==="CopyShader")&&(r=!1)}if((e.parent&&e.parent.type==="CubeCamera"||s>=1&&e.type==="OrthographicCamera")&&(r=!1),r){if(Qe||(this.updateInterval==="auto"?L(this,Y)<40&&L(this,T)<10?(W(this,T,L(this,T)+1),G&&console.warn("↓ Reducing LOD updates",L(this,T),L(this,Y).toFixed(0))):L(this,Y)>=60&&L(this,T)>1&&(W(this,T,L(this,T)-1),G&&console.warn("↑ Increasing LOD updates",L(this,T),L(this,Y).toFixed(0))):W(this,T,this.updateInterval),L(this,T)>0&&L(this,Q)%L(this,T)!=0))return;this.internalUpdate(t,e)}}internalUpdate(t,e){var a,c;const s=this.renderer.renderLists.get(t,0),o=s.opaque;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse);const i=this.targetTriangleDensity;for(const l of o){if(l.material&&(((a=l.geometry)==null?void 0:a.type)==="BoxGeometry"||((c=l.geometry)==null?void 0:c.type)==="BufferGeometry")&&(l.material.name==="SphericalGaussianBlur"||l.material.name=="BackgroundCubeMaterial"||l.material.name==="CubemapFromEquirect"||l.material.name==="EquirectangularToCubeUV")){G&&(l.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(l.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",l,l.material.name,l.material.type)));continue}switch(l.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}if(G==="color"&&l.material&&!l.object.progressive_debug_color){l.object.progressive_debug_color=!0;const h=Math.random()*16777215,D=new g.MeshStandardMaterial({color:h});l.object.material=D}const d=l.object;(d instanceof g.Mesh||d.isMesh)&&this.updateLODs(t,e,d,i)}const r=s.transparent;for(const l of r){const d=l.object;(d instanceof g.Mesh||d.isMesh)&&this.updateLODs(t,e,d,i)}const n=s.transmissive;for(const l of n){const d=l.object;(d instanceof g.Mesh||d.isMesh)&&this.updateLODs(t,e,d,i)}}updateLODs(t,e,s,o){var n,a;s.userData||(s.userData={});let i=s[Le];if(i||(i=new Ze,s[Le]=i),i.frames++<2)return;for(const c of H)(n=c.onBeforeUpdateLOD)==null||n.call(c,this.renderer,t,e,s);this.calculateLodLevel(e,s,i,o,I),I.mesh_lod=Math.round(I.mesh_lod),I.texture_lod=Math.round(I.texture_lod),I.mesh_lod>=0&&this.loadProgressiveMeshes(s,I.mesh_lod);let r=I.texture_lod;s.material&&r>=0&&this.loadProgressiveTextures(s.material,r);for(const c of H)(a=c.onAfterUpdatedLOD)==null||a.call(c,this.renderer,t,e,s,I);i.lastLodLevel_Mesh=I.mesh_lod,i.lastLodLevel_Texture=I.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const i of t)this.loadProgressiveTextures(i,e);return}let s=!1;(t[q]===void 0||e<t[q])&&(s=!0);const o=t["DEBUG:LOD"];o!=null&&(s=t[q]!=o,e=o),s&&(t[q]=e,E.assignTextureLOD(t,e).then(i=>{this._lodchangedlisteners.forEach(r=>r({type:"texture",level:e,object:t}))}))}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);let s=t[q]!==e;const o=t["DEBUG:LOD"];if(o!=null&&(s=t[q]!=o,e=o),s){t[q]=e;const i=t.geometry;return E.assignMeshLOD(t,e).then(r=>(r&&t[q]==e&&i!=t.geometry&&this._lodchangedlisteners.forEach(n=>n({type:"mesh",level:e,object:t})),r))}return Promise.resolve(null)}static isInside(t,e){const s=t.min,o=t.max,i=(s.x+o.x)*.5,r=(s.y+o.y)*.5;return this._tempPtInside.set(i,r,s.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,s,o,i){var k;if(!e){i.mesh_lod=-1,i.texture_lod=-1;return}if(!t){i.mesh_lod=-1,i.texture_lod=-1;return}let n=10+1,a=!1;if(G&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const c=E.getMeshLODInformation(e.geometry),l=c==null?void 0:c.lods,d=l&&l.length>0,h=E.getMaterialMinMaxLODsCount(e.material),D=(h==null?void 0:h.min_count)!=1/0&&h.min_count>0&&h.max_count>0;if(!d&&!D){i.mesh_lod=0,i.texture_lod=0;return}d||(a=!0,n=0);const m=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let M=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const x=e;if(!x.boundingBox)x.computeBoundingBox();else if(s.frames%30===0){const f=ee(x),O=x.geometry;f&&(x.geometry=f),x.computeBoundingBox(),x.geometry=O}M=x.boundingBox}if(M){const x=t;if(e.geometry.attributes.color&&e.geometry.attributes.color.count<100&&e.geometry.boundingSphere){this._sphere.copy(e.geometry.boundingSphere),this._sphere.applyMatrix4(e.matrixWorld);const u=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(u)){i.mesh_lod=0,i.texture_lod=0;return}}if(this._tempBox.copy(M),this._tempBox.applyMatrix4(e.matrixWorld),x.isPerspectiveCamera&&B.isInside(this._tempBox,this.projectionScreenMatrix)){i.mesh_lod=0,i.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&x.isPerspectiveCamera&&x.fov>70){const u=this._tempBox.min,p=this._tempBox.max;let v=u.x,b=u.y,P=p.x,X=p.y;const ae=2,he=1.5,le=(u.x+p.x)*.5,ce=(u.y+p.y)*.5;v=(v-le)*ae+le,b=(b-ce)*ae+ce,P=(P-le)*ae+le,X=(X-ce)*ae+ce;const $e=v<0&&P>0?0:Math.min(Math.abs(u.x),Math.abs(p.x)),Ne=b<0&&X>0?0:Math.min(Math.abs(u.y),Math.abs(p.y)),ge=Math.max($e,Ne);s.lastCentrality=(he-ge)*(he-ge)*(he-ge)}else s.lastCentrality=1;const f=this._tempBox.getSize(this._tempBoxSize);f.multiplyScalar(.5),screen.availHeight>0&&m>0&&f.multiplyScalar(m/screen.availHeight),t.isPerspectiveCamera?f.x*=t.aspect:t.isOrthographicCamera;const O=t.matrixWorldInverse,N=this._tempBox2;N.copy(M),N.applyMatrix4(e.matrixWorld),N.applyMatrix4(O);const R=N.getSize(this._tempBox2Size),A=Math.max(R.x,R.y);if(Math.max(f.x,f.y)!=0&&A!=0&&(f.z=R.z/Math.max(R.x,R.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,G&&B.debugDrawLine){const u=this.tempMatrix.copy(this.projectionScreenMatrix);u.invert();const p=B.corner0,v=B.corner1,b=B.corner2,P=B.corner3;p.copy(this._tempBox.min),v.copy(this._tempBox.max),v.x=p.x,b.copy(this._tempBox.max),b.y=p.y,P.copy(this._tempBox.max);const X=(p.z+P.z)*.5;p.z=v.z=b.z=P.z=X,p.applyMatrix4(u),v.applyMatrix4(u),b.applyMatrix4(u),P.applyMatrix4(u),B.debugDrawLine(p,v,255),B.debugDrawLine(p,b,255),B.debugDrawLine(v,P,255),B.debugDrawLine(b,P,255)}let w=999;if(l&&s.lastScreenCoverage>0){for(let u=0;u<l.length;u++)if(l[u].density/s.lastScreenCoverage<o){w=u;break}}w<n&&(n=w,a=!0)}if(a?i.mesh_lod=n:i.mesh_lod=s.lastLodLevel_Mesh,G&&i.mesh_lod!=s.lastLodLevel_Mesh){const f=l==null?void 0:l[i.mesh_lod];f&&console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} → ${i.mesh_lod} (${f.density.toFixed(0)}) - ${e.name}`)}if(D){const x="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(s.lastLodLevel_Texture<0){if(i.texture_lod=h.max_count-1,G){const f=h.lods[h.max_count-1];G&&console.log(`First Texture LOD ${i.texture_lod} (${f.max_height}px) - ${e.name}`)}}else{const f=s.lastScreenspaceVolume.x+s.lastScreenspaceVolume.y+s.lastScreenspaceVolume.z;let O=s.lastScreenCoverage*4;((k=this.context)==null?void 0:k.engine)==="model-viewer"&&(O*=1.5);const R=m/window.devicePixelRatio*O;let A=!1;for(let V=h.lods.length-1;V>=0;V--){let w=h.lods[V];if(!(x&&w.max_height>=2048)&&!(Xe()&&w.max_height>4096)&&(w.max_height>R||!A&&V===0)){if(A=!0,i.texture_lod=V,i.texture_lod<s.lastLodLevel_Texture){const S=w.max_height;G&&console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${i.texture_lod} = ${S}px
Screensize: ${R.toFixed(0)}px, Coverage: ${(100*s.lastScreenCoverage).toFixed(2)}%, Volume ${f.toFixed(1)}
${e.name}`)}break}}}}else i.texture_lod=0}};let U=B;T=new WeakMap;K=new WeakMap;ve=new WeakMap;Q=new WeakMap;ie=new WeakMap;fe=new WeakMap;Y=new WeakMap;U.corner0=new g.Vector3;U.corner1=new g.Vector3;U.corner2=new g.Vector3;U.corner3=new g.Vector3;U._tempPtInside=new g.Vector3;class Ze{constructor(){this.frames=0,this.lastLodLevel_Mesh=-1,this.lastLodLevel_Texture=-1,this.lastScreenCoverage=0,this.lastScreenspaceVolume=new g.Vector3,this.lastCentrality=0}}const Te=Symbol("NEEDLE_mesh_lod"),ue=Symbol("NEEDLE_texture_lod");let re=null;function Ge(){const t=je();t&&(t.mapURLs(function(e){return Ee(),e}),Ee(),re==null||re.disconnect(),re=new MutationObserver(e=>{e.forEach(s=>{s.addedNodes.forEach(o=>{o instanceof HTMLElement&&o.tagName.toLowerCase()==="model-viewer"&&Ie(o)})})}),re.observe(document,{childList:!0,subtree:!0}))}function je(){if(typeof customElements>"u")return null;const t=customElements.get("model-viewer");return t||(customElements.whenDefined("model-viewer").then(()=>{console.debug("[gltf-progressive] model-viewer defined"),Ge()}),null)}function Ee(){if(typeof document>"u")return;document.querySelectorAll("model-viewer").forEach(e=>{Ie(e)})}const Ae=new WeakSet;let et=0;function Ie(t){if(!t||Ae.has(t))return null;Ae.add(t),console.debug("[gltf-progressive] found new model-viewer..."+ ++et+`
`,t.getAttribute("src"));let e=null,s=null,o=null;for(let i=t;i!=null;i=Object.getPrototypeOf(i)){const r=Object.getOwnPropertySymbols(i),n=r.find(l=>l.toString()=="Symbol(renderer)"),a=r.find(l=>l.toString()=="Symbol(scene)"),c=r.find(l=>l.toString()=="Symbol(needsRender)");!e&&n!=null&&(e=t[n].threeRenderer),!s&&a!=null&&(s=t[a]),!o&&c!=null&&(o=t[c])}if(e&&s){let i=function(){if(o){let n=0,a=setInterval(()=>{if(n++>5){clearInterval(a);return}o==null||o.call(t)},300)}};console.debug("[gltf-progressive] setup model-viewer");const r=U.get(e,{engine:"model-viewer"});return U.addPlugin(new tt),r.enable(),r.addEventListener("changed",()=>{o==null||o.call(t)}),t.addEventListener("model-visibility",n=>{n.detail.visible&&(o==null||o.call(t))}),t.addEventListener("load",()=>{i()}),()=>{r.disable()}}return null}class tt{constructor(){this._didWarnAboutMissingUrl=!1}onBeforeUpdateLOD(e,s,o,i){this.tryParseMeshLOD(s,i),this.tryParseTextureLOD(s,i)}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[ue]==!0)return;s[ue]=!0;const o=this.tryGetCurrentGLTF(e),i=this.tryGetCurrentModelViewer(e),r=this.getUrl(i);if(r&&o&&s.material){let n=function(c){var d,h,D;if(c[ue]==!0)return;c[ue]=!0,c.userData&&(c.userData.LOD=-1);const l=Object.keys(c);for(let m=0;m<l.length;m++){const M=l[m],k=c[M];if((k==null?void 0:k.isTexture)===!0){const x=(h=(d=k.userData)==null?void 0:d.associations)==null?void 0:h.textures;if(x==null)continue;const f=o.parser.json.textures[x];if(!f){console.warn("Texture data not found for texture index "+x);continue}if((D=f==null?void 0:f.extensions)!=null&&D[z]){const O=f.extensions[z];O&&r&&E.registerTexture(r,k,O.lods.length,x,O)}}}};const a=s.material;if(Array.isArray(a))for(const c of a)n(c);else n(a)}}tryParseMeshLOD(e,s){var n,a;if(s[Te]==!0)return;s[Te]=!0;const o=this.tryGetCurrentModelViewer(e),i=this.getUrl(o);if(!i)return;const r=(a=(n=s.userData)==null?void 0:n.gltfExtensions)==null?void 0:a[z];if(r&&i){const c=s.uuid;E.registerMesh(i,c,s,0,r.lods.length,r)}}}function st(t,e,s,o){we(e),Oe(s),Se(s,{progressive:!0,...o==null?void 0:o.hints}),s.register(r=>new E(r,t));const i=U.get(e);return(o==null?void 0:o.enableLODsManager)!==!1&&i.enable(),i}Ge();if(!qe){const t={gltfProgressive:{useNeedleProgressive:st,LODsManager:U,configureLoader:Se,getRaycastMesh:ee,useRaycastMeshes:Ye}};if(!globalThis.Needle)globalThis.Needle=t;else for(const e in t)globalThis.Needle[e]=t[e]}exports.LODsManager=U;exports.NEEDLE_progressive=E;exports.addDracoAndKTX2Loaders=Oe;exports.configureLoader=Se;exports.createLoaders=we;exports.getRaycastMesh=ee;exports.setDracoDecoderLocation=Ce;exports.setKTX2TranscoderLocation=Be;