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