@needle-tools/gltf-progressive 1.0.0-alpha.13 → 1.0.0-alpha.14

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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,9 @@ All notable changes to this package will be documented in this file.
4
4
  The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5
5
  and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [1.0.0-alpha.13] - 2023-05-24
8
+ - fix: modelviewer error when trying to access undefined texture extensions
9
+
7
10
  ## [1.0.0-alpha.13] - 2023-05-24
8
11
  - add: vanilla three.js example
9
12
  - fix: texture LODs losing filter setting
package/README.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  Support for loading of glTF or GLB files with progressive mesh or texture data for three.js based engines.
4
4
 
5
+ ## Samples
6
+
7
+ - [Vanilla three.js Example](https://engine.needle.tools/demos/gltf-progressive/threejs/)
8
+ - [\<model-viewer\> Example](https://engine.needle.tools/demos/gltf-progressive/modelviewer)
9
+
10
+
5
11
  # Contact ✒️
6
12
  <b>[🌵 needle — tools for creators](https://needle.tools)</b> •
7
13
  [Twitter](https://twitter.com/NeedleTools) •
@@ -11,10 +11,10 @@
11
11
  }
12
12
  </script>
13
13
  <script type="module" src="https://ajax.googleapis.com/ajax/libs/model-viewer/3.4.0/model-viewer.min.js"></script>
14
- <script type="module" src="https://www.unpkg.com/@needle-tools/gltf-progressive@1.0.0-alpha.4"></script>
14
+ <script type="module" src="https://www.unpkg.com/@needle-tools/gltf-progressive@latest"></script>
15
15
  </head>
16
16
 
17
- <model-viewer src="https://engine.needle.tools/demos/lods/assets/ganesha.glb" ar shadow-intensity="1" camera-controls
17
+ <model-viewer src="https://engine.needle.tools/demos/gltf-progressive/assets/church/model.glb" ar shadow-intensity="1" camera-controls
18
18
  touch-action="pan-y"></model-viewer>
19
19
 
20
20
  <style>
@@ -3,7 +3,7 @@
3
3
 
4
4
  <head>
5
5
  <meta charset="utf-8">
6
- <title>My first three.js app</title>
6
+ <title>Threejs Progressive Loading</title>
7
7
  <style>
8
8
  body {
9
9
  margin: 0;
@@ -20,16 +20,16 @@ window.addEventListener('resize', () => {
20
20
  });
21
21
 
22
22
  const orbit = new OrbitControls(camera, renderer.domElement);
23
- orbit.target = new THREE.Vector3(0, .6, 0);
24
- camera.position.x = -1;
25
- camera.position.y = 1.5;
26
- camera.position.z = 1.8;
23
+ orbit.target = new THREE.Vector3(0, 14, 0);
24
+ camera.position.x = 20;
25
+ camera.position.y = 20.5;
26
+ camera.position.z = 20.8;
27
27
 
28
- const grid = new THREE.GridHelper(10, 10, 0x444444, 0x666666);
28
+ const grid = new THREE.GridHelper(50, 50, 0x444444, 0x666666);
29
29
  scene.add(grid);
30
30
 
31
- const directionalLight = new THREE.DirectionalLight(0xffffff, .2);
32
- directionalLight.position.set(1, 1, 0);
31
+ const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
32
+ directionalLight.position.set(-50, 20, 50);
33
33
  scene.add(directionalLight);
34
34
 
35
35
 
@@ -56,7 +56,7 @@ new EXRLoader().load(environmentTextureUrl, texture => {
56
56
 
57
57
  // Integrate @needle-tools/gltf-progressive
58
58
  // This is the model we want to load
59
- const url = "https://engine.needle.tools/demos/gltf-progressive/threejs/assets/model.glb";
59
+ const url = "https://engine.needle.tools/demos/gltf-progressive/assets/church/model.glb";
60
60
 
61
61
  const gltfLoader = new GLTFLoader();
62
62
 
@@ -1,7 +1,7 @@
1
1
  var le = Object.defineProperty;
2
2
  var ue = (l, e, t) => e in l ? le(l, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : l[e] = t;
3
3
  var c = (l, e, t) => (ue(l, typeof e != "symbol" ? e + "" : e, t), t);
4
- import { Mesh as q, BufferGeometry as Y, Material as ce, Texture as I, TextureLoader as fe, Matrix4 as te, Frustum as de, Sphere as ge, Box3 as re, Vector3 as C } from "three";
4
+ import { Mesh as q, BufferGeometry as Y, Material as ce, Texture as I, TextureLoader as fe, Matrix4 as te, Frustum as de, Sphere as ge, Box3 as re, Vector3 as R } from "three";
5
5
  import { GLTFLoader as he } from "three/examples/jsm/loaders/GLTFLoader.js";
6
6
  import { MeshoptDecoder as pe } from "three/examples/jsm/libs/meshopt_decoder.module.js";
7
7
  import { DRACOLoader as ye } from "three/examples/jsm/loaders/DRACOLoader.js";
@@ -43,7 +43,7 @@ const Q = new Array();
43
43
  function ke(l) {
44
44
  Q.push(l);
45
45
  }
46
- const R = "NEEDLE_progressive", S = ee("debugprogressive"), V = Symbol("needle-progressive-texture"), z = /* @__PURE__ */ new Map(), Z = /* @__PURE__ */ new Set();
46
+ const E = "NEEDLE_progressive", S = ee("debugprogressive"), V = Symbol("needle-progressive-texture"), z = /* @__PURE__ */ new Map(), Z = /* @__PURE__ */ new Set();
47
47
  if (S) {
48
48
  let l = function() {
49
49
  e += 1, console.log("Toggle LOD level", e, z), z.forEach((i, n) => {
@@ -81,7 +81,7 @@ const M = class {
81
81
  }
82
82
  /** The name of the extension */
83
83
  get name() {
84
- return R;
84
+ return E;
85
85
  }
86
86
  static getMeshLODInformation(e) {
87
87
  const t = this.getAssignedLODInformation(e);
@@ -217,7 +217,7 @@ const M = class {
217
217
  var t, r;
218
218
  return S && console.log("AFTER", this.url, e), (t = this.parser.json.textures) == null || t.forEach((i, n) => {
219
219
  if (i != null && i.extensions) {
220
- const s = i == null ? void 0 : i.extensions[R];
220
+ const s = i == null ? void 0 : i.extensions[E];
221
221
  if (s) {
222
222
  let o = !1;
223
223
  for (const a of this.parser.associations.keys())
@@ -229,7 +229,7 @@ const M = class {
229
229
  }
230
230
  }), (r = this.parser.json.meshes) == null || r.forEach((i, n) => {
231
231
  if (i != null && i.extensions) {
232
- const s = i == null ? void 0 : i.extensions[R];
232
+ const s = i == null ? void 0 : i.extensions[E];
233
233
  if (s && s.lods) {
234
234
  for (const o of this.parser.associations.keys())
235
235
  if (o.isMesh) {
@@ -269,11 +269,11 @@ const M = class {
269
269
  if (h !== void 0) {
270
270
  r && console.log(`LOD ${t} was already loading/loaded: ${u}`);
271
271
  let x = await h.catch((F) => (console.error(`Error loading LOD ${t} from ${p}
272
- `, F), null)), k = !1;
273
- if (x == null || (x instanceof I && e instanceof I ? (o = x.image) != null && o.data || (a = x.source) != null && a.data ? x = this.copySettings(e, x) : (k = !0, this.previouslyLoaded.delete(u)) : x instanceof Y && e instanceof Y && ((g = x.attributes.position) != null && g.array || (k = !0, this.previouslyLoaded.delete(u)))), !k)
272
+ `, F), null)), C = !1;
273
+ if (x == null || (x instanceof I && e instanceof I ? (o = x.image) != null && o.data || (a = x.source) != null && a.data ? x = this.copySettings(e, x) : (C = !0, this.previouslyLoaded.delete(u)) : x instanceof Y && e instanceof Y && ((g = x.attributes.position) != null && g.array || (C = !0, this.previouslyLoaded.delete(u)))), !C)
274
274
  return x;
275
275
  }
276
- const D = s, A = new Promise(async (x, k) => {
276
+ const D = s, b = new Promise(async (x, C) => {
277
277
  const F = new he();
278
278
  oe(F), S && (await new Promise((m) => setTimeout(m, 1e3)), r && console.warn("Start loading (delayed) " + p, D.guid));
279
279
  let L = p;
@@ -292,7 +292,7 @@ const M = class {
292
292
  let m = !1;
293
293
  for (const d of y.parser.json.textures) {
294
294
  if (d != null && d.extensions) {
295
- const O = d == null ? void 0 : d.extensions[R];
295
+ const O = d == null ? void 0 : d.extensions[E];
296
296
  if (O != null && O.guid && O.guid === D.guid) {
297
297
  m = !0;
298
298
  break;
@@ -309,7 +309,7 @@ const M = class {
309
309
  let m = !1;
310
310
  for (const d of y.parser.json.meshes) {
311
311
  if (d != null && d.extensions) {
312
- const O = d == null ? void 0 : d.extensions[R];
312
+ const O = d == null ? void 0 : d.extensions[E];
313
313
  if (O != null && O.guid && O.guid === D.guid) {
314
314
  m = !0;
315
315
  break;
@@ -325,9 +325,9 @@ const M = class {
325
325
  } else {
326
326
  const P = new Array();
327
327
  for (let _ = 0; _ < d.children.length; _++) {
328
- const E = d.children[_];
329
- if (E instanceof q) {
330
- const N = E.geometry;
328
+ const G = d.children[_];
329
+ if (G instanceof q) {
330
+ const N = G.geometry;
331
331
  M.assignLODInformation(i.url, N, n, t, _, O.density), P.push(N);
332
332
  }
333
333
  }
@@ -337,7 +337,7 @@ const M = class {
337
337
  }
338
338
  return x(null);
339
339
  });
340
- return this.previouslyLoaded.set(u, A), await A;
340
+ return this.previouslyLoaded.set(u, b), await b;
341
341
  } else if (e instanceof I) {
342
342
  r && console.log("Load texture from uri: " + p);
343
343
  const h = await new fe().loadAsync(p);
@@ -400,7 +400,7 @@ class De {
400
400
  this.url = e, this.key = t, this.level = r, i != null && (this.index = i), n != null && (this.density = n);
401
401
  }
402
402
  }
403
- const H = ee("debugprogressive"), xe = ee("noprogressive"), b = class {
403
+ const H = ee("debugprogressive"), xe = ee("noprogressive"), A = class {
404
404
  constructor(e) {
405
405
  c(this, "renderer");
406
406
  c(this, "projectionScreenMatrix", new te());
@@ -420,9 +420,9 @@ const H = ee("debugprogressive"), xe = ee("noprogressive"), b = class {
420
420
  c(this, "_sphere", new ge());
421
421
  c(this, "_tempBox", new re());
422
422
  c(this, "tempMatrix", new te());
423
- c(this, "_tempWorldPosition", new C());
424
- c(this, "_tempBoxSize", new C());
425
- c(this, "_tempBox2Size", new C());
423
+ c(this, "_tempWorldPosition", new R());
424
+ c(this, "_tempBoxSize", new R());
425
+ c(this, "_tempBox2Size", new R());
426
426
  this.renderer = e;
427
427
  }
428
428
  /** @internal */
@@ -549,8 +549,8 @@ const H = ee("debugprogressive"), xe = ee("noprogressive"), b = class {
549
549
  if (this._tempBox.copy(f), this._tempBox.applyMatrix4(t.matrixWorld), this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled && p.fov > 70) {
550
550
  const L = this._tempBox.min, y = this._tempBox.max;
551
551
  let T = L.x, w = L.y, m = y.x, d = y.y;
552
- const O = 2, P = 1.5, _ = (L.x + y.x) * 0.5, E = (L.y + y.y) * 0.5;
553
- T = (T - _) * O + _, w = (w - E) * O + E, m = (m - _) * O + _, d = (d - E) * O + E;
552
+ const O = 2, P = 1.5, _ = (L.x + y.x) * 0.5, G = (L.y + y.y) * 0.5;
553
+ T = (T - _) * O + _, w = (w - G) * O + G, m = (m - _) * O + _, d = (d - G) * O + G;
554
554
  const N = T < 0 && m > 0 ? 0 : Math.min(Math.abs(L.x), Math.abs(y.x)), ae = w < 0 && d > 0 ? 0 : Math.min(Math.abs(L.y), Math.abs(y.y)), X = Math.max(N, ae);
555
555
  r.lastCentrality = (P - X) * (P - X) * (P - X);
556
556
  } else
@@ -559,38 +559,38 @@ const H = ee("debugprogressive"), xe = ee("noprogressive"), b = class {
559
559
  u.multiplyScalar(0.5), screen.availHeight > 0 && u.multiplyScalar(this.renderer.domElement.clientHeight / screen.availHeight), u.x *= p.aspect;
560
560
  const h = e.matrixWorldInverse, D = new re();
561
561
  D.copy(f), D.applyMatrix4(t.matrixWorld), D.applyMatrix4(h);
562
- const A = D.getSize(this._tempBox2Size), G = Math.max(A.x, A.y);
563
- if (Math.max(u.x, u.y) != 0 && G != 0 && (u.z = A.z / Math.max(A.x, A.y) * Math.max(u.x, u.y)), r.lastScreenCoverage = Math.max(u.x, u.y, u.z), r.lastScreenspaceVolume.copy(u), r.lastScreenCoverage *= r.lastCentrality, H && b.debugDrawLine) {
562
+ const b = D.getSize(this._tempBox2Size), k = Math.max(b.x, b.y);
563
+ if (Math.max(u.x, u.y) != 0 && k != 0 && (u.z = b.z / Math.max(b.x, b.y) * Math.max(u.x, u.y)), r.lastScreenCoverage = Math.max(u.x, u.y, u.z), r.lastScreenspaceVolume.copy(u), r.lastScreenCoverage *= r.lastCentrality, H && A.debugDrawLine) {
564
564
  const L = this.tempMatrix.copy(this.projectionScreenMatrix);
565
565
  L.invert();
566
- const y = b.corner0, T = b.corner1, w = b.corner2, m = b.corner3;
566
+ const y = A.corner0, T = A.corner1, w = A.corner2, m = A.corner3;
567
567
  y.copy(this._tempBox.min), T.copy(this._tempBox.max), T.x = y.x, w.copy(this._tempBox.max), w.y = y.y, m.copy(this._tempBox.max);
568
568
  const d = (y.z + m.z) * 0.5;
569
- y.z = T.z = w.z = m.z = d, y.applyMatrix4(L), T.applyMatrix4(L), w.applyMatrix4(L), m.applyMatrix4(L), b.debugDrawLine(y, T, 255), b.debugDrawLine(y, w, 255), b.debugDrawLine(T, m, 255), b.debugDrawLine(w, m, 255);
569
+ y.z = T.z = w.z = m.z = d, y.applyMatrix4(L), T.applyMatrix4(L), w.applyMatrix4(L), m.applyMatrix4(L), A.debugDrawLine(y, T, 255), A.debugDrawLine(y, w, 255), A.debugDrawLine(T, m, 255), A.debugDrawLine(w, m, 255);
570
570
  }
571
- let k = 999;
571
+ let C = 999;
572
572
  if (g && r.lastScreenCoverage > 0) {
573
573
  for (let L = 0; L < g.length; L++)
574
574
  if (g[L].density / r.lastScreenCoverage < i) {
575
- k = L;
575
+ C = L;
576
576
  break;
577
577
  }
578
578
  }
579
- k < s && (s = k);
579
+ C < s && (s = C);
580
580
  }
581
581
  }
582
582
  return s;
583
583
  }
584
584
  };
585
- let B = b;
585
+ let B = A;
586
586
  /** Assign a function to draw debug lines for the LODs. This function will be called with the start and end position of the line and the color of the line when the `debugprogressive` query parameter is set.
587
587
  */
588
- c(B, "debugDrawLine"), c(B, "corner0", new C()), c(B, "corner1", new C()), c(B, "corner2", new C()), c(B, "corner3", new C());
588
+ c(B, "debugDrawLine"), c(B, "corner0", new R()), c(B, "corner1", new R()), c(B, "corner2", new R()), c(B, "corner3", new R());
589
589
  class we {
590
590
  constructor() {
591
591
  c(this, "lastLodLevel", 0);
592
592
  c(this, "lastScreenCoverage", 0);
593
- c(this, "lastScreenspaceVolume", new C());
593
+ c(this, "lastScreenspaceVolume", new R());
594
594
  c(this, "lastCentrality", 0);
595
595
  }
596
596
  }
@@ -647,9 +647,13 @@ class Me {
647
647
  for (let u = 0; u < a.length; u++) {
648
648
  const h = a[u], D = o[h];
649
649
  if ((D == null ? void 0 : D.isTexture) === !0) {
650
- const A = (f = (g = D.userData) == null ? void 0 : g.associations) == null ? void 0 : f.textures, G = r.parser.json.textures[A];
651
- if ((p = G.extensions) != null && p[R]) {
652
- const x = G.extensions[R];
650
+ const b = (f = (g = D.userData) == null ? void 0 : g.associations) == null ? void 0 : f.textures, k = r.parser.json.textures[b];
651
+ if (!k) {
652
+ console.warn("Texture data not found for texture index " + b);
653
+ continue;
654
+ }
655
+ if ((p = k == null ? void 0 : k.extensions) != null && p[E]) {
656
+ const x = k.extensions[E];
653
657
  x && i && v.registerTexture(i, D, x.lods.length, x);
654
658
  }
655
659
  }
@@ -671,7 +675,7 @@ class Me {
671
675
  const r = this.getUrl();
672
676
  if (!r)
673
677
  return;
674
- const i = (s = (n = t.userData) == null ? void 0 : n.gltfExtensions) == null ? void 0 : s[R];
678
+ const i = (s = (n = t.userData) == null ? void 0 : n.gltfExtensions) == null ? void 0 : s[E];
675
679
  if (i && r) {
676
680
  const o = t.uuid;
677
681
  v.registerMesh(r, o, t, 0, i.lods.length, i);
@@ -687,7 +691,7 @@ document.addEventListener("DOMContentLoaded", () => {
687
691
  Oe(document.querySelector("model-viewer"));
688
692
  });
689
693
  export {
690
- R as EXTENSION_NAME,
694
+ E as EXTENSION_NAME,
691
695
  B as LODsManager,
692
696
  v as NEEDLE_progressive,
693
697
  oe as addDracoAndKTX2Loaders,
@@ -1,3 +1,3 @@
1
- var ne=Object.defineProperty,ie=(r,e,t)=>e in r?ne(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t,c=(r,e,t)=>(ie(r,typeof e!="symbol"?e+"":e,t),t);import{Mesh as W,BufferGeometry as $,Material as ae,Texture as C,TextureLoader as le,Matrix4 as ee,Frustum as ue,Sphere as ce,Box3 as re,Vector3 as B}from"three";import{GLTFLoader as de}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as he}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as fe}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as ge}from"three/examples/jsm/loaders/KTX2Loader.js";let U="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",q="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(U+"draco_decoder.js",{method:"head"}).catch(r=>{U="./include/draco/",q="./include/ktx2/"});function me(r){U=r}function pe(r){q=r}let R,V,G;function X(r){R||(R=new fe,R.setDecoderPath(U),R.setDecoderConfig({type:"js"})),G||(G=new ge,G.setTranscoderPath(q)),V||(V=he),r?G.detectSupport(r):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function K(r){r.dracoLoader||r.setDRACOLoader(R),r.ktx2Loader||r.setKTX2Loader(G),r.meshoptDecoder||r.setMeshoptDecoder(V)}function H(r){const e=new URL(window.location.href).searchParams.get(r);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function ye(r,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||r===void 0)return e;const t=r.lastIndexOf("/");if(t>=0){const o=r.substring(0,t+1);for(;o.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return o+e}return e}const Y=new Array;function Le(r){Y.push(r)}const P="NEEDLE_progressive",v=H("debugprogressive"),J=Symbol("needle-progressive-texture"),N=new Map,Q=new Set;if(v){let r=function(){e+=1,console.log("Toggle LOD level",e,N),N.forEach((n,s)=>{for(const a of n.keys){const i=s[a];if(i.isBufferGeometry===!0){const l=w.getMeshLODInformation(i),d=l?Math.min(e,l.lods.length):0;s["DEBUG:LOD"]=e,w.assignMeshLOD(s,d),l&&(t=Math.max(t,l.lods.length-1))}else if(s.isMaterial===!0){s["DEBUG:LOD"]=e,w.assignTextureLOD(s,e);break}}}),e>=t&&(e=-1)},e=-1,t=2,o=!1;window.addEventListener("keyup",n=>{n.key==="p"&&r(),n.key==="w"&&(o=!o,Q&&Q.forEach(s=>{s.name!="BackgroundCubeMaterial"&&"wireframe"in s&&(s.wireframe=o)}))})}function te(r,e,t){var o;if(!v)return;N.has(r)||N.set(r,{keys:[],sourceId:t});const n=N.get(r);((o=n?.keys)==null?void 0:o.includes(e))==!1&&n.keys.push(e)}const O=class{constructor(r,e){c(this,"parser"),c(this,"url"),v&&console.log("Progressive extension registered for",e),this.parser=r,this.url=e}get name(){return P}static getMeshLODInformation(r){const e=this.getAssignedLODInformation(r);return e!=null&&e.key?this.lodInfos.get(e.key):null}static hasLODLevelAvailable(r,e){var t;if(r.isMaterial===!0){for(const s of Object.keys(r)){const a=r[s];if(a.isTexture&&this.hasLODLevelAvailable(a,e))return!0}return!1}else if(r.isGroup===!0){for(const s of r.children)if(s.isMesh===!0&&this.hasLODLevelAvailable(s,e))return!0}let o,n;if(r.isMesh?o=r.geometry:(r.isBufferGeometry||r.isTexture)&&(o=r),o&&(t=o?.userData)!=null&&t.LODS){const s=o.userData.LODS;if(n=this.lodInfos.get(s.key),e===void 0)return n!=null;if(n)return Array.isArray(n.lods)?e<n.lods.length:e===0}return!1}static assignMeshLOD(r,e){var t;if(!r)return Promise.resolve(null);if(r instanceof W||r.isMesh===!0){const o=r.geometry,n=this.getAssignedLODInformation(o);if(!n)return Promise.resolve(null);for(const s of Y)(t=s.onBeforeGetLODMesh)==null||t.call(s,r,e);return r["LOD:requested level"]=e,O.getOrLoadLOD(o,e).then(s=>{if(r["LOD:requested level"]===e){if(delete r["LOD:requested level"],Array.isArray(s)){const a=n.index||0;s=s[a]}s&&o!=s&&s instanceof $&&(r.geometry=s,v&&te(r,"geometry",n.url))}return s}).catch(s=>(console.error("Error loading mesh LOD",r,s),null))}else v&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",r);return Promise.resolve(null)}static assignTextureLOD(r,e=0){if(!r)return Promise.resolve(null);if(r instanceof ae||r.isMaterial===!0){const t=r,o=[],n=new Array;if(v&&Q.add(t),t.uniforms&&t.isRawShaderMaterial||t.isShaderMaterial===!0){const s=t;for(const a of Object.keys(s.uniforms)){const i=s.uniforms[a].value;if(i?.isTexture===!0){const l=this.assignTextureLODForSlot(i,e,t,a);o.push(l),n.push(a)}}}else for(const s of Object.keys(t)){const a=t[s];if(a?.isTexture===!0){const i=this.assignTextureLODForSlot(a,e,t,s);o.push(i),n.push(s)}}return Promise.all(o).then(s=>{const a=new Array;for(let i=0;i<s.length;i++){const l=s[i],d=n[i];l&&l.isTexture===!0?a.push({material:t,slot:d,texture:l,level:e}):a.push({material:t,slot:d,texture:null,level:e})}return a})}if(r instanceof C||r.isTexture===!0){const t=r;return this.assignTextureLODForSlot(t,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(r,e,t,o){return r?.isTexture!==!0?Promise.resolve(null):O.getOrLoadLOD(r,e).then(n=>{if(Array.isArray(n))return null;if(n?.isTexture===!0){if(n!=r&&(t&&o&&(t[o]=n),v&&o&&t)){const s=this.getAssignedLODInformation(r);s&&te(t,o,s.url)}return n}else v=="verbose"&&console.warn("No LOD found for",r,e);return null}).catch(n=>(console.error("Error loading LOD",r,n),null))}afterRoot(r){var e,t;return v&&console.log("AFTER",this.url,r),(e=this.parser.json.textures)==null||e.forEach((o,n)=>{if(o!=null&&o.extensions){const s=o?.extensions[P];if(s){let a=!1;for(const i of this.parser.associations.keys())i.isTexture===!0&&this.parser.associations.get(i).textures===n&&(a=!0,O.registerTexture(this.url,i,n,s));a||this.parser.getDependency("texture",n).then(i=>{i&&O.registerTexture(this.url,i,n,s)})}}}),(t=this.parser.json.meshes)==null||t.forEach((o,n)=>{if(o!=null&&o.extensions){const s=o?.extensions[P];if(s&&s.lods){for(const a of this.parser.associations.keys())if(a.isMesh){const i=this.parser.associations.get(a);i.meshes===n&&O.registerMesh(this.url,s.guid,a,s.lods.length,i.primitives,s)}}}}),null}static async getOrLoadLOD(r,e){var t,o,n;const s=v=="verbose",a=r.userData.LODS;if(!a)return null;const i=a?.key;let l;if(r.isTexture===!0){const d=r;d.source&&d.source[J]&&(l=d.source[J])}if(l||(l=O.lodInfos.get(i)),l){if(e>0){let u=!1;const p=Array.isArray(l.lods);if(p&&e>=l.lods.length?u=!0:p||(u=!0),u)return this.lowresCache.get(i)}const d=Array.isArray(l.lods)?l.lods[e].path:l.lods;if(!d)return v&&!l["missing:uri"]&&(l["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,l)),null;const h=ye(a.url,d);if(h.endsWith(".glb")||h.endsWith(".gltf")){if(!l.guid)return console.warn("missing pointer for glb/gltf texture",l),null;const u=h+"_"+l.guid,p=this.previouslyLoaded.get(u);if(p!==void 0){s&&console.log(`LOD ${e} was already loading/loaded: ${u}`);let y=await p.catch(m=>(console.error(`Error loading LOD ${e} from ${h}
2
- `,m),null)),g=!1;if(y==null||(y instanceof C&&r instanceof C?(t=y.image)!=null&&t.data||(o=y.source)!=null&&o.data?y=this.copySettings(r,y):(g=!0,this.previouslyLoaded.delete(u)):y instanceof $&&r instanceof $&&((n=y.attributes.position)!=null&&n.array||(g=!0,this.previouslyLoaded.delete(u)))),!g)return y}const L=l,A=new Promise(async(y,g)=>{const m=new de;K(m),v&&(await new Promise(x=>setTimeout(x,1e3)),s&&console.warn("Start loading (delayed) "+h,L.guid));let b=h;if(L&&Array.isArray(L.lods)){const x=L.lods[e];x.hash&&(b+="?v="+x.hash)}const D=await m.loadAsync(b).catch(x=>(console.error(`Error loading LOD ${e} from ${h}
3
- `,x),null));if(!D)return null;const S=D.parser;s&&console.log("Loading finished "+h,L.guid);let T=0;if(D.parser.json.textures){let x=!1;for(const f of D.parser.json.textures){if(f!=null&&f.extensions){const M=f?.extensions[P];if(M!=null&&M.guid&&M.guid===L.guid){x=!0;break}}T++}if(x){let f=await S.getDependency("texture",T);return s&&console.log('change "'+r.name+'" \u2192 "'+f.name+'"',h,T,f,u),r instanceof C&&(f=this.copySettings(r,f)),f&&(f.guid=L.guid),y(f)}}if(T=0,D.parser.json.meshes){let x=!1;for(const f of D.parser.json.meshes){if(f!=null&&f.extensions){const M=f?.extensions[P];if(M!=null&&M.guid&&M.guid===L.guid){x=!0;break}}T++}if(x){const f=await S.getDependency("mesh",T),M=L;if(s&&console.log(`Loaded Mesh "${f.name}"`,h,T,f,u),f.isMesh===!0){const _=f.geometry;return O.assignLODInformation(a.url,_,i,e,void 0,M.density),y(_)}else{const _=new Array;for(let k=0;k<f.children.length;k++){const F=f.children[k];if(F instanceof W){const j=F.geometry;O.assignLODInformation(a.url,j,i,e,k,M.density),_.push(j)}}return y(_)}}}return y(null)});return this.previouslyLoaded.set(u,A),await A}else if(r instanceof C){s&&console.log("Load texture from uri: "+h);const u=await new le().loadAsync(h);return u?(u.guid=l.guid,u.flipY=!1,u.needsUpdate=!0,u.colorSpace=r.colorSpace,s&&console.log(l,u)):v&&console.warn("failed loading",h),u}}else v&&console.warn(`Can not load LOD ${e}: no LOD info found for "${i}" ${r.name}`,r.type);return null}static assignLODInformation(r,e,t,o,n,s){if(!e)return;e.userData||(e.userData={});const a=new De(r,t,o,n,s);e.userData.LODS=a,e.userData.LOD=o}static getAssignedLODInformation(r){var e;return((e=r?.userData)==null?void 0:e.LODS)||null}static copySettings(r,e){return this._copiedTextures.get(r)||(e=e.clone(),this._copiedTextures.set(r,e),e.offset=r.offset,e.repeat=r.repeat,e.colorSpace=r.colorSpace,e.magFilter=r.magFilter,e.minFilter=r.minFilter,e.wrapS=r.wrapS,e.wrapT=r.wrapT,e.flipY=r.flipY,e.anisotropy=r.anisotropy,e.generateMipmaps=r.generateMipmaps,e)}};let w=O;c(w,"registerTexture",(r,e,t,o)=>{v&&console.log("> Progressive: register texture",t,e.name,e.uuid,e,o),e.source&&(e.source[J]=o);const n=o.guid;O.assignLODInformation(r,e,n,0,0,void 0),O.lodInfos.set(n,o),O.lowresCache.set(n,e)}),c(w,"registerMesh",(r,e,t,o,n,s)=>{var a;v&&console.log("> Progressive: register mesh",n,t.name,s,t.uuid,t);const i=t.geometry;i.userData||(i.userData={}),O.assignLODInformation(r,i,e,o,n,s.density),O.lodInfos.set(e,s);let l=O.lowresCache.get(e);l?l.push(t.geometry):l=[t.geometry],O.lowresCache.set(e,l);for(const d of Y)(a=d.onRegisteredNewMesh)==null||a.call(d,t,s)}),c(w,"lodInfos",new Map),c(w,"previouslyLoaded",new Map),c(w,"lowresCache",new Map),c(w,"_copiedTextures",new Map);class De{constructor(e,t,o,n,s){c(this,"url"),c(this,"key"),c(this,"level"),c(this,"index"),c(this,"density"),this.url=e,this.key=t,this.level=o,n!=null&&(this.index=n),s!=null&&(this.density=s)}}const Z=H("debugprogressive"),xe=H("noprogressive"),E=class{constructor(r){c(this,"renderer"),c(this,"projectionScreenMatrix",new ee),c(this,"cameraFrustrum",new ue),c(this,"updateInterval",0),c(this,"pause",!1),c(this,"plugins",[]),c(this,"_frame",0),c(this,"_originalRender"),c(this,"_sphere",new ce),c(this,"_tempBox",new re),c(this,"tempMatrix",new ee),c(this,"_tempWorldPosition",new B),c(this,"_tempBoxSize",new B),c(this,"_tempBox2Size",new B),this.renderer=r}static getObjectLODState(r){var e;return(e=r.userData)==null?void 0:e.LOD_state}enable(){if(this._originalRender)return;let r=0;this._originalRender=this.renderer.render;const e=this;X(this.renderer),this.renderer.render=function(t,o){e.renderer.getRenderTarget()==null&&(r=0,e._frame+=1);const n=e._frame,s=r++;e.onBeforeRender(t,o,s,n),e._originalRender.call(this,t,o),e.onAfterRender(t,o,s,n)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(r,e,t,o){}onAfterRender(r,e,t,o){var n,s;if(this.pause)return;const a=this.renderer.renderLists.get(r,0),i=a.opaque;let l=!0;if(i.length===1){const d=i[0].material;(d.name==="EffectMaterial"||d.name==="CopyShader")&&(l=!1)}if(l){if(xe||this.updateInterval>0&&o%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const d=1e5;for(const u of i){if(u.material&&(((n=u.geometry)==null?void 0:n.type)==="BoxGeometry"||((s=u.geometry)==null?void 0:s.type)==="BufferGeometry")&&(u.material.name==="SphericalGaussianBlur"||u.material.name=="BackgroundCubeMaterial"||u.material.name==="CubemapFromEquirect"||u.material.name==="EquirectangularToCubeUV")){Z&&(u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",u,u.material.name,u.material.type)));continue}const p=u.object;(p instanceof W||p.isMesh)&&this.updateLODs(r,e,p,d)}const h=a.transparent;for(const u of h){const p=u.object;(p instanceof W||p.isMesh)&&this.updateLODs(r,e,p,d)}}}updateLODs(r,e,t,o){var n,s;for(const d of this.plugins)(n=d.onBeforeUpdateLOD)==null||n.call(d,this.renderer,r,e,t);let a=t.userData.LOD_state;a||(a=new ve,t.userData.LOD_state=a);let i=this.calculateLodLevel(e,t,a,o);i=Math.round(i),i>=0&&this.loadProgressiveMeshes(t,i);let l=0;if(t.material){const d=t["DEBUG:LOD"];if(d!=null&&(l=d),Array.isArray(t.material))for(const h of t.material)this.loadProgressiveTextures(h,l);else this.loadProgressiveTextures(t.material,l)}for(const d of this.plugins)(s=d.onAfterUpdatedLOD)==null||s.call(d,this.renderer,r,e,t,i);a.lastLodLevel=i}loadProgressiveTextures(r,e){return r&&r.userData&&r.userData.LOD!==e?(r.userData.LOD=e,w.assignTextureLOD(r,e)):Promise.resolve(null)}loadProgressiveMeshes(r,e){if(!r)return Promise.resolve(null);if(r.userData||(r.userData={}),r.userData.LOD!==e){r.userData.LOD=e;const t=r.geometry;return w.assignMeshLOD(r,e).then(o=>(o&&r.userData.LOD==e&&t!=r.geometry,o))}return Promise.resolve(null)}calculateLodLevel(r,e,t,o){var n;if(!e)return-1;let s=10+1;if(r){if(Z&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const a=w.getMeshLODInformation(e.geometry),i=a?.lods;if(!i||i.length<=0||!((n=this.cameraFrustrum)!=null&&n.intersectsObject(e)))return 99;const l=e.geometry.boundingBox;if(l&&r.isPerspectiveCamera){const d=r;if(e.geometry.attributes.color&&e.geometry.attributes.color.count<100&&e.geometry.boundingSphere){this._sphere.copy(e.geometry.boundingSphere),this._sphere.applyMatrix4(e.matrixWorld);const g=r.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(g))return 0}if(this._tempBox.copy(l),this._tempBox.applyMatrix4(e.matrixWorld),this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&d.fov>70){const g=this._tempBox.min,m=this._tempBox.max;let b=g.x,D=g.y,S=m.x,T=m.y;const x=2,f=1.5,M=(g.x+m.x)*.5,_=(g.y+m.y)*.5;b=(b-M)*x+M,D=(D-_)*x+_,S=(S-M)*x+M,T=(T-_)*x+_;const k=b<0&&S>0?0:Math.min(Math.abs(g.x),Math.abs(m.x)),F=D<0&&T>0?0:Math.min(Math.abs(g.y),Math.abs(m.y)),j=Math.max(k,F);t.lastCentrality=(f-j)*(f-j)*(f-j)}else t.lastCentrality=1;const h=this._tempBox.getSize(this._tempBoxSize);h.multiplyScalar(.5),screen.availHeight>0&&h.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),h.x*=d.aspect;const u=r.matrixWorldInverse,p=new re;p.copy(l),p.applyMatrix4(e.matrixWorld),p.applyMatrix4(u);const L=p.getSize(this._tempBox2Size),A=Math.max(L.x,L.y);if(Math.max(h.x,h.y)!=0&&A!=0&&(h.z=L.z/Math.max(L.x,L.y)*Math.max(h.x,h.y)),t.lastScreenCoverage=Math.max(h.x,h.y,h.z),t.lastScreenspaceVolume.copy(h),t.lastScreenCoverage*=t.lastCentrality,Z&&E.debugDrawLine){const g=this.tempMatrix.copy(this.projectionScreenMatrix);g.invert();const m=E.corner0,b=E.corner1,D=E.corner2,S=E.corner3;m.copy(this._tempBox.min),b.copy(this._tempBox.max),b.x=m.x,D.copy(this._tempBox.max),D.y=m.y,S.copy(this._tempBox.max);const T=(m.z+S.z)*.5;m.z=b.z=D.z=S.z=T,m.applyMatrix4(g),b.applyMatrix4(g),D.applyMatrix4(g),S.applyMatrix4(g),E.debugDrawLine(m,b,255),E.debugDrawLine(m,D,255),E.debugDrawLine(b,S,255),E.debugDrawLine(D,S,255)}let y=999;if(i&&t.lastScreenCoverage>0){for(let g=0;g<i.length;g++)if(i[g].density/t.lastScreenCoverage<o){y=g;break}}y<s&&(s=y)}}return s}};let I=E;c(I,"debugDrawLine"),c(I,"corner0",new B),c(I,"corner1",new B),c(I,"corner2",new B),c(I,"corner3",new B);class ve{constructor(){c(this,"lastLodLevel",0),c(this,"lastScreenCoverage",0),c(this,"lastScreenspaceVolume",new B),c(this,"lastCentrality",0)}}const se=Symbol("NEEDLE_mesh_lod"),z=Symbol("NEEDLE_texture_lod");function oe(r){if(!r)return null;let e=null,t=null;for(let o=r;o!=null;o=Object.getPrototypeOf(o)){const n=Object.getOwnPropertySymbols(o),s=n.find(i=>i.toString()=="Symbol(renderer)"),a=n.find(i=>i.toString()=="Symbol(scene)");!e&&s!=null&&(e=r[s].threeRenderer),!t&&a!=null&&(t=r[a])}if(e){console.log("Adding Needle LODs to modelviewer");const o=new I(e);if(o.plugins.push(new Oe(r)),o.enable(),t){const n=t.camera||t.traverse(s=>s.type=="PerspectiveCamera")[0];n&&e.render(t,n)}return()=>{o.disable()}}return null}class Oe{constructor(e){c(this,"modelviewer"),c(this,"_didWarnAboutMissingUrl",!1),this.modelviewer=e}onBeforeUpdateLOD(e,t,o,n){this.tryParseMeshLOD(t,n),this.tryParseTextureLOD(t,n)}getUrl(){let e=this.modelviewer.getAttribute("src");return e||(e=this.modelviewer.src),e||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",this.modelviewer),this._didWarnAboutMissingUrl=!0),e}tryGetCurrentGLTF(e){return e._currentGLTF}tryParseTextureLOD(e,t){if(t[z]==!0)return;t[z]=!0;const o=this.tryGetCurrentGLTF(e),n=this.getUrl();if(n&&o&&t.material){let s=function(i){var l,d,h;if(i[z]==!0)return;i[z]=!0,i.userData&&(i.userData.LOD=-1);const u=Object.keys(i);for(let p=0;p<u.length;p++){const L=u[p],A=i[L];if(A?.isTexture===!0){const y=(d=(l=A.userData)==null?void 0:l.associations)==null?void 0:d.textures,g=o.parser.json.textures[y];if((h=g.extensions)!=null&&h[P]){const m=g.extensions[P];m&&n&&w.registerTexture(n,A,m.lods.length,m)}}}};const a=t.material;if(Array.isArray(a))for(const i of a)s(i);else s(a)}}tryParseMeshLOD(e,t){var o,n;if(t[se]==!0)return;t[se]=!0;const s=this.getUrl();if(!s)return;const a=(n=(o=t.userData)==null?void 0:o.gltfExtensions)==null?void 0:n[P];if(a&&s){const i=t.uuid;w.registerMesh(s,i,t,0,a.lods.length,a)}}}function we(r,e,t,o){X(e),K(t),t.register(s=>new w(s,r));const n=new I(e);return o?.enableLODsManager!==!1&&n.enable(),n}document.addEventListener("DOMContentLoaded",()=>{oe(document.querySelector("model-viewer"))});export{P as EXTENSION_NAME,I as LODsManager,w as NEEDLE_progressive,K as addDracoAndKTX2Loaders,X as createLoaders,oe as patchModelViewer,Le as registerPlugin,me as setDracoDecoderLocation,pe as setKTX2TranscoderLocation,we as useNeedleProgressive};
1
+ var ne=Object.defineProperty,ie=(r,e,t)=>e in r?ne(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t,c=(r,e,t)=>(ie(r,typeof e!="symbol"?e+"":e,t),t);import{Mesh as W,BufferGeometry as $,Material as ae,Texture as j,TextureLoader as le,Matrix4 as ee,Frustum as ue,Sphere as ce,Box3 as re,Vector3 as B}from"three";import{GLTFLoader as de}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as he}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as fe}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as ge}from"three/examples/jsm/loaders/KTX2Loader.js";let U="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",q="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(U+"draco_decoder.js",{method:"head"}).catch(r=>{U="./include/draco/",q="./include/ktx2/"});function me(r){U=r}function pe(r){q=r}let R,V,G;function X(r){R||(R=new fe,R.setDecoderPath(U),R.setDecoderConfig({type:"js"})),G||(G=new ge,G.setTranscoderPath(q)),V||(V=he),r?G.detectSupport(r):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function K(r){r.dracoLoader||r.setDRACOLoader(R),r.ktx2Loader||r.setKTX2Loader(G),r.meshoptDecoder||r.setMeshoptDecoder(V)}function H(r){const e=new URL(window.location.href).searchParams.get(r);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function ye(r,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||r===void 0)return e;const t=r.lastIndexOf("/");if(t>=0){const o=r.substring(0,t+1);for(;o.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return o+e}return e}const Y=new Array;function xe(r){Y.push(r)}const P="NEEDLE_progressive",v=H("debugprogressive"),J=Symbol("needle-progressive-texture"),N=new Map,Q=new Set;if(v){let r=function(){e+=1,console.log("Toggle LOD level",e,N),N.forEach((n,s)=>{for(const a of n.keys){const i=s[a];if(i.isBufferGeometry===!0){const l=w.getMeshLODInformation(i),d=l?Math.min(e,l.lods.length):0;s["DEBUG:LOD"]=e,w.assignMeshLOD(s,d),l&&(t=Math.max(t,l.lods.length-1))}else if(s.isMaterial===!0){s["DEBUG:LOD"]=e,w.assignTextureLOD(s,e);break}}}),e>=t&&(e=-1)},e=-1,t=2,o=!1;window.addEventListener("keyup",n=>{n.key==="p"&&r(),n.key==="w"&&(o=!o,Q&&Q.forEach(s=>{s.name!="BackgroundCubeMaterial"&&"wireframe"in s&&(s.wireframe=o)}))})}function te(r,e,t){var o;if(!v)return;N.has(r)||N.set(r,{keys:[],sourceId:t});const n=N.get(r);((o=n?.keys)==null?void 0:o.includes(e))==!1&&n.keys.push(e)}const O=class{constructor(r,e){c(this,"parser"),c(this,"url"),v&&console.log("Progressive extension registered for",e),this.parser=r,this.url=e}get name(){return P}static getMeshLODInformation(r){const e=this.getAssignedLODInformation(r);return e!=null&&e.key?this.lodInfos.get(e.key):null}static hasLODLevelAvailable(r,e){var t;if(r.isMaterial===!0){for(const s of Object.keys(r)){const a=r[s];if(a.isTexture&&this.hasLODLevelAvailable(a,e))return!0}return!1}else if(r.isGroup===!0){for(const s of r.children)if(s.isMesh===!0&&this.hasLODLevelAvailable(s,e))return!0}let o,n;if(r.isMesh?o=r.geometry:(r.isBufferGeometry||r.isTexture)&&(o=r),o&&(t=o?.userData)!=null&&t.LODS){const s=o.userData.LODS;if(n=this.lodInfos.get(s.key),e===void 0)return n!=null;if(n)return Array.isArray(n.lods)?e<n.lods.length:e===0}return!1}static assignMeshLOD(r,e){var t;if(!r)return Promise.resolve(null);if(r instanceof W||r.isMesh===!0){const o=r.geometry,n=this.getAssignedLODInformation(o);if(!n)return Promise.resolve(null);for(const s of Y)(t=s.onBeforeGetLODMesh)==null||t.call(s,r,e);return r["LOD:requested level"]=e,O.getOrLoadLOD(o,e).then(s=>{if(r["LOD:requested level"]===e){if(delete r["LOD:requested level"],Array.isArray(s)){const a=n.index||0;s=s[a]}s&&o!=s&&s instanceof $&&(r.geometry=s,v&&te(r,"geometry",n.url))}return s}).catch(s=>(console.error("Error loading mesh LOD",r,s),null))}else v&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",r);return Promise.resolve(null)}static assignTextureLOD(r,e=0){if(!r)return Promise.resolve(null);if(r instanceof ae||r.isMaterial===!0){const t=r,o=[],n=new Array;if(v&&Q.add(t),t.uniforms&&t.isRawShaderMaterial||t.isShaderMaterial===!0){const s=t;for(const a of Object.keys(s.uniforms)){const i=s.uniforms[a].value;if(i?.isTexture===!0){const l=this.assignTextureLODForSlot(i,e,t,a);o.push(l),n.push(a)}}}else for(const s of Object.keys(t)){const a=t[s];if(a?.isTexture===!0){const i=this.assignTextureLODForSlot(a,e,t,s);o.push(i),n.push(s)}}return Promise.all(o).then(s=>{const a=new Array;for(let i=0;i<s.length;i++){const l=s[i],d=n[i];l&&l.isTexture===!0?a.push({material:t,slot:d,texture:l,level:e}):a.push({material:t,slot:d,texture:null,level:e})}return a})}if(r instanceof j||r.isTexture===!0){const t=r;return this.assignTextureLODForSlot(t,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(r,e,t,o){return r?.isTexture!==!0?Promise.resolve(null):O.getOrLoadLOD(r,e).then(n=>{if(Array.isArray(n))return null;if(n?.isTexture===!0){if(n!=r&&(t&&o&&(t[o]=n),v&&o&&t)){const s=this.getAssignedLODInformation(r);s&&te(t,o,s.url)}return n}else v=="verbose"&&console.warn("No LOD found for",r,e);return null}).catch(n=>(console.error("Error loading LOD",r,n),null))}afterRoot(r){var e,t;return v&&console.log("AFTER",this.url,r),(e=this.parser.json.textures)==null||e.forEach((o,n)=>{if(o!=null&&o.extensions){const s=o?.extensions[P];if(s){let a=!1;for(const i of this.parser.associations.keys())i.isTexture===!0&&this.parser.associations.get(i).textures===n&&(a=!0,O.registerTexture(this.url,i,n,s));a||this.parser.getDependency("texture",n).then(i=>{i&&O.registerTexture(this.url,i,n,s)})}}}),(t=this.parser.json.meshes)==null||t.forEach((o,n)=>{if(o!=null&&o.extensions){const s=o?.extensions[P];if(s&&s.lods){for(const a of this.parser.associations.keys())if(a.isMesh){const i=this.parser.associations.get(a);i.meshes===n&&O.registerMesh(this.url,s.guid,a,s.lods.length,i.primitives,s)}}}}),null}static async getOrLoadLOD(r,e){var t,o,n;const s=v=="verbose",a=r.userData.LODS;if(!a)return null;const i=a?.key;let l;if(r.isTexture===!0){const d=r;d.source&&d.source[J]&&(l=d.source[J])}if(l||(l=O.lodInfos.get(i)),l){if(e>0){let u=!1;const p=Array.isArray(l.lods);if(p&&e>=l.lods.length?u=!0:p||(u=!0),u)return this.lowresCache.get(i)}const d=Array.isArray(l.lods)?l.lods[e].path:l.lods;if(!d)return v&&!l["missing:uri"]&&(l["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,l)),null;const h=ye(a.url,d);if(h.endsWith(".glb")||h.endsWith(".gltf")){if(!l.guid)return console.warn("missing pointer for glb/gltf texture",l),null;const u=h+"_"+l.guid,p=this.previouslyLoaded.get(u);if(p!==void 0){s&&console.log(`LOD ${e} was already loading/loaded: ${u}`);let y=await p.catch(m=>(console.error(`Error loading LOD ${e} from ${h}
2
+ `,m),null)),f=!1;if(y==null||(y instanceof j&&r instanceof j?(t=y.image)!=null&&t.data||(o=y.source)!=null&&o.data?y=this.copySettings(r,y):(f=!0,this.previouslyLoaded.delete(u)):y instanceof $&&r instanceof $&&((n=y.attributes.position)!=null&&n.array||(f=!0,this.previouslyLoaded.delete(u)))),!f)return y}const x=l,A=new Promise(async(y,f)=>{const m=new de;K(m),v&&(await new Promise(D=>setTimeout(D,1e3)),s&&console.warn("Start loading (delayed) "+h,x.guid));let b=h;if(x&&Array.isArray(x.lods)){const D=x.lods[e];D.hash&&(b+="?v="+D.hash)}const L=await m.loadAsync(b).catch(D=>(console.error(`Error loading LOD ${e} from ${h}
3
+ `,D),null));if(!L)return null;const S=L.parser;s&&console.log("Loading finished "+h,x.guid);let T=0;if(L.parser.json.textures){let D=!1;for(const g of L.parser.json.textures){if(g!=null&&g.extensions){const M=g?.extensions[P];if(M!=null&&M.guid&&M.guid===x.guid){D=!0;break}}T++}if(D){let g=await S.getDependency("texture",T);return s&&console.log('change "'+r.name+'" \u2192 "'+g.name+'"',h,T,g,u),r instanceof j&&(g=this.copySettings(r,g)),g&&(g.guid=x.guid),y(g)}}if(T=0,L.parser.json.meshes){let D=!1;for(const g of L.parser.json.meshes){if(g!=null&&g.extensions){const M=g?.extensions[P];if(M!=null&&M.guid&&M.guid===x.guid){D=!0;break}}T++}if(D){const g=await S.getDependency("mesh",T),M=x;if(s&&console.log(`Loaded Mesh "${g.name}"`,h,T,g,u),g.isMesh===!0){const _=g.geometry;return O.assignLODInformation(a.url,_,i,e,void 0,M.density),y(_)}else{const _=new Array;for(let k=0;k<g.children.length;k++){const F=g.children[k];if(F instanceof W){const C=F.geometry;O.assignLODInformation(a.url,C,i,e,k,M.density),_.push(C)}}return y(_)}}}return y(null)});return this.previouslyLoaded.set(u,A),await A}else if(r instanceof j){s&&console.log("Load texture from uri: "+h);const u=await new le().loadAsync(h);return u?(u.guid=l.guid,u.flipY=!1,u.needsUpdate=!0,u.colorSpace=r.colorSpace,s&&console.log(l,u)):v&&console.warn("failed loading",h),u}}else v&&console.warn(`Can not load LOD ${e}: no LOD info found for "${i}" ${r.name}`,r.type);return null}static assignLODInformation(r,e,t,o,n,s){if(!e)return;e.userData||(e.userData={});const a=new Le(r,t,o,n,s);e.userData.LODS=a,e.userData.LOD=o}static getAssignedLODInformation(r){var e;return((e=r?.userData)==null?void 0:e.LODS)||null}static copySettings(r,e){return this._copiedTextures.get(r)||(e=e.clone(),this._copiedTextures.set(r,e),e.offset=r.offset,e.repeat=r.repeat,e.colorSpace=r.colorSpace,e.magFilter=r.magFilter,e.minFilter=r.minFilter,e.wrapS=r.wrapS,e.wrapT=r.wrapT,e.flipY=r.flipY,e.anisotropy=r.anisotropy,e.generateMipmaps=r.generateMipmaps,e)}};let w=O;c(w,"registerTexture",(r,e,t,o)=>{v&&console.log("> Progressive: register texture",t,e.name,e.uuid,e,o),e.source&&(e.source[J]=o);const n=o.guid;O.assignLODInformation(r,e,n,0,0,void 0),O.lodInfos.set(n,o),O.lowresCache.set(n,e)}),c(w,"registerMesh",(r,e,t,o,n,s)=>{var a;v&&console.log("> Progressive: register mesh",n,t.name,s,t.uuid,t);const i=t.geometry;i.userData||(i.userData={}),O.assignLODInformation(r,i,e,o,n,s.density),O.lodInfos.set(e,s);let l=O.lowresCache.get(e);l?l.push(t.geometry):l=[t.geometry],O.lowresCache.set(e,l);for(const d of Y)(a=d.onRegisteredNewMesh)==null||a.call(d,t,s)}),c(w,"lodInfos",new Map),c(w,"previouslyLoaded",new Map),c(w,"lowresCache",new Map),c(w,"_copiedTextures",new Map);class Le{constructor(e,t,o,n,s){c(this,"url"),c(this,"key"),c(this,"level"),c(this,"index"),c(this,"density"),this.url=e,this.key=t,this.level=o,n!=null&&(this.index=n),s!=null&&(this.density=s)}}const Z=H("debugprogressive"),De=H("noprogressive"),E=class{constructor(r){c(this,"renderer"),c(this,"projectionScreenMatrix",new ee),c(this,"cameraFrustrum",new ue),c(this,"updateInterval",0),c(this,"pause",!1),c(this,"plugins",[]),c(this,"_frame",0),c(this,"_originalRender"),c(this,"_sphere",new ce),c(this,"_tempBox",new re),c(this,"tempMatrix",new ee),c(this,"_tempWorldPosition",new B),c(this,"_tempBoxSize",new B),c(this,"_tempBox2Size",new B),this.renderer=r}static getObjectLODState(r){var e;return(e=r.userData)==null?void 0:e.LOD_state}enable(){if(this._originalRender)return;let r=0;this._originalRender=this.renderer.render;const e=this;X(this.renderer),this.renderer.render=function(t,o){e.renderer.getRenderTarget()==null&&(r=0,e._frame+=1);const n=e._frame,s=r++;e.onBeforeRender(t,o,s,n),e._originalRender.call(this,t,o),e.onAfterRender(t,o,s,n)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(r,e,t,o){}onAfterRender(r,e,t,o){var n,s;if(this.pause)return;const a=this.renderer.renderLists.get(r,0),i=a.opaque;let l=!0;if(i.length===1){const d=i[0].material;(d.name==="EffectMaterial"||d.name==="CopyShader")&&(l=!1)}if(l){if(De||this.updateInterval>0&&o%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const d=1e5;for(const u of i){if(u.material&&(((n=u.geometry)==null?void 0:n.type)==="BoxGeometry"||((s=u.geometry)==null?void 0:s.type)==="BufferGeometry")&&(u.material.name==="SphericalGaussianBlur"||u.material.name=="BackgroundCubeMaterial"||u.material.name==="CubemapFromEquirect"||u.material.name==="EquirectangularToCubeUV")){Z&&(u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",u,u.material.name,u.material.type)));continue}const p=u.object;(p instanceof W||p.isMesh)&&this.updateLODs(r,e,p,d)}const h=a.transparent;for(const u of h){const p=u.object;(p instanceof W||p.isMesh)&&this.updateLODs(r,e,p,d)}}}updateLODs(r,e,t,o){var n,s;for(const d of this.plugins)(n=d.onBeforeUpdateLOD)==null||n.call(d,this.renderer,r,e,t);let a=t.userData.LOD_state;a||(a=new ve,t.userData.LOD_state=a);let i=this.calculateLodLevel(e,t,a,o);i=Math.round(i),i>=0&&this.loadProgressiveMeshes(t,i);let l=0;if(t.material){const d=t["DEBUG:LOD"];if(d!=null&&(l=d),Array.isArray(t.material))for(const h of t.material)this.loadProgressiveTextures(h,l);else this.loadProgressiveTextures(t.material,l)}for(const d of this.plugins)(s=d.onAfterUpdatedLOD)==null||s.call(d,this.renderer,r,e,t,i);a.lastLodLevel=i}loadProgressiveTextures(r,e){return r&&r.userData&&r.userData.LOD!==e?(r.userData.LOD=e,w.assignTextureLOD(r,e)):Promise.resolve(null)}loadProgressiveMeshes(r,e){if(!r)return Promise.resolve(null);if(r.userData||(r.userData={}),r.userData.LOD!==e){r.userData.LOD=e;const t=r.geometry;return w.assignMeshLOD(r,e).then(o=>(o&&r.userData.LOD==e&&t!=r.geometry,o))}return Promise.resolve(null)}calculateLodLevel(r,e,t,o){var n;if(!e)return-1;let s=10+1;if(r){if(Z&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const a=w.getMeshLODInformation(e.geometry),i=a?.lods;if(!i||i.length<=0||!((n=this.cameraFrustrum)!=null&&n.intersectsObject(e)))return 99;const l=e.geometry.boundingBox;if(l&&r.isPerspectiveCamera){const d=r;if(e.geometry.attributes.color&&e.geometry.attributes.color.count<100&&e.geometry.boundingSphere){this._sphere.copy(e.geometry.boundingSphere),this._sphere.applyMatrix4(e.matrixWorld);const f=r.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(f))return 0}if(this._tempBox.copy(l),this._tempBox.applyMatrix4(e.matrixWorld),this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&d.fov>70){const f=this._tempBox.min,m=this._tempBox.max;let b=f.x,L=f.y,S=m.x,T=m.y;const D=2,g=1.5,M=(f.x+m.x)*.5,_=(f.y+m.y)*.5;b=(b-M)*D+M,L=(L-_)*D+_,S=(S-M)*D+M,T=(T-_)*D+_;const k=b<0&&S>0?0:Math.min(Math.abs(f.x),Math.abs(m.x)),F=L<0&&T>0?0:Math.min(Math.abs(f.y),Math.abs(m.y)),C=Math.max(k,F);t.lastCentrality=(g-C)*(g-C)*(g-C)}else t.lastCentrality=1;const h=this._tempBox.getSize(this._tempBoxSize);h.multiplyScalar(.5),screen.availHeight>0&&h.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),h.x*=d.aspect;const u=r.matrixWorldInverse,p=new re;p.copy(l),p.applyMatrix4(e.matrixWorld),p.applyMatrix4(u);const x=p.getSize(this._tempBox2Size),A=Math.max(x.x,x.y);if(Math.max(h.x,h.y)!=0&&A!=0&&(h.z=x.z/Math.max(x.x,x.y)*Math.max(h.x,h.y)),t.lastScreenCoverage=Math.max(h.x,h.y,h.z),t.lastScreenspaceVolume.copy(h),t.lastScreenCoverage*=t.lastCentrality,Z&&E.debugDrawLine){const f=this.tempMatrix.copy(this.projectionScreenMatrix);f.invert();const m=E.corner0,b=E.corner1,L=E.corner2,S=E.corner3;m.copy(this._tempBox.min),b.copy(this._tempBox.max),b.x=m.x,L.copy(this._tempBox.max),L.y=m.y,S.copy(this._tempBox.max);const T=(m.z+S.z)*.5;m.z=b.z=L.z=S.z=T,m.applyMatrix4(f),b.applyMatrix4(f),L.applyMatrix4(f),S.applyMatrix4(f),E.debugDrawLine(m,b,255),E.debugDrawLine(m,L,255),E.debugDrawLine(b,S,255),E.debugDrawLine(L,S,255)}let y=999;if(i&&t.lastScreenCoverage>0){for(let f=0;f<i.length;f++)if(i[f].density/t.lastScreenCoverage<o){y=f;break}}y<s&&(s=y)}}return s}};let I=E;c(I,"debugDrawLine"),c(I,"corner0",new B),c(I,"corner1",new B),c(I,"corner2",new B),c(I,"corner3",new B);class ve{constructor(){c(this,"lastLodLevel",0),c(this,"lastScreenCoverage",0),c(this,"lastScreenspaceVolume",new B),c(this,"lastCentrality",0)}}const se=Symbol("NEEDLE_mesh_lod"),z=Symbol("NEEDLE_texture_lod");function oe(r){if(!r)return null;let e=null,t=null;for(let o=r;o!=null;o=Object.getPrototypeOf(o)){const n=Object.getOwnPropertySymbols(o),s=n.find(i=>i.toString()=="Symbol(renderer)"),a=n.find(i=>i.toString()=="Symbol(scene)");!e&&s!=null&&(e=r[s].threeRenderer),!t&&a!=null&&(t=r[a])}if(e){console.log("Adding Needle LODs to modelviewer");const o=new I(e);if(o.plugins.push(new Oe(r)),o.enable(),t){const n=t.camera||t.traverse(s=>s.type=="PerspectiveCamera")[0];n&&e.render(t,n)}return()=>{o.disable()}}return null}class Oe{constructor(e){c(this,"modelviewer"),c(this,"_didWarnAboutMissingUrl",!1),this.modelviewer=e}onBeforeUpdateLOD(e,t,o,n){this.tryParseMeshLOD(t,n),this.tryParseTextureLOD(t,n)}getUrl(){let e=this.modelviewer.getAttribute("src");return e||(e=this.modelviewer.src),e||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",this.modelviewer),this._didWarnAboutMissingUrl=!0),e}tryGetCurrentGLTF(e){return e._currentGLTF}tryParseTextureLOD(e,t){if(t[z]==!0)return;t[z]=!0;const o=this.tryGetCurrentGLTF(e),n=this.getUrl();if(n&&o&&t.material){let s=function(i){var l,d,h;if(i[z]==!0)return;i[z]=!0,i.userData&&(i.userData.LOD=-1);const u=Object.keys(i);for(let p=0;p<u.length;p++){const x=u[p],A=i[x];if(A?.isTexture===!0){const y=(d=(l=A.userData)==null?void 0:l.associations)==null?void 0:d.textures,f=o.parser.json.textures[y];if(!f){console.warn("Texture data not found for texture index "+y);continue}if((h=f?.extensions)!=null&&h[P]){const m=f.extensions[P];m&&n&&w.registerTexture(n,A,m.lods.length,m)}}}};const a=t.material;if(Array.isArray(a))for(const i of a)s(i);else s(a)}}tryParseMeshLOD(e,t){var o,n;if(t[se]==!0)return;t[se]=!0;const s=this.getUrl();if(!s)return;const a=(n=(o=t.userData)==null?void 0:o.gltfExtensions)==null?void 0:n[P];if(a&&s){const i=t.uuid;w.registerMesh(s,i,t,0,a.lods.length,a)}}}function we(r,e,t,o){X(e),K(t),t.register(s=>new w(s,r));const n=new I(e);return o?.enableLODsManager!==!1&&n.enable(),n}document.addEventListener("DOMContentLoaded",()=>{oe(document.querySelector("model-viewer"))});export{P as EXTENSION_NAME,I as LODsManager,w as NEEDLE_progressive,K as addDracoAndKTX2Loaders,X as createLoaders,oe as patchModelViewer,xe as registerPlugin,me as setDracoDecoderLocation,pe as setKTX2TranscoderLocation,we as useNeedleProgressive};
@@ -1,3 +1,3 @@
1
1
  "use strict";var ie=Object.defineProperty;var ne=(l,e,t)=>e in l?ie(l,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):l[e]=t;var c=(l,e,t)=>(ne(l,typeof e!="symbol"?e+"":e,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const h=require("three"),oe=require("three/examples/jsm/loaders/GLTFLoader.js"),ae=require("three/examples/jsm/libs/meshopt_decoder.module.js"),le=require("three/examples/jsm/loaders/DRACOLoader.js"),ue=require("three/examples/jsm/loaders/KTX2Loader.js");let V="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",J="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(V+"draco_decoder.js",{method:"head"}).catch(l=>{V="./include/draco/",J="./include/ktx2/"});function ce(l){V=l}function fe(l){J=l}let I,$,U;function Q(l){I||(I=new le.DRACOLoader,I.setDecoderPath(V),I.setDecoderConfig({type:"js"})),U||(U=new ue.KTX2Loader,U.setTranscoderPath(J)),$||($=ae.MeshoptDecoder),l?U.detectSupport(l):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function Z(l){l.dracoLoader||l.setDRACOLoader(I),l.ktx2Loader||l.setKTX2Loader(U),l.meshoptDecoder||l.setMeshoptDecoder($)}function j(l){const t=new URL(window.location.href).searchParams.get(l);return t==null||t==="0"||t==="false"?!1:t===""?!0:t}function de(l,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||l===void 0)return e;const t=l.lastIndexOf("/");if(t>=0){const r=l.substring(0,t+1);for(;r.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return r+e}return e}const Y=new Array;function ge(l){Y.push(l)}const C="NEEDLE_progressive",T=j("debugprogressive"),X=Symbol("needle-progressive-texture"),N=new Map,H=new Set;if(T){let l=function(){e+=1,console.log("Toggle LOD level",e,N),N.forEach((i,n)=>{for(const s of i.keys){const o=n[s];if(o.isBufferGeometry===!0){const a=M.getMeshLODInformation(o),g=a?Math.min(e,a.lods.length):0;n["DEBUG:LOD"]=e,M.assignMeshLOD(n,g),a&&(t=Math.max(t,a.lods.length-1))}else if(n.isMaterial===!0){n["DEBUG:LOD"]=e,M.assignTextureLOD(n,e);break}}}),e>=t&&(e=-1)},e=-1,t=2,r=!1;window.addEventListener("keyup",i=>{i.key==="p"&&l(),i.key==="w"&&(r=!r,H&&H.forEach(n=>{n.name!="BackgroundCubeMaterial"&&"wireframe"in n&&(n.wireframe=r)}))})}function ee(l,e,t){var i;if(!T)return;N.has(l)||N.set(l,{keys:[],sourceId:t});const r=N.get(l);((i=r==null?void 0:r.keys)==null?void 0:i.includes(e))==!1&&r.keys.push(e)}const S=class{constructor(e,t){c(this,"parser");c(this,"url");T&&console.log("Progressive extension registered for",t),this.parser=e,this.url=t}get name(){return C}static getMeshLODInformation(e){const t=this.getAssignedLODInformation(e);return t!=null&&t.key?this.lodInfos.get(t.key):null}static hasLODLevelAvailable(e,t){var n;if(e.isMaterial===!0){for(const s of Object.keys(e)){const o=e[s];if(o.isTexture&&this.hasLODLevelAvailable(o,t))return!0}return!1}else if(e.isGroup===!0){for(const s of e.children)if(s.isMesh===!0&&this.hasLODLevelAvailable(s,t))return!0}let r,i;if(e.isMesh?r=e.geometry:(e.isBufferGeometry||e.isTexture)&&(r=e),r&&(n=r==null?void 0:r.userData)!=null&&n.LODS){const s=r.userData.LODS;if(i=this.lodInfos.get(s.key),t===void 0)return i!=null;if(i)return Array.isArray(i.lods)?t<i.lods.length:t===0}return!1}static assignMeshLOD(e,t){var r;if(!e)return Promise.resolve(null);if(e instanceof h.Mesh||e.isMesh===!0){const i=e.geometry,n=this.getAssignedLODInformation(i);if(!n)return Promise.resolve(null);for(const s of Y)(r=s.onBeforeGetLODMesh)==null||r.call(s,e,t);return e["LOD:requested level"]=t,S.getOrLoadLOD(i,t).then(s=>{if(e["LOD:requested level"]===t){if(delete e["LOD:requested level"],Array.isArray(s)){const o=n.index||0;s=s[o]}s&&i!=s&&s instanceof h.BufferGeometry&&(e.geometry=s,T&&ee(e,"geometry",n.url))}return s}).catch(s=>(console.error("Error loading mesh LOD",e,s),null))}else T&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",e);return Promise.resolve(null)}static assignTextureLOD(e,t=0){if(!e)return Promise.resolve(null);if(e instanceof h.Material||e.isMaterial===!0){const r=e,i=[],n=new Array;if(T&&H.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const s=r;for(const o of Object.keys(s.uniforms)){const a=s.uniforms[o].value;if((a==null?void 0:a.isTexture)===!0){const g=this.assignTextureLODForSlot(a,t,r,o);i.push(g),n.push(o)}}}else for(const s of Object.keys(r)){const o=r[s];if((o==null?void 0:o.isTexture)===!0){const a=this.assignTextureLODForSlot(o,t,r,s);i.push(a),n.push(s)}}return Promise.all(i).then(s=>{const o=new Array;for(let a=0;a<s.length;a++){const g=s[a],f=n[a];g&&g.isTexture===!0?o.push({material:r,slot:f,texture:g,level:t}):o.push({material:r,slot:f,texture:null,level:t})}return o})}if(e instanceof h.Texture||e.isTexture===!0){const r=e;return this.assignTextureLODForSlot(r,t,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(e,t,r,i){return(e==null?void 0:e.isTexture)!==!0?Promise.resolve(null):S.getOrLoadLOD(e,t).then(n=>{if(Array.isArray(n))return null;if((n==null?void 0:n.isTexture)===!0){if(n!=e&&(r&&i&&(r[i]=n),T&&i&&r)){const s=this.getAssignedLODInformation(e);s&&ee(r,i,s.url)}return n}else T=="verbose"&&console.warn("No LOD found for",e,t);return null}).catch(n=>(console.error("Error loading LOD",e,n),null))}afterRoot(e){var t,r;return T&&console.log("AFTER",this.url,e),(t=this.parser.json.textures)==null||t.forEach((i,n)=>{if(i!=null&&i.extensions){const s=i==null?void 0:i.extensions[C];if(s){let o=!1;for(const a of this.parser.associations.keys())a.isTexture===!0&&this.parser.associations.get(a).textures===n&&(o=!0,S.registerTexture(this.url,a,n,s));o||this.parser.getDependency("texture",n).then(a=>{a&&S.registerTexture(this.url,a,n,s)})}}}),(r=this.parser.json.meshes)==null||r.forEach((i,n)=>{if(i!=null&&i.extensions){const s=i==null?void 0:i.extensions[C];if(s&&s.lods){for(const o of this.parser.associations.keys())if(o.isMesh){const a=this.parser.associations.get(o);a.meshes===n&&S.registerMesh(this.url,s.guid,o,s.lods.length,a.primitives,s)}}}}),null}static async getOrLoadLOD(e,t){var o,a,g;const r=T=="verbose",i=e.userData.LODS;if(!i)return null;const n=i==null?void 0:i.key;let s;if(e.isTexture===!0){const f=e;f.source&&f.source[X]&&(s=f.source[X])}if(s||(s=S.lodInfos.get(n)),s){if(t>0){let u=!1;const p=Array.isArray(s.lods);if(p&&t>=s.lods.length?u=!0:p||(u=!0),u)return this.lowresCache.get(n)}const f=Array.isArray(s.lods)?s.lods[t].path:s.lods;if(!f)return T&&!s["missing:uri"]&&(s["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+t,s)),null;const y=de(i.url,f);if(y.endsWith(".glb")||y.endsWith(".gltf")){if(!s.guid)return console.warn("missing pointer for glb/gltf texture",s),null;const u=y+"_"+s.guid,p=this.previouslyLoaded.get(u);if(p!==void 0){r&&console.log(`LOD ${t} was already loading/loaded: ${u}`);let w=await p.catch(F=>(console.error(`Error loading LOD ${t} from ${y}
2
- `,F),null)),k=!1;if(w==null||(w instanceof h.Texture&&e instanceof h.Texture?(o=w.image)!=null&&o.data||(a=w.source)!=null&&a.data?w=this.copySettings(e,w):(k=!0,this.previouslyLoaded.delete(u)):w instanceof h.BufferGeometry&&e instanceof h.BufferGeometry&&((g=w.attributes.position)!=null&&g.array||(k=!0,this.previouslyLoaded.delete(u)))),!k)return w}const x=s,P=new Promise(async(w,k)=>{const F=new oe.GLTFLoader;Z(F),T&&(await new Promise(L=>setTimeout(L,1e3)),r&&console.warn("Start loading (delayed) "+y,x.guid));let D=y;if(x&&Array.isArray(x.lods)){const L=x.lods[t];L.hash&&(D+="?v="+L.hash)}const m=await F.loadAsync(D).catch(L=>(console.error(`Error loading LOD ${t} from ${y}
3
- `,L),null));if(!m)return null;const b=m.parser;r&&console.log("Loading finished "+y,x.guid);let O=0;if(m.parser.json.textures){let L=!1;for(const d of m.parser.json.textures){if(d!=null&&d.extensions){const v=d==null?void 0:d.extensions[C];if(v!=null&&v.guid&&v.guid===x.guid){L=!0;break}}O++}if(L){let d=await b.getDependency("texture",O);return r&&console.log('change "'+e.name+'" → "'+d.name+'"',y,O,d,u),e instanceof h.Texture&&(d=this.copySettings(e,d)),d&&(d.guid=x.guid),w(d)}}if(O=0,m.parser.json.meshes){let L=!1;for(const d of m.parser.json.meshes){if(d!=null&&d.extensions){const v=d==null?void 0:d.extensions[C];if(v!=null&&v.guid&&v.guid===x.guid){L=!0;break}}O++}if(L){const d=await b.getDependency("mesh",O),v=x;if(r&&console.log(`Loaded Mesh "${d.name}"`,y,O,d,u),d.isMesh===!0){const B=d.geometry;return S.assignLODInformation(i.url,B,n,t,void 0,v.density),w(B)}else{const B=new Array;for(let E=0;E<d.children.length;E++){const R=d.children[E];if(R instanceof h.Mesh){const W=R.geometry;S.assignLODInformation(i.url,W,n,t,E,v.density),B.push(W)}}return w(B)}}}return w(null)});return this.previouslyLoaded.set(u,P),await P}else if(e instanceof h.Texture){r&&console.log("Load texture from uri: "+y);const p=await new h.TextureLoader().loadAsync(y);return p?(p.guid=s.guid,p.flipY=!1,p.needsUpdate=!0,p.colorSpace=e.colorSpace,r&&console.log(s,p)):T&&console.warn("failed loading",y),p}}else T&&console.warn(`Can not load LOD ${t}: no LOD info found for "${n}" ${e.name}`,e.type);return null}static assignLODInformation(e,t,r,i,n,s){if(!t)return;t.userData||(t.userData={});const o=new he(e,r,i,n,s);t.userData.LODS=o,t.userData.LOD=i}static getAssignedLODInformation(e){var t;return((t=e==null?void 0:e.userData)==null?void 0:t.LODS)||null}static copySettings(e,t){const r=this._copiedTextures.get(e);return r||(t=t.clone(),this._copiedTextures.set(e,t),t.offset=e.offset,t.repeat=e.repeat,t.colorSpace=e.colorSpace,t.magFilter=e.magFilter,t.minFilter=e.minFilter,t.wrapS=e.wrapS,t.wrapT=e.wrapT,t.flipY=e.flipY,t.anisotropy=e.anisotropy,t.generateMipmaps=e.generateMipmaps,t)}};let M=S;c(M,"registerTexture",(e,t,r,i)=>{T&&console.log("> Progressive: register texture",r,t.name,t.uuid,t,i),t.source&&(t.source[X]=i);const n=i.guid;S.assignLODInformation(e,t,n,0,0,void 0),S.lodInfos.set(n,i),S.lowresCache.set(n,t)}),c(M,"registerMesh",(e,t,r,i,n,s)=>{var g;T&&console.log("> Progressive: register mesh",n,r.name,s,r.uuid,r);const o=r.geometry;o.userData||(o.userData={}),S.assignLODInformation(e,o,t,i,n,s.density),S.lodInfos.set(t,s);let a=S.lowresCache.get(t);a?a.push(r.geometry):a=[r.geometry],S.lowresCache.set(t,a);for(const f of Y)(g=f.onRegisteredNewMesh)==null||g.call(f,r,s)}),c(M,"lodInfos",new Map),c(M,"previouslyLoaded",new Map),c(M,"lowresCache",new Map),c(M,"_copiedTextures",new Map);class he{constructor(e,t,r,i,n){c(this,"url");c(this,"key");c(this,"level");c(this,"index");c(this,"density");this.url=e,this.key=t,this.level=r,i!=null&&(this.index=i),n!=null&&(this.density=n)}}const K=j("debugprogressive"),pe=j("noprogressive"),A=class{constructor(e){c(this,"renderer");c(this,"projectionScreenMatrix",new h.Matrix4);c(this,"cameraFrustrum",new h.Frustum);c(this,"updateInterval",0);c(this,"pause",!1);c(this,"plugins",[]);c(this,"_frame",0);c(this,"_originalRender");c(this,"_sphere",new h.Sphere);c(this,"_tempBox",new h.Box3);c(this,"tempMatrix",new h.Matrix4);c(this,"_tempWorldPosition",new h.Vector3);c(this,"_tempBoxSize",new h.Vector3);c(this,"_tempBox2Size",new h.Vector3);this.renderer=e}static getObjectLODState(e){var t;return(t=e.userData)==null?void 0:t.LOD_state}enable(){if(this._originalRender)return;let e=0;this._originalRender=this.renderer.render;const t=this;Q(this.renderer),this.renderer.render=function(r,i){t.renderer.getRenderTarget()==null&&(e=0,t._frame+=1);const s=t._frame,o=e++;t.onBeforeRender(r,i,o,s),t._originalRender.call(this,r,i),t.onAfterRender(r,i,o,s)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(e,t,r,i){}onAfterRender(e,t,r,i){var a,g;if(this.pause)return;const n=this.renderer.renderLists.get(e,0),s=n.opaque;let o=!0;if(s.length===1){const f=s[0].material;(f.name==="EffectMaterial"||f.name==="CopyShader")&&(o=!1)}if(o){if(pe||this.updateInterval>0&&i%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const f=1e5;for(const u of s){if(u.material&&(((a=u.geometry)==null?void 0:a.type)==="BoxGeometry"||((g=u.geometry)==null?void 0:g.type)==="BufferGeometry")&&(u.material.name==="SphericalGaussianBlur"||u.material.name=="BackgroundCubeMaterial"||u.material.name==="CubemapFromEquirect"||u.material.name==="EquirectangularToCubeUV")){K&&(u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",u,u.material.name,u.material.type)));continue}const p=u.object;(p instanceof h.Mesh||p.isMesh)&&this.updateLODs(e,t,p,f)}const y=n.transparent;for(const u of y){const p=u.object;(p instanceof h.Mesh||p.isMesh)&&this.updateLODs(e,t,p,f)}}}updateLODs(e,t,r,i){var a,g;for(const f of this.plugins)(a=f.onBeforeUpdateLOD)==null||a.call(f,this.renderer,e,t,r);let n=r.userData.LOD_state;n||(n=new ye,r.userData.LOD_state=n);let s=this.calculateLodLevel(t,r,n,i);s=Math.round(s),s>=0&&this.loadProgressiveMeshes(r,s);let o=0;if(r.material){const f=r["DEBUG:LOD"];if(f!=null&&(o=f),Array.isArray(r.material))for(const y of r.material)this.loadProgressiveTextures(y,o);else this.loadProgressiveTextures(r.material,o)}for(const f of this.plugins)(g=f.onAfterUpdatedLOD)==null||g.call(f,this.renderer,e,t,r,s);n.lastLodLevel=s}loadProgressiveTextures(e,t){return e&&e.userData&&e.userData.LOD!==t?(e.userData.LOD=t,M.assignTextureLOD(e,t)):Promise.resolve(null)}loadProgressiveMeshes(e,t){if(!e)return Promise.resolve(null);if(e.userData||(e.userData={}),e.userData.LOD!==t){e.userData.LOD=t;const r=e.geometry;return M.assignMeshLOD(e,t).then(i=>(i&&e.userData.LOD==t&&r!=e.geometry,i))}return Promise.resolve(null)}calculateLodLevel(e,t,r,i){var o;if(!t)return-1;let s=10+1;if(e){if(K&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const a=M.getMeshLODInformation(t.geometry),g=a==null?void 0:a.lods;if(!g||g.length<=0||!((o=this.cameraFrustrum)!=null&&o.intersectsObject(t)))return 99;const f=t.geometry.boundingBox;if(f&&e.isPerspectiveCamera){const y=e;if(t.geometry.attributes.color&&t.geometry.attributes.color.count<100&&t.geometry.boundingSphere){this._sphere.copy(t.geometry.boundingSphere),this._sphere.applyMatrix4(t.matrixWorld);const D=e.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(D))return 0}if(this._tempBox.copy(f),this._tempBox.applyMatrix4(t.matrixWorld),this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&y.fov>70){const D=this._tempBox.min,m=this._tempBox.max;let b=D.x,O=D.y,L=m.x,d=m.y;const v=2,B=1.5,E=(D.x+m.x)*.5,R=(D.y+m.y)*.5;b=(b-E)*v+E,O=(O-R)*v+R,L=(L-E)*v+E,d=(d-R)*v+R;const W=b<0&&L>0?0:Math.min(Math.abs(D.x),Math.abs(m.x)),se=O<0&&d>0?0:Math.min(Math.abs(D.y),Math.abs(m.y)),q=Math.max(W,se);r.lastCentrality=(B-q)*(B-q)*(B-q)}else r.lastCentrality=1;const u=this._tempBox.getSize(this._tempBoxSize);u.multiplyScalar(.5),screen.availHeight>0&&u.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),u.x*=y.aspect;const p=e.matrixWorldInverse,x=new h.Box3;x.copy(f),x.applyMatrix4(t.matrixWorld),x.applyMatrix4(p);const P=x.getSize(this._tempBox2Size),G=Math.max(P.x,P.y);if(Math.max(u.x,u.y)!=0&&G!=0&&(u.z=P.z/Math.max(P.x,P.y)*Math.max(u.x,u.y)),r.lastScreenCoverage=Math.max(u.x,u.y,u.z),r.lastScreenspaceVolume.copy(u),r.lastScreenCoverage*=r.lastCentrality,K&&A.debugDrawLine){const D=this.tempMatrix.copy(this.projectionScreenMatrix);D.invert();const m=A.corner0,b=A.corner1,O=A.corner2,L=A.corner3;m.copy(this._tempBox.min),b.copy(this._tempBox.max),b.x=m.x,O.copy(this._tempBox.max),O.y=m.y,L.copy(this._tempBox.max);const d=(m.z+L.z)*.5;m.z=b.z=O.z=L.z=d,m.applyMatrix4(D),b.applyMatrix4(D),O.applyMatrix4(D),L.applyMatrix4(D),A.debugDrawLine(m,b,255),A.debugDrawLine(m,O,255),A.debugDrawLine(b,L,255),A.debugDrawLine(O,L,255)}let k=999;if(g&&r.lastScreenCoverage>0){for(let D=0;D<g.length;D++)if(g[D].density/r.lastScreenCoverage<i){k=D;break}}k<s&&(s=k)}}return s}};let _=A;c(_,"debugDrawLine"),c(_,"corner0",new h.Vector3),c(_,"corner1",new h.Vector3),c(_,"corner2",new h.Vector3),c(_,"corner3",new h.Vector3);class ye{constructor(){c(this,"lastLodLevel",0);c(this,"lastScreenCoverage",0);c(this,"lastScreenspaceVolume",new h.Vector3);c(this,"lastCentrality",0)}}const te=Symbol("NEEDLE_mesh_lod"),z=Symbol("NEEDLE_texture_lod");function re(l){if(!l)return null;let e=null,t=null;for(let r=l;r!=null;r=Object.getPrototypeOf(r)){const i=Object.getOwnPropertySymbols(r),n=i.find(o=>o.toString()=="Symbol(renderer)"),s=i.find(o=>o.toString()=="Symbol(scene)");!e&&n!=null&&(e=l[n].threeRenderer),!t&&s!=null&&(t=l[s])}if(e){console.log("Adding Needle LODs to modelviewer");const r=new _(e);if(r.plugins.push(new me(l)),r.enable(),t){const i=t.camera||t.traverse(n=>n.type=="PerspectiveCamera")[0];i&&e.render(t,i)}return()=>{r.disable()}}return null}class me{constructor(e){c(this,"modelviewer");c(this,"_didWarnAboutMissingUrl",!1);this.modelviewer=e}onBeforeUpdateLOD(e,t,r,i){this.tryParseMeshLOD(t,i),this.tryParseTextureLOD(t,i)}getUrl(){let e=this.modelviewer.getAttribute("src");return e||(e=this.modelviewer.src),e||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",this.modelviewer),this._didWarnAboutMissingUrl=!0),e}tryGetCurrentGLTF(e){return e._currentGLTF}tryParseTextureLOD(e,t){if(t[z]==!0)return;t[z]=!0;const r=this.tryGetCurrentGLTF(e),i=this.getUrl();if(i&&r&&t.material){let n=function(o){var g,f,y;if(o[z]==!0)return;o[z]=!0,o.userData&&(o.userData.LOD=-1);const a=Object.keys(o);for(let u=0;u<a.length;u++){const p=a[u],x=o[p];if((x==null?void 0:x.isTexture)===!0){const P=(f=(g=x.userData)==null?void 0:g.associations)==null?void 0:f.textures,G=r.parser.json.textures[P];if((y=G.extensions)!=null&&y[C]){const w=G.extensions[C];w&&i&&M.registerTexture(i,x,w.lods.length,w)}}}};const s=t.material;if(Array.isArray(s))for(const o of s)n(o);else n(s)}}tryParseMeshLOD(e,t){var n,s;if(t[te]==!0)return;t[te]=!0;const r=this.getUrl();if(!r)return;const i=(s=(n=t.userData)==null?void 0:n.gltfExtensions)==null?void 0:s[C];if(i&&r){const o=t.uuid;M.registerMesh(r,o,t,0,i.lods.length,i)}}}function Le(l,e,t,r){Q(e),Z(t),t.register(n=>new M(n,l));const i=new _(e);return(r==null?void 0:r.enableLODsManager)!==!1&&i.enable(),i}document.addEventListener("DOMContentLoaded",()=>{re(document.querySelector("model-viewer"))});exports.EXTENSION_NAME=C;exports.LODsManager=_;exports.NEEDLE_progressive=M;exports.addDracoAndKTX2Loaders=Z;exports.createLoaders=Q;exports.patchModelViewer=re;exports.registerPlugin=ge;exports.setDracoDecoderLocation=ce;exports.setKTX2TranscoderLocation=fe;exports.useNeedleProgressive=Le;
2
+ `,F),null)),R=!1;if(w==null||(w instanceof h.Texture&&e instanceof h.Texture?(o=w.image)!=null&&o.data||(a=w.source)!=null&&a.data?w=this.copySettings(e,w):(R=!0,this.previouslyLoaded.delete(u)):w instanceof h.BufferGeometry&&e instanceof h.BufferGeometry&&((g=w.attributes.position)!=null&&g.array||(R=!0,this.previouslyLoaded.delete(u)))),!R)return w}const x=s,A=new Promise(async(w,R)=>{const F=new oe.GLTFLoader;Z(F),T&&(await new Promise(L=>setTimeout(L,1e3)),r&&console.warn("Start loading (delayed) "+y,x.guid));let D=y;if(x&&Array.isArray(x.lods)){const L=x.lods[t];L.hash&&(D+="?v="+L.hash)}const m=await F.loadAsync(D).catch(L=>(console.error(`Error loading LOD ${t} from ${y}
3
+ `,L),null));if(!m)return null;const b=m.parser;r&&console.log("Loading finished "+y,x.guid);let O=0;if(m.parser.json.textures){let L=!1;for(const d of m.parser.json.textures){if(d!=null&&d.extensions){const v=d==null?void 0:d.extensions[C];if(v!=null&&v.guid&&v.guid===x.guid){L=!0;break}}O++}if(L){let d=await b.getDependency("texture",O);return r&&console.log('change "'+e.name+'" → "'+d.name+'"',y,O,d,u),e instanceof h.Texture&&(d=this.copySettings(e,d)),d&&(d.guid=x.guid),w(d)}}if(O=0,m.parser.json.meshes){let L=!1;for(const d of m.parser.json.meshes){if(d!=null&&d.extensions){const v=d==null?void 0:d.extensions[C];if(v!=null&&v.guid&&v.guid===x.guid){L=!0;break}}O++}if(L){const d=await b.getDependency("mesh",O),v=x;if(r&&console.log(`Loaded Mesh "${d.name}"`,y,O,d,u),d.isMesh===!0){const B=d.geometry;return S.assignLODInformation(i.url,B,n,t,void 0,v.density),w(B)}else{const B=new Array;for(let E=0;E<d.children.length;E++){const G=d.children[E];if(G instanceof h.Mesh){const W=G.geometry;S.assignLODInformation(i.url,W,n,t,E,v.density),B.push(W)}}return w(B)}}}return w(null)});return this.previouslyLoaded.set(u,A),await A}else if(e instanceof h.Texture){r&&console.log("Load texture from uri: "+y);const p=await new h.TextureLoader().loadAsync(y);return p?(p.guid=s.guid,p.flipY=!1,p.needsUpdate=!0,p.colorSpace=e.colorSpace,r&&console.log(s,p)):T&&console.warn("failed loading",y),p}}else T&&console.warn(`Can not load LOD ${t}: no LOD info found for "${n}" ${e.name}`,e.type);return null}static assignLODInformation(e,t,r,i,n,s){if(!t)return;t.userData||(t.userData={});const o=new he(e,r,i,n,s);t.userData.LODS=o,t.userData.LOD=i}static getAssignedLODInformation(e){var t;return((t=e==null?void 0:e.userData)==null?void 0:t.LODS)||null}static copySettings(e,t){const r=this._copiedTextures.get(e);return r||(t=t.clone(),this._copiedTextures.set(e,t),t.offset=e.offset,t.repeat=e.repeat,t.colorSpace=e.colorSpace,t.magFilter=e.magFilter,t.minFilter=e.minFilter,t.wrapS=e.wrapS,t.wrapT=e.wrapT,t.flipY=e.flipY,t.anisotropy=e.anisotropy,t.generateMipmaps=e.generateMipmaps,t)}};let M=S;c(M,"registerTexture",(e,t,r,i)=>{T&&console.log("> Progressive: register texture",r,t.name,t.uuid,t,i),t.source&&(t.source[X]=i);const n=i.guid;S.assignLODInformation(e,t,n,0,0,void 0),S.lodInfos.set(n,i),S.lowresCache.set(n,t)}),c(M,"registerMesh",(e,t,r,i,n,s)=>{var g;T&&console.log("> Progressive: register mesh",n,r.name,s,r.uuid,r);const o=r.geometry;o.userData||(o.userData={}),S.assignLODInformation(e,o,t,i,n,s.density),S.lodInfos.set(t,s);let a=S.lowresCache.get(t);a?a.push(r.geometry):a=[r.geometry],S.lowresCache.set(t,a);for(const f of Y)(g=f.onRegisteredNewMesh)==null||g.call(f,r,s)}),c(M,"lodInfos",new Map),c(M,"previouslyLoaded",new Map),c(M,"lowresCache",new Map),c(M,"_copiedTextures",new Map);class he{constructor(e,t,r,i,n){c(this,"url");c(this,"key");c(this,"level");c(this,"index");c(this,"density");this.url=e,this.key=t,this.level=r,i!=null&&(this.index=i),n!=null&&(this.density=n)}}const K=j("debugprogressive"),pe=j("noprogressive"),P=class{constructor(e){c(this,"renderer");c(this,"projectionScreenMatrix",new h.Matrix4);c(this,"cameraFrustrum",new h.Frustum);c(this,"updateInterval",0);c(this,"pause",!1);c(this,"plugins",[]);c(this,"_frame",0);c(this,"_originalRender");c(this,"_sphere",new h.Sphere);c(this,"_tempBox",new h.Box3);c(this,"tempMatrix",new h.Matrix4);c(this,"_tempWorldPosition",new h.Vector3);c(this,"_tempBoxSize",new h.Vector3);c(this,"_tempBox2Size",new h.Vector3);this.renderer=e}static getObjectLODState(e){var t;return(t=e.userData)==null?void 0:t.LOD_state}enable(){if(this._originalRender)return;let e=0;this._originalRender=this.renderer.render;const t=this;Q(this.renderer),this.renderer.render=function(r,i){t.renderer.getRenderTarget()==null&&(e=0,t._frame+=1);const s=t._frame,o=e++;t.onBeforeRender(r,i,o,s),t._originalRender.call(this,r,i),t.onAfterRender(r,i,o,s)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(e,t,r,i){}onAfterRender(e,t,r,i){var a,g;if(this.pause)return;const n=this.renderer.renderLists.get(e,0),s=n.opaque;let o=!0;if(s.length===1){const f=s[0].material;(f.name==="EffectMaterial"||f.name==="CopyShader")&&(o=!1)}if(o){if(pe||this.updateInterval>0&&i%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const f=1e5;for(const u of s){if(u.material&&(((a=u.geometry)==null?void 0:a.type)==="BoxGeometry"||((g=u.geometry)==null?void 0:g.type)==="BufferGeometry")&&(u.material.name==="SphericalGaussianBlur"||u.material.name=="BackgroundCubeMaterial"||u.material.name==="CubemapFromEquirect"||u.material.name==="EquirectangularToCubeUV")){K&&(u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",u,u.material.name,u.material.type)));continue}const p=u.object;(p instanceof h.Mesh||p.isMesh)&&this.updateLODs(e,t,p,f)}const y=n.transparent;for(const u of y){const p=u.object;(p instanceof h.Mesh||p.isMesh)&&this.updateLODs(e,t,p,f)}}}updateLODs(e,t,r,i){var a,g;for(const f of this.plugins)(a=f.onBeforeUpdateLOD)==null||a.call(f,this.renderer,e,t,r);let n=r.userData.LOD_state;n||(n=new ye,r.userData.LOD_state=n);let s=this.calculateLodLevel(t,r,n,i);s=Math.round(s),s>=0&&this.loadProgressiveMeshes(r,s);let o=0;if(r.material){const f=r["DEBUG:LOD"];if(f!=null&&(o=f),Array.isArray(r.material))for(const y of r.material)this.loadProgressiveTextures(y,o);else this.loadProgressiveTextures(r.material,o)}for(const f of this.plugins)(g=f.onAfterUpdatedLOD)==null||g.call(f,this.renderer,e,t,r,s);n.lastLodLevel=s}loadProgressiveTextures(e,t){return e&&e.userData&&e.userData.LOD!==t?(e.userData.LOD=t,M.assignTextureLOD(e,t)):Promise.resolve(null)}loadProgressiveMeshes(e,t){if(!e)return Promise.resolve(null);if(e.userData||(e.userData={}),e.userData.LOD!==t){e.userData.LOD=t;const r=e.geometry;return M.assignMeshLOD(e,t).then(i=>(i&&e.userData.LOD==t&&r!=e.geometry,i))}return Promise.resolve(null)}calculateLodLevel(e,t,r,i){var o;if(!t)return-1;let s=10+1;if(e){if(K&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const a=M.getMeshLODInformation(t.geometry),g=a==null?void 0:a.lods;if(!g||g.length<=0||!((o=this.cameraFrustrum)!=null&&o.intersectsObject(t)))return 99;const f=t.geometry.boundingBox;if(f&&e.isPerspectiveCamera){const y=e;if(t.geometry.attributes.color&&t.geometry.attributes.color.count<100&&t.geometry.boundingSphere){this._sphere.copy(t.geometry.boundingSphere),this._sphere.applyMatrix4(t.matrixWorld);const D=e.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(D))return 0}if(this._tempBox.copy(f),this._tempBox.applyMatrix4(t.matrixWorld),this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&y.fov>70){const D=this._tempBox.min,m=this._tempBox.max;let b=D.x,O=D.y,L=m.x,d=m.y;const v=2,B=1.5,E=(D.x+m.x)*.5,G=(D.y+m.y)*.5;b=(b-E)*v+E,O=(O-G)*v+G,L=(L-E)*v+E,d=(d-G)*v+G;const W=b<0&&L>0?0:Math.min(Math.abs(D.x),Math.abs(m.x)),se=O<0&&d>0?0:Math.min(Math.abs(D.y),Math.abs(m.y)),q=Math.max(W,se);r.lastCentrality=(B-q)*(B-q)*(B-q)}else r.lastCentrality=1;const u=this._tempBox.getSize(this._tempBoxSize);u.multiplyScalar(.5),screen.availHeight>0&&u.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),u.x*=y.aspect;const p=e.matrixWorldInverse,x=new h.Box3;x.copy(f),x.applyMatrix4(t.matrixWorld),x.applyMatrix4(p);const A=x.getSize(this._tempBox2Size),k=Math.max(A.x,A.y);if(Math.max(u.x,u.y)!=0&&k!=0&&(u.z=A.z/Math.max(A.x,A.y)*Math.max(u.x,u.y)),r.lastScreenCoverage=Math.max(u.x,u.y,u.z),r.lastScreenspaceVolume.copy(u),r.lastScreenCoverage*=r.lastCentrality,K&&P.debugDrawLine){const D=this.tempMatrix.copy(this.projectionScreenMatrix);D.invert();const m=P.corner0,b=P.corner1,O=P.corner2,L=P.corner3;m.copy(this._tempBox.min),b.copy(this._tempBox.max),b.x=m.x,O.copy(this._tempBox.max),O.y=m.y,L.copy(this._tempBox.max);const d=(m.z+L.z)*.5;m.z=b.z=O.z=L.z=d,m.applyMatrix4(D),b.applyMatrix4(D),O.applyMatrix4(D),L.applyMatrix4(D),P.debugDrawLine(m,b,255),P.debugDrawLine(m,O,255),P.debugDrawLine(b,L,255),P.debugDrawLine(O,L,255)}let R=999;if(g&&r.lastScreenCoverage>0){for(let D=0;D<g.length;D++)if(g[D].density/r.lastScreenCoverage<i){R=D;break}}R<s&&(s=R)}}return s}};let _=P;c(_,"debugDrawLine"),c(_,"corner0",new h.Vector3),c(_,"corner1",new h.Vector3),c(_,"corner2",new h.Vector3),c(_,"corner3",new h.Vector3);class ye{constructor(){c(this,"lastLodLevel",0);c(this,"lastScreenCoverage",0);c(this,"lastScreenspaceVolume",new h.Vector3);c(this,"lastCentrality",0)}}const te=Symbol("NEEDLE_mesh_lod"),z=Symbol("NEEDLE_texture_lod");function re(l){if(!l)return null;let e=null,t=null;for(let r=l;r!=null;r=Object.getPrototypeOf(r)){const i=Object.getOwnPropertySymbols(r),n=i.find(o=>o.toString()=="Symbol(renderer)"),s=i.find(o=>o.toString()=="Symbol(scene)");!e&&n!=null&&(e=l[n].threeRenderer),!t&&s!=null&&(t=l[s])}if(e){console.log("Adding Needle LODs to modelviewer");const r=new _(e);if(r.plugins.push(new me(l)),r.enable(),t){const i=t.camera||t.traverse(n=>n.type=="PerspectiveCamera")[0];i&&e.render(t,i)}return()=>{r.disable()}}return null}class me{constructor(e){c(this,"modelviewer");c(this,"_didWarnAboutMissingUrl",!1);this.modelviewer=e}onBeforeUpdateLOD(e,t,r,i){this.tryParseMeshLOD(t,i),this.tryParseTextureLOD(t,i)}getUrl(){let e=this.modelviewer.getAttribute("src");return e||(e=this.modelviewer.src),e||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",this.modelviewer),this._didWarnAboutMissingUrl=!0),e}tryGetCurrentGLTF(e){return e._currentGLTF}tryParseTextureLOD(e,t){if(t[z]==!0)return;t[z]=!0;const r=this.tryGetCurrentGLTF(e),i=this.getUrl();if(i&&r&&t.material){let n=function(o){var g,f,y;if(o[z]==!0)return;o[z]=!0,o.userData&&(o.userData.LOD=-1);const a=Object.keys(o);for(let u=0;u<a.length;u++){const p=a[u],x=o[p];if((x==null?void 0:x.isTexture)===!0){const A=(f=(g=x.userData)==null?void 0:g.associations)==null?void 0:f.textures,k=r.parser.json.textures[A];if(!k){console.warn("Texture data not found for texture index "+A);continue}if((y=k==null?void 0:k.extensions)!=null&&y[C]){const w=k.extensions[C];w&&i&&M.registerTexture(i,x,w.lods.length,w)}}}};const s=t.material;if(Array.isArray(s))for(const o of s)n(o);else n(s)}}tryParseMeshLOD(e,t){var n,s;if(t[te]==!0)return;t[te]=!0;const r=this.getUrl();if(!r)return;const i=(s=(n=t.userData)==null?void 0:n.gltfExtensions)==null?void 0:s[C];if(i&&r){const o=t.uuid;M.registerMesh(r,o,t,0,i.lods.length,i)}}}function Le(l,e,t,r){Q(e),Z(t),t.register(n=>new M(n,l));const i=new _(e);return(r==null?void 0:r.enableLODsManager)!==!1&&i.enable(),i}document.addEventListener("DOMContentLoaded",()=>{re(document.querySelector("model-viewer"))});exports.EXTENSION_NAME=C;exports.LODsManager=_;exports.NEEDLE_progressive=M;exports.addDracoAndKTX2Loaders=Z;exports.createLoaders=Q;exports.patchModelViewer=re;exports.registerPlugin=ge;exports.setDracoDecoderLocation=ce;exports.setKTX2TranscoderLocation=fe;exports.useNeedleProgressive=Le;
@@ -104,7 +104,11 @@ class RegisterModelviewerDataPlugin {
104
104
  if (value?.isTexture === true) {
105
105
  const textureIndex = value.userData?.associations?.textures;
106
106
  const textureData = currentGLTF.parser.json.textures[textureIndex];
107
- if (textureData.extensions?.[EXTENSION_NAME]) {
107
+ if (!textureData) {
108
+ console.warn("Texture data not found for texture index " + textureIndex);
109
+ continue;
110
+ }
111
+ if (textureData?.extensions?.[EXTENSION_NAME]) {
108
112
  const ext = textureData.extensions[EXTENSION_NAME];
109
113
  if (ext && url) {
110
114
  NEEDLE_progressive.registerTexture(url, value, ext.lods.length, ext);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/gltf-progressive",
3
- "version": "1.0.0-alpha.13",
3
+ "version": "1.0.0-alpha.14",
4
4
  "description": "three.js support for loading glTF or GLB files that contain progressive loading data",
5
5
  "homepage": "https://needle.tools",
6
6
  "author": {