@needle-tools/gltf-progressive 3.6.0-canary.5401de9 → 3.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,10 @@
1
- import*as et from"three";import{RedFormat as tt,RedIntegerFormat as rt,RGFormat as st,RGIntegerFormat as ot,RGBFormat as nt,RGBAFormat as it,RGBAIntegerFormat as at,BufferGeometry as V,Mesh as X,Box3 as ne,Vector3 as k,Sphere as ke,CompressedTexture as lt,Texture as I,Matrix3 as ut,InterleavedBuffer as ct,InterleavedBufferAttribute as dt,BufferAttribute as ht,TextureLoader as gt,Color as Pe,Matrix4 as Re}from"three";import{GLTFLoader as de}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as ft}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as mt}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as pt}from"three/examples/jsm/loaders/KTX2Loader.js";const Ce="";globalThis.GLTF_PROGRESSIVE_VERSION=Ce,console.debug("[gltf-progressive] version -");let C="https://www.gstatic.com/draco/versioned/decoders/1.5.7/",H="https://cdn.needle.tools/static/three/0.179.1/basis2/";const xt=C,yt=H,Ae=new URL(C+"draco_decoder.js");Ae.searchParams.append("range","true"),fetch(Ae,{method:"GET",headers:{Range:"bytes=0-1"}}).catch(n=>{console.debug(`Failed to fetch remote Draco decoder from ${C} (offline: ${typeof navigator<"u"?navigator.onLine:"unknown"})`),C===xt&&Ee("./include/draco/"),H===yt&&Ie("./include/ktx2/")}).finally(()=>{$e()});const vt=()=>({dracoDecoderPath:C,ktx2TranscoderPath:H});function Ee(n){C=n,O&&O[ge]!=C?(console.debug("Updating Draco decoder path to "+n),O[ge]=C,O.setDecoderPath(C),O.preload()):console.debug("Setting Draco decoder path to "+n)}function Ie(n){H=n,A&&A.transcoderPath!=H?(console.debug("Updating KTX2 transcoder path to "+n),A.setTranscoderPath(H),A.init()):console.debug("Setting KTX2 transcoder path to "+n)}function ie(n){return $e(),n?A.detectSupport(n):n!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:O,ktx2Loader:A,meshoptDecoder:ae}}function he(n){n.dracoLoader||n.setDRACOLoader(O),n.ktx2Loader||n.setKTX2Loader(A),n.meshoptDecoder||n.setMeshoptDecoder(ae)}const ge=Symbol("dracoDecoderPath");let O,ae,A;function $e(){O||(O=new mt,O[ge]=C,O.setDecoderPath(C),O.setDecoderConfig({type:"js"}),O.preload()),A||(A=new pt,A.setTranscoderPath(H),A.init()),ae||(ae=ft)}const fe=new WeakMap;function me(n,t){let e=fe.get(n);e?e=Object.assign(e,t):e=t,fe.set(n,e)}const wt=de.prototype.load;function Lt(...n){const t=fe.get(this);let e=n[0];const r=bt(e);if(r?.hostname.endsWith("needle.tools")){const s=t?.progressive!==void 0?t.progressive:!0,o=t?.usecase?t.usecase:"default";s?this.requestHeader.Accept=`*/*;progressive=allowed;usecase=${o}`:this.requestHeader.Accept=`*/*;usecase=${o}`,e=r.toString()}return n[0]=e,wt?.call(this,...n)}de.prototype.load=Lt;function bt(n){try{if(n instanceof URL)return n;const t=globalThis.location?.href;return t?new URL(n,t):new URL(n)}catch{return null}}function Be(n){return n!=null&&n.data!=null}function pe(n){const t=n.source?.data;return t!=null&&typeof t=="object"?t:null}function Dt(n){const t=n.image;return t!=null&&typeof t=="object"?t:null}function xe(n){const t=Dt(n),e=pe(n);return{width:t?.width||e?.width||0,height:t?.height||e?.height||0}}W("debugprogressive");function W(n){const t=globalThis.location?.href;if(!t)return!1;const e=new URL(t).searchParams.get(n);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function Mt(n,t){if(t===void 0||n===void 0||t.startsWith("./")||t.startsWith("http")||t.startsWith("data:")||t.startsWith("blob:"))return t;const e=n.lastIndexOf("/");if(e>=0){const r=n.substring(0,e+1);for(;r.endsWith("/")&&t.startsWith("/");)t=t.substring(1);return r+t}return t}function ye(){if(ee!==void 0)return ee;const n=globalThis.navigator?.userAgent||"";return ee=/iPhone|iPad|iPod|Android|IEMobile/i.test(n),W("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",ee),ee}let ee;function Ge(){const n=globalThis.location?.href;if(!n)return!1;const t=new URL(n),e=t.hostname==="localhost"||/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(t.hostname);return t.hostname==="127.0.0.1"||e}class _t{constructor(t,e={}){this.maxConcurrent=t,this.debug=e.debug??!1,typeof window<"u"&&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:s}=this._queue.shift();s({use:o=>this.add(r,o)})}}}function Tt(n){const t=n.image,e=t?.width??0,r=t?.height??0,s=t?.depth??1,o=Math.floor(Math.log2(Math.max(e,r,s)))+1,i=St(n);return e*r*s*i*(1-Math.pow(.25,o))/(1-.25)}function St(n){let t=4;const e=n.format;e===tt||e===rt?t=1:e===st||e===ot?t=2:e===nt||e===1029?t=3:(e===it||e===at)&&(t=4);let r=1;const s=n.type;return s===1009||s===1010?r=1:s===1011||s===1012?r=2:s===1013||s===1014||s===1015?r=4:s===1016&&(r=2),t*r}const Ot=typeof window>"u"&&typeof document>"u",ve=Symbol("needle:raycast-mesh");function Y(n){return n?.[ve]instanceof V?n[ve]:null}function qe(n,t){if((n.type==="Mesh"||n.type==="SkinnedMesh")&&!Y(n)){const e=kt(t);e.userData={isRaycastMesh:!0},n[ve]=e}}function We(n=!0){if(n){if(te)return;const t=te=X.prototype.raycast;X.prototype.raycast=function(e,r){const s=this,o=Y(s);let i;o&&s.isMesh&&(i=s.geometry,s.geometry=o),t.call(this,e,r),i&&(s.geometry=i)}}else{if(!te)return;X.prototype.raycast=te,te=null}}let te=null;function kt(n){const t=new V;for(const e in n.attributes)t.setAttribute(e,n.getAttribute(e));return t.setIndex(n.getIndex()),t}const G=new Array,g=W("debugprogressive");let re,K=-1;if(g&&typeof window<"u"){let n=function(){K+=1,K>=t&&(K=-1),console.log(`Toggle LOD level [${K}]`)};const t=6;window.addEventListener("keyup",e=>{e.key==="p"&&n(),e.key==="w"&&(re=!re,console.log(`Toggle wireframe [${re}]`));const r=parseInt(e.key);!isNaN(r)&&r>=0&&(K=r,console.log(`Set LOD level to [${K}]`))})}function Ne(n){if(g&&re!==void 0)if(Array.isArray(n))for(const t of n)Ne(t);else n&&"wireframe"in n&&(n.wireframe=re===!0)}const se=new Array;let Pt=0;const Rt=ye()?2:10;function Ct(n){if(se.length<Rt){const e=se.length;g&&console.warn(`[Worker] Creating new worker #${e}`);const r=Oe.createWorker(n||{});return se.push(r),r}const t=Pt++%se.length;return se[t]}class Oe{constructor(t,e){this.worker=t,this._debug=e.debug??!1,t.onmessage=r=>{const s=r.data;switch(this._debug&&console.log("[Worker] EVENT",s),s.type){case"loaded-gltf":for(const o of this._running)if(o.url===s.result.url){At(s.result),o.resolve(s.result);const i=o.url;i.startsWith("blob:")&&URL.revokeObjectURL(i)}}},t.onerror=r=>{console.error("[Worker] Error in gltf-progressive worker:",r)},t.postMessage({type:"init"})}static async createWorker(t){const e=new Worker(new URL("/assets/gltf-progressive.worker-CCrD-Ycm.js",import.meta.url),{type:"module"});return new Oe(e,t)}_running=[];_webglRenderer=null;async load(t,e){const r=vt();let s=e?.renderer;s||(this._webglRenderer??=(async()=>{const{WebGLRenderer:a}=await import("three");return new a})(),s=await this._webglRenderer);const o=ie(s).ktx2Loader.workerConfig;if(t instanceof URL)t=t.toString();else if(t.startsWith("file:"))t=URL.createObjectURL(new Blob([t]));else if(!t.startsWith("blob:")&&!t.startsWith("http:")&&!t.startsWith("https:")){const a=globalThis.location?.href;a&&(t=new URL(t,a).toString())}const i={type:"load",url:t,dracoDecoderPath:r.dracoDecoderPath,ktx2TranscoderPath:r.ktx2TranscoderPath,ktx2LoaderConfig:o};return this._debug&&console.debug("[Worker] Sending load request",i),this.worker.postMessage(i),new Promise(a=>{this._running.push({url:t.toString(),resolve:a})})}_debug=!1}function At(n){for(const t of n.geometries){const e=t.geometry,r=new V;if(r.name=e.name||"",e.index){const s=e.index;r.setIndex(we(s))}for(const s in e.attributes){const o=e.attributes[s],i=we(o);r.setAttribute(s,i)}if(e.morphAttributes)for(const s in e.morphAttributes){const o=e.morphAttributes[s].map(i=>we(i));r.morphAttributes[s]=o}if(r.morphTargetsRelative=e.morphTargetsRelative??!1,r.boundingBox=new ne,r.boundingBox.min=new k(e.boundingBox?.min.x,e.boundingBox?.min.y,e.boundingBox?.min.z),r.boundingBox.max=new k(e.boundingBox?.max.x,e.boundingBox?.max.y,e.boundingBox?.max.z),r.boundingSphere=new ke(new k(e.boundingSphere?.center.x,e.boundingSphere?.center.y,e.boundingSphere?.center.z),e.boundingSphere?.radius),e.groups)for(const s of e.groups)r.addGroup(s.start,s.count,s.materialIndex);e.userData&&(r.userData=e.userData),t.geometry=r}for(const t of n.textures){const e=t.texture;let r=null;if(e.isCompressedTexture){const s=e.mipmaps,{width:o,height:i}=xe(e);r=new lt(s,o,i,e.format,e.type,e.mapping,e.wrapS,e.wrapT,e.magFilter,e.minFilter,e.anisotropy,e.colorSpace)}else r=new I(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 ut(...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 n}function we(n){let t=n;if("isInterleavedBufferAttribute"in n&&n.isInterleavedBufferAttribute){const e=n.data,r=e.array,s=new ct(r,e.stride);t=new dt(s,n.itemSize,r.byteOffset,n.normalized),t.offset=n.offset}else"isBufferAttribute"in n&&n.isBufferAttribute&&(t=new ht(n.array,n.itemSize,n.normalized),t.usage=n.usage,t.gpuType=n.gpuType,t.updateRanges=n.updateRanges);return t}const Et=W("gltf-progressive-worker");W("gltf-progressive-reduce-mipmaps");const oe=W("gltf-progressive-gc"),Le=Symbol("needle-progressive-texture"),$="NEEDLE_progressive";class f{get name(){return $}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,s="LODS:minmax",o=t[s];if(o!=null)return o;if(e||(e={min_count:1/0,max_count:0,lods:[]}),Array.isArray(t)){for(const a of t)this.getMaterialMinMaxLODsCount(a,e);return t[s]=e,e}if(g==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const a=t;for(const l of Object.keys(a.uniforms)){const u=a.uniforms[l].value;u?.isTexture===!0&&i(u,e)}}else if(t.isMaterial)for(const a of Object.keys(t)){const l=t[a];l?.isTexture===!0&&i(l,e)}else g&&console.warn(`[getMaterialMinMaxLODsCount] Unsupported material type: ${t.type}`);return t[s]=e,e;function i(a,l){const u=r.getAssignedLODInformation(a);if(u){const c=r.lodInfos.get(u.key);if(c&&c.lods){l.min_count=Math.min(l.min_count,c.lods.length),l.max_count=Math.max(l.max_count,c.lods.length);for(let d=0;d<c.lods.length;d++){const p=c.lods[d];p.width&&(l.lods[d]=l.lods[d]||{min_height:1/0,max_height:0},l.lods[d].min_height=Math.min(l.lods[d].min_height,p.height),l.lods[d].max_height=Math.max(l.lods[d].max_height,p.height))}}}}}static hasLODLevelAvailable(t,e){if(Array.isArray(t)){for(const o of t)if(this.hasLODLevelAvailable(o,e))return!0;return!1}if(t.isMaterial===!0){for(const o of Object.keys(t)){const i=t[o];if(i&&i.isTexture&&this.hasLODLevelAvailable(i,e))return!0}return!1}else if(t.isGroup===!0){for(const o of t.children)if(o.isMesh===!0&&this.hasLODLevelAvailable(o,e))return!0}let r,s;if(t.isMesh?r=t.geometry:(t.isBufferGeometry||t.isTexture)&&(r=t),r&&r?.userData?.LODS){const o=r.userData.LODS;if(s=this.lodInfos.get(o.key),e===void 0)return s!=null;if(s)return Array.isArray(s.lods)?e<s.lods.length:e===0}return!1}static assignMeshLOD(t,e,r){if(!t)return Promise.resolve(null);if(t instanceof X||t.isMesh===!0){const s=t.geometry,o=this.getAssignedLODInformation(s);if(!o)return Promise.resolve(null);for(const a of G)a.onBeforeGetLODMesh?.(t,e);t["LOD:requested level"]=e;const i=()=>t["LOD:requested level"]===e||this.shouldApplyStaleMeshLOD(t,e);return f.getOrLoadLOD(s,e,{isCurrent:i}).then(a=>{if(Array.isArray(a)){const u=o.index||0;a=a[u]}const l=t["LOD:requested level"]===e;return(l||this.shouldApplyStaleMeshLOD(t,e))&&(l&&delete t["LOD:requested level"],a&&s!=a&&(a?.isBufferGeometry?typeof r?.apply=="function"?r.apply(a,e,t):r?.apply!==!1&&(t.geometry=a):g&&console.error("Invalid LOD geometry",a))),a}).catch(a=>(console.error("Error loading mesh LOD",t,a),null))}else g&&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,r){if(!t)return Promise.resolve(null);const s=r?.force===!0;if(t.isMesh===!0){const o=t;if(Array.isArray(o.material)){const i=new Array;for(const a of o.material){const l=this.assignTextureLOD(a,e,r);i.push(l)}return Promise.all(i).then(a=>{const l=new Array;for(const u of a)Array.isArray(u)&&l.push(...u);return l})}else return this.assignTextureLOD(o.material,e,r)}if(t.isMaterial===!0){const o=t,i=[],a=new Array;if(this.trackCurrentMaterialTextureSlots(o),o.uniforms&&(o.isRawShaderMaterial||o.isShaderMaterial===!0)){const l=o;for(const u of Object.keys(l.uniforms)){const c=l.uniforms[u].value;if(c?.isTexture===!0){const d=this.assignTextureLODForSlot(c,e,o,u,s).then(p=>(p&&l.uniforms[u].value!=p&&(l.uniforms[u].value=p,l.uniformsNeedUpdate=!0),p));i.push(d),a.push(u)}}}else for(const l of Object.keys(o)){const u=o[l];if(u?.isTexture===!0){const c=this.assignTextureLODForSlot(u,e,o,l,s);i.push(c),a.push(l)}}return Promise.all(i).then(l=>{const u=new Array;for(let c=0;c<l.length;c++){const d=l[c],p=a[c];d&&d.isTexture===!0?u.push({material:o,slot:p,texture:d,level:e}):u.push({material:o,slot:p,texture:null,level:e})}return u})}if(t instanceof I||t.isTexture===!0){const o=t;return this.assignTextureLODForSlot(o,e,null,null,s)}return Promise.resolve(null)}static set maxConcurrentLoadingTasks(t){f.queue.maxConcurrent=t}static get maxConcurrentLoadingTasks(){return f.queue.maxConcurrent}static assignTextureLODForSlot(t,e,r,s,o){if(t?.isTexture!==!0)return Promise.resolve(null);if(s==="glyphMap")return Promise.resolve(t);const i=this.getAssignedLODInformation(t);if(i&&(i.level===e||!o&&i.level<e))return Promise.resolve(t);if(r&&s){const d=this.getPendingTextureSlotRequest(r,s);if(d&&d.level===e&&d.force===o)return d.promise}const a=r&&s?this.nextTextureSlotRequestId(r,s,e,o):0,l=()=>!r||!s||this.getLatestTextureSlotRequest(r,s)?.id===a,u=()=>l()||this.shouldApplyStaleTextureSlotLOD(r,s,e,o),c=f.getOrLoadLOD(t,e,{isCurrent:u}).then(d=>{if(!l()&&!this.shouldApplyStaleTextureSlotLOD(r,s,e,o))return null;if(Array.isArray(d))return console.warn("Progressive: Got an array of textures for a texture slot, this should not happen..."),null;if(d?.isTexture===!0){if(d!=t&&r&&s){const p=this.getMaterialTextureSlot(r,s)??t;if(p&&!o){const m=this.getAssignedLODInformation(p);if(m&&m?.level<e)return g==="verbose"&&console.warn("Assigned texture level is already higher: ",m.level,e,r,p,d),null}this.assignTrackedTextureSlot(r,s,d)}return d}else g=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(d=>(console.error("Error loading LOD",t,d),null));return r&&s&&this.setPendingTextureSlotRequest(r,s,e,o,a,c),c}static trackedTextureSlots=new WeakMap;static pendingTextureSlotRequests=new WeakMap;static latestTextureSlotRequests=new WeakMap;static textureSlotRequestId=0;static trackCurrentMaterialTextureSlots(t){if(t.uniforms&&(t.isRawShaderMaterial||t.isShaderMaterial===!0)){const e=t;for(const r of Object.keys(e.uniforms)){const s=e.uniforms[r].value;s?.isTexture===!0&&this.ensureTrackedTextureSlot(t,r,s)}return}for(const e of Object.keys(t)){const r=t[e];r?.isTexture===!0&&this.ensureTrackedTextureSlot(t,e,r)}}static getPendingTextureSlotRequest(t,e){return this.pendingTextureSlotRequests.get(t)?.get(e)}static nextTextureSlotRequestId(t,e,r,s){let o=this.latestTextureSlotRequests.get(t);o||(o=new Map,this.latestTextureSlotRequests.set(t,o));const i=++this.textureSlotRequestId;return o.set(e,{id:i,level:r,force:s}),i}static getLatestTextureSlotRequest(t,e){return this.latestTextureSlotRequests.get(t)?.get(e)}static shouldApplyStaleTextureSlotLOD(t,e,r,s){if(!t||!e)return!1;const o=this.getLatestTextureSlotRequest(t,e),i=this.getMaterialTextureSlot(t,e),a=this.getAssignedLODInformation(i)?.level??1/0;return r>=a?!1:s?o?r>=o.level:!1:!0}static shouldApplyStaleMeshLOD(t,e){const r=t["LOD:requested level"];if(typeof r!="number")return!1;const s=this.getAssignedLODInformation(t.geometry)?.level??1/0;return e<s&&e>=r}static setPendingTextureSlotRequest(t,e,r,s,o,i){let a=this.pendingTextureSlotRequests.get(t);a||(a=new Map,this.pendingTextureSlotRequests.set(t,a));const l={level:r,force:s,id:o,promise:i};a.set(e,l),i.finally(()=>{a.get(e)?.id===o&&a.delete(e)})}static getMaterialTextureSlot(t,e){const r=t.uniforms?.[e];if(r?.value?.isTexture===!0)return r.value;const s=t[e];return s?.isTexture===!0?s:null}static setMaterialTextureSlot(t,e,r){const s=t.uniforms?.[e];if(s?.value?.isTexture===!0){s.value=r,t.uniformsNeedUpdate=!0;return}t[e]=r}static assignTrackedTextureSlot(t,e,r){let s=this.trackedTextureSlots.get(t);s||(s=new Map,this.trackedTextureSlots.set(t,s));const o=this.getMaterialTextureSlot(t,e);let i=s.get(e);!i&&o?i=this.ensureTrackedTextureSlot(t,e,o):i&&o&&i!==o&&(this.releaseTrackedTextureSlot(t,e,i),i=this.ensureTrackedTextureSlot(t,e,o)),!(i===r&&o===r)&&(i&&i!==r&&this.releaseTrackedTextureSlot(t,e,i),i!==r&&(this.trackTextureUsage(r),s.set(e,r)),o!==r&&this.setMaterialTextureSlot(t,e,r))}static ensureTrackedTextureSlot(t,e,r){let s=this.trackedTextureSlots.get(t);s||(s=new Map,this.trackedTextureSlots.set(t,s));const o=s.get(e);return o===r?o:(o&&this.releaseTrackedTextureSlot(t,e,o),this.trackTextureUsage(r),s.set(e,r),r)}static releaseTrackedTextureSlot(t,e,r){const s=this.trackedTextureSlots.get(t);if(s?.get(e)===r&&s.delete(e),this.untrackTextureUsage(r)&&(g||oe)){const o=this.getAssignedLODInformation(r);console.log(`[gltf-progressive] Disposed old texture LOD ${o?.level??"?"} for ${t.name||t.type}.${e}`,r.uuid)}}parser;url;constructor(t){const e=t.options.path;g&&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?.[$];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 g&&console.log("AFTER",this.url,t),this.parser.json.textures?.forEach((e,r)=>{if(e?.extensions){const s=e?.extensions[$];if(s){if(!s.lods){g&&console.warn("Texture has no LODs",s);return}let o=!1;for(const i of this.parser.associations.keys())i.isTexture===!0&&this.parser.associations.get(i)?.textures===r&&(o=!0,f.registerTexture(this.url,i,s.lods?.length,r,s));o||this.parser.getDependency("texture",r).then(i=>{i&&f.registerTexture(this.url,i,s.lods?.length,r,s)})}}}),this.parser.json.meshes?.forEach((e,r)=>{if(e?.extensions){const s=e?.extensions[$];if(s&&s.lods){for(const o of this.parser.associations.keys())if(o.isMesh){const i=this.parser.associations.get(o);i?.meshes===r&&f.registerMesh(this.url,s.guid,o,s.lods.length,i.primitives,s)}}}}),null}static registerTexture=(t,e,r,s,o)=>{if(!e){g&&console.error("!! gltf-progressive: Called register texture without texture");return}if(g){const{width:a,height:l}=xe(e);console.log(`> gltf-progressive: register texture[${s}] "${e.name||e.uuid}", Current: ${a}x${l}, Max: ${o.lods[0]?.width}x${o.lods[0]?.height}, uuid: ${e.uuid}`,o,e)}e.source&&(e.source[Le]=o);const i=o.guid;f.assignLODInformation(t,e,i,r,s),f.lodInfos.set(i,o),f.lowresCache.set(i,new WeakRef(e))};static registerMesh=(t,e,r,s,o,i)=>{const a=r.geometry;if(!a){g&&console.warn("gltf-progressive: Register mesh without geometry");return}a.userData||(a.userData={}),g&&console.log("> Progressive: register mesh "+r.name,{index:o,uuid:r.uuid},i,r),f.assignLODInformation(t,a,e,s,o),f.lodInfos.set(e,i);let l=f.lowresCache.get(e)?.deref();l?l.push(r.geometry):l=[r.geometry],f.lowresCache.set(e,new WeakRef(l)),s>0&&!Y(r)&&qe(r,a);for(const u of G)u.onRegisteredNewMesh?.(r,i)};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 s=r;this.textureRefCounts.delete(s.uuid),s.dispose()}else if(Array.isArray(r))for(const s of r)s.dispose()}this.lowresCache.delete(t)}for(const[r,s]of this.cache)r.includes(t)&&(this._disposeCacheEntry(s),this.cache.delete(r))}else{this.lodInfos.clear();for(const[,e]of this.lowresCache){const r=e.deref();if(r){if(r.isTexture){const s=r;this.textureRefCounts.delete(s.uuid),s.dispose()}else if(Array.isArray(r))for(const s of r)s.dispose()}}this.lowresCache.clear();for(const[,e]of this.cache)this._disposeCacheEntry(e);this.cache.clear(),this.textureRefCounts.clear(),this.trackedTextureSlots=new WeakMap,this.pendingTextureSlotRequests=new WeakMap,this.latestTextureSlotRequests=new WeakMap,this.textureSlotRequestId=0}}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);(g||oe)&&console.debug(`[gltf-progressive] Memory: Resource GC'd
2
- ${t}`),e instanceof WeakRef&&(e.deref()||(f.cache.delete(t),(g||oe)&&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),g==="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(g==="verbose"||oe)&&o("[gltf-progressive] Memory: Untrack untracked texture (dispose immediately)",0),t.dispose(),!0;const s=r-1;if(s<=0)return this.textureRefCounts.delete(e),(g||oe)&&o("[gltf-progressive] Memory: Dispose texture",s),t.dispose(),!0;return this.textureRefCounts.set(e,s),g==="verbose"&&o("[gltf-progressive] Memory: Untrack texture",s),!1;function o(i,a){let{width:l,height:u}=xe(t);const c=l&&u?`${l}x${u}`:"N/A";let d="N/A";l&&u&&(d=`~${(Tt(t)/(1024*1024)).toFixed(2)} MB`),console.log(`${i} \u2014 ${t.name} ${c} (${d}), refCount: ${r} \u2192 ${a}
3
- ${e}`)}}static workers=[];static _workersIndex=0;static async getOrLoadLOD(t,e,r){const s=g=="verbose",o=this.getAssignedLODInformation(t);if(!o)return g&&console.warn(`[gltf-progressive] No LOD information found: ${t.name}, uuid: ${t.uuid}, type: ${t.type}`,t),null;const i=o?.key;let a;if(t.isTexture===!0){const l=t;l.source&&l.source[Le]&&(a=l.source[Le])}if(a||(a=f.lodInfos.get(i)),!a)g&&console.warn(`Can not load LOD ${e}: no LOD info found for "${i}" ${t.name}`,t.type,f.lodInfos);else{if(e>0){let c=!1;const d=Array.isArray(a.lods);if(d&&e>=a.lods.length?c=!0:d||(c=!0),c){const p=this.lowresCache.get(i);if(p){const m=p.deref();if(m)return m;this.lowresCache.delete(i),g&&console.log(`[gltf-progressive] Lowres cache entry was GC'd: ${i}`)}return null}}const l=Array.isArray(a.lods)?a.lods[e]?.path:a.lods;if(!l)return g&&!a["missing:uri"]&&(a["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,a)),null;const u=Mt(o.url,l);if(u.endsWith(".glb")||u.endsWith(".gltf")){if(!a.guid)return console.warn("missing pointer for glb/gltf texture",a),null;const c=u+"_"+a.guid,d=await this.tryResolveLODCacheEntry(this.cache.get(c),c,u,t,e,s);if(d.found)return d.value;if(r?.isCurrent?.()===!1)return s&&console.log(`Skipping stale LOD ${e} request before queue: ${u}`),null;const p=await this.queue.slot(u);if(r?.isCurrent?.()===!1)return s&&console.log(`Skipping stale LOD ${e} request after queue: ${u}`),null;const m=await this.tryResolveLODCacheEntry(this.cache.get(c),c,u,t,e,s);if(m.found)return m.value;if(!p.use)return g&&console.log(`LOD ${e} was aborted: ${u}`),null;const w=a,h=new Promise(async(M,j)=>{if(Et){const b=await(await Ct({})).load(u);if(b.textures.length>0)for(const x of b.textures){let v=x.texture;return f.assignLODInformation(o.url,v,i,e,void 0),t instanceof I&&(v=this.copySettings(t,v)),v&&(v.guid=w.guid),M(v)}if(b.geometries.length>0){const x=new Array;for(const v of b.geometries){const R=v.geometry;f.assignLODInformation(o.url,R,i,e,v.primitiveIndex),x.push(R)}return M(x)}return M(null)}const B=new de;he(B),g&&(await new Promise(b=>setTimeout(b,1e3)),s&&console.warn("Start loading (delayed) "+u,w.guid));let L=u;if(w&&Array.isArray(w.lods)){const b=w.lods[e];b.hash&&(L+="?v="+b.hash)}const y=await B.loadAsync(L).catch(b=>(console.error(`Error loading LOD ${e} from ${u}
4
- `,b),M(null)));if(!y)return M(null);const T=y.parser;s&&console.log("Loading finished "+u,w.guid);let S=0;if(y.parser.json.textures){let b=!1;for(const x of y.parser.json.textures){if(x?.extensions){const v=x?.extensions[$];if(v?.guid&&v.guid===w.guid){b=!0;break}}S++}if(b){let x=await T.getDependency("texture",S);return x&&f.assignLODInformation(o.url,x,i,e,void 0),s&&console.log('change "'+t.name+'" \u2192 "'+x.name+'"',u,S,x,c),t instanceof I&&(x=this.copySettings(t,x)),x&&(x.guid=w.guid),M(x)}else g&&console.warn("Could not find texture with guid",w.guid,y.parser.json)}if(S=0,y.parser.json.meshes){let b=!1;for(const x of y.parser.json.meshes){if(x?.extensions){const v=x?.extensions[$];if(v?.guid&&v.guid===w.guid){b=!0;break}}S++}if(b){const x=await T.getDependency("mesh",S);if(s&&console.log(`Loaded Mesh "${x.name}"`,u,S,x,c),x.isMesh===!0){const v=x.geometry;return f.assignLODInformation(o.url,v,i,e,0),M(v)}else{const v=new Array;for(let R=0;R<x.children.length;R++){const F=x.children[R];if(F.isMesh===!0){const z=F.geometry;f.assignLODInformation(o.url,z,i,e,R),v.push(z)}}return M(v)}}else g&&console.warn("Could not find mesh with guid",w.guid,y.parser.json)}return M(null)});this.cache.set(c,h),p.use(h);const D=await h;return D!=null?D instanceof I?(this.cache.set(c,new WeakRef(D)),f._resourceRegistry.register(D,c)):Array.isArray(D)?this.cache.set(c,Promise.resolve(D)):this.cache.set(c,Promise.resolve(D)):this.cache.set(c,Promise.resolve(null)),D}else if(t instanceof I){if(r?.isCurrent?.()===!1)return s&&console.log(`Skipping stale texture LOD ${e} request: ${u}`),null;s&&console.log("Load texture from uri: "+u);const c=await new gt().loadAsync(u);return r?.isCurrent?.()===!1?(c?.dispose(),null):(c?(c.guid=a.guid,c.flipY=!1,c.needsUpdate=!0,c.colorSpace=t.colorSpace,s&&console.log(a,c)):g&&console.warn("failed loading",u),c)}}return null}static async tryResolveLODCacheEntry(t,e,r,s,o,i){if(t===void 0)return{found:!1};if(i&&console.log(`LOD ${o} was already loading/loaded: ${e}`),t instanceof WeakRef){const u=t.deref();if(u){let c=u,d=!1;if(c instanceof I&&s instanceof I?Be(c.image)||pe(c)?c=this.copySettings(s,c):d=!0:c instanceof V&&s instanceof V&&(c.attributes.position?.array||(d=!0)),!d)return{found:!0,value:c}}return this.cache.delete(e),g&&console.log(`[gltf-progressive] Re-loading GC'd/disposed resource: ${e}`),{found:!1}}let a=await t.catch(u=>(console.error(`Error loading LOD ${o} from ${r}
5
- `,u),null)),l=!1;return a==null||(a instanceof I&&s instanceof I?Be(a.image)||pe(a)?a=this.copySettings(s,a):(l=!0,this.cache.delete(e)):a instanceof V&&s instanceof V&&(a.attributes.position?.array||(l=!0,this.cache.delete(e)))),l?{found:!1}:{found:!0,value:a}}static _queue;static get queue(){return this._queue??=new _t(ye()?20:50,{debug:g!=!1})}static assignLODInformation(t,e,r,s,o){if(!e)return;e.userData||(e.userData={});const i=new It(t,r,s,o);e.userData.LODS=i,"source"in e&&typeof e.source=="object"&&(e.source.LODS=i)}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?(g==="verbose"&&console.debug(`Copy texture settings
1
+ import*as et from"three";import{RedFormat as tt,RedIntegerFormat as rt,RGFormat as st,RGIntegerFormat as ot,RGBFormat as nt,RGBAFormat as it,RGBAIntegerFormat as at,BufferGeometry as V,Mesh as X,Box3 as ne,Vector3 as k,Sphere as ke,CompressedTexture as lt,Texture as I,Matrix3 as ut,InterleavedBuffer as ct,InterleavedBufferAttribute as dt,BufferAttribute as ht,TextureLoader as ft,Color as Pe,Matrix4 as Re}from"three";import{GLTFLoader as de}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as gt}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as mt}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as pt}from"three/examples/jsm/loaders/KTX2Loader.js";const Ce="";globalThis.GLTF_PROGRESSIVE_VERSION=Ce,console.debug("[gltf-progressive] version -");let C="https://www.gstatic.com/draco/versioned/decoders/1.5.7/",H="https://cdn.needle.tools/static/three/0.179.1/basis2/";const xt=C,yt=H,Ae=new URL(C+"draco_decoder.js");Ae.searchParams.append("range","true"),fetch(Ae,{method:"GET",headers:{Range:"bytes=0-1"}}).catch(n=>{console.debug(`Failed to fetch remote Draco decoder from ${C} (offline: ${typeof navigator<"u"?navigator.onLine:"unknown"})`),C===xt&&Ee("./include/draco/"),H===yt&&Ie("./include/ktx2/")}).finally(()=>{$e()});const vt=()=>({dracoDecoderPath:C,ktx2TranscoderPath:H});function Ee(n){C=n,O&&O[fe]!=C?(console.debug("Updating Draco decoder path to "+n),O[fe]=C,O.setDecoderPath(C),O.preload()):console.debug("Setting Draco decoder path to "+n)}function Ie(n){H=n,A&&A.transcoderPath!=H?(console.debug("Updating KTX2 transcoder path to "+n),A.setTranscoderPath(H),A.init()):console.debug("Setting KTX2 transcoder path to "+n)}function ie(n){return $e(),n?A.detectSupport(n):n!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:O,ktx2Loader:A,meshoptDecoder:ae}}function he(n){n.dracoLoader||n.setDRACOLoader(O),n.ktx2Loader||n.setKTX2Loader(A),n.meshoptDecoder||n.setMeshoptDecoder(ae)}const fe=Symbol("dracoDecoderPath");let O,ae,A;function $e(){O||(O=new mt,O[fe]=C,O.setDecoderPath(C),O.setDecoderConfig({type:"js"}),O.preload()),A||(A=new pt,A.setTranscoderPath(H),A.init()),ae||(ae=gt)}const ge=new WeakMap;function me(n,t){let e=ge.get(n);e?e=Object.assign(e,t):e=t,ge.set(n,e)}const wt=de.prototype.load;function Lt(...n){const t=ge.get(this);let e=n[0];const r=bt(e);if(r?.hostname.endsWith("needle.tools")){const s=t?.progressive!==void 0?t.progressive:!0,o=t?.usecase?t.usecase:"default";s?this.requestHeader.Accept=`*/*;progressive=allowed;usecase=${o}`:this.requestHeader.Accept=`*/*;usecase=${o}`,e=r.toString()}return n[0]=e,wt?.call(this,...n)}de.prototype.load=Lt;function bt(n){try{if(n instanceof URL)return n;const t=globalThis.location?.href;return t?new URL(n,t):new URL(n)}catch{return null}}function Be(n){return n!=null&&n.data!=null}function pe(n){const t=n.source?.data;return t!=null&&typeof t=="object"?t:null}function Dt(n){const t=n.image;return t!=null&&typeof t=="object"?t:null}function xe(n){const t=Dt(n),e=pe(n);return{width:t?.width||e?.width||0,height:t?.height||e?.height||0}}W("debugprogressive");function W(n){const t=globalThis.location?.href;if(!t)return!1;const e=new URL(t).searchParams.get(n);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function Mt(n,t){if(t===void 0||n===void 0||t.startsWith("./")||t.startsWith("http")||t.startsWith("data:")||t.startsWith("blob:"))return t;const e=n.lastIndexOf("/");if(e>=0){const r=n.substring(0,e+1);for(;r.endsWith("/")&&t.startsWith("/");)t=t.substring(1);return r+t}return t}function ye(){if(ee!==void 0)return ee;const n=globalThis.navigator?.userAgent||"";return ee=/iPhone|iPad|iPod|Android|IEMobile/i.test(n),W("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",ee),ee}let ee;function Ge(){const n=globalThis.location?.href;if(!n)return!1;const t=new URL(n),e=t.hostname==="localhost"||/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(t.hostname);return t.hostname==="127.0.0.1"||e}class _t{constructor(t,e={}){this.maxConcurrent=t,this.debug=e.debug??!1,typeof globalThis.requestAnimationFrame=="function"?globalThis.requestAnimationFrame(this.tick):setTimeout(this.tick,0)}_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:s}=this._queue.shift();s({use:o=>this.add(r,o)})}}}function Tt(n){const t=n.image,e=t?.width??0,r=t?.height??0,s=t?.depth??1,o=Math.floor(Math.log2(Math.max(e,r,s)))+1,i=St(n);return e*r*s*i*(1-Math.pow(.25,o))/(1-.25)}function St(n){let t=4;const e=n.format;e===tt||e===rt?t=1:e===st||e===ot?t=2:e===nt||e===1029?t=3:(e===it||e===at)&&(t=4);let r=1;const s=n.type;return s===1009||s===1010?r=1:s===1011||s===1012?r=2:s===1013||s===1014||s===1015?r=4:s===1016&&(r=2),t*r}const Ot=typeof window>"u"&&typeof document>"u",ve=Symbol("needle:raycast-mesh");function Y(n){return n?.[ve]instanceof V?n[ve]:null}function qe(n,t){if((n.type==="Mesh"||n.type==="SkinnedMesh")&&!Y(n)){const e=kt(t);e.userData={isRaycastMesh:!0},n[ve]=e}}function We(n=!0){if(n){if(te)return;const t=te=X.prototype.raycast;X.prototype.raycast=function(e,r){const s=this,o=Y(s);let i;o&&s.isMesh&&(i=s.geometry,s.geometry=o),t.call(this,e,r),i&&(s.geometry=i)}}else{if(!te)return;X.prototype.raycast=te,te=null}}let te=null;function kt(n){const t=new V;for(const e in n.attributes)t.setAttribute(e,n.getAttribute(e));return t.setIndex(n.getIndex()),t}const G=new Array,f=W("debugprogressive");let re,K=-1;if(f&&typeof window<"u"){let n=function(){K+=1,K>=t&&(K=-1),console.log(`Toggle LOD level [${K}]`)};const t=6;window.addEventListener("keyup",e=>{e.key==="p"&&n(),e.key==="w"&&(re=!re,console.log(`Toggle wireframe [${re}]`));const r=parseInt(e.key);!isNaN(r)&&r>=0&&(K=r,console.log(`Set LOD level to [${K}]`))})}function Ne(n){if(f&&re!==void 0)if(Array.isArray(n))for(const t of n)Ne(t);else n&&"wireframe"in n&&(n.wireframe=re===!0)}const se=new Array;let Pt=0;const Rt=ye()?2:10;function Ct(n){if(se.length<Rt){const e=se.length;f&&console.warn(`[Worker] Creating new worker #${e}`);const r=Oe.createWorker(n||{});return se.push(r),r}const t=Pt++%se.length;return se[t]}class Oe{constructor(t,e){this.worker=t,this._debug=e.debug??!1,t.onmessage=r=>{const s=r.data;switch(this._debug&&console.log("[Worker] EVENT",s),s.type){case"loaded-gltf":for(const o of this._running)if(o.url===s.result.url){At(s.result),o.resolve(s.result);const i=o.url;i.startsWith("blob:")&&URL.revokeObjectURL(i)}}},t.onerror=r=>{console.error("[Worker] Error in gltf-progressive worker:",r)},t.postMessage({type:"init"})}static async createWorker(t){const e=new Worker(new URL("/assets/gltf-progressive.worker-CCrD-Ycm.js",import.meta.url),{type:"module"});return new Oe(e,t)}_running=[];_webglRenderer=null;async load(t,e){const r=vt();let s=e?.renderer;s||(this._webglRenderer??=(async()=>{const{WebGLRenderer:a}=await import("three");return new a})(),s=await this._webglRenderer);const o=ie(s).ktx2Loader.workerConfig;if(t instanceof URL)t=t.toString();else if(t.startsWith("file:"))t=URL.createObjectURL(new Blob([t]));else if(!t.startsWith("blob:")&&!t.startsWith("http:")&&!t.startsWith("https:")){const a=globalThis.location?.href;a&&(t=new URL(t,a).toString())}const i={type:"load",url:t,dracoDecoderPath:r.dracoDecoderPath,ktx2TranscoderPath:r.ktx2TranscoderPath,ktx2LoaderConfig:o};return this._debug&&console.debug("[Worker] Sending load request",i),this.worker.postMessage(i),new Promise(a=>{this._running.push({url:t.toString(),resolve:a})})}_debug=!1}function At(n){for(const t of n.geometries){const e=t.geometry,r=new V;if(r.name=e.name||"",e.index){const s=e.index;r.setIndex(we(s))}for(const s in e.attributes){const o=e.attributes[s],i=we(o);r.setAttribute(s,i)}if(e.morphAttributes)for(const s in e.morphAttributes){const o=e.morphAttributes[s].map(i=>we(i));r.morphAttributes[s]=o}if(r.morphTargetsRelative=e.morphTargetsRelative??!1,r.boundingBox=new ne,r.boundingBox.min=new k(e.boundingBox?.min.x,e.boundingBox?.min.y,e.boundingBox?.min.z),r.boundingBox.max=new k(e.boundingBox?.max.x,e.boundingBox?.max.y,e.boundingBox?.max.z),r.boundingSphere=new ke(new k(e.boundingSphere?.center.x,e.boundingSphere?.center.y,e.boundingSphere?.center.z),e.boundingSphere?.radius),e.groups)for(const s of e.groups)r.addGroup(s.start,s.count,s.materialIndex);e.userData&&(r.userData=e.userData),t.geometry=r}for(const t of n.textures){const e=t.texture;let r=null;if(e.isCompressedTexture){const s=e.mipmaps,{width:o,height:i}=xe(e);r=new lt(s,o,i,e.format,e.type,e.mapping,e.wrapS,e.wrapT,e.magFilter,e.minFilter,e.anisotropy,e.colorSpace)}else r=new I(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 ut(...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 n}function we(n){let t=n;if("isInterleavedBufferAttribute"in n&&n.isInterleavedBufferAttribute){const e=n.data,r=e.array,s=new ct(r,e.stride);t=new dt(s,n.itemSize,r.byteOffset,n.normalized),t.offset=n.offset}else"isBufferAttribute"in n&&n.isBufferAttribute&&(t=new ht(n.array,n.itemSize,n.normalized),t.usage=n.usage,t.gpuType=n.gpuType,t.updateRanges=n.updateRanges);return t}const Et=W("gltf-progressive-worker");W("gltf-progressive-reduce-mipmaps");const oe=W("gltf-progressive-gc"),Le=Symbol("needle-progressive-texture"),$="NEEDLE_progressive";class g{get name(){return $}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,s="LODS:minmax",o=t[s];if(o!=null)return o;if(e||(e={min_count:1/0,max_count:0,lods:[]}),Array.isArray(t)){for(const a of t)this.getMaterialMinMaxLODsCount(a,e);return t[s]=e,e}if(f==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const a=t;for(const l of Object.keys(a.uniforms)){const u=a.uniforms[l].value;u?.isTexture===!0&&i(u,e)}}else if(t.isMaterial)for(const a of Object.keys(t)){const l=t[a];l?.isTexture===!0&&i(l,e)}else f&&console.warn(`[getMaterialMinMaxLODsCount] Unsupported material type: ${t.type}`);return t[s]=e,e;function i(a,l){const u=r.getAssignedLODInformation(a);if(u){const c=r.lodInfos.get(u.key);if(c&&c.lods){l.min_count=Math.min(l.min_count,c.lods.length),l.max_count=Math.max(l.max_count,c.lods.length);for(let d=0;d<c.lods.length;d++){const p=c.lods[d];p.width&&(l.lods[d]=l.lods[d]||{min_height:1/0,max_height:0},l.lods[d].min_height=Math.min(l.lods[d].min_height,p.height),l.lods[d].max_height=Math.max(l.lods[d].max_height,p.height))}}}}}static hasLODLevelAvailable(t,e){if(Array.isArray(t)){for(const o of t)if(this.hasLODLevelAvailable(o,e))return!0;return!1}if(t.isMaterial===!0){for(const o of Object.keys(t)){const i=t[o];if(i&&i.isTexture&&this.hasLODLevelAvailable(i,e))return!0}return!1}else if(t.isGroup===!0){for(const o of t.children)if(o.isMesh===!0&&this.hasLODLevelAvailable(o,e))return!0}let r,s;if(t.isMesh?r=t.geometry:(t.isBufferGeometry||t.isTexture)&&(r=t),r&&r?.userData?.LODS){const o=r.userData.LODS;if(s=this.lodInfos.get(o.key),e===void 0)return s!=null;if(s)return Array.isArray(s.lods)?e<s.lods.length:e===0}return!1}static assignMeshLOD(t,e,r){if(!t)return Promise.resolve(null);if(t instanceof X||t.isMesh===!0){const s=t.geometry,o=this.getAssignedLODInformation(s);if(!o)return Promise.resolve(null);for(const a of G)a.onBeforeGetLODMesh?.(t,e);t["LOD:requested level"]=e;const i=()=>t["LOD:requested level"]===e||this.shouldApplyStaleMeshLOD(t,e);return g.getOrLoadLOD(s,e,{isCurrent:i}).then(a=>{if(Array.isArray(a)){const u=o.index||0;a=a[u]}const l=t["LOD:requested level"]===e;return(l||this.shouldApplyStaleMeshLOD(t,e))&&(l&&delete t["LOD:requested level"],a&&s!=a&&(a?.isBufferGeometry?typeof r?.apply=="function"?r.apply(a,e,t):r?.apply!==!1&&(t.geometry=a):f&&console.error("Invalid LOD geometry",a))),a}).catch(a=>(console.error("Error loading mesh LOD",t,a),null))}else f&&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,r){if(!t)return Promise.resolve(null);const s=r?.force===!0;if(t.isMesh===!0){const o=t;if(Array.isArray(o.material)){const i=new Array;for(const a of o.material){const l=this.assignTextureLOD(a,e,r);i.push(l)}return Promise.all(i).then(a=>{const l=new Array;for(const u of a)Array.isArray(u)&&l.push(...u);return l})}else return this.assignTextureLOD(o.material,e,r)}if(t.isMaterial===!0){const o=t,i=[],a=new Array;if(this.trackCurrentMaterialTextureSlots(o),o.uniforms&&(o.isRawShaderMaterial||o.isShaderMaterial===!0)){const l=o;for(const u of Object.keys(l.uniforms)){const c=l.uniforms[u].value;if(c?.isTexture===!0){const d=this.assignTextureLODForSlot(c,e,o,u,s).then(p=>(p&&l.uniforms[u].value!=p&&(l.uniforms[u].value=p,l.uniformsNeedUpdate=!0),p));i.push(d),a.push(u)}}}else for(const l of Object.keys(o)){const u=o[l];if(u?.isTexture===!0){const c=this.assignTextureLODForSlot(u,e,o,l,s);i.push(c),a.push(l)}}return Promise.all(i).then(l=>{const u=new Array;for(let c=0;c<l.length;c++){const d=l[c],p=a[c];d&&d.isTexture===!0?u.push({material:o,slot:p,texture:d,level:e}):u.push({material:o,slot:p,texture:null,level:e})}return u})}if(t instanceof I||t.isTexture===!0){const o=t;return this.assignTextureLODForSlot(o,e,null,null,s)}return Promise.resolve(null)}static set maxConcurrentLoadingTasks(t){g.queue.maxConcurrent=t}static get maxConcurrentLoadingTasks(){return g.queue.maxConcurrent}static assignTextureLODForSlot(t,e,r,s,o){if(t?.isTexture!==!0)return Promise.resolve(null);if(s==="glyphMap")return Promise.resolve(t);const i=this.getAssignedLODInformation(t);if(i&&(i.level===e||!o&&i.level<e))return Promise.resolve(t);if(r&&s){const d=this.getPendingTextureSlotRequest(r,s);if(d&&d.level===e&&d.force===o)return d.promise}const a=r&&s?this.nextTextureSlotRequestId(r,s,e,o):0,l=()=>!r||!s||this.getLatestTextureSlotRequest(r,s)?.id===a,u=()=>l()||this.shouldApplyStaleTextureSlotLOD(r,s,e,o),c=g.getOrLoadLOD(t,e,{isCurrent:u}).then(d=>{if(!l()&&!this.shouldApplyStaleTextureSlotLOD(r,s,e,o))return null;if(Array.isArray(d))return console.warn("Progressive: Got an array of textures for a texture slot, this should not happen..."),null;if(d?.isTexture===!0){if(d!=t&&r&&s){const p=this.getMaterialTextureSlot(r,s)??t;if(p&&!o){const m=this.getAssignedLODInformation(p);if(m&&m?.level<e)return f==="verbose"&&console.warn("Assigned texture level is already higher: ",m.level,e,r,p,d),null}this.assignTrackedTextureSlot(r,s,d)}return d}else f=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(d=>(console.error("Error loading LOD",t,d),null));return r&&s&&this.setPendingTextureSlotRequest(r,s,e,o,a,c),c}static trackedTextureSlots=new WeakMap;static pendingTextureSlotRequests=new WeakMap;static latestTextureSlotRequests=new WeakMap;static textureSlotRequestId=0;static trackCurrentMaterialTextureSlots(t){if(t.uniforms&&(t.isRawShaderMaterial||t.isShaderMaterial===!0)){const e=t;for(const r of Object.keys(e.uniforms)){const s=e.uniforms[r].value;s?.isTexture===!0&&this.ensureTrackedTextureSlot(t,r,s)}return}for(const e of Object.keys(t)){const r=t[e];r?.isTexture===!0&&this.ensureTrackedTextureSlot(t,e,r)}}static getPendingTextureSlotRequest(t,e){return this.pendingTextureSlotRequests.get(t)?.get(e)}static nextTextureSlotRequestId(t,e,r,s){let o=this.latestTextureSlotRequests.get(t);o||(o=new Map,this.latestTextureSlotRequests.set(t,o));const i=++this.textureSlotRequestId;return o.set(e,{id:i,level:r,force:s}),i}static getLatestTextureSlotRequest(t,e){return this.latestTextureSlotRequests.get(t)?.get(e)}static shouldApplyStaleTextureSlotLOD(t,e,r,s){if(!t||!e)return!1;const o=this.getLatestTextureSlotRequest(t,e),i=this.getMaterialTextureSlot(t,e),a=this.getAssignedLODInformation(i)?.level??1/0;return r>=a?!1:s?o?r>=o.level:!1:!0}static shouldApplyStaleMeshLOD(t,e){const r=t["LOD:requested level"];if(typeof r!="number")return!1;const s=this.getAssignedLODInformation(t.geometry)?.level??1/0;return e<s&&e>=r}static setPendingTextureSlotRequest(t,e,r,s,o,i){let a=this.pendingTextureSlotRequests.get(t);a||(a=new Map,this.pendingTextureSlotRequests.set(t,a));const l={level:r,force:s,id:o,promise:i};a.set(e,l),i.finally(()=>{a.get(e)?.id===o&&a.delete(e)})}static getMaterialTextureSlot(t,e){const r=t.uniforms?.[e];if(r?.value?.isTexture===!0)return r.value;const s=t[e];return s?.isTexture===!0?s:null}static setMaterialTextureSlot(t,e,r){const s=t.uniforms?.[e];if(s?.value?.isTexture===!0){s.value=r,t.uniformsNeedUpdate=!0;return}t[e]=r}static assignTrackedTextureSlot(t,e,r){let s=this.trackedTextureSlots.get(t);s||(s=new Map,this.trackedTextureSlots.set(t,s));const o=this.getMaterialTextureSlot(t,e);let i=s.get(e);!i&&o?i=this.ensureTrackedTextureSlot(t,e,o):i&&o&&i!==o&&(this.releaseTrackedTextureSlot(t,e,i),i=this.ensureTrackedTextureSlot(t,e,o)),!(i===r&&o===r)&&(i&&i!==r&&this.releaseTrackedTextureSlot(t,e,i),i!==r&&(this.trackTextureUsage(r),s.set(e,r)),o!==r&&this.setMaterialTextureSlot(t,e,r))}static ensureTrackedTextureSlot(t,e,r){let s=this.trackedTextureSlots.get(t);s||(s=new Map,this.trackedTextureSlots.set(t,s));const o=s.get(e);return o===r?o:(o&&this.releaseTrackedTextureSlot(t,e,o),this.trackTextureUsage(r),s.set(e,r),r)}static releaseTrackedTextureSlot(t,e,r){const s=this.trackedTextureSlots.get(t);if(s?.get(e)===r&&s.delete(e),this.untrackTextureUsage(r)&&(f||oe)){const o=this.getAssignedLODInformation(r);console.log(`[gltf-progressive] Disposed old texture LOD ${o?.level??"?"} for ${t.name||t.type}.${e}`,r.uuid)}}parser;url;constructor(t){const e=t.options.path;f&&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?.[$];return e?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",t).then(r=>(this._isLoadingMesh=!1,r&&g.registerMesh(this.url,e.guid,r,e.lods?.length,0,e),r))):null};afterRoot(t){return f&&console.log("AFTER",this.url,t),this.parser.json.textures?.forEach((e,r)=>{if(e?.extensions){const s=e?.extensions[$];if(s){if(!s.lods){f&&console.warn("Texture has no LODs",s);return}let o=!1;for(const i of this.parser.associations.keys())i.isTexture===!0&&this.parser.associations.get(i)?.textures===r&&(o=!0,g.registerTexture(this.url,i,s.lods?.length,r,s));o||this.parser.getDependency("texture",r).then(i=>{i&&g.registerTexture(this.url,i,s.lods?.length,r,s)})}}}),this.parser.json.meshes?.forEach((e,r)=>{if(e?.extensions){const s=e?.extensions[$];if(s&&s.lods){for(const o of this.parser.associations.keys())if(o.isMesh){const i=this.parser.associations.get(o);i?.meshes===r&&g.registerMesh(this.url,s.guid,o,s.lods.length,i.primitives,s)}}}}),null}static registerTexture=(t,e,r,s,o)=>{if(!e){f&&console.error("!! gltf-progressive: Called register texture without texture");return}if(f){const{width:a,height:l}=xe(e);console.log(`> gltf-progressive: register texture[${s}] "${e.name||e.uuid}", Current: ${a}x${l}, Max: ${o.lods[0]?.width}x${o.lods[0]?.height}, uuid: ${e.uuid}`,o,e)}e.source&&(e.source[Le]=o);const i=o.guid;g.assignLODInformation(t,e,i,r,s),g.lodInfos.set(i,o),g.lowresCache.set(i,new WeakRef(e))};static registerMesh=(t,e,r,s,o,i)=>{const a=r.geometry;if(!a){f&&console.warn("gltf-progressive: Register mesh without geometry");return}a.userData||(a.userData={}),f&&console.log("> Progressive: register mesh "+r.name,{index:o,uuid:r.uuid},i,r),g.assignLODInformation(t,a,e,s,o),g.lodInfos.set(e,i);let l=g.lowresCache.get(e)?.deref();l?l.push(r.geometry):l=[r.geometry],g.lowresCache.set(e,new WeakRef(l)),s>0&&!Y(r)&&qe(r,a);for(const u of G)u.onRegisteredNewMesh?.(r,i)};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 s=r;this.textureRefCounts.delete(s.uuid),s.dispose()}else if(Array.isArray(r))for(const s of r)s.dispose()}this.lowresCache.delete(t)}for(const[r,s]of this.cache)r.includes(t)&&(this._disposeCacheEntry(s),this.cache.delete(r))}else{this.lodInfos.clear();for(const[,e]of this.lowresCache){const r=e.deref();if(r){if(r.isTexture){const s=r;this.textureRefCounts.delete(s.uuid),s.dispose()}else if(Array.isArray(r))for(const s of r)s.dispose()}}this.lowresCache.clear();for(const[,e]of this.cache)this._disposeCacheEntry(e);this.cache.clear(),this.textureRefCounts.clear(),this.trackedTextureSlots=new WeakMap,this.pendingTextureSlotRequests=new WeakMap,this.latestTextureSlotRequests=new WeakMap,this.textureSlotRequestId=0}}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=g.cache.get(t);(f||oe)&&console.debug(`[gltf-progressive] Memory: Resource GC'd
2
+ ${t}`),e instanceof WeakRef&&(e.deref()||(g.cache.delete(t),(f||oe)&&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),f==="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(f==="verbose"||oe)&&o("[gltf-progressive] Memory: Untrack untracked texture (dispose immediately)",0),t.dispose(),!0;const s=r-1;if(s<=0)return this.textureRefCounts.delete(e),(f||oe)&&o("[gltf-progressive] Memory: Dispose texture",s),t.dispose(),!0;return this.textureRefCounts.set(e,s),f==="verbose"&&o("[gltf-progressive] Memory: Untrack texture",s),!1;function o(i,a){let{width:l,height:u}=xe(t);const c=l&&u?`${l}x${u}`:"N/A";let d="N/A";l&&u&&(d=`~${(Tt(t)/(1024*1024)).toFixed(2)} MB`),console.log(`${i} \u2014 ${t.name} ${c} (${d}), refCount: ${r} \u2192 ${a}
3
+ ${e}`)}}static workers=[];static _workersIndex=0;static async getOrLoadLOD(t,e,r){const s=f=="verbose",o=this.getAssignedLODInformation(t);if(!o)return f&&console.warn(`[gltf-progressive] No LOD information found: ${t.name}, uuid: ${t.uuid}, type: ${t.type}`,t),null;const i=o?.key;let a;if(t.isTexture===!0){const l=t;l.source&&l.source[Le]&&(a=l.source[Le])}if(a||(a=g.lodInfos.get(i)),!a)f&&console.warn(`Can not load LOD ${e}: no LOD info found for "${i}" ${t.name}`,t.type,g.lodInfos);else{if(e>0){let c=!1;const d=Array.isArray(a.lods);if(d&&e>=a.lods.length?c=!0:d||(c=!0),c){const p=this.lowresCache.get(i);if(p){const m=p.deref();if(m)return m;this.lowresCache.delete(i),f&&console.log(`[gltf-progressive] Lowres cache entry was GC'd: ${i}`)}return null}}const l=Array.isArray(a.lods)?a.lods[e]?.path:a.lods;if(!l)return f&&!a["missing:uri"]&&(a["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,a)),null;const u=Mt(o.url,l);if(u.endsWith(".glb")||u.endsWith(".gltf")){if(!a.guid)return console.warn("missing pointer for glb/gltf texture",a),null;const c=u+"_"+a.guid,d=await this.tryResolveLODCacheEntry(this.cache.get(c),c,u,t,e,s);if(d.found)return d.value;if(r?.isCurrent?.()===!1)return s&&console.log(`Skipping stale LOD ${e} request before queue: ${u}`),null;const p=await this.queue.slot(u);if(r?.isCurrent?.()===!1)return s&&console.log(`Skipping stale LOD ${e} request after queue: ${u}`),null;const m=await this.tryResolveLODCacheEntry(this.cache.get(c),c,u,t,e,s);if(m.found)return m.value;if(!p.use)return f&&console.log(`LOD ${e} was aborted: ${u}`),null;const w=a,h=new Promise(async(M,j)=>{if(Et){const b=await(await Ct({})).load(u);if(b.textures.length>0)for(const x of b.textures){let v=x.texture;return g.assignLODInformation(o.url,v,i,e,void 0),t instanceof I&&(v=this.copySettings(t,v)),v&&(v.guid=w.guid),M(v)}if(b.geometries.length>0){const x=new Array;for(const v of b.geometries){const R=v.geometry;g.assignLODInformation(o.url,R,i,e,v.primitiveIndex),x.push(R)}return M(x)}return M(null)}const B=new de;he(B),f&&(await new Promise(b=>setTimeout(b,1e3)),s&&console.warn("Start loading (delayed) "+u,w.guid));let L=u;if(w&&Array.isArray(w.lods)){const b=w.lods[e];b.hash&&(L+="?v="+b.hash)}const y=await B.loadAsync(L).catch(b=>(console.error(`Error loading LOD ${e} from ${u}
4
+ `,b),M(null)));if(!y)return M(null);const T=y.parser;s&&console.log("Loading finished "+u,w.guid);let S=0;if(y.parser.json.textures){let b=!1;for(const x of y.parser.json.textures){if(x?.extensions){const v=x?.extensions[$];if(v?.guid&&v.guid===w.guid){b=!0;break}}S++}if(b){let x=await T.getDependency("texture",S);return x&&g.assignLODInformation(o.url,x,i,e,void 0),s&&console.log('change "'+t.name+'" \u2192 "'+x.name+'"',u,S,x,c),t instanceof I&&(x=this.copySettings(t,x)),x&&(x.guid=w.guid),M(x)}else f&&console.warn("Could not find texture with guid",w.guid,y.parser.json)}if(S=0,y.parser.json.meshes){let b=!1;for(const x of y.parser.json.meshes){if(x?.extensions){const v=x?.extensions[$];if(v?.guid&&v.guid===w.guid){b=!0;break}}S++}if(b){const x=await T.getDependency("mesh",S);if(s&&console.log(`Loaded Mesh "${x.name}"`,u,S,x,c),x.isMesh===!0){const v=x.geometry;return g.assignLODInformation(o.url,v,i,e,0),M(v)}else{const v=new Array;for(let R=0;R<x.children.length;R++){const F=x.children[R];if(F.isMesh===!0){const z=F.geometry;g.assignLODInformation(o.url,z,i,e,R),v.push(z)}}return M(v)}}else f&&console.warn("Could not find mesh with guid",w.guid,y.parser.json)}return M(null)});this.cache.set(c,h),p.use(h);const D=await h;return D!=null?D instanceof I?(this.cache.set(c,new WeakRef(D)),g._resourceRegistry.register(D,c)):Array.isArray(D)?this.cache.set(c,Promise.resolve(D)):this.cache.set(c,Promise.resolve(D)):this.cache.set(c,Promise.resolve(null)),D}else if(t instanceof I){if(r?.isCurrent?.()===!1)return s&&console.log(`Skipping stale texture LOD ${e} request: ${u}`),null;s&&console.log("Load texture from uri: "+u);const c=await new ft().loadAsync(u);return r?.isCurrent?.()===!1?(c?.dispose(),null):(c?(c.guid=a.guid,c.flipY=!1,c.needsUpdate=!0,c.colorSpace=t.colorSpace,s&&console.log(a,c)):f&&console.warn("failed loading",u),c)}}return null}static async tryResolveLODCacheEntry(t,e,r,s,o,i){if(t===void 0)return{found:!1};if(i&&console.log(`LOD ${o} was already loading/loaded: ${e}`),t instanceof WeakRef){const u=t.deref();if(u){let c=u,d=!1;if(c instanceof I&&s instanceof I?Be(c.image)||pe(c)?c=this.copySettings(s,c):d=!0:c instanceof V&&s instanceof V&&(c.attributes.position?.array||(d=!0)),!d)return{found:!0,value:c}}return this.cache.delete(e),f&&console.log(`[gltf-progressive] Re-loading GC'd/disposed resource: ${e}`),{found:!1}}let a=await t.catch(u=>(console.error(`Error loading LOD ${o} from ${r}
5
+ `,u),null)),l=!1;return a==null||(a instanceof I&&s instanceof I?Be(a.image)||pe(a)?a=this.copySettings(s,a):(l=!0,this.cache.delete(e)):a instanceof V&&s instanceof V&&(a.attributes.position?.array||(l=!0,this.cache.delete(e)))),l?{found:!1}:{found:!0,value:a}}static _queue;static get queue(){return this._queue??=new _t(ye()?20:50,{debug:f!=!1})}static assignLODInformation(t,e,r,s,o){if(!e)return;e.userData||(e.userData={});const i=new It(t,r,s,o);e.userData.LODS=i,"source"in e&&typeof e.source=="object"&&(e.source.LODS=i)}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?(f==="verbose"&&console.debug(`Copy texture settings
6
6
  `,t.uuid,`
7
- `,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 It{url;key;level;index;constructor(t,e,r,s){this.url=t,this.key=e,this.level=r,s!=null&&(this.index=s)}}class le{static addPromise=(t,e,r,s)=>{s.forEach(o=>{o.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(s=>{this._resolve=s}),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){g&&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)){const s=this._seen.get(e);if(s>=this._maxPromisesPerObject){g&&console.warn("PromiseGroup: Already awaiting object ignoring new promise for it.");return}this._seen.set(e,s+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=W("debugprogressive"),$t=E==="colors",Bt=W("noprogressive"),be=Symbol("Needle:LODSManager"),De=Symbol("Needle:LODState"),N=Symbol("Needle:CurrentLOD"),Ue=et,_={mesh_lod:-1,texture_lod:-1},Gt=new Pe,Me=[3526751,11065402,15978811,15897394,15749691,11032304,4827122,3332036,16739229,7306743,14053330,3516499,12035359,14703919,3963096,42662,14100029,8344319,4633680,16229681,3120096,12076434,9083434,2060171,15751837,10182117,48121,62932,16704576,15817653,5083278,5592405];function qt(){const n=Ue.Timer||Ue.Clock;return new n}const _e=new ne,U=new ne,je=new ne,Wt=new k,Nt=new k,Ut=new Re,q=new k,Q=new k,J=new k,Z=new k;function jt(n,t){const e=n.min,r=n.max,s=(e.x+r.x)*.5,o=(e.y+r.y)*.5;return q.set(s,o,e.z).applyMatrix4(t).z<0}function Fe(n){const{geometry:t,matrixWorld:e,camera:r,projectionScreenMatrix:s,desiredDensity:o,canvasHeight:i=0,currentLevel:a=-1,xrEnabled:l=!1,debugDrawLine:u,warnMissingPrimitiveDensities:c=!1}=n,d=f.getMeshLODExtension(t)?.lods,p=f.getPrimitiveIndex(t),m=n.target??{level:a,primitiveIndex:p,screenCoverage:0,screenspaceVolume:new k,centrality:1};if(m.level=a,m.primitiveIndex=p,m.screenCoverage=0,m.screenspaceVolume.set(0,0,0),m.centrality=1,!d?.length)return m;let w=n.boundingBox??t.boundingBox;if(w||(t.computeBoundingBox(),w=t.boundingBox),!w)return m;if(_e.copy(w).applyMatrix4(e),r.isPerspectiveCamera&&jt(_e,s))return m.level=0,m.screenCoverage=1/0,m.screenspaceVolume.set(1/0,1/0,1/0),m;if(U.copy(_e).applyMatrix4(s),l&&r.isPerspectiveCamera&&r.fov>70){const L=U.min,y=U.max;let T=L.x,S=L.y,b=y.x,x=y.y;const v=2,R=1.5,F=(L.x+y.x)*.5,z=(L.y+y.y)*.5;T=(T-F)*v+F,S=(S-z)*v+z,b=(b-F)*v+F,x=(x-z)*v+z;const Je=T<0&&b>0?0:Math.min(Math.abs(L.x),Math.abs(y.x)),Ze=S<0&&x>0?0:Math.min(Math.abs(L.y),Math.abs(y.y)),ce=Math.max(Je,Ze);m.centrality=(R-ce)*(R-ce)*(R-ce)}const h=U.getSize(Wt);h.multiplyScalar(.5),globalThis.screen?.availHeight>0&&i>0&&h.multiplyScalar(i/globalThis.screen.availHeight),r.isPerspectiveCamera&&(h.x*=r.aspect),je.copy(w).applyMatrix4(e).applyMatrix4(r.matrixWorldInverse);const D=je.getSize(Nt),M=Math.max(h.x,h.y),j=Math.max(D.x,D.y);M!==0&&j!==0&&(h.z=D.z/j*M);const B=Math.max(h.x,h.y,h.z)*m.centrality;if(m.screenCoverage=B,m.screenspaceVolume.copy(h),B<=0)return m;if(u){const L=Ut.copy(s);L.invert(),q.copy(U.min),Q.copy(U.max),Q.x=q.x,J.copy(U.max),J.y=q.y,Z.copy(U.max);const y=(q.z+Z.z)*.5;q.z=Q.z=J.z=Z.z=y,q.applyMatrix4(L),Q.applyMatrix4(L),J.applyMatrix4(L),Z.applyMatrix4(L),u(q,Q,255),u(q,J,255),u(Q,Z,255),u(J,Z,255)}for(let L=0;L<d.length;L++){const y=d[L],T=y.densities?.[p]||y.density||1e-5;if(p>0&&c&&Ge()&&!y.densities&&!globalThis["NEEDLE:MISSING_LOD_PRIMITIVE_DENSITIES"]&&(globalThis["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.")),T/B<o){m.level=L;break}}return m}class P{static debugDrawLine;static getObjectLODState(t){return t[De]}static addPlugin(t){G.push(t)}static removePlugin(t){const e=G.indexOf(t);e>=0&&G.splice(e,1)}static getPlugins(){return G}static get(t,e){if(t[be])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[be];const r=new P(t,{engine:"unknown",...e});return t[be]=r,r}renderer;context;projectionScreenMatrix=new Re;get plugins(){return G}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 le(this.#s,{...t});this._newPromiseGroups.push(r);const s=performance.now();return r.ready.finally(()=>{const o=this._newPromiseGroups.indexOf(r);o>=0&&(this._newPromiseGroups.splice(o,1),Ge()&&performance.measure("LODsManager:awaitLoading",{start:s,detail:{id:e,name:t?.name,awaited:r.awaitedCount,resolved:r.resolvedCount}}))}),r.ready}trackLoadingPromise(t,e,r){return le.addPromise(t,e,r,this._newPromiseGroups),r}_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){return t==="changed"?(this._lodchangedlisteners.push(e),()=>{this.removeEventListener(t,e)}):()=>{}}removeEventListener(t,e){let r=!1;if(t==="changed"){const s=this._lodchangedlisteners.indexOf(e);s>=0&&(this._lodchangedlisteners.splice(s,1),r=!0)}return r}constructor(t,e){this.renderer=t,this.context={...e}}#t;#s=0;#o=0;#i=0;#r=0;#n=qt();_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;ie(this.renderer),this.renderer.render=function(r,s){const o=e.renderer.getRenderTarget();(o==null||"isXRRenderTarget"in o&&o.isXRRenderTarget)&&(t=0,e.#s+=1,e.#n.update?.(),e.#o=Math.max(e.#n.getDelta(),1/1e3),e.#i+=e.#o,e._fpsBuffer.shift(),e._fpsBuffer.push(1/e.#o),e.#r=e._fpsBuffer.reduce((a,l)=>a+l)/e._fpsBuffer.length,E&&e.#s%200===0&&console.log("FPS",Math.round(e.#r),"Interval:",e.#e));const i=t++;e.#t.call(this,r,s),e.onAfterRender(r,s,i)}}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 s=this.getRenderList(t,e,r);if(!s)return;const o=s.opaque;let i=!0;if(o.length===1){const a=o[0].material;(a.name==="EffectMaterial"||a.name==="CopyShader")&&(i=!1)}if((e.parent&&e.parent.type==="CubeCamera"||r>=1&&e.type==="OrthographicCamera")&&(i=!1),i){if(Bt||(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.getRenderList(t,e,0);if(!r)return;const s=r.opaque;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse);const o=this.targetTriangleDensity;for(const l of s){if(l.material&&(l.geometry?.type==="BoxGeometry"||l.geometry?.type==="BufferGeometry")&&(l.material.name==="SphericalGaussianBlur"||l.material.name=="BackgroundCubeMaterial"||l.material.name==="CubemapFromEquirect"||l.material.name==="EquirectangularToCubeUV")){E&&(l.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(l.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",l,l.material.name,l.material.type)));continue}switch(l.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}const u=l.object;(u instanceof X||u.isMesh)&&this.updateLODs(t,e,u,o)}const i=r.transparent;for(const l of i){const u=l.object;(u instanceof X||u.isMesh)&&this.updateLODs(t,e,u,o)}const a=r.transmissive;for(const l of a){const u=l.object;(u instanceof X||u.isMesh)&&this.updateLODs(t,e,u,o)}}getRenderList(t,e,r){const s=this.renderer;let o=null;if(s.isWebGPURenderer===!0){const i=s._renderLists;if(!i)return null;o=i.get(t,e)}else if(s.isWebGLRenderer===!0){const i=s.renderLists;if(!i)return null;o=i.get(t,r)}return o?{opaque:o.opaque||[],transparent:o.transparent||[],transmissive:o.transmissive||o.transparentDoublePass||[],transparentDoublePass:o.transparentDoublePass||[]}:null}updateLODs(t,e,r,s){r.userData||(r.userData={});let o=r[De];if(o||(o=new Ft,r[De]=o),o.frames++<2)return;for(const a of G)a.onBeforeUpdateLOD?.(this.renderer,t,e,r);const i=this.overrideLodLevel!==void 0?this.overrideLodLevel:K;i>=0?(_.mesh_lod=i,_.texture_lod=i):(this.calculateLodLevel(e,r,o,s,_),_.mesh_lod=Math.round(_.mesh_lod),_.texture_lod=Math.round(_.texture_lod)),_.mesh_lod>=0&&this.loadProgressiveMeshes(r,_.mesh_lod),r.material&&_.texture_lod>=0&&this.loadProgressiveTextures(r.material,_.texture_lod,i),g&&r.material&&!r.isGizmo&&Ne(r.material),$t&&r.material&&!r.isGizmo&&!r.isBatchedMesh&&ze(r.material,_.mesh_lod);for(const a of G)a.onAfterUpdatedLOD?.(this.renderer,t,e,r,_);o.lastLodLevel_Mesh=_.mesh_lod,o.lastLodLevel_Texture=_.texture_lod}loadProgressiveTextures(t,e,r){if(!t)return;if(Array.isArray(t)){for(const i of t)this.loadProgressiveTextures(i,e,r);return}let s=!1;(t[N]===void 0||e<t[N])&&(s=!0);const o=r!==void 0&&r>=0;if(o&&(s=t[N]!=r,e=r),s){t[N]=e;const i=o?{force:!0}:void 0,a=f.assignTextureLOD(t,e,i).then(l=>{this._lodchangedlisteners.forEach(u=>u({type:"texture",level:e,object:t}))});le.addPromise("texture",t,a,this._newPromiseGroups)}}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);let r=t[N]!==e;const s=t["DEBUG:LOD"];if(s!=null&&(r=t[N]!=s,e=s),r){t[N]=e;const o=t.geometry,i=f.assignMeshLOD(t,e).then(a=>(a&&t[N]==e&&o!=t.geometry&&this._lodchangedlisteners.forEach(l=>l({type:"mesh",level:e,object:t})),a));return le.addPromise("mesh",t,i,this._newPromiseGroups),i}return Promise.resolve(null)}_sphere=new ke;_tempWorldPosition=new k;static skinnedMeshBoundsFrameOffsetCounter=0;static $skinnedMeshBoundsOffset=Symbol("gltf-progressive-skinnedMeshBoundsOffset");calculateLodLevel(t,e,r,s,o){if(!e){o.mesh_lod=-1,o.texture_lod=-1;return}if(!t){o.mesh_lod=-1,o.texture_lod=-1;return}let i=11,a=!1;if(E&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const l=f.getMeshLODExtension(e.geometry)?.lods,u=f.getPrimitiveIndex(e.geometry),c=l&&l.length>0,d=f.getMaterialMinMaxLODsCount(e.material),p=d.min_count!==1/0&&d.min_count>=0&&d.max_count>=0;if(!c&&!p){o.mesh_lod=0,o.texture_lod=0;return}c||(a=!0,i=0);const m=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let w=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const h=e;if(!h.boundingBox)h.computeBoundingBox();else if(this.skinnedMeshAutoUpdateBoundsInterval>0){if(!h[P.$skinnedMeshBoundsOffset]){const M=P.skinnedMeshBoundsFrameOffsetCounter++;h[P.$skinnedMeshBoundsOffset]=M}const D=h[P.$skinnedMeshBoundsOffset];if((r.frames+D)%this.skinnedMeshAutoUpdateBoundsInterval===0){const M=Y(h),j=h.geometry;M&&(h.geometry=M),h.computeBoundingBox(),h.geometry=j}}w=h.boundingBox}if(w){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=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(D)){o.mesh_lod=0,o.texture_lod=0;return}}const h=Fe({geometry:e.geometry,matrixWorld:e.matrixWorld,camera:t,projectionScreenMatrix:this.projectionScreenMatrix,desiredDensity:s,canvasHeight:m,currentLevel:r.lastLodLevel_Mesh,boundingBox:w,xrEnabled:this.renderer.xr.enabled,debugDrawLine:E?P.debugDrawLine:void 0,warnMissingPrimitiveDensities:!0});if(r.lastCentrality=h.centrality,r.lastScreenCoverage=h.screenCoverage,r.lastScreenspaceVolume.copy(h.screenspaceVolume),h.screenCoverage===1/0){o.mesh_lod=0,o.texture_lod=0;return}h.level>=0&&h.level<i&&(i=h.level,a=!0)}if(a?o.mesh_lod=i:o.mesh_lod=r.lastLodLevel_Mesh,E&&o.mesh_lod!=r.lastLodLevel_Mesh){const h=l?.[o.mesh_lod];h&&console.log(`Mesh LOD changed: ${r.lastLodLevel_Mesh} \u2192 ${o.mesh_lod} (density: ${h.densities?.[u].toFixed(0)}) | ${e.name}`)}if(p){const h="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(r.lastLodLevel_Texture<0){if(o.texture_lod=d.max_count-1,E){const D=d.lods[d.max_count-1];E&&console.log(`First Texture LOD ${o.texture_lod} (${D.max_height}px) - ${e.name}`)}}else{const D=r.lastScreenspaceVolume.x+r.lastScreenspaceVolume.y+r.lastScreenspaceVolume.z;let M=r.lastScreenCoverage*4;this.context?.engine==="model-viewer"&&(M*=1.5);const j=this.renderer.getPixelRatio?.()||globalThis.devicePixelRatio||1,B=m/j*M;let L=!1;for(let y=d.lods.length-1;y>=0;y--){const T=d.lods[y];if(!(h&&T.max_height>=2048)&&!(ye()&&T.max_height>4096)&&(T.max_height>B||!L&&y===0)){if(L=!0,o.texture_lod=y,E&&o.texture_lod<r.lastLodLevel_Texture){const S=T.max_height;console.log(`Texture LOD changed: ${r.lastLodLevel_Texture} \u2192 ${o.texture_lod} = ${S}px
7
+ `,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 It{url;key;level;index;constructor(t,e,r,s){this.url=t,this.key=e,this.level=r,s!=null&&(this.index=s)}}class le{static addPromise=(t,e,r,s)=>{s.forEach(o=>{o.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(s=>{this._resolve=s}),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){f&&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)){const s=this._seen.get(e);if(s>=this._maxPromisesPerObject){f&&console.warn("PromiseGroup: Already awaiting object ignoring new promise for it.");return}this._seen.set(e,s+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=W("debugprogressive"),$t=E==="colors",Bt=W("noprogressive"),be=Symbol("Needle:LODSManager"),De=Symbol("Needle:LODState"),N=Symbol("Needle:CurrentLOD"),Ue=et,_={mesh_lod:-1,texture_lod:-1},Gt=new Pe,Me=[3526751,11065402,15978811,15897394,15749691,11032304,4827122,3332036,16739229,7306743,14053330,3516499,12035359,14703919,3963096,42662,14100029,8344319,4633680,16229681,3120096,12076434,9083434,2060171,15751837,10182117,48121,62932,16704576,15817653,5083278,5592405];function qt(){const n=Ue.Timer||Ue.Clock;return new n}const _e=new ne,U=new ne,je=new ne,Wt=new k,Nt=new k,Ut=new Re,q=new k,Q=new k,J=new k,Z=new k;function jt(n,t){const e=n.min,r=n.max,s=(e.x+r.x)*.5,o=(e.y+r.y)*.5;return q.set(s,o,e.z).applyMatrix4(t).z<0}function Fe(n){const{geometry:t,matrixWorld:e,camera:r,projectionScreenMatrix:s,desiredDensity:o,canvasHeight:i=0,currentLevel:a=-1,xrEnabled:l=!1,debugDrawLine:u,warnMissingPrimitiveDensities:c=!1}=n,d=g.getMeshLODExtension(t)?.lods,p=g.getPrimitiveIndex(t),m=n.target??{level:a,primitiveIndex:p,screenCoverage:0,screenspaceVolume:new k,centrality:1};m.level=a,m.primitiveIndex=p,m.screenCoverage=0,m.screenspaceVolume.set(0,0,0),m.centrality=1;let w=n.boundingBox??t.boundingBox;if(w||(t.computeBoundingBox(),w=t.boundingBox),!w)return m;if(_e.copy(w).applyMatrix4(e),r.isPerspectiveCamera&&jt(_e,s))return m.level=0,m.screenCoverage=1/0,m.screenspaceVolume.set(1/0,1/0,1/0),m;if(U.copy(_e).applyMatrix4(s),l&&r.isPerspectiveCamera&&r.fov>70){const L=U.min,y=U.max;let T=L.x,S=L.y,b=y.x,x=y.y;const v=2,R=1.5,F=(L.x+y.x)*.5,z=(L.y+y.y)*.5;T=(T-F)*v+F,S=(S-z)*v+z,b=(b-F)*v+F,x=(x-z)*v+z;const Je=T<0&&b>0?0:Math.min(Math.abs(L.x),Math.abs(y.x)),Ze=S<0&&x>0?0:Math.min(Math.abs(L.y),Math.abs(y.y)),ce=Math.max(Je,Ze);m.centrality=(R-ce)*(R-ce)*(R-ce)}const h=U.getSize(Wt);h.multiplyScalar(.5),globalThis.screen?.availHeight>0&&i>0&&h.multiplyScalar(i/globalThis.screen.availHeight),r.isPerspectiveCamera&&(h.x*=r.aspect),je.copy(w).applyMatrix4(e).applyMatrix4(r.matrixWorldInverse);const D=je.getSize(Nt),M=Math.max(h.x,h.y),j=Math.max(D.x,D.y);M!==0&&j!==0&&(h.z=D.z/j*M);const B=Math.max(h.x,h.y,h.z)*m.centrality;if(m.screenCoverage=B,m.screenspaceVolume.copy(h),B<=0)return m;if(u){const L=Ut.copy(s);L.invert(),q.copy(U.min),Q.copy(U.max),Q.x=q.x,J.copy(U.max),J.y=q.y,Z.copy(U.max);const y=(q.z+Z.z)*.5;q.z=Q.z=J.z=Z.z=y,q.applyMatrix4(L),Q.applyMatrix4(L),J.applyMatrix4(L),Z.applyMatrix4(L),u(q,Q,255),u(q,J,255),u(Q,Z,255),u(J,Z,255)}if(d?.length)for(let L=0;L<d.length;L++){const y=d[L],T=y.densities?.[p]||y.density||1e-5;if(p>0&&c&&Ge()&&!y.densities&&!globalThis["NEEDLE:MISSING_LOD_PRIMITIVE_DENSITIES"]&&(globalThis["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.")),T/B<o){m.level=L;break}}return m}class P{static debugDrawLine;static getObjectLODState(t){return t[De]}static addPlugin(t){G.push(t)}static removePlugin(t){const e=G.indexOf(t);e>=0&&G.splice(e,1)}static getPlugins(){return G}static get(t,e){if(t[be])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[be];const r=new P(t,{engine:"unknown",...e});return t[be]=r,r}renderer;context;projectionScreenMatrix=new Re;get plugins(){return G}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 le(this.#s,{...t});this._newPromiseGroups.push(r);const s=performance.now();return r.ready.finally(()=>{const o=this._newPromiseGroups.indexOf(r);o>=0&&(this._newPromiseGroups.splice(o,1),Ge()&&performance.measure("LODsManager:awaitLoading",{start:s,detail:{id:e,name:t?.name,awaited:r.awaitedCount,resolved:r.resolvedCount}}))}),r.ready}trackLoadingPromise(t,e,r){return le.addPromise(t,e,r,this._newPromiseGroups),r}_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){return t==="changed"?(this._lodchangedlisteners.push(e),()=>{this.removeEventListener(t,e)}):()=>{}}removeEventListener(t,e){let r=!1;if(t==="changed"){const s=this._lodchangedlisteners.indexOf(e);s>=0&&(this._lodchangedlisteners.splice(s,1),r=!0)}return r}constructor(t,e){this.renderer=t,this.context={...e}}#t;#s=0;#o=0;#i=0;#r=0;#n=qt();_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;ie(this.renderer),this.renderer.render=function(r,s){const o=e.renderer.getRenderTarget();(o==null||"isXRRenderTarget"in o&&o.isXRRenderTarget)&&(t=0,e.#s+=1,e.#n.update?.(),e.#o=Math.max(e.#n.getDelta(),1/1e3),e.#i+=e.#o,e._fpsBuffer.shift(),e._fpsBuffer.push(1/e.#o),e.#r=e._fpsBuffer.reduce((a,l)=>a+l)/e._fpsBuffer.length,E&&e.#s%200===0&&console.log("FPS",Math.round(e.#r),"Interval:",e.#e));const i=t++;e.#t.call(this,r,s),e.onAfterRender(r,s,i)}}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 s=this.getRenderList(t,e,r);if(!s)return;const o=s.opaque;let i=!0;if(o.length===1){const a=o[0].material;(a.name==="EffectMaterial"||a.name==="CopyShader")&&(i=!1)}if((e.parent&&e.parent.type==="CubeCamera"||r>=1&&e.type==="OrthographicCamera")&&(i=!1),i){if(Bt||(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.getRenderList(t,e,0);if(!r)return;const s=r.opaque;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse);const o=this.targetTriangleDensity;for(const l of s){if(l.material&&(l.geometry?.type==="BoxGeometry"||l.geometry?.type==="BufferGeometry")&&(l.material.name==="SphericalGaussianBlur"||l.material.name=="BackgroundCubeMaterial"||l.material.name==="CubemapFromEquirect"||l.material.name==="EquirectangularToCubeUV")){E&&(l.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(l.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",l,l.material.name,l.material.type)));continue}switch(l.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}const u=l.object;(u instanceof X||u.isMesh)&&this.updateLODs(t,e,u,o)}const i=r.transparent;for(const l of i){const u=l.object;(u instanceof X||u.isMesh)&&this.updateLODs(t,e,u,o)}const a=r.transmissive;for(const l of a){const u=l.object;(u instanceof X||u.isMesh)&&this.updateLODs(t,e,u,o)}}getRenderList(t,e,r){const s=this.renderer;let o=null;if(s.isWebGPURenderer===!0){const i=s._renderLists;if(!i)return null;o=i.get(t,e)}else if(s.isWebGLRenderer===!0){const i=s.renderLists;if(!i)return null;o=i.get(t,r)}return o?{opaque:o.opaque||[],transparent:o.transparent||[],transmissive:o.transmissive||o.transparentDoublePass||[],transparentDoublePass:o.transparentDoublePass||[]}:null}updateLODs(t,e,r,s){r.userData||(r.userData={});let o=r[De];if(o||(o=new Ft,r[De]=o),o.frames++<2)return;for(const a of G)a.onBeforeUpdateLOD?.(this.renderer,t,e,r);const i=this.overrideLodLevel!==void 0?this.overrideLodLevel:K;i>=0?(_.mesh_lod=i,_.texture_lod=i):(this.calculateLodLevel(e,r,o,s,_),_.mesh_lod=Math.round(_.mesh_lod),_.texture_lod=Math.round(_.texture_lod)),_.mesh_lod>=0&&this.loadProgressiveMeshes(r,_.mesh_lod),r.material&&_.texture_lod>=0&&this.loadProgressiveTextures(r.material,_.texture_lod,i),f&&r.material&&!r.isGizmo&&Ne(r.material),$t&&r.material&&!r.isGizmo&&!r.isBatchedMesh&&ze(r.material,_.mesh_lod);for(const a of G)a.onAfterUpdatedLOD?.(this.renderer,t,e,r,_);o.lastLodLevel_Mesh=_.mesh_lod,o.lastLodLevel_Texture=_.texture_lod}loadProgressiveTextures(t,e,r){if(!t)return;if(Array.isArray(t)){for(const i of t)this.loadProgressiveTextures(i,e,r);return}let s=!1;(t[N]===void 0||e<t[N])&&(s=!0);const o=r!==void 0&&r>=0;if(o&&(s=t[N]!=r,e=r),s){t[N]=e;const i=o?{force:!0}:void 0,a=g.assignTextureLOD(t,e,i).then(l=>{this._lodchangedlisteners.forEach(u=>u({type:"texture",level:e,object:t}))});le.addPromise("texture",t,a,this._newPromiseGroups)}}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);let r=t[N]!==e;const s=t["DEBUG:LOD"];if(s!=null&&(r=t[N]!=s,e=s),r){t[N]=e;const o=t.geometry,i=g.assignMeshLOD(t,e).then(a=>(a&&t[N]==e&&o!=t.geometry&&this._lodchangedlisteners.forEach(l=>l({type:"mesh",level:e,object:t})),a));return le.addPromise("mesh",t,i,this._newPromiseGroups),i}return Promise.resolve(null)}_sphere=new ke;_tempWorldPosition=new k;static skinnedMeshBoundsFrameOffsetCounter=0;static $skinnedMeshBoundsOffset=Symbol("gltf-progressive-skinnedMeshBoundsOffset");calculateLodLevel(t,e,r,s,o){if(!e){o.mesh_lod=-1,o.texture_lod=-1;return}if(!t){o.mesh_lod=-1,o.texture_lod=-1;return}let i=11,a=!1;if(E&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const l=g.getMeshLODExtension(e.geometry)?.lods,u=g.getPrimitiveIndex(e.geometry),c=l&&l.length>0,d=g.getMaterialMinMaxLODsCount(e.material),p=d.min_count!==1/0&&d.min_count>=0&&d.max_count>=0;if(!c&&!p){o.mesh_lod=0,o.texture_lod=0;return}c||(a=!0,i=0);const m=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let w=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const h=e;if(!h.boundingBox)h.computeBoundingBox();else if(this.skinnedMeshAutoUpdateBoundsInterval>0){if(!h[P.$skinnedMeshBoundsOffset]){const M=P.skinnedMeshBoundsFrameOffsetCounter++;h[P.$skinnedMeshBoundsOffset]=M}const D=h[P.$skinnedMeshBoundsOffset];if((r.frames+D)%this.skinnedMeshAutoUpdateBoundsInterval===0){const M=Y(h),j=h.geometry;M&&(h.geometry=M),h.computeBoundingBox(),h.geometry=j}}w=h.boundingBox}if(w){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=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(D)){o.mesh_lod=0,o.texture_lod=0;return}}const h=Fe({geometry:e.geometry,matrixWorld:e.matrixWorld,camera:t,projectionScreenMatrix:this.projectionScreenMatrix,desiredDensity:s,canvasHeight:m,currentLevel:r.lastLodLevel_Mesh,boundingBox:w,xrEnabled:this.renderer.xr.enabled,debugDrawLine:E?P.debugDrawLine:void 0,warnMissingPrimitiveDensities:!0});if(r.lastCentrality=h.centrality,r.lastScreenCoverage=h.screenCoverage,r.lastScreenspaceVolume.copy(h.screenspaceVolume),h.screenCoverage===1/0){o.mesh_lod=0,o.texture_lod=0;return}h.level>=0&&h.level<i&&(i=h.level,a=!0)}if(a?o.mesh_lod=i:o.mesh_lod=r.lastLodLevel_Mesh,E&&o.mesh_lod!=r.lastLodLevel_Mesh){const h=l?.[o.mesh_lod];h&&console.log(`Mesh LOD changed: ${r.lastLodLevel_Mesh} \u2192 ${o.mesh_lod} (density: ${h.densities?.[u].toFixed(0)}) | ${e.name}`)}if(p){const h="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(r.lastLodLevel_Texture<0){if(o.texture_lod=d.max_count-1,E){const D=d.lods[d.max_count-1];E&&console.log(`First Texture LOD ${o.texture_lod} (${D.max_height}px) - ${e.name}`)}}else{const D=r.lastScreenspaceVolume.x+r.lastScreenspaceVolume.y+r.lastScreenspaceVolume.z;let M=r.lastScreenCoverage*4;this.context?.engine==="model-viewer"&&(M*=1.5);const j=this.renderer.getPixelRatio?.()||globalThis.devicePixelRatio||1,B=m/j*M;let L=!1;for(let y=d.lods.length-1;y>=0;y--){const T=d.lods[y];if(!(h&&T.max_height>=2048)&&!(ye()&&T.max_height>4096)&&(T.max_height>B||!L&&y===0)){if(L=!0,o.texture_lod=y,E&&o.texture_lod<r.lastLodLevel_Texture){const S=T.max_height;console.log(`Texture LOD changed: ${r.lastLodLevel_Texture} \u2192 ${o.texture_lod} = ${S}px
8
8
  Screensize: ${B.toFixed(0)}px, Coverage: ${(100*r.lastScreenCoverage).toFixed(2)}%, Volume ${D.toFixed(1)}
9
9
  ${e.name}`)}break}}}}else o.texture_lod=0}}class Ft{frames=0;lastLodLevel_Mesh=-1;lastLodLevel_Texture=-1;lastScreenCoverage=0;lastScreenspaceVolume=new k;lastCentrality=0}function ze(n,t){if(!(t<0)){if(Array.isArray(n)){for(const e of n)ze(e,t);return}"color"in n&&n.color instanceof Pe&&(n.color.copy(Ve(t,Gt)),n.needsUpdate=!0)}}function Ve(n,t){const e=Math.max(0,Math.min(Me.length-1,Math.floor(n)));return t.setHex(Me[e])}const Xe=Symbol("NEEDLE_mesh_lod"),ue=Symbol("NEEDLE_texture_lod");let Te=null;function Se(){const n=zt();n&&(n.mapURLs(function(t){return He(),t}),He(),Te?.disconnect(),Te=new MutationObserver(t=>{t.forEach(e=>{e.addedNodes.forEach(r=>{r instanceof HTMLElement&&r.tagName.toLowerCase()==="model-viewer"&&Ye(r)})})}),Te.observe(document,{childList:!0,subtree:!0}))}function zt(){return typeof customElements>"u"?null:customElements.get("model-viewer")||(customElements.whenDefined("model-viewer").then(()=>{console.debug("[gltf-progressive] model-viewer defined"),Se()}),null)}function He(){typeof document>"u"||document.querySelectorAll("model-viewer").forEach(n=>{Ye(n)})}const Ke=new WeakSet;let Vt=0;function Ye(n){if(!n||Ke.has(n))return null;Ke.add(n),console.debug("[gltf-progressive] found new model-viewer..."+ ++Vt+`
10
- `,n.getAttribute("src"));let t=null,e=null,r=null;for(let s=n;s!=null;s=Object.getPrototypeOf(s)){const o=Object.getOwnPropertySymbols(s),i=o.find(u=>u.toString()=="Symbol(renderer)"),a=o.find(u=>u.toString()=="Symbol(scene)"),l=o.find(u=>u.toString()=="Symbol(needsRender)");!t&&i!=null&&(t=n[i].threeRenderer),!e&&a!=null&&(e=n[a]),!r&&l!=null&&(r=n[l])}if(t&&e){let s=function(){if(r){let i=0;const a=setInterval(()=>{if(i++>5){clearInterval(a);return}r?.call(n)},300)}};console.debug("[gltf-progressive] setup model-viewer");const o=P.get(t,{engine:"model-viewer"});return P.addPlugin(new Xt),o.enable(),o.addEventListener("changed",()=>{r?.call(n)}),n.addEventListener("model-visibility",i=>{i.detail.visible&&r?.call(n)}),n.addEventListener("load",()=>{s()}),()=>{o.disable()}}return null}class Xt{_didWarnAboutMissingUrl=!1;onBeforeUpdateLOD(t,e,r,s){this.tryParseMeshLOD(e,s),this.tryParseTextureLOD(e,s)}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[ue]==!0)return;e[ue]=!0;const r=this.tryGetCurrentGLTF(t),s=this.tryGetCurrentModelViewer(t),o=this.getUrl(s);if(o&&r&&e.material){let i=function(l){if(l[ue]==!0)return;l[ue]=!0,l.userData&&(l.userData.LOD=-1);const u=Object.keys(l);for(let c=0;c<u.length;c++){const d=u[c],p=l[d];if(p?.isTexture===!0){const m=p.userData?.associations?.textures;if(m==null)continue;const w=r.parser.json.textures[m];if(!w){console.warn("Texture data not found for texture index "+m);continue}if(w?.extensions?.[$]){const h=w.extensions[$];h&&o&&f.registerTexture(o,p,h.lods.length,m,h)}}}};const a=e.material;if(Array.isArray(a))for(const l of a)i(l);else i(a)}}tryParseMeshLOD(t,e){if(e[Xe]==!0)return;e[Xe]=!0;const r=this.tryGetCurrentModelViewer(t),s=this.getUrl(r);if(!s)return;const o=e.userData?.gltfExtensions?.[$];if(o&&s){const i=e.uuid;f.registerMesh(s,i,e,0,o.lods.length,o)}}}function Qe(...n){let t,e,r,s;switch(n.length){case 2:[r,e]=n,s={};break;case 3:[r,e,s]=n;break;case 4:[t,e,r,s]=n;break;default:throw new Error("Invalid arguments")}ie(e),he(r),me(r,{progressive:!0,...s?.hints}),r.register(i=>new f(i));const o=P.get(e);return s?.enableLODsManager!==!1&&o.enable(),o}if(Se(),!Ot){const n={gltfProgressive:{useNeedleProgressive:Qe,LODsManager:P,configureLoader:me,getRaycastMesh:Y,useRaycastMeshes:We}};if(!globalThis.Needle)globalThis.Needle=n;else for(const t in n)globalThis.Needle[t]=n[t]}export{$ as EXTENSION_NAME,P as LODsManager,f as NEEDLE_progressive,Ce as VERSION,he as addDracoAndKTX2Loaders,Fe as calculateMeshLODLevel,me as configureLoader,ie as createLoaders,Ve as getLODColor,Y as getRaycastMesh,Me as lodDebugColors,Se as patchModelViewer,qe as registerRaycastMesh,Ee as setDracoDecoderLocation,Ie as setKTX2TranscoderLocation,Qe as useNeedleProgressive,We as useRaycastMeshes};
10
+ `,n.getAttribute("src"));let t=null,e=null,r=null;for(let s=n;s!=null;s=Object.getPrototypeOf(s)){const o=Object.getOwnPropertySymbols(s),i=o.find(u=>u.toString()=="Symbol(renderer)"),a=o.find(u=>u.toString()=="Symbol(scene)"),l=o.find(u=>u.toString()=="Symbol(needsRender)");!t&&i!=null&&(t=n[i].threeRenderer),!e&&a!=null&&(e=n[a]),!r&&l!=null&&(r=n[l])}if(t&&e){let s=function(){if(r){let i=0;const a=setInterval(()=>{if(i++>5){clearInterval(a);return}r?.call(n)},300)}};console.debug("[gltf-progressive] setup model-viewer");const o=P.get(t,{engine:"model-viewer"});return P.addPlugin(new Xt),o.enable(),o.addEventListener("changed",()=>{r?.call(n)}),n.addEventListener("model-visibility",i=>{i.detail.visible&&r?.call(n)}),n.addEventListener("load",()=>{s()}),()=>{o.disable()}}return null}class Xt{_didWarnAboutMissingUrl=!1;onBeforeUpdateLOD(t,e,r,s){this.tryParseMeshLOD(e,s),this.tryParseTextureLOD(e,s)}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[ue]==!0)return;e[ue]=!0;const r=this.tryGetCurrentGLTF(t),s=this.tryGetCurrentModelViewer(t),o=this.getUrl(s);if(o&&r&&e.material){let i=function(l){if(l[ue]==!0)return;l[ue]=!0,l.userData&&(l.userData.LOD=-1);const u=Object.keys(l);for(let c=0;c<u.length;c++){const d=u[c],p=l[d];if(p?.isTexture===!0){const m=p.userData?.associations?.textures;if(m==null)continue;const w=r.parser.json.textures[m];if(!w){console.warn("Texture data not found for texture index "+m);continue}if(w?.extensions?.[$]){const h=w.extensions[$];h&&o&&g.registerTexture(o,p,h.lods.length,m,h)}}}};const a=e.material;if(Array.isArray(a))for(const l of a)i(l);else i(a)}}tryParseMeshLOD(t,e){if(e[Xe]==!0)return;e[Xe]=!0;const r=this.tryGetCurrentModelViewer(t),s=this.getUrl(r);if(!s)return;const o=e.userData?.gltfExtensions?.[$];if(o&&s){const i=e.uuid;g.registerMesh(s,i,e,0,o.lods.length,o)}}}function Qe(...n){let t,e,r,s;switch(n.length){case 2:[r,e]=n,s={};break;case 3:[r,e,s]=n;break;case 4:[t,e,r,s]=n;break;default:throw new Error("Invalid arguments")}ie(e),he(r),me(r,{progressive:!0,...s?.hints}),r.register(i=>new g(i));const o=P.get(e);return s?.enableLODsManager!==!1&&o.enable(),o}if(Se(),!Ot){const n={gltfProgressive:{useNeedleProgressive:Qe,LODsManager:P,configureLoader:me,getRaycastMesh:Y,useRaycastMeshes:We}};if(!globalThis.Needle)globalThis.Needle=n;else for(const t in n)globalThis.Needle[t]=n[t]}export{$ as EXTENSION_NAME,P as LODsManager,g as NEEDLE_progressive,Ce as VERSION,he as addDracoAndKTX2Loaders,Fe as calculateMeshLODLevel,me as configureLoader,ie as createLoaders,Ve as getLODColor,Y as getRaycastMesh,Me as lodDebugColors,Se as patchModelViewer,qe as registerRaycastMesh,Ee as setDracoDecoderLocation,Ie as setKTX2TranscoderLocation,Qe as useNeedleProgressive,We as useRaycastMeshes};
@@ -1,10 +1,10 @@
1
- "use strict";var He=Object.create;var Oe=Object.defineProperty;var Ye=Object.getOwnPropertyDescriptor;var Qe=Object.getOwnPropertyNames;var Je=Object.getPrototypeOf,Ze=Object.prototype.hasOwnProperty;var et=(o,t,e,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of Qe(t))!Ze.call(o,r)&&r!==e&&Oe(o,r,{get:()=>t[r],enumerable:!(s=Ye(t,r))||s.enumerable});return o};var tt=(o,t,e)=>(e=o!=null?He(Je(o)):{},et(t||!o||!o.__esModule?Oe(e,"default",{value:o,enumerable:!0}):e,o));Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const d=require("three"),ve=require("three/examples/jsm/loaders/GLTFLoader.js"),st=require("three/examples/jsm/libs/meshopt_decoder.module.js"),rt=require("three/examples/jsm/loaders/DRACOLoader.js"),nt=require("three/examples/jsm/loaders/KTX2Loader.js");var le=typeof document<"u"?document.currentScript:null;function ot(o){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(o){for(const e in o)if(e!=="default"){const s=Object.getOwnPropertyDescriptor(o,e);Object.defineProperty(t,e,s.get?s:{enumerable:!0,get:()=>o[e]})}}return t.default=o,Object.freeze(t)}const it=ot(d),Ie="";globalThis.GLTF_PROGRESSIVE_VERSION=Ie;console.debug("[gltf-progressive] version -");let $="https://www.gstatic.com/draco/versioned/decoders/1.5.7/",j="https://cdn.needle.tools/static/three/0.179.1/basis2/";const at=$,lt=j,$e=new URL($+"draco_decoder.js");$e.searchParams.append("range","true");fetch($e,{method:"GET",headers:{Range:"bytes=0-1"}}).catch(o=>{console.debug(`Failed to fetch remote Draco decoder from ${$} (offline: ${typeof navigator<"u"?navigator.onLine:"unknown"})`),$===at&&Be("./include/draco/"),j===lt&&Ge("./include/ktx2/")}).finally(()=>{qe()});const ut=()=>({dracoDecoderPath:$,ktx2TranscoderPath:j});function Be(o){$=o,P&&P[pe]!=$?(console.debug("Updating Draco decoder path to "+o),P[pe]=$,P.setDecoderPath($),P.preload()):console.debug("Setting Draco decoder path to "+o)}function Ge(o){j=o,B&&B.transcoderPath!=j?(console.debug("Updating KTX2 transcoder path to "+o),B.setTranscoderPath(j),B.init()):console.debug("Setting KTX2 transcoder path to "+o)}function ie(o){return qe(),o?B.detectSupport(o):o!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:P,ktx2Loader:B,meshoptDecoder:oe}}function De(o){o.dracoLoader||o.setDRACOLoader(P),o.ktx2Loader||o.setKTX2Loader(B),o.meshoptDecoder||o.setMeshoptDecoder(oe)}const pe=Symbol("dracoDecoderPath");let P,oe,B;function qe(){P||(P=new rt.DRACOLoader,P[pe]=$,P.setDecoderPath($),P.setDecoderConfig({type:"js"}),P.preload()),B||(B=new nt.KTX2Loader,B.setTranscoderPath(j),B.init()),oe||(oe=st.MeshoptDecoder)}const me=new WeakMap;function Me(o,t){let e=me.get(o);e?e=Object.assign(e,t):e=t,me.set(o,e)}const ct=ve.GLTFLoader.prototype.load;function ft(...o){const t=me.get(this);let e=o[0];const s=dt(e);if(s?.hostname.endsWith("needle.tools")){const n=t?.progressive!==void 0?t.progressive:!0,i=t?.usecase?t.usecase:"default";n?this.requestHeader.Accept=`*/*;progressive=allowed;usecase=${i}`:this.requestHeader.Accept=`*/*;usecase=${i}`,e=s.toString()}return o[0]=e,ct?.call(this,...o)}ve.GLTFLoader.prototype.load=ft;function dt(o){try{if(o instanceof URL)return o;const t=globalThis.location?.href;return t?new URL(o,t):new URL(o)}catch{return null}}function Se(o){return o!=null&&o.data!=null}function ye(o){const t=o.source?.data;return t!=null&&typeof t=="object"?t:null}function ht(o){const t=o.image;return t!=null&&typeof t=="object"?t:null}function xe(o){const t=ht(o),e=ye(o);return{width:t?.width||e?.width||0,height:t?.height||e?.height||0}}z("debugprogressive");function z(o){const t=globalThis.location?.href;if(!t)return!1;const s=new URL(t).searchParams.get(o);return s==null||s==="0"||s==="false"?!1:s===""?!0:s}function gt(o,t){if(t===void 0||o===void 0||t.startsWith("./")||t.startsWith("http")||t.startsWith("data:")||t.startsWith("blob:"))return t;const e=o.lastIndexOf("/");if(e>=0){const s=o.substring(0,e+1);for(;s.endsWith("/")&&t.startsWith("/");)t=t.substring(1);return s+t}return t}function _e(){if(Q!==void 0)return Q;const o=globalThis.navigator?.userAgent||"";return Q=/iPhone|iPad|iPod|Android|IEMobile/i.test(o),z("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",Q),Q}let Q;function Fe(){const o=globalThis.location?.href;if(!o)return!1;const t=new URL(o),e=t.hostname==="localhost"||/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(t.hostname);return t.hostname==="127.0.0.1"||e}class pt{constructor(t,e={}){this.maxConcurrent=t,this.debug=e.debug??!1,typeof window<"u"&&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:s,resolve:r}=this._queue.shift();r({use:n=>this.add(s,n)})}}}function mt(o){const t=o.image,e=t?.width??0,s=t?.height??0,r=t?.depth??1,n=Math.floor(Math.log2(Math.max(e,s,r)))+1,i=yt(o);return e*s*r*i*(1-Math.pow(.25,n))/(1-.25)}function yt(o){let t=4;const e=o.format;e===d.RedFormat||e===d.RedIntegerFormat?t=1:e===d.RGFormat||e===d.RGIntegerFormat?t=2:e===d.RGBFormat||e===1029?t=3:(e===d.RGBAFormat||e===d.RGBAIntegerFormat)&&(t=4);let s=1;const r=o.type;return r===1009||r===1010?s=1:r===1011||r===1012?s=2:r===1013||r===1014||r===1015?s=4:r===1016&&(s=2),t*s}const xt=typeof window>"u"&&typeof document>"u",Le=Symbol("needle:raycast-mesh");function Y(o){return o?.[Le]instanceof d.BufferGeometry?o[Le]:null}function Ue(o,t){if((o.type==="Mesh"||o.type==="SkinnedMesh")&&!Y(o)){const s=Lt(t);s.userData={isRaycastMesh:!0},o[Le]=s}}function We(o=!0){if(o){if(J)return;const t=J=d.Mesh.prototype.raycast;d.Mesh.prototype.raycast=function(e,s){const r=this,n=Y(r);let i;n&&r.isMesh&&(i=r.geometry,r.geometry=n),t.call(this,e,s),i&&(r.geometry=i)}}else{if(!J)return;d.Mesh.prototype.raycast=J,J=null}}let J=null;function Lt(o){const t=new d.BufferGeometry;for(const e in o.attributes)t.setAttribute(e,o.getAttribute(e));return t.setIndex(o.getIndex()),t}const U=new Array,g=z("debugprogressive");let te,N=-1;if(g&&typeof window<"u"){let o=function(){N+=1,N>=t&&(N=-1),console.log(`Toggle LOD level [${N}]`)};const t=6;window.addEventListener("keyup",e=>{e.key==="p"&&o(),e.key==="w"&&(te=!te,console.log(`Toggle wireframe [${te}]`));const s=parseInt(e.key);!isNaN(s)&&s>=0&&(N=s,console.log(`Set LOD level to [${N}]`))})}function Ee(o){if(g&&te!==void 0)if(Array.isArray(o))for(const t of o)Ee(t);else o&&"wireframe"in o&&(o.wireframe=te===!0)}const Z=new Array;let wt=0;const vt=_e()?2:10;function Dt(o){if(Z.length<vt){const s=Z.length;g&&console.warn(`[Worker] Creating new worker #${s}`);const r=Te.createWorker(o||{});return Z.push(r),r}const t=wt++%Z.length;return Z[t]}class Te{constructor(t,e){this.worker=t,this._debug=e.debug??!1,t.onmessage=s=>{const r=s.data;switch(this._debug&&console.log("[Worker] EVENT",r),r.type){case"loaded-gltf":for(const n of this._running)if(n.url===r.result.url){Mt(r.result),n.resolve(r.result);const i=n.url;i.startsWith("blob:")&&URL.revokeObjectURL(i)}}},t.onerror=s=>{console.error("[Worker] Error in gltf-progressive worker:",s)},t.postMessage({type:"init"})}static async createWorker(t){const e=new Worker(new URL("/assets/gltf-progressive.worker-CCrD-Ycm.js",typeof document>"u"?require("url").pathToFileURL(__filename).href:le&&le.tagName.toUpperCase()==="SCRIPT"&&le.src||new URL("gltf-progressive.umd.cjs",document.baseURI).href),{type:"module"});return new Te(e,t)}_running=[];_webglRenderer=null;async load(t,e){const s=ut();let r=e?.renderer;r||(this._webglRenderer??=(async()=>{const{WebGLRenderer:u}=await import("three");return new u})(),r=await this._webglRenderer);const a=ie(r).ktx2Loader.workerConfig;if(t instanceof URL)t=t.toString();else if(t.startsWith("file:"))t=URL.createObjectURL(new Blob([t]));else if(!t.startsWith("blob:")&&!t.startsWith("http:")&&!t.startsWith("https:")){const u=globalThis.location?.href;u&&(t=new URL(t,u).toString())}const l={type:"load",url:t,dracoDecoderPath:s.dracoDecoderPath,ktx2TranscoderPath:s.ktx2TranscoderPath,ktx2LoaderConfig:a};return this._debug&&console.debug("[Worker] Sending load request",l),this.worker.postMessage(l),new Promise(u=>{this._running.push({url:t.toString(),resolve:u})})}_debug=!1}function Mt(o){for(const t of o.geometries){const e=t.geometry,s=new d.BufferGeometry;if(s.name=e.name||"",e.index){const r=e.index;s.setIndex(ue(r))}for(const r in e.attributes){const n=e.attributes[r],i=ue(n);s.setAttribute(r,i)}if(e.morphAttributes)for(const r in e.morphAttributes){const i=e.morphAttributes[r].map(a=>ue(a));s.morphAttributes[r]=i}if(s.morphTargetsRelative=e.morphTargetsRelative??!1,s.boundingBox=new d.Box3,s.boundingBox.min=new d.Vector3(e.boundingBox?.min.x,e.boundingBox?.min.y,e.boundingBox?.min.z),s.boundingBox.max=new d.Vector3(e.boundingBox?.max.x,e.boundingBox?.max.y,e.boundingBox?.max.z),s.boundingSphere=new d.Sphere(new d.Vector3(e.boundingSphere?.center.x,e.boundingSphere?.center.y,e.boundingSphere?.center.z),e.boundingSphere?.radius),e.groups)for(const r of e.groups)s.addGroup(r.start,r.count,r.materialIndex);e.userData&&(s.userData=e.userData),t.geometry=s}for(const t of o.textures){const e=t.texture;let s=null;if(e.isCompressedTexture){const r=e.mipmaps,{width:n,height:i}=xe(e);s=new d.CompressedTexture(r,n,i,e.format,e.type,e.mapping,e.wrapS,e.wrapT,e.magFilter,e.minFilter,e.anisotropy,e.colorSpace)}else s=new d.Texture(e.image,e.mapping,e.wrapS,e.wrapT,e.magFilter,e.minFilter,e.format,e.type,e.anisotropy,e.colorSpace),s.mipmaps=e.mipmaps,s.channel=e.channel,s.source.data=e.source.data,s.flipY=e.flipY,s.premultiplyAlpha=e.premultiplyAlpha,s.unpackAlignment=e.unpackAlignment,s.matrix=new d.Matrix3(...e.matrix.elements);if(!s){console.error("[Worker] Failed to create new texture from received data. Texture is not a CompressedTexture or Texture.");continue}t.texture=s}return o}function ue(o){let t=o;if("isInterleavedBufferAttribute"in o&&o.isInterleavedBufferAttribute){const e=o.data,s=e.array,r=new d.InterleavedBuffer(s,e.stride);t=new d.InterleavedBufferAttribute(r,o.itemSize,s.byteOffset,o.normalized),t.offset=o.offset}else"isBufferAttribute"in o&&o.isBufferAttribute&&(t=new d.BufferAttribute(o.array,o.itemSize,o.normalized),t.usage=o.usage,t.gpuType=o.gpuType,t.updateRanges=o.updateRanges);return t}const _t=z("gltf-progressive-worker");z("gltf-progressive-reduce-mipmaps");const ee=z("gltf-progressive-gc"),ce=Symbol("needle-progressive-texture"),q="NEEDLE_progressive";class p{get name(){return q}static getMeshLODExtension(t){const e=this.getAssignedLODInformation(t);return e?.key?this.lodInfos.get(e.key):null}static getPrimitiveIndex(t){const e=this.getAssignedLODInformation(t)?.index;return e??-1}static getMaterialMinMaxLODsCount(t,e){const s=this,r="LODS:minmax",n=t[r];if(n!=null)return n;if(e||(e={min_count:1/0,max_count:0,lods:[]}),Array.isArray(t)){for(const a of t)this.getMaterialMinMaxLODsCount(a,e);return t[r]=e,e}if(g==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const a=t;for(const l of Object.keys(a.uniforms)){const u=a.uniforms[l].value;u?.isTexture===!0&&i(u,e)}}else if(t.isMaterial)for(const a of Object.keys(t)){const l=t[a];l?.isTexture===!0&&i(l,e)}else g&&console.warn(`[getMaterialMinMaxLODsCount] Unsupported material type: ${t.type}`);return t[r]=e,e;function i(a,l){const u=s.getAssignedLODInformation(a);if(u){const f=s.lodInfos.get(u.key);if(f&&f.lods){l.min_count=Math.min(l.min_count,f.lods.length),l.max_count=Math.max(l.max_count,f.lods.length);for(let c=0;c<f.lods.length;c++){const h=f.lods[c];h.width&&(l.lods[c]=l.lods[c]||{min_height:1/0,max_height:0},l.lods[c].min_height=Math.min(l.lods[c].min_height,h.height),l.lods[c].max_height=Math.max(l.lods[c].max_height,h.height))}}}}}static hasLODLevelAvailable(t,e){if(Array.isArray(t)){for(const n of t)if(this.hasLODLevelAvailable(n,e))return!0;return!1}if(t.isMaterial===!0){for(const n of Object.keys(t)){const i=t[n];if(i&&i.isTexture&&this.hasLODLevelAvailable(i,e))return!0}return!1}else if(t.isGroup===!0){for(const n of t.children)if(n.isMesh===!0&&this.hasLODLevelAvailable(n,e))return!0}let s,r;if(t.isMesh?s=t.geometry:(t.isBufferGeometry||t.isTexture)&&(s=t),s&&s?.userData?.LODS){const n=s.userData.LODS;if(r=this.lodInfos.get(n.key),e===void 0)return r!=null;if(r)return Array.isArray(r.lods)?e<r.lods.length:e===0}return!1}static assignMeshLOD(t,e,s){if(!t)return Promise.resolve(null);if(t instanceof d.Mesh||t.isMesh===!0){const r=t.geometry,n=this.getAssignedLODInformation(r);if(!n)return Promise.resolve(null);for(const a of U)a.onBeforeGetLODMesh?.(t,e);t["LOD:requested level"]=e;const i=()=>t["LOD:requested level"]===e||this.shouldApplyStaleMeshLOD(t,e);return p.getOrLoadLOD(r,e,{isCurrent:i}).then(a=>{if(Array.isArray(a)){const u=n.index||0;a=a[u]}const l=t["LOD:requested level"]===e;return(l||this.shouldApplyStaleMeshLOD(t,e))&&(l&&delete t["LOD:requested level"],a&&r!=a&&(a?.isBufferGeometry?typeof s?.apply=="function"?s.apply(a,e,t):s?.apply!==!1&&(t.geometry=a):g&&console.error("Invalid LOD geometry",a))),a}).catch(a=>(console.error("Error loading mesh LOD",t,a),null))}else g&&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,s){if(!t)return Promise.resolve(null);const r=s?.force===!0;if(t.isMesh===!0){const n=t;if(Array.isArray(n.material)){const i=new Array;for(const a of n.material){const l=this.assignTextureLOD(a,e,s);i.push(l)}return Promise.all(i).then(a=>{const l=new Array;for(const u of a)Array.isArray(u)&&l.push(...u);return l})}else return this.assignTextureLOD(n.material,e,s)}if(t.isMaterial===!0){const n=t,i=[],a=new Array;if(this.trackCurrentMaterialTextureSlots(n),n.uniforms&&(n.isRawShaderMaterial||n.isShaderMaterial===!0)){const l=n;for(const u of Object.keys(l.uniforms)){const f=l.uniforms[u].value;if(f?.isTexture===!0){const c=this.assignTextureLODForSlot(f,e,n,u,r).then(h=>(h&&l.uniforms[u].value!=h&&(l.uniforms[u].value=h,l.uniformsNeedUpdate=!0),h));i.push(c),a.push(u)}}}else for(const l of Object.keys(n)){const u=n[l];if(u?.isTexture===!0){const f=this.assignTextureLODForSlot(u,e,n,l,r);i.push(f),a.push(l)}}return Promise.all(i).then(l=>{const u=new Array;for(let f=0;f<l.length;f++){const c=l[f],h=a[f];c&&c.isTexture===!0?u.push({material:n,slot:h,texture:c,level:e}):u.push({material:n,slot:h,texture:null,level:e})}return u})}if(t instanceof d.Texture||t.isTexture===!0){const n=t;return this.assignTextureLODForSlot(n,e,null,null,r)}return Promise.resolve(null)}static set maxConcurrentLoadingTasks(t){p.queue.maxConcurrent=t}static get maxConcurrentLoadingTasks(){return p.queue.maxConcurrent}static assignTextureLODForSlot(t,e,s,r,n){if(t?.isTexture!==!0)return Promise.resolve(null);if(r==="glyphMap")return Promise.resolve(t);const i=this.getAssignedLODInformation(t);if(i&&(i.level===e||!n&&i.level<e))return Promise.resolve(t);if(s&&r){const c=this.getPendingTextureSlotRequest(s,r);if(c&&c.level===e&&c.force===n)return c.promise}const a=s&&r?this.nextTextureSlotRequestId(s,r,e,n):0,l=()=>!s||!r||this.getLatestTextureSlotRequest(s,r)?.id===a,u=()=>l()||this.shouldApplyStaleTextureSlotLOD(s,r,e,n),f=p.getOrLoadLOD(t,e,{isCurrent:u}).then(c=>{if(!l()&&!this.shouldApplyStaleTextureSlotLOD(s,r,e,n))return null;if(Array.isArray(c))return console.warn("Progressive: Got an array of textures for a texture slot, this should not happen..."),null;if(c?.isTexture===!0){if(c!=t&&s&&r){const h=this.getMaterialTextureSlot(s,r)??t;if(h&&!n){const m=this.getAssignedLODInformation(h);if(m&&m?.level<e)return g==="verbose"&&console.warn("Assigned texture level is already higher: ",m.level,e,s,h,c),null}this.assignTrackedTextureSlot(s,r,c)}return c}else g=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(c=>(console.error("Error loading LOD",t,c),null));return s&&r&&this.setPendingTextureSlotRequest(s,r,e,n,a,f),f}static trackedTextureSlots=new WeakMap;static pendingTextureSlotRequests=new WeakMap;static latestTextureSlotRequests=new WeakMap;static textureSlotRequestId=0;static trackCurrentMaterialTextureSlots(t){if(t.uniforms&&(t.isRawShaderMaterial||t.isShaderMaterial===!0)){const e=t;for(const s of Object.keys(e.uniforms)){const r=e.uniforms[s].value;r?.isTexture===!0&&this.ensureTrackedTextureSlot(t,s,r)}return}for(const e of Object.keys(t)){const s=t[e];s?.isTexture===!0&&this.ensureTrackedTextureSlot(t,e,s)}}static getPendingTextureSlotRequest(t,e){return this.pendingTextureSlotRequests.get(t)?.get(e)}static nextTextureSlotRequestId(t,e,s,r){let n=this.latestTextureSlotRequests.get(t);n||(n=new Map,this.latestTextureSlotRequests.set(t,n));const i=++this.textureSlotRequestId;return n.set(e,{id:i,level:s,force:r}),i}static getLatestTextureSlotRequest(t,e){return this.latestTextureSlotRequests.get(t)?.get(e)}static shouldApplyStaleTextureSlotLOD(t,e,s,r){if(!t||!e)return!1;const n=this.getLatestTextureSlotRequest(t,e),i=this.getMaterialTextureSlot(t,e),a=this.getAssignedLODInformation(i)?.level??1/0;return s>=a?!1:r?n?s>=n.level:!1:!0}static shouldApplyStaleMeshLOD(t,e){const s=t["LOD:requested level"];if(typeof s!="number")return!1;const r=this.getAssignedLODInformation(t.geometry)?.level??1/0;return e<r&&e>=s}static setPendingTextureSlotRequest(t,e,s,r,n,i){let a=this.pendingTextureSlotRequests.get(t);a||(a=new Map,this.pendingTextureSlotRequests.set(t,a));const l={level:s,force:r,id:n,promise:i};a.set(e,l),i.finally(()=>{a.get(e)?.id===n&&a.delete(e)})}static getMaterialTextureSlot(t,e){const r=t.uniforms?.[e];if(r?.value?.isTexture===!0)return r.value;const n=t[e];return n?.isTexture===!0?n:null}static setMaterialTextureSlot(t,e,s){const n=t.uniforms?.[e];if(n?.value?.isTexture===!0){n.value=s,t.uniformsNeedUpdate=!0;return}t[e]=s}static assignTrackedTextureSlot(t,e,s){let r=this.trackedTextureSlots.get(t);r||(r=new Map,this.trackedTextureSlots.set(t,r));const n=this.getMaterialTextureSlot(t,e);let i=r.get(e);!i&&n?i=this.ensureTrackedTextureSlot(t,e,n):i&&n&&i!==n&&(this.releaseTrackedTextureSlot(t,e,i),i=this.ensureTrackedTextureSlot(t,e,n)),!(i===s&&n===s)&&(i&&i!==s&&this.releaseTrackedTextureSlot(t,e,i),i!==s&&(this.trackTextureUsage(s),r.set(e,s)),n!==s&&this.setMaterialTextureSlot(t,e,s))}static ensureTrackedTextureSlot(t,e,s){let r=this.trackedTextureSlots.get(t);r||(r=new Map,this.trackedTextureSlots.set(t,r));const n=r.get(e);return n===s?n:(n&&this.releaseTrackedTextureSlot(t,e,n),this.trackTextureUsage(s),r.set(e,s),s)}static releaseTrackedTextureSlot(t,e,s){const r=this.trackedTextureSlots.get(t);if(r?.get(e)===s&&r.delete(e),this.untrackTextureUsage(s)&&(g||ee)){const i=this.getAssignedLODInformation(s);console.log(`[gltf-progressive] Disposed old texture LOD ${i?.level??"?"} for ${t.name||t.type}.${e}`,s.uuid)}}parser;url;constructor(t){const e=t.options.path;g&&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?.[q];return e?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",t).then(s=>(this._isLoadingMesh=!1,s&&p.registerMesh(this.url,e.guid,s,e.lods?.length,0,e),s))):null};afterRoot(t){return g&&console.log("AFTER",this.url,t),this.parser.json.textures?.forEach((e,s)=>{if(e?.extensions){const r=e?.extensions[q];if(r){if(!r.lods){g&&console.warn("Texture has no LODs",r);return}let n=!1;for(const i of this.parser.associations.keys())i.isTexture===!0&&this.parser.associations.get(i)?.textures===s&&(n=!0,p.registerTexture(this.url,i,r.lods?.length,s,r));n||this.parser.getDependency("texture",s).then(i=>{i&&p.registerTexture(this.url,i,r.lods?.length,s,r)})}}}),this.parser.json.meshes?.forEach((e,s)=>{if(e?.extensions){const r=e?.extensions[q];if(r&&r.lods){for(const n of this.parser.associations.keys())if(n.isMesh){const i=this.parser.associations.get(n);i?.meshes===s&&p.registerMesh(this.url,r.guid,n,r.lods.length,i.primitives,r)}}}}),null}static registerTexture=(t,e,s,r,n)=>{if(!e){g&&console.error("!! gltf-progressive: Called register texture without texture");return}if(g){const{width:a,height:l}=xe(e);console.log(`> gltf-progressive: register texture[${r}] "${e.name||e.uuid}", Current: ${a}x${l}, Max: ${n.lods[0]?.width}x${n.lods[0]?.height}, uuid: ${e.uuid}`,n,e)}e.source&&(e.source[ce]=n);const i=n.guid;p.assignLODInformation(t,e,i,s,r),p.lodInfos.set(i,n),p.lowresCache.set(i,new WeakRef(e))};static registerMesh=(t,e,s,r,n,i)=>{const a=s.geometry;if(!a){g&&console.warn("gltf-progressive: Register mesh without geometry");return}a.userData||(a.userData={}),g&&console.log("> Progressive: register mesh "+s.name,{index:n,uuid:s.uuid},i,s),p.assignLODInformation(t,a,e,r,n),p.lodInfos.set(e,i);let u=p.lowresCache.get(e)?.deref();u?u.push(s.geometry):u=[s.geometry],p.lowresCache.set(e,new WeakRef(u)),r>0&&!Y(s)&&Ue(s,a);for(const f of U)f.onRegisteredNewMesh?.(s,i)};static dispose(t){if(t){this.lodInfos.delete(t);const e=this.lowresCache.get(t);if(e){const s=e.deref();if(s){if(s.isTexture){const r=s;this.textureRefCounts.delete(r.uuid),r.dispose()}else if(Array.isArray(s))for(const r of s)r.dispose()}this.lowresCache.delete(t)}for(const[s,r]of this.cache)s.includes(t)&&(this._disposeCacheEntry(r),this.cache.delete(s))}else{this.lodInfos.clear();for(const[,e]of this.lowresCache){const s=e.deref();if(s){if(s.isTexture){const r=s;this.textureRefCounts.delete(r.uuid),r.dispose()}else if(Array.isArray(s))for(const r of s)r.dispose()}}this.lowresCache.clear();for(const[,e]of this.cache)this._disposeCacheEntry(e);this.cache.clear(),this.textureRefCounts.clear(),this.trackedTextureSlots=new WeakMap,this.pendingTextureSlotRequests=new WeakMap,this.latestTextureSlotRequests=new WeakMap,this.textureSlotRequestId=0}}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 s of e)s.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=p.cache.get(t);(g||ee)&&console.debug(`[gltf-progressive] Memory: Resource GC'd
1
+ "use strict";var He=Object.create;var Oe=Object.defineProperty;var Ye=Object.getOwnPropertyDescriptor;var Qe=Object.getOwnPropertyNames;var Je=Object.getPrototypeOf,Ze=Object.prototype.hasOwnProperty;var et=(o,t,e,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of Qe(t))!Ze.call(o,r)&&r!==e&&Oe(o,r,{get:()=>t[r],enumerable:!(s=Ye(t,r))||s.enumerable});return o};var tt=(o,t,e)=>(e=o!=null?He(Je(o)):{},et(t||!o||!o.__esModule?Oe(e,"default",{value:o,enumerable:!0}):e,o));Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const d=require("three"),ve=require("three/examples/jsm/loaders/GLTFLoader.js"),st=require("three/examples/jsm/libs/meshopt_decoder.module.js"),rt=require("three/examples/jsm/loaders/DRACOLoader.js"),nt=require("three/examples/jsm/loaders/KTX2Loader.js");var le=typeof document<"u"?document.currentScript:null;function ot(o){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(o){for(const e in o)if(e!=="default"){const s=Object.getOwnPropertyDescriptor(o,e);Object.defineProperty(t,e,s.get?s:{enumerable:!0,get:()=>o[e]})}}return t.default=o,Object.freeze(t)}const it=ot(d),Ie="";globalThis.GLTF_PROGRESSIVE_VERSION=Ie;console.debug("[gltf-progressive] version -");let $="https://www.gstatic.com/draco/versioned/decoders/1.5.7/",j="https://cdn.needle.tools/static/three/0.179.1/basis2/";const at=$,lt=j,$e=new URL($+"draco_decoder.js");$e.searchParams.append("range","true");fetch($e,{method:"GET",headers:{Range:"bytes=0-1"}}).catch(o=>{console.debug(`Failed to fetch remote Draco decoder from ${$} (offline: ${typeof navigator<"u"?navigator.onLine:"unknown"})`),$===at&&Be("./include/draco/"),j===lt&&Ge("./include/ktx2/")}).finally(()=>{qe()});const ut=()=>({dracoDecoderPath:$,ktx2TranscoderPath:j});function Be(o){$=o,P&&P[pe]!=$?(console.debug("Updating Draco decoder path to "+o),P[pe]=$,P.setDecoderPath($),P.preload()):console.debug("Setting Draco decoder path to "+o)}function Ge(o){j=o,B&&B.transcoderPath!=j?(console.debug("Updating KTX2 transcoder path to "+o),B.setTranscoderPath(j),B.init()):console.debug("Setting KTX2 transcoder path to "+o)}function ie(o){return qe(),o?B.detectSupport(o):o!==null&&console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures might fail"),{dracoLoader:P,ktx2Loader:B,meshoptDecoder:oe}}function De(o){o.dracoLoader||o.setDRACOLoader(P),o.ktx2Loader||o.setKTX2Loader(B),o.meshoptDecoder||o.setMeshoptDecoder(oe)}const pe=Symbol("dracoDecoderPath");let P,oe,B;function qe(){P||(P=new rt.DRACOLoader,P[pe]=$,P.setDecoderPath($),P.setDecoderConfig({type:"js"}),P.preload()),B||(B=new nt.KTX2Loader,B.setTranscoderPath(j),B.init()),oe||(oe=st.MeshoptDecoder)}const me=new WeakMap;function Me(o,t){let e=me.get(o);e?e=Object.assign(e,t):e=t,me.set(o,e)}const ct=ve.GLTFLoader.prototype.load;function ft(...o){const t=me.get(this);let e=o[0];const s=dt(e);if(s?.hostname.endsWith("needle.tools")){const n=t?.progressive!==void 0?t.progressive:!0,i=t?.usecase?t.usecase:"default";n?this.requestHeader.Accept=`*/*;progressive=allowed;usecase=${i}`:this.requestHeader.Accept=`*/*;usecase=${i}`,e=s.toString()}return o[0]=e,ct?.call(this,...o)}ve.GLTFLoader.prototype.load=ft;function dt(o){try{if(o instanceof URL)return o;const t=globalThis.location?.href;return t?new URL(o,t):new URL(o)}catch{return null}}function Se(o){return o!=null&&o.data!=null}function ye(o){const t=o.source?.data;return t!=null&&typeof t=="object"?t:null}function ht(o){const t=o.image;return t!=null&&typeof t=="object"?t:null}function xe(o){const t=ht(o),e=ye(o);return{width:t?.width||e?.width||0,height:t?.height||e?.height||0}}z("debugprogressive");function z(o){const t=globalThis.location?.href;if(!t)return!1;const s=new URL(t).searchParams.get(o);return s==null||s==="0"||s==="false"?!1:s===""?!0:s}function gt(o,t){if(t===void 0||o===void 0||t.startsWith("./")||t.startsWith("http")||t.startsWith("data:")||t.startsWith("blob:"))return t;const e=o.lastIndexOf("/");if(e>=0){const s=o.substring(0,e+1);for(;s.endsWith("/")&&t.startsWith("/");)t=t.substring(1);return s+t}return t}function _e(){if(Q!==void 0)return Q;const o=globalThis.navigator?.userAgent||"";return Q=/iPhone|iPad|iPod|Android|IEMobile/i.test(o),z("debugprogressive")&&console.log("[glTF Progressive]: isMobileDevice",Q),Q}let Q;function Fe(){const o=globalThis.location?.href;if(!o)return!1;const t=new URL(o),e=t.hostname==="localhost"||/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(t.hostname);return t.hostname==="127.0.0.1"||e}class pt{constructor(t,e={}){this.maxConcurrent=t,this.debug=e.debug??!1,typeof globalThis.requestAnimationFrame=="function"?globalThis.requestAnimationFrame(this.tick):setTimeout(this.tick,0)}_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:s,resolve:r}=this._queue.shift();r({use:n=>this.add(s,n)})}}}function mt(o){const t=o.image,e=t?.width??0,s=t?.height??0,r=t?.depth??1,n=Math.floor(Math.log2(Math.max(e,s,r)))+1,i=yt(o);return e*s*r*i*(1-Math.pow(.25,n))/(1-.25)}function yt(o){let t=4;const e=o.format;e===d.RedFormat||e===d.RedIntegerFormat?t=1:e===d.RGFormat||e===d.RGIntegerFormat?t=2:e===d.RGBFormat||e===1029?t=3:(e===d.RGBAFormat||e===d.RGBAIntegerFormat)&&(t=4);let s=1;const r=o.type;return r===1009||r===1010?s=1:r===1011||r===1012?s=2:r===1013||r===1014||r===1015?s=4:r===1016&&(s=2),t*s}const xt=typeof window>"u"&&typeof document>"u",Le=Symbol("needle:raycast-mesh");function Y(o){return o?.[Le]instanceof d.BufferGeometry?o[Le]:null}function Ue(o,t){if((o.type==="Mesh"||o.type==="SkinnedMesh")&&!Y(o)){const s=Lt(t);s.userData={isRaycastMesh:!0},o[Le]=s}}function We(o=!0){if(o){if(J)return;const t=J=d.Mesh.prototype.raycast;d.Mesh.prototype.raycast=function(e,s){const r=this,n=Y(r);let i;n&&r.isMesh&&(i=r.geometry,r.geometry=n),t.call(this,e,s),i&&(r.geometry=i)}}else{if(!J)return;d.Mesh.prototype.raycast=J,J=null}}let J=null;function Lt(o){const t=new d.BufferGeometry;for(const e in o.attributes)t.setAttribute(e,o.getAttribute(e));return t.setIndex(o.getIndex()),t}const U=new Array,g=z("debugprogressive");let te,N=-1;if(g&&typeof window<"u"){let o=function(){N+=1,N>=t&&(N=-1),console.log(`Toggle LOD level [${N}]`)};const t=6;window.addEventListener("keyup",e=>{e.key==="p"&&o(),e.key==="w"&&(te=!te,console.log(`Toggle wireframe [${te}]`));const s=parseInt(e.key);!isNaN(s)&&s>=0&&(N=s,console.log(`Set LOD level to [${N}]`))})}function Ee(o){if(g&&te!==void 0)if(Array.isArray(o))for(const t of o)Ee(t);else o&&"wireframe"in o&&(o.wireframe=te===!0)}const Z=new Array;let wt=0;const vt=_e()?2:10;function Dt(o){if(Z.length<vt){const s=Z.length;g&&console.warn(`[Worker] Creating new worker #${s}`);const r=Te.createWorker(o||{});return Z.push(r),r}const t=wt++%Z.length;return Z[t]}class Te{constructor(t,e){this.worker=t,this._debug=e.debug??!1,t.onmessage=s=>{const r=s.data;switch(this._debug&&console.log("[Worker] EVENT",r),r.type){case"loaded-gltf":for(const n of this._running)if(n.url===r.result.url){Mt(r.result),n.resolve(r.result);const i=n.url;i.startsWith("blob:")&&URL.revokeObjectURL(i)}}},t.onerror=s=>{console.error("[Worker] Error in gltf-progressive worker:",s)},t.postMessage({type:"init"})}static async createWorker(t){const e=new Worker(new URL("/assets/gltf-progressive.worker-CCrD-Ycm.js",typeof document>"u"?require("url").pathToFileURL(__filename).href:le&&le.tagName.toUpperCase()==="SCRIPT"&&le.src||new URL("gltf-progressive.umd.cjs",document.baseURI).href),{type:"module"});return new Te(e,t)}_running=[];_webglRenderer=null;async load(t,e){const s=ut();let r=e?.renderer;r||(this._webglRenderer??=(async()=>{const{WebGLRenderer:u}=await import("three");return new u})(),r=await this._webglRenderer);const a=ie(r).ktx2Loader.workerConfig;if(t instanceof URL)t=t.toString();else if(t.startsWith("file:"))t=URL.createObjectURL(new Blob([t]));else if(!t.startsWith("blob:")&&!t.startsWith("http:")&&!t.startsWith("https:")){const u=globalThis.location?.href;u&&(t=new URL(t,u).toString())}const l={type:"load",url:t,dracoDecoderPath:s.dracoDecoderPath,ktx2TranscoderPath:s.ktx2TranscoderPath,ktx2LoaderConfig:a};return this._debug&&console.debug("[Worker] Sending load request",l),this.worker.postMessage(l),new Promise(u=>{this._running.push({url:t.toString(),resolve:u})})}_debug=!1}function Mt(o){for(const t of o.geometries){const e=t.geometry,s=new d.BufferGeometry;if(s.name=e.name||"",e.index){const r=e.index;s.setIndex(ue(r))}for(const r in e.attributes){const n=e.attributes[r],i=ue(n);s.setAttribute(r,i)}if(e.morphAttributes)for(const r in e.morphAttributes){const i=e.morphAttributes[r].map(a=>ue(a));s.morphAttributes[r]=i}if(s.morphTargetsRelative=e.morphTargetsRelative??!1,s.boundingBox=new d.Box3,s.boundingBox.min=new d.Vector3(e.boundingBox?.min.x,e.boundingBox?.min.y,e.boundingBox?.min.z),s.boundingBox.max=new d.Vector3(e.boundingBox?.max.x,e.boundingBox?.max.y,e.boundingBox?.max.z),s.boundingSphere=new d.Sphere(new d.Vector3(e.boundingSphere?.center.x,e.boundingSphere?.center.y,e.boundingSphere?.center.z),e.boundingSphere?.radius),e.groups)for(const r of e.groups)s.addGroup(r.start,r.count,r.materialIndex);e.userData&&(s.userData=e.userData),t.geometry=s}for(const t of o.textures){const e=t.texture;let s=null;if(e.isCompressedTexture){const r=e.mipmaps,{width:n,height:i}=xe(e);s=new d.CompressedTexture(r,n,i,e.format,e.type,e.mapping,e.wrapS,e.wrapT,e.magFilter,e.minFilter,e.anisotropy,e.colorSpace)}else s=new d.Texture(e.image,e.mapping,e.wrapS,e.wrapT,e.magFilter,e.minFilter,e.format,e.type,e.anisotropy,e.colorSpace),s.mipmaps=e.mipmaps,s.channel=e.channel,s.source.data=e.source.data,s.flipY=e.flipY,s.premultiplyAlpha=e.premultiplyAlpha,s.unpackAlignment=e.unpackAlignment,s.matrix=new d.Matrix3(...e.matrix.elements);if(!s){console.error("[Worker] Failed to create new texture from received data. Texture is not a CompressedTexture or Texture.");continue}t.texture=s}return o}function ue(o){let t=o;if("isInterleavedBufferAttribute"in o&&o.isInterleavedBufferAttribute){const e=o.data,s=e.array,r=new d.InterleavedBuffer(s,e.stride);t=new d.InterleavedBufferAttribute(r,o.itemSize,s.byteOffset,o.normalized),t.offset=o.offset}else"isBufferAttribute"in o&&o.isBufferAttribute&&(t=new d.BufferAttribute(o.array,o.itemSize,o.normalized),t.usage=o.usage,t.gpuType=o.gpuType,t.updateRanges=o.updateRanges);return t}const _t=z("gltf-progressive-worker");z("gltf-progressive-reduce-mipmaps");const ee=z("gltf-progressive-gc"),ce=Symbol("needle-progressive-texture"),q="NEEDLE_progressive";class p{get name(){return q}static getMeshLODExtension(t){const e=this.getAssignedLODInformation(t);return e?.key?this.lodInfos.get(e.key):null}static getPrimitiveIndex(t){const e=this.getAssignedLODInformation(t)?.index;return e??-1}static getMaterialMinMaxLODsCount(t,e){const s=this,r="LODS:minmax",n=t[r];if(n!=null)return n;if(e||(e={min_count:1/0,max_count:0,lods:[]}),Array.isArray(t)){for(const a of t)this.getMaterialMinMaxLODsCount(a,e);return t[r]=e,e}if(g==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const a=t;for(const l of Object.keys(a.uniforms)){const u=a.uniforms[l].value;u?.isTexture===!0&&i(u,e)}}else if(t.isMaterial)for(const a of Object.keys(t)){const l=t[a];l?.isTexture===!0&&i(l,e)}else g&&console.warn(`[getMaterialMinMaxLODsCount] Unsupported material type: ${t.type}`);return t[r]=e,e;function i(a,l){const u=s.getAssignedLODInformation(a);if(u){const f=s.lodInfos.get(u.key);if(f&&f.lods){l.min_count=Math.min(l.min_count,f.lods.length),l.max_count=Math.max(l.max_count,f.lods.length);for(let c=0;c<f.lods.length;c++){const h=f.lods[c];h.width&&(l.lods[c]=l.lods[c]||{min_height:1/0,max_height:0},l.lods[c].min_height=Math.min(l.lods[c].min_height,h.height),l.lods[c].max_height=Math.max(l.lods[c].max_height,h.height))}}}}}static hasLODLevelAvailable(t,e){if(Array.isArray(t)){for(const n of t)if(this.hasLODLevelAvailable(n,e))return!0;return!1}if(t.isMaterial===!0){for(const n of Object.keys(t)){const i=t[n];if(i&&i.isTexture&&this.hasLODLevelAvailable(i,e))return!0}return!1}else if(t.isGroup===!0){for(const n of t.children)if(n.isMesh===!0&&this.hasLODLevelAvailable(n,e))return!0}let s,r;if(t.isMesh?s=t.geometry:(t.isBufferGeometry||t.isTexture)&&(s=t),s&&s?.userData?.LODS){const n=s.userData.LODS;if(r=this.lodInfos.get(n.key),e===void 0)return r!=null;if(r)return Array.isArray(r.lods)?e<r.lods.length:e===0}return!1}static assignMeshLOD(t,e,s){if(!t)return Promise.resolve(null);if(t instanceof d.Mesh||t.isMesh===!0){const r=t.geometry,n=this.getAssignedLODInformation(r);if(!n)return Promise.resolve(null);for(const a of U)a.onBeforeGetLODMesh?.(t,e);t["LOD:requested level"]=e;const i=()=>t["LOD:requested level"]===e||this.shouldApplyStaleMeshLOD(t,e);return p.getOrLoadLOD(r,e,{isCurrent:i}).then(a=>{if(Array.isArray(a)){const u=n.index||0;a=a[u]}const l=t["LOD:requested level"]===e;return(l||this.shouldApplyStaleMeshLOD(t,e))&&(l&&delete t["LOD:requested level"],a&&r!=a&&(a?.isBufferGeometry?typeof s?.apply=="function"?s.apply(a,e,t):s?.apply!==!1&&(t.geometry=a):g&&console.error("Invalid LOD geometry",a))),a}).catch(a=>(console.error("Error loading mesh LOD",t,a),null))}else g&&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,s){if(!t)return Promise.resolve(null);const r=s?.force===!0;if(t.isMesh===!0){const n=t;if(Array.isArray(n.material)){const i=new Array;for(const a of n.material){const l=this.assignTextureLOD(a,e,s);i.push(l)}return Promise.all(i).then(a=>{const l=new Array;for(const u of a)Array.isArray(u)&&l.push(...u);return l})}else return this.assignTextureLOD(n.material,e,s)}if(t.isMaterial===!0){const n=t,i=[],a=new Array;if(this.trackCurrentMaterialTextureSlots(n),n.uniforms&&(n.isRawShaderMaterial||n.isShaderMaterial===!0)){const l=n;for(const u of Object.keys(l.uniforms)){const f=l.uniforms[u].value;if(f?.isTexture===!0){const c=this.assignTextureLODForSlot(f,e,n,u,r).then(h=>(h&&l.uniforms[u].value!=h&&(l.uniforms[u].value=h,l.uniformsNeedUpdate=!0),h));i.push(c),a.push(u)}}}else for(const l of Object.keys(n)){const u=n[l];if(u?.isTexture===!0){const f=this.assignTextureLODForSlot(u,e,n,l,r);i.push(f),a.push(l)}}return Promise.all(i).then(l=>{const u=new Array;for(let f=0;f<l.length;f++){const c=l[f],h=a[f];c&&c.isTexture===!0?u.push({material:n,slot:h,texture:c,level:e}):u.push({material:n,slot:h,texture:null,level:e})}return u})}if(t instanceof d.Texture||t.isTexture===!0){const n=t;return this.assignTextureLODForSlot(n,e,null,null,r)}return Promise.resolve(null)}static set maxConcurrentLoadingTasks(t){p.queue.maxConcurrent=t}static get maxConcurrentLoadingTasks(){return p.queue.maxConcurrent}static assignTextureLODForSlot(t,e,s,r,n){if(t?.isTexture!==!0)return Promise.resolve(null);if(r==="glyphMap")return Promise.resolve(t);const i=this.getAssignedLODInformation(t);if(i&&(i.level===e||!n&&i.level<e))return Promise.resolve(t);if(s&&r){const c=this.getPendingTextureSlotRequest(s,r);if(c&&c.level===e&&c.force===n)return c.promise}const a=s&&r?this.nextTextureSlotRequestId(s,r,e,n):0,l=()=>!s||!r||this.getLatestTextureSlotRequest(s,r)?.id===a,u=()=>l()||this.shouldApplyStaleTextureSlotLOD(s,r,e,n),f=p.getOrLoadLOD(t,e,{isCurrent:u}).then(c=>{if(!l()&&!this.shouldApplyStaleTextureSlotLOD(s,r,e,n))return null;if(Array.isArray(c))return console.warn("Progressive: Got an array of textures for a texture slot, this should not happen..."),null;if(c?.isTexture===!0){if(c!=t&&s&&r){const h=this.getMaterialTextureSlot(s,r)??t;if(h&&!n){const m=this.getAssignedLODInformation(h);if(m&&m?.level<e)return g==="verbose"&&console.warn("Assigned texture level is already higher: ",m.level,e,s,h,c),null}this.assignTrackedTextureSlot(s,r,c)}return c}else g=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(c=>(console.error("Error loading LOD",t,c),null));return s&&r&&this.setPendingTextureSlotRequest(s,r,e,n,a,f),f}static trackedTextureSlots=new WeakMap;static pendingTextureSlotRequests=new WeakMap;static latestTextureSlotRequests=new WeakMap;static textureSlotRequestId=0;static trackCurrentMaterialTextureSlots(t){if(t.uniforms&&(t.isRawShaderMaterial||t.isShaderMaterial===!0)){const e=t;for(const s of Object.keys(e.uniforms)){const r=e.uniforms[s].value;r?.isTexture===!0&&this.ensureTrackedTextureSlot(t,s,r)}return}for(const e of Object.keys(t)){const s=t[e];s?.isTexture===!0&&this.ensureTrackedTextureSlot(t,e,s)}}static getPendingTextureSlotRequest(t,e){return this.pendingTextureSlotRequests.get(t)?.get(e)}static nextTextureSlotRequestId(t,e,s,r){let n=this.latestTextureSlotRequests.get(t);n||(n=new Map,this.latestTextureSlotRequests.set(t,n));const i=++this.textureSlotRequestId;return n.set(e,{id:i,level:s,force:r}),i}static getLatestTextureSlotRequest(t,e){return this.latestTextureSlotRequests.get(t)?.get(e)}static shouldApplyStaleTextureSlotLOD(t,e,s,r){if(!t||!e)return!1;const n=this.getLatestTextureSlotRequest(t,e),i=this.getMaterialTextureSlot(t,e),a=this.getAssignedLODInformation(i)?.level??1/0;return s>=a?!1:r?n?s>=n.level:!1:!0}static shouldApplyStaleMeshLOD(t,e){const s=t["LOD:requested level"];if(typeof s!="number")return!1;const r=this.getAssignedLODInformation(t.geometry)?.level??1/0;return e<r&&e>=s}static setPendingTextureSlotRequest(t,e,s,r,n,i){let a=this.pendingTextureSlotRequests.get(t);a||(a=new Map,this.pendingTextureSlotRequests.set(t,a));const l={level:s,force:r,id:n,promise:i};a.set(e,l),i.finally(()=>{a.get(e)?.id===n&&a.delete(e)})}static getMaterialTextureSlot(t,e){const r=t.uniforms?.[e];if(r?.value?.isTexture===!0)return r.value;const n=t[e];return n?.isTexture===!0?n:null}static setMaterialTextureSlot(t,e,s){const n=t.uniforms?.[e];if(n?.value?.isTexture===!0){n.value=s,t.uniformsNeedUpdate=!0;return}t[e]=s}static assignTrackedTextureSlot(t,e,s){let r=this.trackedTextureSlots.get(t);r||(r=new Map,this.trackedTextureSlots.set(t,r));const n=this.getMaterialTextureSlot(t,e);let i=r.get(e);!i&&n?i=this.ensureTrackedTextureSlot(t,e,n):i&&n&&i!==n&&(this.releaseTrackedTextureSlot(t,e,i),i=this.ensureTrackedTextureSlot(t,e,n)),!(i===s&&n===s)&&(i&&i!==s&&this.releaseTrackedTextureSlot(t,e,i),i!==s&&(this.trackTextureUsage(s),r.set(e,s)),n!==s&&this.setMaterialTextureSlot(t,e,s))}static ensureTrackedTextureSlot(t,e,s){let r=this.trackedTextureSlots.get(t);r||(r=new Map,this.trackedTextureSlots.set(t,r));const n=r.get(e);return n===s?n:(n&&this.releaseTrackedTextureSlot(t,e,n),this.trackTextureUsage(s),r.set(e,s),s)}static releaseTrackedTextureSlot(t,e,s){const r=this.trackedTextureSlots.get(t);if(r?.get(e)===s&&r.delete(e),this.untrackTextureUsage(s)&&(g||ee)){const i=this.getAssignedLODInformation(s);console.log(`[gltf-progressive] Disposed old texture LOD ${i?.level??"?"} for ${t.name||t.type}.${e}`,s.uuid)}}parser;url;constructor(t){const e=t.options.path;g&&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?.[q];return e?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",t).then(s=>(this._isLoadingMesh=!1,s&&p.registerMesh(this.url,e.guid,s,e.lods?.length,0,e),s))):null};afterRoot(t){return g&&console.log("AFTER",this.url,t),this.parser.json.textures?.forEach((e,s)=>{if(e?.extensions){const r=e?.extensions[q];if(r){if(!r.lods){g&&console.warn("Texture has no LODs",r);return}let n=!1;for(const i of this.parser.associations.keys())i.isTexture===!0&&this.parser.associations.get(i)?.textures===s&&(n=!0,p.registerTexture(this.url,i,r.lods?.length,s,r));n||this.parser.getDependency("texture",s).then(i=>{i&&p.registerTexture(this.url,i,r.lods?.length,s,r)})}}}),this.parser.json.meshes?.forEach((e,s)=>{if(e?.extensions){const r=e?.extensions[q];if(r&&r.lods){for(const n of this.parser.associations.keys())if(n.isMesh){const i=this.parser.associations.get(n);i?.meshes===s&&p.registerMesh(this.url,r.guid,n,r.lods.length,i.primitives,r)}}}}),null}static registerTexture=(t,e,s,r,n)=>{if(!e){g&&console.error("!! gltf-progressive: Called register texture without texture");return}if(g){const{width:a,height:l}=xe(e);console.log(`> gltf-progressive: register texture[${r}] "${e.name||e.uuid}", Current: ${a}x${l}, Max: ${n.lods[0]?.width}x${n.lods[0]?.height}, uuid: ${e.uuid}`,n,e)}e.source&&(e.source[ce]=n);const i=n.guid;p.assignLODInformation(t,e,i,s,r),p.lodInfos.set(i,n),p.lowresCache.set(i,new WeakRef(e))};static registerMesh=(t,e,s,r,n,i)=>{const a=s.geometry;if(!a){g&&console.warn("gltf-progressive: Register mesh without geometry");return}a.userData||(a.userData={}),g&&console.log("> Progressive: register mesh "+s.name,{index:n,uuid:s.uuid},i,s),p.assignLODInformation(t,a,e,r,n),p.lodInfos.set(e,i);let u=p.lowresCache.get(e)?.deref();u?u.push(s.geometry):u=[s.geometry],p.lowresCache.set(e,new WeakRef(u)),r>0&&!Y(s)&&Ue(s,a);for(const f of U)f.onRegisteredNewMesh?.(s,i)};static dispose(t){if(t){this.lodInfos.delete(t);const e=this.lowresCache.get(t);if(e){const s=e.deref();if(s){if(s.isTexture){const r=s;this.textureRefCounts.delete(r.uuid),r.dispose()}else if(Array.isArray(s))for(const r of s)r.dispose()}this.lowresCache.delete(t)}for(const[s,r]of this.cache)s.includes(t)&&(this._disposeCacheEntry(r),this.cache.delete(s))}else{this.lodInfos.clear();for(const[,e]of this.lowresCache){const s=e.deref();if(s){if(s.isTexture){const r=s;this.textureRefCounts.delete(r.uuid),r.dispose()}else if(Array.isArray(s))for(const r of s)r.dispose()}}this.lowresCache.clear();for(const[,e]of this.cache)this._disposeCacheEntry(e);this.cache.clear(),this.textureRefCounts.clear(),this.trackedTextureSlots=new WeakMap,this.pendingTextureSlotRequests=new WeakMap,this.latestTextureSlotRequests=new WeakMap,this.textureSlotRequestId=0}}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 s of e)s.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=p.cache.get(t);(g||ee)&&console.debug(`[gltf-progressive] Memory: Resource GC'd
2
2
  ${t}`),e instanceof WeakRef&&(e.deref()||(p.cache.delete(t),(g||ee)&&console.log("[gltf-progressive] ↪ Cache entry deleted (GC)")))});static trackTextureUsage(t){const e=t.uuid,s=this.textureRefCounts.get(e)||0;this.textureRefCounts.set(e,s+1),g==="verbose"&&console.log(`[gltf-progressive] Track texture ${e}, refCount: ${s} → ${s+1}`)}static untrackTextureUsage(t){const e=t.uuid,s=this.textureRefCounts.get(e);if(!s)return(g==="verbose"||ee)&&n("[gltf-progressive] Memory: Untrack untracked texture (dispose immediately)",0),t.dispose(),!0;const r=s-1;if(r<=0)return this.textureRefCounts.delete(e),(g||ee)&&n("[gltf-progressive] Memory: Dispose texture",r),t.dispose(),!0;return this.textureRefCounts.set(e,r),g==="verbose"&&n("[gltf-progressive] Memory: Untrack texture",r),!1;function n(i,a){let{width:l,height:u}=xe(t);const f=l&&u?`${l}x${u}`:"N/A";let c="N/A";l&&u&&(c=`~${(mt(t)/(1024*1024)).toFixed(2)} MB`),console.log(`${i} — ${t.name} ${f} (${c}), refCount: ${s} → ${a}
3
3
  ${e}`)}}static workers=[];static _workersIndex=0;static async getOrLoadLOD(t,e,s){const r=g=="verbose",n=this.getAssignedLODInformation(t);if(!n)return g&&console.warn(`[gltf-progressive] No LOD information found: ${t.name}, uuid: ${t.uuid}, type: ${t.type}`,t),null;const i=n?.key;let a;if(t.isTexture===!0){const u=t;u.source&&u.source[ce]&&(a=u.source[ce])}if(a||(a=p.lodInfos.get(i)),!a)g&&console.warn(`Can not load LOD ${e}: no LOD info found for "${i}" ${t.name}`,t.type,p.lodInfos);else{if(e>0){let c=!1;const h=Array.isArray(a.lods);if(h&&e>=a.lods.length?c=!0:h||(c=!0),c){const m=this.lowresCache.get(i);if(m){const b=m.deref();if(b)return b;this.lowresCache.delete(i),g&&console.log(`[gltf-progressive] Lowres cache entry was GC'd: ${i}`)}return null}}const u=Array.isArray(a.lods)?a.lods[e]?.path:a.lods;if(!u)return g&&!a["missing:uri"]&&(a["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,a)),null;const f=gt(n.url,u);if(f.endsWith(".glb")||f.endsWith(".gltf")){if(!a.guid)return console.warn("missing pointer for glb/gltf texture",a),null;const c=f+"_"+a.guid,h=await this.tryResolveLODCacheEntry(this.cache.get(c),c,f,t,e,r);if(h.found)return h.value;if(s?.isCurrent?.()===!1)return r&&console.log(`Skipping stale LOD ${e} request before queue: ${f}`),null;const m=await this.queue.slot(f);if(s?.isCurrent?.()===!1)return r&&console.log(`Skipping stale LOD ${e} request after queue: ${f}`),null;const b=await this.tryResolveLODCacheEntry(this.cache.get(c),c,f,t,e,r);if(b.found)return b.value;if(!m.use)return g&&console.log(`LOD ${e} was aborted: ${f}`),null;const x=a,L=new Promise(async(w,W)=>{if(_t){const y=await(await Dt({})).load(f);if(y.textures.length>0)for(const M of y.textures){let T=M.texture;return p.assignLODInformation(n.url,T,i,e,void 0),t instanceof d.Texture&&(T=this.copySettings(t,T)),T&&(T.guid=x.guid),w(T)}if(y.geometries.length>0){const M=new Array;for(const T of y.geometries){const G=T.geometry;p.assignLODInformation(n.url,G,i,e,T.primitiveIndex),M.push(G)}return w(M)}return w(null)}const D=new ve.GLTFLoader;De(D),g&&(await new Promise(_=>setTimeout(_,1e3)),r&&console.warn("Start loading (delayed) "+f,x.guid));let O=f;if(x&&Array.isArray(x.lods)){const _=x.lods[e];_.hash&&(O+="?v="+_.hash)}const S=await D.loadAsync(O).catch(_=>(console.error(`Error loading LOD ${e} from ${f}
4
4
  `,_),w(null)));if(!S)return w(null);const k=S.parser;r&&console.log("Loading finished "+f,x.guid);let R=0;if(S.parser.json.textures){let _=!1;for(const y of S.parser.json.textures){if(y?.extensions){const M=y?.extensions[q];if(M?.guid&&M.guid===x.guid){_=!0;break}}R++}if(_){let y=await k.getDependency("texture",R);return y&&p.assignLODInformation(n.url,y,i,e,void 0),r&&console.log('change "'+t.name+'" → "'+y.name+'"',f,R,y,c),t instanceof d.Texture&&(y=this.copySettings(t,y)),y&&(y.guid=x.guid),w(y)}else g&&console.warn("Could not find texture with guid",x.guid,S.parser.json)}if(R=0,S.parser.json.meshes){let _=!1;for(const y of S.parser.json.meshes){if(y?.extensions){const M=y?.extensions[q];if(M?.guid&&M.guid===x.guid){_=!0;break}}R++}if(_){const y=await k.getDependency("mesh",R);if(r&&console.log(`Loaded Mesh "${y.name}"`,f,R,y,c),y.isMesh===!0){const M=y.geometry;return p.assignLODInformation(n.url,M,i,e,0),w(M)}else{const M=new Array;for(let T=0;T<y.children.length;T++){const G=y.children[T];if(G.isMesh===!0){const se=G.geometry;p.assignLODInformation(n.url,se,i,e,T),M.push(se)}}return w(M)}}else g&&console.warn("Could not find mesh with guid",x.guid,S.parser.json)}return w(null)});this.cache.set(c,L),m.use(L);const v=await L;return v!=null?v instanceof d.Texture?(this.cache.set(c,new WeakRef(v)),p._resourceRegistry.register(v,c)):Array.isArray(v)?this.cache.set(c,Promise.resolve(v)):this.cache.set(c,Promise.resolve(v)):this.cache.set(c,Promise.resolve(null)),v}else if(t instanceof d.Texture){if(s?.isCurrent?.()===!1)return r&&console.log(`Skipping stale texture LOD ${e} request: ${f}`),null;r&&console.log("Load texture from uri: "+f);const h=await new d.TextureLoader().loadAsync(f);return s?.isCurrent?.()===!1?(h?.dispose(),null):(h?(h.guid=a.guid,h.flipY=!1,h.needsUpdate=!0,h.colorSpace=t.colorSpace,r&&console.log(a,h)):g&&console.warn("failed loading",f),h)}}return null}static async tryResolveLODCacheEntry(t,e,s,r,n,i){if(t===void 0)return{found:!1};if(i&&console.log(`LOD ${n} was already loading/loaded: ${e}`),t instanceof WeakRef){const u=t.deref();if(u){let f=u,c=!1;if(f instanceof d.Texture&&r instanceof d.Texture?Se(f.image)||ye(f)?f=this.copySettings(r,f):c=!0:f instanceof d.BufferGeometry&&r instanceof d.BufferGeometry&&(f.attributes.position?.array||(c=!0)),!c)return{found:!0,value:f}}return this.cache.delete(e),g&&console.log(`[gltf-progressive] Re-loading GC'd/disposed resource: ${e}`),{found:!1}}let a=await t.catch(u=>(console.error(`Error loading LOD ${n} from ${s}
5
5
  `,u),null)),l=!1;return a==null||(a instanceof d.Texture&&r instanceof d.Texture?Se(a.image)||ye(a)?a=this.copySettings(r,a):(l=!0,this.cache.delete(e)):a instanceof d.BufferGeometry&&r instanceof d.BufferGeometry&&(a.attributes.position?.array||(l=!0,this.cache.delete(e)))),l?{found:!1}:{found:!0,value:a}}static _queue;static get queue(){return this._queue??=new pt(_e()?20:50,{debug:g!=!1})}static assignLODInformation(t,e,s,r,n){if(!e)return;e.userData||(e.userData={});const i=new Tt(t,s,r,n);e.userData.LODS=i,"source"in e&&typeof e.source=="object"&&(e.source.LODS=i)}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?(g==="verbose"&&console.debug(`Copy texture settings
6
6
  `,t.uuid,`
7
- `,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 Tt{url;key;level;index;constructor(t,e,s,r){this.url=t,this.key=e,this.level=s,r!=null&&(this.index=r)}}class re{static addPromise=(t,e,s,r)=>{r.forEach(n=>{n.add(t,e,s)})};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,s){if(this._resolved){g&&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)){const r=this._seen.get(e);if(r>=this._maxPromisesPerObject){g&&console.warn("PromiseGroup: Already awaiting object ignoring new promise for it.");return}this._seen.set(e,r+1)}else this._seen.set(e,1);this._awaiting.push(s),this._addedCount++,s.finally(()=>{this._resolvedCount++,this._awaiting.splice(this._awaiting.indexOf(s),1)})}}resolveNow(){this._resolved||this._resolve?.({awaited_count:this._addedCount,resolved_count:this._resolvedCount,cancelled:this._signal?.aborted??!1})}}const I=z("debugprogressive"),bt=I==="colors",Ot=z("noprogressive"),fe=Symbol("Needle:LODSManager"),de=Symbol("Needle:LODState"),E=Symbol("Needle:CurrentLOD"),Re=it,C={mesh_lod:-1,texture_lod:-1},St=new d.Color,we=[3526751,11065402,15978811,15897394,15749691,11032304,4827122,3332036,16739229,7306743,14053330,3516499,12035359,14703919,3963096,42662,14100029,8344319,4633680,16229681,3120096,12076434,9083434,2060171,15751837,10182117,48121,62932,16704576,15817653,5083278,5592405];function Rt(){const o=Re.Timer||Re.Clock;return new o}const he=new d.Box3,V=new d.Box3,Ce=new d.Box3,Ct=new d.Vector3,Pt=new d.Vector3,kt=new d.Matrix4,F=new d.Vector3,X=new d.Vector3,K=new d.Vector3,H=new d.Vector3;function At(o,t){const e=o.min,s=o.max,r=(e.x+s.x)*.5,n=(e.y+s.y)*.5;return F.set(r,n,e.z).applyMatrix4(t).z<0}function Ve(o){const{geometry:t,matrixWorld:e,camera:s,projectionScreenMatrix:r,desiredDensity:n,canvasHeight:i=0,currentLevel:a=-1,xrEnabled:l=!1,debugDrawLine:u,warnMissingPrimitiveDensities:f=!1}=o,c=p.getMeshLODExtension(t)?.lods,h=p.getPrimitiveIndex(t),m=o.target??{level:a,primitiveIndex:h,screenCoverage:0,screenspaceVolume:new d.Vector3,centrality:1};if(m.level=a,m.primitiveIndex=h,m.screenCoverage=0,m.screenspaceVolume.set(0,0,0),m.centrality=1,!c?.length)return m;let b=o.boundingBox??t.boundingBox;if(b||(t.computeBoundingBox(),b=t.boundingBox),!b)return m;if(he.copy(b).applyMatrix4(e),s.isPerspectiveCamera&&At(he,r))return m.level=0,m.screenCoverage=1/0,m.screenspaceVolume.set(1/0,1/0,1/0),m;if(V.copy(he).applyMatrix4(r),l&&s.isPerspectiveCamera&&s.fov>70){const D=V.min,O=V.max;let S=D.x,k=D.y,R=O.x,_=O.y;const y=2,M=1.5,T=(D.x+O.x)*.5,G=(D.y+O.y)*.5;S=(S-T)*y+T,k=(k-G)*y+G,R=(R-T)*y+T,_=(_-G)*y+G;const se=S<0&&R>0?0:Math.min(Math.abs(D.x),Math.abs(O.x)),Ke=k<0&&_>0?0:Math.min(Math.abs(D.y),Math.abs(O.y)),ae=Math.max(se,Ke);m.centrality=(M-ae)*(M-ae)*(M-ae)}const x=V.getSize(Ct);x.multiplyScalar(.5),globalThis.screen?.availHeight>0&&i>0&&x.multiplyScalar(i/globalThis.screen.availHeight),s.isPerspectiveCamera&&(x.x*=s.aspect),Ce.copy(b).applyMatrix4(e).applyMatrix4(s.matrixWorldInverse);const L=Ce.getSize(Pt),v=Math.max(x.x,x.y),w=Math.max(L.x,L.y);v!==0&&w!==0&&(x.z=L.z/w*v);const W=Math.max(x.x,x.y,x.z)*m.centrality;if(m.screenCoverage=W,m.screenspaceVolume.copy(x),W<=0)return m;if(u){const D=kt.copy(r);D.invert(),F.copy(V.min),X.copy(V.max),X.x=F.x,K.copy(V.max),K.y=F.y,H.copy(V.max);const O=(F.z+H.z)*.5;F.z=X.z=K.z=H.z=O,F.applyMatrix4(D),X.applyMatrix4(D),K.applyMatrix4(D),H.applyMatrix4(D),u(F,X,255),u(F,K,255),u(X,H,255),u(K,H,255)}for(let D=0;D<c.length;D++){const O=c[D],S=O.densities?.[h]||O.density||1e-5;if(h>0&&f&&Fe()&&!O.densities&&!globalThis["NEEDLE:MISSING_LOD_PRIMITIVE_DENSITIES"]&&(globalThis["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.")),S/W<n){m.level=D;break}}return m}class A{static debugDrawLine;static getObjectLODState(t){return t[de]}static addPlugin(t){U.push(t)}static removePlugin(t){const e=U.indexOf(t);e>=0&&U.splice(e,1)}static getPlugins(){return U}static get(t,e){if(t[fe])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[fe];const s=new A(t,{engine:"unknown",...e});return t[fe]=s,s}renderer;context;projectionScreenMatrix=new d.Matrix4;get plugins(){return U}overrideLodLevel=void 0;targetTriangleDensity=2e5;skinnedMeshAutoUpdateBoundsInterval=30;updateInterval="auto";#e=1;pause=!1;manual=!1;_newPromiseGroups=[];_promiseGroupIds=0;awaitLoading(t){const e=this._promiseGroupIds++,s=new re(this.#r,{...t});this._newPromiseGroups.push(s);const r=performance.now();return s.ready.finally(()=>{const n=this._newPromiseGroups.indexOf(s);n>=0&&(this._newPromiseGroups.splice(n,1),Fe()&&performance.measure("LODsManager:awaitLoading",{start:r,detail:{id:e,name:t?.name,awaited:s.awaitedCount,resolved:s.resolvedCount}}))}),s.ready}trackLoadingPromise(t,e,s){return re.addPromise(t,e,s,this._newPromiseGroups),s}_postprocessPromiseGroups(){if(this._newPromiseGroups.length!==0)for(let t=this._newPromiseGroups.length-1;t>=0;t--)this._newPromiseGroups[t].update(this.#r)}_lodchangedlisteners=[];addEventListener(t,e){return t==="changed"?(this._lodchangedlisteners.push(e),()=>{this.removeEventListener(t,e)}):()=>{}}removeEventListener(t,e){let s=!1;if(t==="changed"){const r=this._lodchangedlisteners.indexOf(e);r>=0&&(this._lodchangedlisteners.splice(r,1),s=!0)}return s}constructor(t,e){this.renderer=t,this.context={...e}}#t;#r=0;#n=0;#i=0;#s=0;#o=Rt();_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;ie(this.renderer),this.renderer.render=function(s,r){const n=e.renderer.getRenderTarget();(n==null||"isXRRenderTarget"in n&&n.isXRRenderTarget)&&(t=0,e.#r+=1,e.#o.update?.(),e.#n=Math.max(e.#o.getDelta(),1/1e3),e.#i+=e.#n,e._fpsBuffer.shift(),e._fpsBuffer.push(1/e.#n),e.#s=e._fpsBuffer.reduce((a,l)=>a+l)/e._fpsBuffer.length,I&&e.#r%200===0&&console.log("FPS",Math.round(e.#s),"Interval:",e.#e));const i=t++;e.#t.call(this,s,r),e.onAfterRender(s,r,i)}}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,s){if(this.pause)return;const r=this.getRenderList(t,e,s);if(!r)return;const n=r.opaque;let i=!0;if(n.length===1){const a=n[0].material;(a.name==="EffectMaterial"||a.name==="CopyShader")&&(i=!1)}if((e.parent&&e.parent.type==="CubeCamera"||s>=1&&e.type==="OrthographicCamera")&&(i=!1),i){if(Ot||(this.updateInterval==="auto"?this.#s<40&&this.#e<10?(this.#e+=1,I&&console.warn("↓ Reducing LOD updates",this.#e,this.#s.toFixed(0))):this.#s>=60&&this.#e>1&&(this.#e-=1,I&&console.warn("↑ Increasing LOD updates",this.#e,this.#s.toFixed(0))):this.#e=this.updateInterval,this.#e>0&&this.#r%this.#e!=0))return;this.internalUpdate(t,e),this._postprocessPromiseGroups()}}internalUpdate(t,e){const s=this.getRenderList(t,e,0);if(!s)return;const r=s.opaque;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse);const n=this.targetTriangleDensity;for(const l of r){if(l.material&&(l.geometry?.type==="BoxGeometry"||l.geometry?.type==="BufferGeometry")&&(l.material.name==="SphericalGaussianBlur"||l.material.name=="BackgroundCubeMaterial"||l.material.name==="CubemapFromEquirect"||l.material.name==="EquirectangularToCubeUV")){I&&(l.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(l.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",l,l.material.name,l.material.type)));continue}switch(l.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}const u=l.object;(u instanceof d.Mesh||u.isMesh)&&this.updateLODs(t,e,u,n)}const i=s.transparent;for(const l of i){const u=l.object;(u instanceof d.Mesh||u.isMesh)&&this.updateLODs(t,e,u,n)}const a=s.transmissive;for(const l of a){const u=l.object;(u instanceof d.Mesh||u.isMesh)&&this.updateLODs(t,e,u,n)}}getRenderList(t,e,s){const r=this.renderer;let n=null;if(r.isWebGPURenderer===!0){const i=r._renderLists;if(!i)return null;n=i.get(t,e)}else if(r.isWebGLRenderer===!0){const i=r.renderLists;if(!i)return null;n=i.get(t,s)}return n?{opaque:n.opaque||[],transparent:n.transparent||[],transmissive:n.transmissive||n.transparentDoublePass||[],transparentDoublePass:n.transparentDoublePass||[]}:null}updateLODs(t,e,s,r){s.userData||(s.userData={});let n=s[de];if(n||(n=new It,s[de]=n),n.frames++<2)return;for(const a of U)a.onBeforeUpdateLOD?.(this.renderer,t,e,s);const i=this.overrideLodLevel!==void 0?this.overrideLodLevel:N;i>=0?(C.mesh_lod=i,C.texture_lod=i):(this.calculateLodLevel(e,s,n,r,C),C.mesh_lod=Math.round(C.mesh_lod),C.texture_lod=Math.round(C.texture_lod)),C.mesh_lod>=0&&this.loadProgressiveMeshes(s,C.mesh_lod),s.material&&C.texture_lod>=0&&this.loadProgressiveTextures(s.material,C.texture_lod,i),g&&s.material&&!s.isGizmo&&Ee(s.material),bt&&s.material&&!s.isGizmo&&!s.isBatchedMesh&&ze(s.material,C.mesh_lod);for(const a of U)a.onAfterUpdatedLOD?.(this.renderer,t,e,s,C);n.lastLodLevel_Mesh=C.mesh_lod,n.lastLodLevel_Texture=C.texture_lod}loadProgressiveTextures(t,e,s){if(!t)return;if(Array.isArray(t)){for(const i of t)this.loadProgressiveTextures(i,e,s);return}let r=!1;(t[E]===void 0||e<t[E])&&(r=!0);const n=s!==void 0&&s>=0;if(n&&(r=t[E]!=s,e=s),r){t[E]=e;const i=n?{force:!0}:void 0,a=p.assignTextureLOD(t,e,i).then(l=>{this._lodchangedlisteners.forEach(u=>u({type:"texture",level:e,object:t}))});re.addPromise("texture",t,a,this._newPromiseGroups)}}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);let s=t[E]!==e;const r=t["DEBUG:LOD"];if(r!=null&&(s=t[E]!=r,e=r),s){t[E]=e;const n=t.geometry,i=p.assignMeshLOD(t,e).then(a=>(a&&t[E]==e&&n!=t.geometry&&this._lodchangedlisteners.forEach(l=>l({type:"mesh",level:e,object:t})),a));return re.addPromise("mesh",t,i,this._newPromiseGroups),i}return Promise.resolve(null)}_sphere=new d.Sphere;_tempWorldPosition=new d.Vector3;static skinnedMeshBoundsFrameOffsetCounter=0;static $skinnedMeshBoundsOffset=Symbol("gltf-progressive-skinnedMeshBoundsOffset");calculateLodLevel(t,e,s,r,n){if(!e){n.mesh_lod=-1,n.texture_lod=-1;return}if(!t){n.mesh_lod=-1,n.texture_lod=-1;return}let a=10+1,l=!1;if(I&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const u=p.getMeshLODExtension(e.geometry)?.lods,f=p.getPrimitiveIndex(e.geometry),c=u&&u.length>0,h=p.getMaterialMinMaxLODsCount(e.material),m=h.min_count!==1/0&&h.min_count>=0&&h.max_count>=0;if(!c&&!m){n.mesh_lod=0,n.texture_lod=0;return}c||(l=!0,a=0);const b=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let x=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const L=e;if(!L.boundingBox)L.computeBoundingBox();else if(this.skinnedMeshAutoUpdateBoundsInterval>0){if(!L[A.$skinnedMeshBoundsOffset]){const w=A.skinnedMeshBoundsFrameOffsetCounter++;L[A.$skinnedMeshBoundsOffset]=w}const v=L[A.$skinnedMeshBoundsOffset];if((s.frames+v)%this.skinnedMeshAutoUpdateBoundsInterval===0){const w=Y(L),W=L.geometry;w&&(L.geometry=w),L.computeBoundingBox(),L.geometry=W}}x=L.boundingBox}if(x){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 w=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(w)){n.mesh_lod=0,n.texture_lod=0;return}}const L=Ve({geometry:e.geometry,matrixWorld:e.matrixWorld,camera:t,projectionScreenMatrix:this.projectionScreenMatrix,desiredDensity:r,canvasHeight:b,currentLevel:s.lastLodLevel_Mesh,boundingBox:x,xrEnabled:this.renderer.xr.enabled,debugDrawLine:I?A.debugDrawLine:void 0,warnMissingPrimitiveDensities:!0});if(s.lastCentrality=L.centrality,s.lastScreenCoverage=L.screenCoverage,s.lastScreenspaceVolume.copy(L.screenspaceVolume),L.screenCoverage===1/0){n.mesh_lod=0,n.texture_lod=0;return}L.level>=0&&L.level<a&&(a=L.level,l=!0)}if(l?n.mesh_lod=a:n.mesh_lod=s.lastLodLevel_Mesh,I&&n.mesh_lod!=s.lastLodLevel_Mesh){const v=u?.[n.mesh_lod];v&&console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} → ${n.mesh_lod} (density: ${v.densities?.[f].toFixed(0)}) | ${e.name}`)}if(m){const L="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(s.lastLodLevel_Texture<0){if(n.texture_lod=h.max_count-1,I){const v=h.lods[h.max_count-1];I&&console.log(`First Texture LOD ${n.texture_lod} (${v.max_height}px) - ${e.name}`)}}else{const v=s.lastScreenspaceVolume.x+s.lastScreenspaceVolume.y+s.lastScreenspaceVolume.z;let w=s.lastScreenCoverage*4;this.context?.engine==="model-viewer"&&(w*=1.5);const W=this.renderer.getPixelRatio?.()||globalThis.devicePixelRatio||1,O=b/W*w;let S=!1;for(let k=h.lods.length-1;k>=0;k--){const R=h.lods[k];if(!(L&&R.max_height>=2048)&&!(_e()&&R.max_height>4096)&&(R.max_height>O||!S&&k===0)){if(S=!0,n.texture_lod=k,I&&n.texture_lod<s.lastLodLevel_Texture){const _=R.max_height;console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${n.texture_lod} = ${_}px
7
+ `,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 Tt{url;key;level;index;constructor(t,e,s,r){this.url=t,this.key=e,this.level=s,r!=null&&(this.index=r)}}class re{static addPromise=(t,e,s,r)=>{r.forEach(n=>{n.add(t,e,s)})};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,s){if(this._resolved){g&&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)){const r=this._seen.get(e);if(r>=this._maxPromisesPerObject){g&&console.warn("PromiseGroup: Already awaiting object ignoring new promise for it.");return}this._seen.set(e,r+1)}else this._seen.set(e,1);this._awaiting.push(s),this._addedCount++,s.finally(()=>{this._resolvedCount++,this._awaiting.splice(this._awaiting.indexOf(s),1)})}}resolveNow(){this._resolved||this._resolve?.({awaited_count:this._addedCount,resolved_count:this._resolvedCount,cancelled:this._signal?.aborted??!1})}}const I=z("debugprogressive"),bt=I==="colors",Ot=z("noprogressive"),fe=Symbol("Needle:LODSManager"),de=Symbol("Needle:LODState"),E=Symbol("Needle:CurrentLOD"),Re=it,C={mesh_lod:-1,texture_lod:-1},St=new d.Color,we=[3526751,11065402,15978811,15897394,15749691,11032304,4827122,3332036,16739229,7306743,14053330,3516499,12035359,14703919,3963096,42662,14100029,8344319,4633680,16229681,3120096,12076434,9083434,2060171,15751837,10182117,48121,62932,16704576,15817653,5083278,5592405];function Rt(){const o=Re.Timer||Re.Clock;return new o}const he=new d.Box3,V=new d.Box3,Ce=new d.Box3,Ct=new d.Vector3,Pt=new d.Vector3,kt=new d.Matrix4,F=new d.Vector3,X=new d.Vector3,K=new d.Vector3,H=new d.Vector3;function At(o,t){const e=o.min,s=o.max,r=(e.x+s.x)*.5,n=(e.y+s.y)*.5;return F.set(r,n,e.z).applyMatrix4(t).z<0}function Ve(o){const{geometry:t,matrixWorld:e,camera:s,projectionScreenMatrix:r,desiredDensity:n,canvasHeight:i=0,currentLevel:a=-1,xrEnabled:l=!1,debugDrawLine:u,warnMissingPrimitiveDensities:f=!1}=o,c=p.getMeshLODExtension(t)?.lods,h=p.getPrimitiveIndex(t),m=o.target??{level:a,primitiveIndex:h,screenCoverage:0,screenspaceVolume:new d.Vector3,centrality:1};m.level=a,m.primitiveIndex=h,m.screenCoverage=0,m.screenspaceVolume.set(0,0,0),m.centrality=1;let b=o.boundingBox??t.boundingBox;if(b||(t.computeBoundingBox(),b=t.boundingBox),!b)return m;if(he.copy(b).applyMatrix4(e),s.isPerspectiveCamera&&At(he,r))return m.level=0,m.screenCoverage=1/0,m.screenspaceVolume.set(1/0,1/0,1/0),m;if(V.copy(he).applyMatrix4(r),l&&s.isPerspectiveCamera&&s.fov>70){const D=V.min,O=V.max;let S=D.x,k=D.y,R=O.x,_=O.y;const y=2,M=1.5,T=(D.x+O.x)*.5,G=(D.y+O.y)*.5;S=(S-T)*y+T,k=(k-G)*y+G,R=(R-T)*y+T,_=(_-G)*y+G;const se=S<0&&R>0?0:Math.min(Math.abs(D.x),Math.abs(O.x)),Ke=k<0&&_>0?0:Math.min(Math.abs(D.y),Math.abs(O.y)),ae=Math.max(se,Ke);m.centrality=(M-ae)*(M-ae)*(M-ae)}const x=V.getSize(Ct);x.multiplyScalar(.5),globalThis.screen?.availHeight>0&&i>0&&x.multiplyScalar(i/globalThis.screen.availHeight),s.isPerspectiveCamera&&(x.x*=s.aspect),Ce.copy(b).applyMatrix4(e).applyMatrix4(s.matrixWorldInverse);const L=Ce.getSize(Pt),v=Math.max(x.x,x.y),w=Math.max(L.x,L.y);v!==0&&w!==0&&(x.z=L.z/w*v);const W=Math.max(x.x,x.y,x.z)*m.centrality;if(m.screenCoverage=W,m.screenspaceVolume.copy(x),W<=0)return m;if(u){const D=kt.copy(r);D.invert(),F.copy(V.min),X.copy(V.max),X.x=F.x,K.copy(V.max),K.y=F.y,H.copy(V.max);const O=(F.z+H.z)*.5;F.z=X.z=K.z=H.z=O,F.applyMatrix4(D),X.applyMatrix4(D),K.applyMatrix4(D),H.applyMatrix4(D),u(F,X,255),u(F,K,255),u(X,H,255),u(K,H,255)}if(c?.length)for(let D=0;D<c.length;D++){const O=c[D],S=O.densities?.[h]||O.density||1e-5;if(h>0&&f&&Fe()&&!O.densities&&!globalThis["NEEDLE:MISSING_LOD_PRIMITIVE_DENSITIES"]&&(globalThis["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.")),S/W<n){m.level=D;break}}return m}class A{static debugDrawLine;static getObjectLODState(t){return t[de]}static addPlugin(t){U.push(t)}static removePlugin(t){const e=U.indexOf(t);e>=0&&U.splice(e,1)}static getPlugins(){return U}static get(t,e){if(t[fe])return console.debug("[gltf-progressive] LODsManager already exists for this renderer"),t[fe];const s=new A(t,{engine:"unknown",...e});return t[fe]=s,s}renderer;context;projectionScreenMatrix=new d.Matrix4;get plugins(){return U}overrideLodLevel=void 0;targetTriangleDensity=2e5;skinnedMeshAutoUpdateBoundsInterval=30;updateInterval="auto";#e=1;pause=!1;manual=!1;_newPromiseGroups=[];_promiseGroupIds=0;awaitLoading(t){const e=this._promiseGroupIds++,s=new re(this.#r,{...t});this._newPromiseGroups.push(s);const r=performance.now();return s.ready.finally(()=>{const n=this._newPromiseGroups.indexOf(s);n>=0&&(this._newPromiseGroups.splice(n,1),Fe()&&performance.measure("LODsManager:awaitLoading",{start:r,detail:{id:e,name:t?.name,awaited:s.awaitedCount,resolved:s.resolvedCount}}))}),s.ready}trackLoadingPromise(t,e,s){return re.addPromise(t,e,s,this._newPromiseGroups),s}_postprocessPromiseGroups(){if(this._newPromiseGroups.length!==0)for(let t=this._newPromiseGroups.length-1;t>=0;t--)this._newPromiseGroups[t].update(this.#r)}_lodchangedlisteners=[];addEventListener(t,e){return t==="changed"?(this._lodchangedlisteners.push(e),()=>{this.removeEventListener(t,e)}):()=>{}}removeEventListener(t,e){let s=!1;if(t==="changed"){const r=this._lodchangedlisteners.indexOf(e);r>=0&&(this._lodchangedlisteners.splice(r,1),s=!0)}return s}constructor(t,e){this.renderer=t,this.context={...e}}#t;#r=0;#n=0;#i=0;#s=0;#o=Rt();_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;ie(this.renderer),this.renderer.render=function(s,r){const n=e.renderer.getRenderTarget();(n==null||"isXRRenderTarget"in n&&n.isXRRenderTarget)&&(t=0,e.#r+=1,e.#o.update?.(),e.#n=Math.max(e.#o.getDelta(),1/1e3),e.#i+=e.#n,e._fpsBuffer.shift(),e._fpsBuffer.push(1/e.#n),e.#s=e._fpsBuffer.reduce((a,l)=>a+l)/e._fpsBuffer.length,I&&e.#r%200===0&&console.log("FPS",Math.round(e.#s),"Interval:",e.#e));const i=t++;e.#t.call(this,s,r),e.onAfterRender(s,r,i)}}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,s){if(this.pause)return;const r=this.getRenderList(t,e,s);if(!r)return;const n=r.opaque;let i=!0;if(n.length===1){const a=n[0].material;(a.name==="EffectMaterial"||a.name==="CopyShader")&&(i=!1)}if((e.parent&&e.parent.type==="CubeCamera"||s>=1&&e.type==="OrthographicCamera")&&(i=!1),i){if(Ot||(this.updateInterval==="auto"?this.#s<40&&this.#e<10?(this.#e+=1,I&&console.warn("↓ Reducing LOD updates",this.#e,this.#s.toFixed(0))):this.#s>=60&&this.#e>1&&(this.#e-=1,I&&console.warn("↑ Increasing LOD updates",this.#e,this.#s.toFixed(0))):this.#e=this.updateInterval,this.#e>0&&this.#r%this.#e!=0))return;this.internalUpdate(t,e),this._postprocessPromiseGroups()}}internalUpdate(t,e){const s=this.getRenderList(t,e,0);if(!s)return;const r=s.opaque;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse);const n=this.targetTriangleDensity;for(const l of r){if(l.material&&(l.geometry?.type==="BoxGeometry"||l.geometry?.type==="BufferGeometry")&&(l.material.name==="SphericalGaussianBlur"||l.material.name=="BackgroundCubeMaterial"||l.material.name==="CubemapFromEquirect"||l.material.name==="EquirectangularToCubeUV")){I&&(l.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(l.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",l,l.material.name,l.material.type)));continue}switch(l.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}const u=l.object;(u instanceof d.Mesh||u.isMesh)&&this.updateLODs(t,e,u,n)}const i=s.transparent;for(const l of i){const u=l.object;(u instanceof d.Mesh||u.isMesh)&&this.updateLODs(t,e,u,n)}const a=s.transmissive;for(const l of a){const u=l.object;(u instanceof d.Mesh||u.isMesh)&&this.updateLODs(t,e,u,n)}}getRenderList(t,e,s){const r=this.renderer;let n=null;if(r.isWebGPURenderer===!0){const i=r._renderLists;if(!i)return null;n=i.get(t,e)}else if(r.isWebGLRenderer===!0){const i=r.renderLists;if(!i)return null;n=i.get(t,s)}return n?{opaque:n.opaque||[],transparent:n.transparent||[],transmissive:n.transmissive||n.transparentDoublePass||[],transparentDoublePass:n.transparentDoublePass||[]}:null}updateLODs(t,e,s,r){s.userData||(s.userData={});let n=s[de];if(n||(n=new It,s[de]=n),n.frames++<2)return;for(const a of U)a.onBeforeUpdateLOD?.(this.renderer,t,e,s);const i=this.overrideLodLevel!==void 0?this.overrideLodLevel:N;i>=0?(C.mesh_lod=i,C.texture_lod=i):(this.calculateLodLevel(e,s,n,r,C),C.mesh_lod=Math.round(C.mesh_lod),C.texture_lod=Math.round(C.texture_lod)),C.mesh_lod>=0&&this.loadProgressiveMeshes(s,C.mesh_lod),s.material&&C.texture_lod>=0&&this.loadProgressiveTextures(s.material,C.texture_lod,i),g&&s.material&&!s.isGizmo&&Ee(s.material),bt&&s.material&&!s.isGizmo&&!s.isBatchedMesh&&ze(s.material,C.mesh_lod);for(const a of U)a.onAfterUpdatedLOD?.(this.renderer,t,e,s,C);n.lastLodLevel_Mesh=C.mesh_lod,n.lastLodLevel_Texture=C.texture_lod}loadProgressiveTextures(t,e,s){if(!t)return;if(Array.isArray(t)){for(const i of t)this.loadProgressiveTextures(i,e,s);return}let r=!1;(t[E]===void 0||e<t[E])&&(r=!0);const n=s!==void 0&&s>=0;if(n&&(r=t[E]!=s,e=s),r){t[E]=e;const i=n?{force:!0}:void 0,a=p.assignTextureLOD(t,e,i).then(l=>{this._lodchangedlisteners.forEach(u=>u({type:"texture",level:e,object:t}))});re.addPromise("texture",t,a,this._newPromiseGroups)}}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);let s=t[E]!==e;const r=t["DEBUG:LOD"];if(r!=null&&(s=t[E]!=r,e=r),s){t[E]=e;const n=t.geometry,i=p.assignMeshLOD(t,e).then(a=>(a&&t[E]==e&&n!=t.geometry&&this._lodchangedlisteners.forEach(l=>l({type:"mesh",level:e,object:t})),a));return re.addPromise("mesh",t,i,this._newPromiseGroups),i}return Promise.resolve(null)}_sphere=new d.Sphere;_tempWorldPosition=new d.Vector3;static skinnedMeshBoundsFrameOffsetCounter=0;static $skinnedMeshBoundsOffset=Symbol("gltf-progressive-skinnedMeshBoundsOffset");calculateLodLevel(t,e,s,r,n){if(!e){n.mesh_lod=-1,n.texture_lod=-1;return}if(!t){n.mesh_lod=-1,n.texture_lod=-1;return}let a=10+1,l=!1;if(I&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const u=p.getMeshLODExtension(e.geometry)?.lods,f=p.getPrimitiveIndex(e.geometry),c=u&&u.length>0,h=p.getMaterialMinMaxLODsCount(e.material),m=h.min_count!==1/0&&h.min_count>=0&&h.max_count>=0;if(!c&&!m){n.mesh_lod=0,n.texture_lod=0;return}c||(l=!0,a=0);const b=this.renderer.domElement.clientHeight||this.renderer.domElement.height;let x=e.geometry.boundingBox;if(e.type==="SkinnedMesh"){const L=e;if(!L.boundingBox)L.computeBoundingBox();else if(this.skinnedMeshAutoUpdateBoundsInterval>0){if(!L[A.$skinnedMeshBoundsOffset]){const w=A.skinnedMeshBoundsFrameOffsetCounter++;L[A.$skinnedMeshBoundsOffset]=w}const v=L[A.$skinnedMeshBoundsOffset];if((s.frames+v)%this.skinnedMeshAutoUpdateBoundsInterval===0){const w=Y(L),W=L.geometry;w&&(L.geometry=w),L.computeBoundingBox(),L.geometry=W}}x=L.boundingBox}if(x){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 w=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(w)){n.mesh_lod=0,n.texture_lod=0;return}}const L=Ve({geometry:e.geometry,matrixWorld:e.matrixWorld,camera:t,projectionScreenMatrix:this.projectionScreenMatrix,desiredDensity:r,canvasHeight:b,currentLevel:s.lastLodLevel_Mesh,boundingBox:x,xrEnabled:this.renderer.xr.enabled,debugDrawLine:I?A.debugDrawLine:void 0,warnMissingPrimitiveDensities:!0});if(s.lastCentrality=L.centrality,s.lastScreenCoverage=L.screenCoverage,s.lastScreenspaceVolume.copy(L.screenspaceVolume),L.screenCoverage===1/0){n.mesh_lod=0,n.texture_lod=0;return}L.level>=0&&L.level<a&&(a=L.level,l=!0)}if(l?n.mesh_lod=a:n.mesh_lod=s.lastLodLevel_Mesh,I&&n.mesh_lod!=s.lastLodLevel_Mesh){const v=u?.[n.mesh_lod];v&&console.log(`Mesh LOD changed: ${s.lastLodLevel_Mesh} → ${n.mesh_lod} (density: ${v.densities?.[f].toFixed(0)}) | ${e.name}`)}if(m){const L="saveData"in globalThis.navigator&&globalThis.navigator.saveData===!0;if(s.lastLodLevel_Texture<0){if(n.texture_lod=h.max_count-1,I){const v=h.lods[h.max_count-1];I&&console.log(`First Texture LOD ${n.texture_lod} (${v.max_height}px) - ${e.name}`)}}else{const v=s.lastScreenspaceVolume.x+s.lastScreenspaceVolume.y+s.lastScreenspaceVolume.z;let w=s.lastScreenCoverage*4;this.context?.engine==="model-viewer"&&(w*=1.5);const W=this.renderer.getPixelRatio?.()||globalThis.devicePixelRatio||1,O=b/W*w;let S=!1;for(let k=h.lods.length-1;k>=0;k--){const R=h.lods[k];if(!(L&&R.max_height>=2048)&&!(_e()&&R.max_height>4096)&&(R.max_height>O||!S&&k===0)){if(S=!0,n.texture_lod=k,I&&n.texture_lod<s.lastLodLevel_Texture){const _=R.max_height;console.log(`Texture LOD changed: ${s.lastLodLevel_Texture} → ${n.texture_lod} = ${_}px
8
8
  Screensize: ${O.toFixed(0)}px, Coverage: ${(100*s.lastScreenCoverage).toFixed(2)}%, Volume ${v.toFixed(1)}
9
9
  ${e.name}`)}break}}}}else n.texture_lod=0}}class It{frames=0;lastLodLevel_Mesh=-1;lastLodLevel_Texture=-1;lastScreenCoverage=0;lastScreenspaceVolume=new d.Vector3;lastCentrality=0}function ze(o,t){if(!(t<0)){if(Array.isArray(o)){for(const e of o)ze(e,t);return}"color"in o&&o.color instanceof d.Color&&(o.color.copy(Ne(t,St)),o.needsUpdate=!0)}}function Ne(o,t){const e=Math.max(0,Math.min(we.length-1,Math.floor(o)));return t.setHex(we[e])}const Pe=Symbol("NEEDLE_mesh_lod"),ne=Symbol("NEEDLE_texture_lod");let ge=null;function be(){const o=$t();o&&(o.mapURLs(function(t){return ke(),t}),ke(),ge?.disconnect(),ge=new MutationObserver(t=>{t.forEach(e=>{e.addedNodes.forEach(s=>{s instanceof HTMLElement&&s.tagName.toLowerCase()==="model-viewer"&&je(s)})})}),ge.observe(document,{childList:!0,subtree:!0}))}function $t(){if(typeof customElements>"u")return null;const o=customElements.get("model-viewer");return o||(customElements.whenDefined("model-viewer").then(()=>{console.debug("[gltf-progressive] model-viewer defined"),be()}),null)}function ke(){if(typeof document>"u")return;document.querySelectorAll("model-viewer").forEach(t=>{je(t)})}const Ae=new WeakSet;let Bt=0;function je(o){if(!o||Ae.has(o))return null;Ae.add(o),console.debug("[gltf-progressive] found new model-viewer..."+ ++Bt+`
10
10
  `,o.getAttribute("src"));let t=null,e=null,s=null;for(let r=o;r!=null;r=Object.getPrototypeOf(r)){const n=Object.getOwnPropertySymbols(r),i=n.find(u=>u.toString()=="Symbol(renderer)"),a=n.find(u=>u.toString()=="Symbol(scene)"),l=n.find(u=>u.toString()=="Symbol(needsRender)");!t&&i!=null&&(t=o[i].threeRenderer),!e&&a!=null&&(e=o[a]),!s&&l!=null&&(s=o[l])}if(t&&e){let r=function(){if(s){let i=0;const a=setInterval(()=>{if(i++>5){clearInterval(a);return}s?.call(o)},300)}};console.debug("[gltf-progressive] setup model-viewer");const n=A.get(t,{engine:"model-viewer"});return A.addPlugin(new Gt),n.enable(),n.addEventListener("changed",()=>{s?.call(o)}),o.addEventListener("model-visibility",i=>{i.detail.visible&&s?.call(o)}),o.addEventListener("load",()=>{r()}),()=>{n.disable()}}return null}class Gt{_didWarnAboutMissingUrl=!1;onBeforeUpdateLOD(t,e,s,r){this.tryParseMeshLOD(e,r),this.tryParseTextureLOD(e,r)}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 s=this.tryGetCurrentGLTF(t),r=this.tryGetCurrentModelViewer(t),n=this.getUrl(r);if(n&&s&&e.material){let i=function(l){if(l[ne]==!0)return;l[ne]=!0,l.userData&&(l.userData.LOD=-1);const u=Object.keys(l);for(let f=0;f<u.length;f++){const c=u[f],h=l[c];if(h?.isTexture===!0){const m=h.userData?.associations?.textures;if(m==null)continue;const b=s.parser.json.textures[m];if(!b){console.warn("Texture data not found for texture index "+m);continue}if(b?.extensions?.[q]){const x=b.extensions[q];x&&n&&p.registerTexture(n,h,x.lods.length,m,x)}}}};const a=e.material;if(Array.isArray(a))for(const l of a)i(l);else i(a)}}tryParseMeshLOD(t,e){if(e[Pe]==!0)return;e[Pe]=!0;const s=this.tryGetCurrentModelViewer(t),r=this.getUrl(s);if(!r)return;const n=e.userData?.gltfExtensions?.[q];if(n&&r){const i=e.uuid;p.registerMesh(r,i,e,0,n.lods.length,n)}}}function Xe(...o){let t,e,s,r;switch(o.length){case 2:[s,e]=o,r={};break;case 3:[s,e,r]=o;break;case 4:[t,e,s,r]=o;break;default:throw new Error("Invalid arguments")}ie(e),De(s),Me(s,{progressive:!0,...r?.hints}),s.register(i=>new p(i));const n=A.get(e);return r?.enableLODsManager!==!1&&n.enable(),n}be();if(!xt){const o={gltfProgressive:{useNeedleProgressive:Xe,LODsManager:A,configureLoader:Me,getRaycastMesh:Y,useRaycastMeshes:We}};if(!globalThis.Needle)globalThis.Needle=o;else for(const t in o)globalThis.Needle[t]=o[t]}exports.EXTENSION_NAME=q;exports.LODsManager=A;exports.NEEDLE_progressive=p;exports.VERSION=Ie;exports.addDracoAndKTX2Loaders=De;exports.calculateMeshLODLevel=Ve;exports.configureLoader=Me;exports.createLoaders=ie;exports.getLODColor=Ne;exports.getRaycastMesh=Y;exports.lodDebugColors=we;exports.patchModelViewer=be;exports.registerRaycastMesh=Ue;exports.setDracoDecoderLocation=Be;exports.setKTX2TranscoderLocation=Ge;exports.useNeedleProgressive=Xe;exports.useRaycastMeshes=We;
package/lib/loaders.d.ts CHANGED
@@ -28,7 +28,14 @@ export declare function setKTX2TranscoderLocation(location: string): void;
28
28
  export declare function createLoaders(renderer: WebGLRenderer | null): {
29
29
  dracoLoader: DRACOLoader;
30
30
  ktx2Loader: KTX2Loader;
31
- meshoptDecoder: any;
31
+ meshoptDecoder: {
32
+ supported: boolean;
33
+ ready: Promise<void>;
34
+ decodeVertexBuffer: (target: Uint8Array, count: number, size: number, source: Uint8Array, filter?: string) => void;
35
+ decodeIndexBuffer: (target: Uint8Array, count: number, size: number, source: Uint8Array) => void;
36
+ decodeIndexSequence: (target: Uint8Array, count: number, size: number, source: Uint8Array) => void;
37
+ decodeGltfBuffer: (target: Uint8Array, count: number, size: number, source: Uint8Array, mode: string, filter?: string) => void;
38
+ };
32
39
  };
33
40
  export declare function addDracoAndKTX2Loaders(loader: GLTFLoader): void;
34
41
  /**
@@ -88,8 +88,10 @@ export function calculateMeshLODLevel(options) {
88
88
  result.screenCoverage = 0;
89
89
  result.screenspaceVolume.set(0, 0, 0);
90
90
  result.centrality = 1;
91
- if (!meshLods?.length)
92
- return result;
91
+ // Note: we intentionally do NOT early-return when there are no mesh LODs.
92
+ // The screen coverage / screenspace volume computed below is also consumed by
93
+ // the texture LOD selection, which must keep working for meshes that only have
94
+ // texture LODs (no mesh LODs). Only the mesh LOD-level selection loop is skipped.
93
95
  let boundingBox = options.boundingBox ?? geometry.boundingBox;
94
96
  if (!boundingBox) {
95
97
  geometry.computeBoundingBox();
@@ -165,16 +167,18 @@ export function calculateMeshLODLevel(options) {
165
167
  debugDrawLine(_meshLODCorner1, _meshLODCorner3, 0x0000ff);
166
168
  debugDrawLine(_meshLODCorner2, _meshLODCorner3, 0x0000ff);
167
169
  }
168
- for (let i = 0; i < meshLods.length; i++) {
169
- const lod = meshLods[i];
170
- const density = lod.densities?.[primitiveIndex] || lod.density || .00001;
171
- if (primitiveIndex > 0 && warnMissingPrimitiveDensities && isDevelopmentServer() && !lod.densities && !globalThis["NEEDLE:MISSING_LOD_PRIMITIVE_DENSITIES"]) {
172
- globalThis["NEEDLE:MISSING_LOD_PRIMITIVE_DENSITIES"] = true;
173
- 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.`);
174
- }
175
- if (density / screenCoverage < desiredDensity) {
176
- result.level = i;
177
- break;
170
+ if (meshLods?.length) {
171
+ for (let i = 0; i < meshLods.length; i++) {
172
+ const lod = meshLods[i];
173
+ const density = lod.densities?.[primitiveIndex] || lod.density || .00001;
174
+ if (primitiveIndex > 0 && warnMissingPrimitiveDensities && isDevelopmentServer() && !lod.densities && !globalThis["NEEDLE:MISSING_LOD_PRIMITIVE_DENSITIES"]) {
175
+ globalThis["NEEDLE:MISSING_LOD_PRIMITIVE_DENSITIES"] = true;
176
+ 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.`);
177
+ }
178
+ if (density / screenCoverage < desiredDensity) {
179
+ result.level = i;
180
+ break;
181
+ }
178
182
  }
179
183
  }
180
184
  return result;
package/lib/utils.d.ts CHANGED
@@ -5,7 +5,7 @@ export declare const isSSR: boolean;
5
5
  * @param obj the object to get the raycast mesh from
6
6
  * @returns the raycast mesh or null if not set
7
7
  */
8
- export declare function getRaycastMesh(obj: Object3D): BufferGeometry<any, any> | null;
8
+ export declare function getRaycastMesh(obj: Object3D): BufferGeometry<any> | null;
9
9
  /**
10
10
  * Set the raycast mesh for an object.
11
11
  * The raycast mesh is a low poly version of the mesh used for raycasting. It is set when a mesh that has LOD level with more vertices is discovered for the first time
@@ -106,8 +106,14 @@ export class PromiseQueue {
106
106
  constructor(maxConcurrent, opts = {}) {
107
107
  this.maxConcurrent = maxConcurrent;
108
108
  this.debug = opts.debug ?? false;
109
- if (typeof window !== "undefined")
110
- window.requestAnimationFrame(this.tick);
109
+ // Dedicated workers can have requestAnimationFrame when they are owned by a window.
110
+ // Other worker-like scopes do not, so keep the frame-based tick when available and fall back to timers otherwise.
111
+ if (typeof globalThis.requestAnimationFrame === "function") {
112
+ globalThis.requestAnimationFrame(this.tick);
113
+ }
114
+ else {
115
+ setTimeout(this.tick, 0);
116
+ }
111
117
  }
112
118
  tick = () => {
113
119
  this.internalUpdate();
package/lib/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  // replaced at build time
2
- export const version = "3.6.0-alpha.3";
2
+ export const version = "3.6.0";
3
3
  globalThis["GLTF_PROGRESSIVE_VERSION"] = version;
4
4
  console.debug(`[gltf-progressive] version ${version || "-"}`);