UNPKG

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