@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.
11 lines (10 loc) • 41.2 kB
JavaScript
import{BufferGeometry as W,Mesh as F,Box3 as ae,Vector3 as A,Sphere as _e,CompressedTexture as Be,Texture as $,Matrix3 as Ge,InterleavedBuffer as je,InterleavedBufferAttribute as Ne,BufferAttribute as Ue,TextureLoader as We,Matrix4 as be,Clock as Fe,MeshStandardMaterial as ze}from"./three.min.js";import{DRACOLoader as qe,KTX2Loader as Ve,MeshoptDecoder as Xe,GLTFLoader as le}from"./three-examples.min.js";const He="";globalThis.GLTF_PROGRESSIVE_VERSION=He,console.debug("[gltf-progressive] version -");let k="https://www.gstatic.com/draco/versioned/decoders/1.5.7/",z="https://cdn.needle.tools/static/three/0.179.1/basis2/";const Ke=k,Ye=z,Me=new URL(k+"draco_decoder.js");Me.searchParams.append("range","true"),fetch(Me,{method:"GET",headers:{Range:"bytes=0-1"}}).catch(i=>{console.debug(`Failed to fetch remote Draco decoder from ${k} (offline: ${typeof navigator<"u"?navigator.onLine:"unknown"})`),k===Ke&&De("./include/draco/"),z===Ye&&Oe("./include/ktx2/")}).finally(()=>{Se()});const Qe=()=>({dracoDecoderPath:k,ktx2TranscoderPath:z});function De(i){k=i,T&&T[ce]!=k?(console.debug("Updating Draco decoder path to "+i),T[ce]=k,T.setDecoderPath(k),T.preload()):console.debug("Setting Draco decoder path to "+i)}function Oe(i){z=i,I&&I.transcoderPath!=z?(console.debug("Updating KTX2 transcoder path to "+i),I.setTranscoderPath(z),I.init()):console.debug("Setting KTX2 transcoder path to "+i)}function te(i){return Se(),i?I.detectSupport(i):i!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:T,ktx2Loader:I,meshoptDecoder:re}}function ue(i){i.dracoLoader||i.setDRACOLoader(T),i.ktx2Loader||i.setKTX2Loader(I),i.meshoptDecoder||i.setMeshoptDecoder(re)}const ce=Symbol("dracoDecoderPath");let T,re,I;function Se(){T||(T=new qe,T[ce]=k,T.setDecoderPath(k),T.setDecoderConfig({type:"js"}),T.preload()),I||(I=new Ve,I.setTranscoderPath(z),I.init()),re||(re=Xe)}const de=new WeakMap;function he(i,t){let e=de.get(i);e?e=Object.assign(e,t):e=t,de.set(i,e)}const Je=le.prototype.load;function Ze(...i){const t=de.get(this);let e=i[0];const r=new URL(e,window.location.href);if(r.hostname.endsWith("needle.tools")){const n=t?.progressive!==void 0?t.progressive:!0,s=t?.usecase?t.usecase:"default";n?this.requestHeader.Accept=`*/*;progressive=allowed;usecase=${s}`:this.requestHeader.Accept=`*/*;usecase=${s}`,e=r.toString()}return i[0]=e,Je?.call(this,...i)}le.prototype.load=Ze,j("debugprogressive");function j(i){if(typeof window>"u")return!1;const t=new URL(window.location.href).searchParams.get(i);return t==null||t==="0"||t==="false"?!1:t===""?!0:t}function et(i,t){if(t===void 0||i===void 0||t.startsWith("./")||t.startsWith("http")||t.startsWith("data:")||t.startsWith("blob:"))return t;const e=i.lastIndexOf("/");if(e>=0){const r=i.substring(0,e+1);for(;r.endsWith("/")&&t.startsWith("/");)t=t.substring(1);return r+t}return t}function ge(){return se!==void 0||(se=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),j("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",se)),se}let se;function Te(){if(typeof window>"u")return!1;const i=new URL(window.location.href),t=i.hostname==="localhost"||/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(i.hostname);return i.hostname==="127.0.0.1"||t}class tt{constructor(t,e={}){this.maxConcurrent=t,this.debug=e.debug??!1,window.requestAnimationFrame(this.tick)}_running=new Map;_queue=[];debug=!1;tick=()=>{this.internalUpdate(),setTimeout(this.tick,10)};slot(t){return this.debug&&console.debug(`[PromiseQueue]: Requesting slot for key ${t}, running: ${this._running.size}, waiting: ${this._queue.length}`),new Promise(e=>{this._queue.push({key:t,resolve:e})})}add(t,e){this._running.has(t)||(this._running.set(t,e),e.finally(()=>{this._running.delete(t),this.debug&&console.debug(`[PromiseQueue]: Promise finished now running: ${this._running.size}, waiting: ${this._queue.length}. (finished ${t})`)}),this.debug&&console.debug(`[PromiseQueue]: Added new promise, now running: ${this._running.size}, waiting: ${this._queue.length}. (added ${t})`))}internalUpdate(){const t=this.maxConcurrent-this._running.size;for(let e=0;e<t&&this._queue.length>0;e++){this.debug&&console.debug(`[PromiseQueue]: Running ${this._running.size} promises, waiting for ${this._queue.length} more.`);const{key:r,resolve:n}=this._queue.shift();n({use:s=>this.add(r,s)})}}}function rt(i){const t=i.image?.width??0,e=i.image?.height??0,r=i.image?.depth??1,n=Math.floor(Math.log2(Math.max(t,e,r)))+1,s=st(i);return t*e*r*s*(1-Math.pow(.25,n))/(1-.25)}function st(i){let t=4;const e=i.format;e===1024||e===1025?t=1:e===1026||e===1027?t=2:e===1022||e===1029?t=3:(e===1023||e===1033)&&(t=4);let r=1;const n=i.type;return n===1009||n===1010?r=1:n===1011||n===1012?r=2:n===1013||n===1014||n===1015?r=4:n===1016&&(r=2),t*r}const nt=typeof window>"u"&&typeof document>"u",fe=Symbol("needle:raycast-mesh");function V(i){return i?.[fe]instanceof W?i[fe]:null}function ot(i,t){if((i.type==="Mesh"||i.type==="SkinnedMesh")&&!V(i)){const e=at(t);e.userData={isRaycastMesh:!0},i[fe]=e}}function it(i=!0){if(i){if(H)return;const t=H=F.prototype.raycast;F.prototype.raycast=function(e,r){const n=this,s=V(n);let o;s&&n.isMesh&&(o=n.geometry,n.geometry=s),t.call(this,e,r),o&&(n.geometry=o)}}else{if(!H)return;F.prototype.raycast=H,H=null}}let H=null;function at(i){const t=new W;for(const e in i.attributes)t.setAttribute(e,i.getAttribute(e));return t.setIndex(i.getIndex()),t}const N=new Array,h=j("debugprogressive");let K,q=-1;if(h){let i=function(){q+=1,q>=t&&(q=-1),console.log(`Toggle LOD level [${q}]`)},t=6;window.addEventListener("keyup",e=>{e.key==="p"&&i(),e.key==="w"&&(K=!K,console.log(`Toggle wireframe [${K}]`));const r=parseInt(e.key);!isNaN(r)&&r>=0&&(q=r,console.log(`Set LOD level to [${q}]`))})}function Pe(i){if(h&&K!==void 0)if(Array.isArray(i))for(const t of i)Pe(t);else i&&"wireframe"in i&&(i.wireframe=K===!0)}const Y=new Array;let lt=0;const ut=ge()?2:10;function ct(i){if(Y.length<ut){const e=Y.length;h&&console.warn(`[Worker] Creating new worker #${e}`);const r=Le.createWorker(i||{});return Y.push(r),r}const t=lt++%Y.length;return Y[t]}class Le{constructor(t,e){this.worker=t,this._debug=e.debug??!1,t.onmessage=r=>{const n=r.data;switch(this._debug&&console.log("[Worker] EVENT",n),n.type){case"loaded-gltf":for(const s of this._running)if(s.url===n.result.url){dt(n.result),s.resolve(n.result);const o=s.url;o.startsWith("blob:")&&URL.revokeObjectURL(o)}}},t.onerror=r=>{console.error("[Worker] Error in gltf-progressive worker:",r)},t.postMessage({type:"init"})}static async createWorker(t){const e=new Worker(URL.createObjectURL(new Blob([`import '${new URL("./loader.worker-BqODMeeW.js",import.meta.url).toString()}';`],{type:"text/javascript"})),{type:"module"});return new Le(e,t)}_running=[];_webglRenderer=null;async load(t,e){const r=Qe();let n=e?.renderer;n||(this._webglRenderer??=(async()=>{const{WebGLRenderer:l}=await import("./three.min.js").then(a=>a.THREE);return new l})(),n=await this._webglRenderer);const s=te(n).ktx2Loader.workerConfig;t instanceof URL?t=t.toString():t.startsWith("file:")?t=URL.createObjectURL(new Blob([t])):!t.startsWith("blob:")&&!t.startsWith("http:")&&!t.startsWith("https:")&&(t=new URL(t,window.location.href).toString());const o={type:"load",url:t,dracoDecoderPath:r.dracoDecoderPath,ktx2TranscoderPath:r.ktx2TranscoderPath,ktx2LoaderConfig:s};return this._debug&&console.debug("[Worker] Sending load request",o),this.worker.postMessage(o),new Promise(l=>{this._running.push({url:t.toString(),resolve:l})})}_debug=!1}function dt(i){for(const t of i.geometries){const e=t.geometry,r=new W;if(r.name=e.name||"",e.index){const n=e.index;r.setIndex(me(n))}for(const n in e.attributes){const s=e.attributes[n],o=me(s);r.setAttribute(n,o)}if(e.morphAttributes)for(const n in e.morphAttributes){const s=e.morphAttributes[n].map(o=>me(o));r.morphAttributes[n]=s}if(r.morphTargetsRelative=e.morphTargetsRelative??!1,r.boundingBox=new ae,r.boundingBox.min=new A(e.boundingBox?.min.x,e.boundingBox?.min.y,e.boundingBox?.min.z),r.boundingBox.max=new A(e.boundingBox?.max.x,e.boundingBox?.max.y,e.boundingBox?.max.z),r.boundingSphere=new _e(new A(e.boundingSphere?.center.x,e.boundingSphere?.center.y,e.boundingSphere?.center.z),e.boundingSphere?.radius),e.groups)for(const n of e.groups)r.addGroup(n.start,n.count,n.materialIndex);e.userData&&(r.userData=e.userData),t.geometry=r}for(const t of i.textures){const e=t.texture;let r=null;if(e.isCompressedTexture){const n=e.mipmaps,s=e.image?.width||e.source?.data?.width||-1,o=e.image?.height||e.source?.data?.height||-1;r=new Be(n,s,o,e.format,e.type,e.mapping,e.wrapS,e.wrapT,e.magFilter,e.minFilter,e.anisotropy,e.colorSpace)}else r=new $(e.image,e.mapping,e.wrapS,e.wrapT,e.magFilter,e.minFilter,e.format,e.type,e.anisotropy,e.colorSpace),r.mipmaps=e.mipmaps,r.channel=e.channel,r.source.data=e.source.data,r.flipY=e.flipY,r.premultiplyAlpha=e.premultiplyAlpha,r.unpackAlignment=e.unpackAlignment,r.matrix=new Ge(...e.matrix.elements);if(!r){console.error("[Worker] Failed to create new texture from received data. Texture is not a CompressedTexture or Texture.");continue}t.texture=r}return i}function me(i){let t=i;if("isInterleavedBufferAttribute"in i&&i.isInterleavedBufferAttribute){const e=i.data,r=e.array,n=new je(r,e.stride);t=new Ne(n,i.itemSize,r.byteOffset,i.normalized),t.offset=i.offset}else"isBufferAttribute"in i&&i.isBufferAttribute&&(t=new Ue(i.array,i.itemSize,i.normalized),t.usage=i.usage,t.gpuType=i.gpuType,t.updateRanges=i.updateRanges);return t}const ht=j("gltf-progressive-worker");j("gltf-progressive-reduce-mipmaps");const X=j("gltf-progressive-gc"),pe=Symbol("needle-progressive-texture"),B="NEEDLE_progressive";class f{get name(){return B}static getMeshLODExtension(t){const e=this.getAssignedLODInformation(t);return e?.key?this.lodInfos.get(e.key):null}static getPrimitiveIndex(t){return this.getAssignedLODInformation(t)?.index??-1}static getMaterialMinMaxLODsCount(t,e){const r=this,n="LODS:minmax",s=t[n];if(s!=null)return s;if(e||(e={min_count:1/0,max_count:0,lods:[]}),Array.isArray(t)){for(const l of t)this.getMaterialMinMaxLODsCount(l,e);return t[n]=e,e}if(h==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const l=t;for(const a of Object.keys(l.uniforms)){const u=l.uniforms[a].value;u?.isTexture===!0&&o(u,e)}}else if(t.isMaterial)for(const l of Object.keys(t)){const a=t[l];a?.isTexture===!0&&o(a,e)}else h&&console.warn(`[getMaterialMinMaxLODsCount] Unsupported material type: ${t.type}`);return t[n]=e,e;function o(l,a){const u=r.getAssignedLODInformation(l);if(u){const y=r.lodInfos.get(u.key);if(y&&y.lods){a.min_count=Math.min(a.min_count,y.lods.length),a.max_count=Math.max(a.max_count,y.lods.length);for(let p=0;p<y.lods.length;p++){const w=y.lods[p];w.width&&(a.lods[p]=a.lods[p]||{min_height:1/0,max_height:0},a.lods[p].min_height=Math.min(a.lods[p].min_height,w.height),a.lods[p].max_height=Math.max(a.lods[p].max_height,w.height))}}}}}static hasLODLevelAvailable(t,e){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 o=t[s];if(o&&o.isTexture&&this.hasLODLevelAvailable(o,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,n;if(t.isMesh?r=t.geometry:(t.isBufferGeometry||t.isTexture)&&(r=t),r&&r?.userData?.LODS){const s=r.userData.LODS;if(n=this.lodInfos.get(s.key),e===void 0)return n!=null;if(n)return Array.isArray(n.lods)?e<n.lods.length:e===0}return!1}static assignMeshLOD(t,e){if(!t)return Promise.resolve(null);if(t instanceof F||t.isMesh===!0){const r=t.geometry,n=this.getAssignedLODInformation(r);if(!n)return Promise.resolve(null);for(const s of N)s.onBeforeGetLODMesh?.(t,e);return t["LOD:requested level"]=e,f.getOrLoadLOD(r,e).then(s=>{if(Array.isArray(s)){const o=n.index||0;s=s[o]}return t["LOD:requested level"]===e&&(delete t["LOD:requested level"],s&&r!=s&&(s?.isBufferGeometry?t.geometry=s:h&&console.error("Invalid LOD geometry",s))),s}).catch(s=>(console.error("Error loading mesh LOD",t,s),null))}else h&&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 n=new Array;for(const s of r.material){const o=this.assignTextureLOD(s,e);n.push(o)}return Promise.all(n).then(s=>{const o=new Array;for(const l of s)Array.isArray(l)&&o.push(...l);return o})}else return this.assignTextureLOD(r.material,e)}if(t.isMaterial===!0){const r=t,n=[],s=new Array;if(r.uniforms&&(r.isRawShaderMaterial||r.isShaderMaterial===!0)){const o=r;for(const l of Object.keys(o.uniforms)){const a=o.uniforms[l].value;if(a?.isTexture===!0){const u=this.assignTextureLODForSlot(a,e,r,l).then(y=>(y&&o.uniforms[l].value!=y&&(o.uniforms[l].value=y,o.uniformsNeedUpdate=!0),y));n.push(u),s.push(l)}}}else for(const o of Object.keys(r)){const l=r[o];if(l?.isTexture===!0){const a=this.assignTextureLODForSlot(l,e,r,o);n.push(a),s.push(o)}}return Promise.all(n).then(o=>{const l=new Array;for(let a=0;a<o.length;a++){const u=o[a],y=s[a];u&&u.isTexture===!0?l.push({material:r,slot:y,texture:u,level:e}):l.push({material:r,slot:y,texture:null,level:e})}return l})}if(t instanceof $||t.isTexture===!0){const r=t;return this.assignTextureLODForSlot(r,e,null,null)}return Promise.resolve(null)}static set maxConcurrentLoadingTasks(t){f.queue.maxConcurrent=t}static get maxConcurrentLoadingTasks(){return f.queue.maxConcurrent}static assignTextureLODForSlot(t,e,r,n){return t?.isTexture!==!0?Promise.resolve(null):n==="glyphMap"?Promise.resolve(t):f.getOrLoadLOD(t,e).then(s=>{if(Array.isArray(s))return console.warn("Progressive: Got an array of textures for a texture slot, this should not happen..."),null;if(s?.isTexture===!0){if(s!=t&&r&&n){const o=r[n];if(o&&!h){const l=this.getAssignedLODInformation(o);if(l&&l?.level<e)return h==="verbose"&&console.warn("Assigned texture level is already higher: ",l.level,e,r,o,s),s&&s!==o&&((h||X)&&console.log(`[gltf-progressive] Disposing rejected lower-quality texture LOD ${e} (assigned is ${l.level})`,s.uuid),s.dispose()),null}if(this.trackTextureUsage(s),o&&o!==s&&this.untrackTextureUsage(o)&&(h||X)){const l=this.getAssignedLODInformation(o);console.log(`[gltf-progressive] Disposed old texture LOD ${l?.level??"?"} \u2192 ${e} for ${r.name||r.type}.${n}`,o.uuid)}r[n]=s}return s}else h=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(s=>(console.error("Error loading LOD",t,s),null))}parser;url;constructor(t){const e=t.options.path;h&&console.log("Progressive extension registered for",e),this.parser=t,this.url=e}_isLoadingMesh;loadMesh=t=>{if(this._isLoadingMesh)return null;const e=this.parser.json.meshes[t]?.extensions?.[B];return e?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",t).then(r=>(this._isLoadingMesh=!1,r&&f.registerMesh(this.url,e.guid,r,e.lods?.length,0,e),r))):null};afterRoot(t){return h&&console.log("AFTER",this.url,t),this.parser.json.textures?.forEach((e,r)=>{if(e?.extensions){const n=e?.extensions[B];if(n){if(!n.lods){h&&console.warn("Texture has no LODs",n);return}let s=!1;for(const o of this.parser.associations.keys())o.isTexture===!0&&this.parser.associations.get(o)?.textures===r&&(s=!0,f.registerTexture(this.url,o,n.lods?.length,r,n));s||this.parser.getDependency("texture",r).then(o=>{o&&f.registerTexture(this.url,o,n.lods?.length,r,n)})}}}),this.parser.json.meshes?.forEach((e,r)=>{if(e?.extensions){const n=e?.extensions[B];if(n&&n.lods){for(const s of this.parser.associations.keys())if(s.isMesh){const o=this.parser.associations.get(s);o?.meshes===r&&f.registerMesh(this.url,n.guid,s,n.lods.length,o.primitives,n)}}}}),null}static registerTexture=(t,e,r,n,s)=>{if(!e){h&&console.error("!! gltf-progressive: Called register texture without texture");return}if(h){const l=e.image?.width||e.source?.data?.width||0,a=e.image?.height||e.source?.data?.height||0;console.log(`> gltf-progressive: register texture[${n}] "${e.name||e.uuid}", Current: ${l}x${a}, Max: ${s.lods[0]?.width}x${s.lods[0]?.height}, uuid: ${e.uuid}`,s,e)}e.source&&(e.source[pe]=s);const o=s.guid;f.assignLODInformation(t,e,o,r,n),f.lodInfos.set(o,s),f.lowresCache.set(o,new WeakRef(e))};static registerMesh=(t,e,r,n,s,o)=>{const l=r.geometry;if(!l){h&&console.warn("gltf-progressive: Register mesh without geometry");return}l.userData||(l.userData={}),h&&console.log("> Progressive: register mesh "+r.name,{index:s,uuid:r.uuid},o,r),f.assignLODInformation(t,l,e,n,s),f.lodInfos.set(e,o);let a=f.lowresCache.get(e)?.deref();a?a.push(r.geometry):a=[r.geometry],f.lowresCache.set(e,new WeakRef(a)),n>0&&!V(r)&&ot(r,l);for(const u of N)u.onRegisteredNewMesh?.(r,o)};static dispose(t){if(t){this.lodInfos.delete(t);const e=this.lowresCache.get(t);if(e){const r=e.deref();if(r){if(r.isTexture){const n=r;this.textureRefCounts.delete(n.uuid),n.dispose()}else if(Array.isArray(r))for(const n of r)n.dispose()}this.lowresCache.delete(t)}for(const[r,n]of this.cache)r.includes(t)&&(this._disposeCacheEntry(n),this.cache.delete(r))}else{this.lodInfos.clear();for(const[,e]of this.lowresCache){const r=e.deref();if(r){if(r.isTexture){const n=r;this.textureRefCounts.delete(n.uuid),n.dispose()}else if(Array.isArray(r))for(const n of r)n.dispose()}}this.lowresCache.clear();for(const[,e]of this.cache)this._disposeCacheEntry(e);this.cache.clear(),this.textureRefCounts.clear()}}static _disposeCacheEntry(t){if(t instanceof WeakRef){const e=t.deref();e&&(e.isTexture&&this.textureRefCounts.delete(e.uuid),e.dispose())}else t.then(e=>{if(e)if(Array.isArray(e))for(const r of e)r.dispose();else e.isTexture&&this.textureRefCounts.delete(e.uuid),e.dispose()}).catch(()=>{})}static lodInfos=new Map;static cache=new Map;static lowresCache=new Map;static textureRefCounts=new Map;static _resourceRegistry=new FinalizationRegistry(t=>{const e=f.cache.get(t);(h||X)&&console.debug(`[gltf-progressive] Memory: Resource GC'd
${t}`),e instanceof WeakRef&&(e.deref()||(f.cache.delete(t),(h||X)&&console.log("[gltf-progressive] \u21AA Cache entry deleted (GC)")))});static trackTextureUsage(t){const e=t.uuid,r=this.textureRefCounts.get(e)||0;this.textureRefCounts.set(e,r+1),h==="verbose"&&console.log(`[gltf-progressive] Track texture ${e}, refCount: ${r} \u2192 ${r+1}`)}static untrackTextureUsage(t){const e=t.uuid,r=this.textureRefCounts.get(e);if(!r)return(h==="verbose"||X)&&s("[gltf-progressive] Memory: Untrack untracked texture (dispose immediately)",0),t.dispose(),!0;const n=r-1;if(n<=0)return this.textureRefCounts.delete(e),(h||X)&&s("[gltf-progressive] Memory: Dispose texture",n),t.dispose(),!0;return this.textureRefCounts.set(e,n),h==="verbose"&&s("[gltf-progressive] Memory: Untrack texture",n),!1;function s(o,l){let a=t.image?.width||t.source?.data?.width||0,u=t.image?.height||t.source?.data?.height||0;const y=a&&u?`${a}x${u}`:"N/A";let p="N/A";a&&u&&(p=`~${(rt(t)/(1024*1024)).toFixed(2)} MB`),console.log(`${o} \u2014 ${t.name} ${y} (${p}), refCount: ${r} \u2192 ${l}
${e}`)}}static workers=[];static _workersIndex=0;static async getOrLoadLOD(t,e){const r=h=="verbose",n=this.getAssignedLODInformation(t);if(!n)return h&&console.warn(`[gltf-progressive] No LOD information found: ${t.name}, uuid: ${t.uuid}, type: ${t.type}`,t),null;const s=n?.key;let o;if(t.isTexture===!0){const l=t;l.source&&l.source[pe]&&(o=l.source[pe])}if(o||(o=f.lodInfos.get(s)),!o)h&&console.warn(`Can not load LOD ${e}: no LOD info found for "${s}" ${t.name}`,t.type,f.lodInfos);else{if(e>0){let u=!1;const y=Array.isArray(o.lods);if(y&&e>=o.lods.length?u=!0:y||(u=!0),u){const p=this.lowresCache.get(s);if(p){const w=p.deref();if(w)return w;this.lowresCache.delete(s),h&&console.log(`[gltf-progressive] Lowres cache entry was GC'd: ${s}`)}return null}}const l=Array.isArray(o.lods)?o.lods[e]?.path:o.lods;if(!l)return h&&!o["missing:uri"]&&(o["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,o)),null;const a=et(n.url,l);if(a.endsWith(".glb")||a.endsWith(".gltf")){if(!o.guid)return console.warn("missing pointer for glb/gltf texture",o),null;const u=a+"_"+o.guid,y=await this.queue.slot(a),p=this.cache.get(u);if(p!==void 0)if(r&&console.log(`LOD ${e} was already loading/loaded: ${u}`),p instanceof WeakRef){const c=p.deref();if(c){let x=c,v=!1;if(x instanceof $&&t instanceof $?x.image?.data||x.source?.data?x=this.copySettings(t,x):v=!0:x instanceof W&&t instanceof W&&(x.attributes.position?.array||(v=!0)),!v)return x}this.cache.delete(u),h&&console.log(`[gltf-progressive] Re-loading GC'd/disposed resource: ${u}`)}else{let c=await p.catch(v=>(console.error(`Error loading LOD ${e} from ${a}
`,v),null)),x=!1;if(c==null||(c instanceof $&&t instanceof $?c.image?.data||c.source?.data?c=this.copySettings(t,c):(x=!0,this.cache.delete(u)):c instanceof W&&t instanceof W&&(c.attributes.position?.array||(x=!0,this.cache.delete(u)))),!x)return c}if(!y.use)return h&&console.log(`LOD ${e} was aborted: ${a}`),null;const w=o,P=new Promise(async(c,x)=>{if(ht){const g=await(await ct({})).load(a);if(g.textures.length>0)for(const d of g.textures){let m=d.texture;return f.assignLODInformation(n.url,m,s,e,void 0),t instanceof $&&(m=this.copySettings(t,m)),m&&(m.guid=w.guid),c(m)}if(g.geometries.length>0){const d=new Array;for(const m of g.geometries){const L=m.geometry;f.assignLODInformation(n.url,L,s,e,m.primitiveIndex),d.push(L)}return c(d)}return c(null)}const v=new le;ue(v),h&&(await new Promise(g=>setTimeout(g,1e3)),r&&console.warn("Start loading (delayed) "+a,w.guid));let C=a;if(w&&Array.isArray(w.lods)){const g=w.lods[e];g.hash&&(C+="?v="+g.hash)}const b=await v.loadAsync(C).catch(g=>(console.error(`Error loading LOD ${e} from ${a}
`,g),c(null)));if(!b)return c(null);const R=b.parser;r&&console.log("Loading finished "+a,w.guid);let M=0;if(b.parser.json.textures){let g=!1;for(const d of b.parser.json.textures){if(d?.extensions){const m=d?.extensions[B];if(m?.guid&&m.guid===w.guid){g=!0;break}}M++}if(g){let d=await R.getDependency("texture",M);return d&&f.assignLODInformation(n.url,d,s,e,void 0),r&&console.log('change "'+t.name+'" \u2192 "'+d.name+'"',a,M,d,u),t instanceof $&&(d=this.copySettings(t,d)),d&&(d.guid=w.guid),c(d)}else h&&console.warn("Could not find texture with guid",w.guid,b.parser.json)}if(M=0,b.parser.json.meshes){let g=!1;for(const d of b.parser.json.meshes){if(d?.extensions){const m=d?.extensions[B];if(m?.guid&&m.guid===w.guid){g=!0;break}}M++}if(g){const d=await R.getDependency("mesh",M);if(r&&console.log(`Loaded Mesh "${d.name}"`,a,M,d,u),d.isMesh===!0){const m=d.geometry;return f.assignLODInformation(n.url,m,s,e,0),c(m)}else{const m=new Array;for(let L=0;L<d.children.length;L++){const S=d.children[L];if(S.isMesh===!0){const G=S.geometry;f.assignLODInformation(n.url,G,s,e,L),m.push(G)}}return c(m)}}else h&&console.warn("Could not find mesh with guid",w.guid,b.parser.json)}return c(null)});this.cache.set(u,P),y.use(P);const _=await P;return _!=null?_ instanceof $?(this.cache.set(u,new WeakRef(_)),f._resourceRegistry.register(_,u)):Array.isArray(_)?this.cache.set(u,Promise.resolve(_)):this.cache.set(u,Promise.resolve(_)):this.cache.set(u,Promise.resolve(null)),_}else if(t instanceof $){r&&console.log("Load texture from uri: "+a);const u=await new We().loadAsync(a);return u?(u.guid=o.guid,u.flipY=!1,u.needsUpdate=!0,u.colorSpace=t.colorSpace,r&&console.log(o,u)):h&&console.warn("failed loading",a),u}}return null}static queue=new tt(ge()?20:50,{debug:h!=!1});static assignLODInformation(t,e,r,n,s){if(!e)return;e.userData||(e.userData={});const o=new gt(t,r,n,s);e.userData.LODS=o,"source"in e&&typeof e.source=="object"&&(e.source.LODS=o)}static getAssignedLODInformation(t){return t?t.userData?.LODS?t.userData.LODS:"source"in t&&t.source?.LODS?t.source.LODS:null:null}static copySettings(t,e){return e?(h==="verbose"&&console.debug(`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}}class gt{url;key;level;index;constructor(t,e,r,n){this.url=t,this.key=e,this.level=r,n!=null&&(this.index=n)}}class xe{static addPromise=(t,e,r,n)=>{n.forEach(s=>{s.add(t,e,r)})};ready;get awaitedCount(){return this._addedCount}get resolvedCount(){return this._resolvedCount}get currentlyAwaiting(){return this._awaiting.length}_resolve;_signal;_frame_start;_frames_to_capture;_resolved=!1;_addedCount=0;_resolvedCount=0;_awaiting=[];_maxPromisesPerObject=1;constructor(t,e){const r=Math.max(e.frames??2,2);this._frame_start=e.waitForFirstCapture?void 0:t,this._frames_to_capture=r,this.ready=new Promise(n=>{this._resolve=n}),this.ready.finally(()=>{this._resolved=!0,this._awaiting.length=0}),this._signal=e.signal,this._signal?.addEventListener("abort",()=>{this.resolveNow()}),this._maxPromisesPerObject=Math.max(1,e.maxPromisesPerObject??1)}_currentFrame=0;update(t){this._currentFrame=t,this._frame_start===void 0&&this._addedCount>0&&(this._frame_start=t),(this._signal?.aborted||this._awaiting.length===0&&this._frame_start!==void 0&&t>this._frame_start+this._frames_to_capture)&&this.resolveNow()}_seen=new WeakMap;add(t,e,r){if(this._resolved){h&&console.warn("PromiseGroup: Trying to add a promise to a resolved group, ignoring.");return}if(!(this._frame_start!==void 0&&this._currentFrame>this._frame_start+this._frames_to_capture)){if(this._maxPromisesPerObject>=1)if(this._seen.has(e)){let n=this._seen.get(e);if(n>=this._maxPromisesPerObject){h&&console.warn("PromiseGroup: Already awaiting object ignoring new promise for it.");return}this._seen.set(e,n+1)}else this._seen.set(e,1);this._awaiting.push(r),this._addedCount++,r.finally(()=>{this._resolvedCount++,this._awaiting.splice(this._awaiting.indexOf(r),1)})}}resolveNow(){this._resolved||this._resolve?.({awaited_count:this._addedCount,resolved_count:this._resolvedCount,cancelled:this._signal?.aborted??!1})}}const E=j("debugprogressive"),ft=j("noprogressive"),ye=Symbol("Needle:LODSManager"),we=Symbol("Needle:LODState"),U=Symbol("Needle:CurrentLOD"),O={mesh_lod:-1,texture_lod:-1};let Q=class D{static debugDrawLine;static getObjectLODState(t){return t[we]}static addPlugin(t){N.push(t)}static removePlugin(t){const e=N.indexOf(t);e>=0&&N.splice(e,1)}static get(t,e){if(t[ye])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[ye];const r=new D(t,{engine:"unknown",...e});return t[ye]=r,r}renderer;context;projectionScreenMatrix=new be;get plugins(){return N}overrideLodLevel=void 0;targetTriangleDensity=2e5;skinnedMeshAutoUpdateBoundsInterval=30;updateInterval="auto";#e=1;pause=!1;manual=!1;_newPromiseGroups=[];_promiseGroupIds=0;awaitLoading(t){const e=this._promiseGroupIds++,r=new xe(this.#s,{...t});this._newPromiseGroups.push(r);const n=performance.now();return r.ready.finally(()=>{const s=this._newPromiseGroups.indexOf(r);s>=0&&(this._newPromiseGroups.splice(s,1),Te()&&performance.measure("LODsManager:awaitLoading",{start:n,detail:{id:e,name:t?.name,awaited:r.awaitedCount,resolved:r.resolvedCount}}))}),r.ready}_postprocessPromiseGroups(){if(this._newPromiseGroups.length!==0)for(let t=this._newPromiseGroups.length-1;t>=0;t--)this._newPromiseGroups[t].update(this.#s)}_lodchangedlisteners=[];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)}}constructor(t,e){this.renderer=t,this.context={...e}}#t;#o=new Fe;#s=0;#n=0;#i=0;#r=0;_fpsBuffer=[60,60,60,60,60];enable(){if(this.#t)return;console.debug("[gltf-progressive] Enabling LODsManager for renderer");let t=0;this.#t=this.renderer.render;const e=this;te(this.renderer),this.renderer.render=function(r,n){const s=e.renderer.getRenderTarget();(s==null||"isXRRenderTarget"in s&&s.isXRRenderTarget)&&(t=0,e.#s+=1,e.#n=e.#o.getDelta(),e.#i+=e.#n,e._fpsBuffer.shift(),e._fpsBuffer.push(1/e.#n),e.#r=e._fpsBuffer.reduce((l,a)=>l+a)/e._fpsBuffer.length,E&&e.#s%200===0&&console.log("FPS",Math.round(e.#r),"Interval:",e.#e));const o=t++;e.#t.call(this,r,n),e.onAfterRender(r,n,o)}}disable(){this.#t&&(console.debug("[gltf-progressive] Disabling LODsManager for renderer"),this.renderer.render=this.#t,this.#t=void 0)}update(t,e){this.internalUpdate(t,e)}onAfterRender(t,e,r){if(this.pause)return;const n=this.renderer.renderLists.get(t,0).opaque;let s=!0;if(n.length===1){const o=n[0].material;(o.name==="EffectMaterial"||o.name==="CopyShader")&&(s=!1)}if((e.parent&&e.parent.type==="CubeCamera"||r>=1&&e.type==="OrthographicCamera")&&(s=!1),s){if(ft||(this.updateInterval==="auto"?this.#r<40&&this.#e<10?(this.#e+=1,E&&console.warn("\u2193 Reducing LOD updates",this.#e,this.#r.toFixed(0))):this.#r>=60&&this.#e>1&&(this.#e-=1,E&&console.warn("\u2191 Increasing LOD updates",this.#e,this.#r.toFixed(0))):this.#e=this.updateInterval,this.#e>0&&this.#s%this.#e!=0))return;this.internalUpdate(t,e),this._postprocessPromiseGroups()}}internalUpdate(t,e){const r=this.renderer.renderLists.get(t,0),n=r.opaque;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse);const s=this.targetTriangleDensity;for(const a of n){if(a.material&&(a.geometry?.type==="BoxGeometry"||a.geometry?.type==="BufferGeometry")&&(a.material.name==="SphericalGaussianBlur"||a.material.name=="BackgroundCubeMaterial"||a.material.name==="CubemapFromEquirect"||a.material.name==="EquirectangularToCubeUV")){E&&(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(E==="color"&&a.material&&!a.object.progressive_debug_color){a.object.progressive_debug_color=!0;const y=Math.random()*16777215,p=new ze({color:y});a.object.material=p}const u=a.object;(u instanceof F||u.isMesh)&&this.updateLODs(t,e,u,s)}const o=r.transparent;for(const a of o){const u=a.object;(u instanceof F||u.isMesh)&&this.updateLODs(t,e,u,s)}const l=r.transmissive;for(const a of l){const u=a.object;(u instanceof F||u.isMesh)&&this.updateLODs(t,e,u,s)}}updateLODs(t,e,r,n){r.userData||(r.userData={});let s=r[we];if(s||(s=new mt,r[we]=s),s.frames++<2)return;for(const l of N)l.onBeforeUpdateLOD?.(this.renderer,t,e,r);const o=this.overrideLodLevel!==void 0?this.overrideLodLevel:q;o>=0?(O.mesh_lod=o,O.texture_lod=o):(this.calculateLodLevel(e,r,s,n,O),O.mesh_lod=Math.round(O.mesh_lod),O.texture_lod=Math.round(O.texture_lod)),O.mesh_lod>=0&&this.loadProgressiveMeshes(r,O.mesh_lod),r.material&&O.texture_lod>=0&&this.loadProgressiveTextures(r.material,O.texture_lod,o),h&&r.material&&!r.isGizmo&&Pe(r.material);for(const l of N)l.onAfterUpdatedLOD?.(this.renderer,t,e,r,O);s.lastLodLevel_Mesh=O.mesh_lod,s.lastLodLevel_Texture=O.texture_lod}loadProgressiveTextures(t,e,r){if(!t)return;if(Array.isArray(t)){for(const s of t)this.loadProgressiveTextures(s,e);return}let n=!1;if((t[U]===void 0||e<t[U])&&(n=!0),r!==void 0&&r>=0&&(n=t[U]!=r,e=r),n){t[U]=e;const s=f.assignTextureLOD(t,e).then(o=>{this._lodchangedlisteners.forEach(l=>l({type:"texture",level:e,object:t}))});xe.addPromise("texture",t,s,this._newPromiseGroups)}}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);let r=t[U]!==e;const n=t["DEBUG:LOD"];if(n!=null&&(r=t[U]!=n,e=n),r){t[U]=e;const s=t.geometry,o=f.assignMeshLOD(t,e).then(l=>(l&&t[U]==e&&s!=t.geometry&&this._lodchangedlisteners.forEach(a=>a({type:"mesh",level:e,object:t})),l));return xe.addPromise("mesh",t,o,this._newPromiseGroups),o}return Promise.resolve(null)}_sphere=new _e;_tempBox=new ae;_tempBox2=new ae;tempMatrix=new be;_tempWorldPosition=new A;_tempBoxSize=new A;_tempBox2Size=new A;static corner0=new A;static corner1=new A;static corner2=new A;static corner3=new A;static _tempPtInside=new A;static isInside(t,e){const r=t.min,n=t.max,s=(r.x+n.x)*.5,o=(r.y+n.y)*.5;return this._tempPtInside.set(s,o,r.z).applyMatrix4(e).z<0}static skinnedMeshBoundsFrameOffsetCounter=0;static $skinnedMeshBoundsOffset=Symbol("gltf-progressive-skinnedMeshBoundsOffset");calculateLodLevel(t,e,r,n,s){if(!e){s.mesh_lod=-1,s.texture_lod=-1;return}if(!t){s.mesh_lod=-1,s.texture_lod=-1;return}let o=10+1,l=!1;if(E&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const a=f.getMeshLODExtension(e.geometry)?.lods,u=f.getPrimitiveIndex(e.geometry),y=a&&a.length>0,p=f.getMaterialMinMaxLODsCount(e.material),w=p.min_count!==1/0&&p.min_count>=0&&p.max_count>=0;if(!y&&!w){s.mesh_lod=0,s.texture_lod=0;return}y||(l=!0,o=0);const P=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let _=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const c=e;if(!c.boundingBox)c.computeBoundingBox();else if(this.skinnedMeshAutoUpdateBoundsInterval>0){if(!c[D.$skinnedMeshBoundsOffset]){const v=D.skinnedMeshBoundsFrameOffsetCounter++;c[D.$skinnedMeshBoundsOffset]=v}const x=c[D.$skinnedMeshBoundsOffset];if((r.frames+x)%this.skinnedMeshAutoUpdateBoundsInterval===0){const v=V(c),C=c.geometry;v&&(c.geometry=v),c.computeBoundingBox(),c.geometry=C}}_=c.boundingBox}if(_){const c=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 g=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(g)){s.mesh_lod=0,s.texture_lod=0;return}}if(this._tempBox.copy(_),this._tempBox.applyMatrix4(e.matrixWorld),c.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&&c.isPerspectiveCamera&&c.fov>70){const g=this._tempBox.min,d=this._tempBox.max;let m=g.x,L=g.y,S=d.x,G=d.y;const J=2,oe=1.5,Z=(g.x+d.x)*.5,ee=(g.y+d.y)*.5;m=(m-Z)*J+Z,L=(L-ee)*J+ee,S=(S-Z)*J+Z,G=(G-ee)*J+ee;const Re=m<0&&S>0?0:Math.min(Math.abs(g.x),Math.abs(d.x)),$e=L<0&&G>0?0:Math.min(Math.abs(g.y),Math.abs(d.y)),ie=Math.max(Re,$e);r.lastCentrality=(oe-ie)*(oe-ie)*(oe-ie)}else r.lastCentrality=1;const x=this._tempBox.getSize(this._tempBoxSize);x.multiplyScalar(.5),screen.availHeight>0&&P>0&&x.multiplyScalar(P/screen.availHeight),t.isPerspectiveCamera?x.x*=t.aspect:t.isOrthographicCamera;const v=t.matrixWorldInverse,C=this._tempBox2;C.copy(_),C.applyMatrix4(e.matrixWorld),C.applyMatrix4(v);const b=C.getSize(this._tempBox2Size),R=Math.max(b.x,b.y);if(Math.max(x.x,x.y)!=0&&R!=0&&(x.z=b.z/Math.max(b.x,b.y)*Math.max(x.x,x.y)),r.lastScreenCoverage=Math.max(x.x,x.y,x.z),r.lastScreenspaceVolume.copy(x),r.lastScreenCoverage*=r.lastCentrality,E&&D.debugDrawLine){const g=this.tempMatrix.copy(this.projectionScreenMatrix);g.invert();const d=D.corner0,m=D.corner1,L=D.corner2,S=D.corner3;d.copy(this._tempBox.min),m.copy(this._tempBox.max),m.x=d.x,L.copy(this._tempBox.max),L.y=d.y,S.copy(this._tempBox.max);const G=(d.z+S.z)*.5;d.z=m.z=L.z=S.z=G,d.applyMatrix4(g),m.applyMatrix4(g),L.applyMatrix4(g),S.applyMatrix4(g),D.debugDrawLine(d,m,255),D.debugDrawLine(d,L,255),D.debugDrawLine(m,S,255),D.debugDrawLine(L,S,255)}let M=999;if(a&&r.lastScreenCoverage>0)for(let g=0;g<a.length;g++){const d=a[g],m=(d.densities?.[u]||d.density||1e-5)/r.lastScreenCoverage;if(u>0&&Te()&&!d.densities&&!globalThis["NEEDLE:MISSING_LOD_PRIMITIVE_DENSITIES"]&&(window["NEEDLE:MISSING_LOD_PRIMITIVE_DENSITIES"]=!0,console.warn("[Needle Progressive] Detected usage of mesh without primitive densities. This might cause incorrect LOD level selection: Consider re-optimizing your model by updating your Needle Integration, Needle glTF Pipeline or running optimization again on Needle Cloud.")),m<n){M=g;break}}M<o&&(o=M,l=!0)}if(l?s.mesh_lod=o:s.mesh_lod=r.lastLodLevel_Mesh,E&&s.mesh_lod!=r.lastLodLevel_Mesh){const c=a?.[s.mesh_lod];c&&console.log(`Mesh LOD changed: ${r.lastLodLevel_Mesh} \u2192 ${s.mesh_lod} (density: ${c.densities?.[u].toFixed(0)}) | ${e.name}`)}if(w){const c="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(r.lastLodLevel_Texture<0){if(s.texture_lod=p.max_count-1,E){const x=p.lods[p.max_count-1];E&&console.log(`First Texture LOD ${s.texture_lod} (${x.max_height}px) - ${e.name}`)}}else{const x=r.lastScreenspaceVolume.x+r.lastScreenspaceVolume.y+r.lastScreenspaceVolume.z;let v=r.lastScreenCoverage*4;this.context?.engine==="model-viewer"&&(v*=1.5);const C=P/window.devicePixelRatio*v;let b=!1;for(let R=p.lods.length-1;R>=0;R--){const M=p.lods[R];if(!(c&&M.max_height>=2048)&&!(ge()&&M.max_height>4096)&&(M.max_height>C||!b&&R===0)){if(b=!0,s.texture_lod=R,E&&s.texture_lod<r.lastLodLevel_Texture){const g=M.max_height;console.log(`Texture LOD changed: ${r.lastLodLevel_Texture} \u2192 ${s.texture_lod} = ${g}px
Screensize: ${C.toFixed(0)}px, Coverage: ${(100*r.lastScreenCoverage).toFixed(2)}%, Volume ${x.toFixed(1)}
${e.name}`)}break}}}}else s.texture_lod=0}};class mt{frames=0;lastLodLevel_Mesh=-1;lastLodLevel_Texture=-1;lastScreenCoverage=0;lastScreenspaceVolume=new A;lastCentrality=0}const Ce=Symbol("NEEDLE_mesh_lod"),ne=Symbol("NEEDLE_texture_lod");let ve=null;function Ae(){const i=pt();i&&(i.mapURLs(function(t){return ke(),t}),ke(),ve?.disconnect(),ve=new MutationObserver(t=>{t.forEach(e=>{e.addedNodes.forEach(r=>{r instanceof HTMLElement&&r.tagName.toLowerCase()==="model-viewer"&&Ee(r)})})}),ve.observe(document,{childList:!0,subtree:!0}))}function pt(){return typeof customElements>"u"?null:customElements.get("model-viewer")||(customElements.whenDefined("model-viewer").then(()=>{console.debug("[gltf-progressive] model-viewer defined"),Ae()}),null)}function ke(){typeof document>"u"||document.querySelectorAll("model-viewer").forEach(i=>{Ee(i)})}const Ie=new WeakSet;let xt=0;function Ee(i){if(!i||Ie.has(i))return null;Ie.add(i),console.debug("[gltf-progressive] found new model-viewer..."+ ++xt+`
`,i.getAttribute("src"));let t=null,e=null,r=null;for(let n=i;n!=null;n=Object.getPrototypeOf(n)){const s=Object.getOwnPropertySymbols(n),o=s.find(u=>u.toString()=="Symbol(renderer)"),l=s.find(u=>u.toString()=="Symbol(scene)"),a=s.find(u=>u.toString()=="Symbol(needsRender)");!t&&o!=null&&(t=i[o].threeRenderer),!e&&l!=null&&(e=i[l]),!r&&a!=null&&(r=i[a])}if(t&&e){let n=function(){if(r){let o=0,l=setInterval(()=>{if(o++>5){clearInterval(l);return}r?.call(i)},300)}};console.debug("[gltf-progressive] setup model-viewer");const s=Q.get(t,{engine:"model-viewer"});return Q.addPlugin(new yt),s.enable(),s.addEventListener("changed",()=>{r?.call(i)}),i.addEventListener("model-visibility",o=>{o.detail.visible&&r?.call(i)}),i.addEventListener("load",()=>{n()}),()=>{s.disable()}}return null}class yt{_didWarnAboutMissingUrl=!1;onBeforeUpdateLOD(t,e,r,n){this.tryParseMeshLOD(e,n),this.tryParseTextureLOD(e,n)}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[ne]==!0)return;e[ne]=!0;const r=this.tryGetCurrentGLTF(t),n=this.tryGetCurrentModelViewer(t),s=this.getUrl(n);if(s&&r&&e.material){let o=function(a){if(a[ne]==!0)return;a[ne]=!0,a.userData&&(a.userData.LOD=-1);const u=Object.keys(a);for(let y=0;y<u.length;y++){const p=u[y],w=a[p];if(w?.isTexture===!0){const P=w.userData?.associations?.textures;if(P==null)continue;const _=r.parser.json.textures[P];if(!_){console.warn("Texture data not found for texture index "+P);continue}if(_?.extensions?.[B]){const c=_.extensions[B];c&&s&&f.registerTexture(s,w,c.lods.length,P,c)}}}};const l=e.material;if(Array.isArray(l))for(const a of l)o(a);else o(l)}}tryParseMeshLOD(t,e){if(e[Ce]==!0)return;e[Ce]=!0;const r=this.tryGetCurrentModelViewer(t),n=this.getUrl(r);if(!n)return;const s=e.userData?.gltfExtensions?.[B];if(s&&n){const o=e.uuid;f.registerMesh(n,o,e,0,s.lods.length,s)}}}function wt(...i){let t,e,r,n;switch(i.length){case 2:[r,e]=i,n={};break;case 3:[r,e,n]=i;break;case 4:[t,e,r,n]=i;break;default:throw new Error("Invalid arguments")}te(e),ue(r),he(r,{progressive:!0,...n?.hints}),r.register(o=>new f(o));const s=Q.get(e);return n?.enableLODsManager!==!1&&s.enable(),s}if(Ae(),!nt){const i={gltfProgressive:{useNeedleProgressive:wt,LODsManager:Q,configureLoader:he,getRaycastMesh:V,useRaycastMeshes:it}};if(!globalThis.Needle)globalThis.Needle=i;else for(const t in i)globalThis.Needle[t]=i[t]}export{Q as LODsManager,f as NEEDLE_progressive,ue as addDracoAndKTX2Loaders,he as configureLoader,te as createLoaders,V as getRaycastMesh,De as setDracoDecoderLocation,Oe as setKTX2TranscoderLocation};