@needle-tools/gltf-progressive 1.2.0-alpha.4 → 1.2.0-alpha.5

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,10 @@ 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.2.0-alpha.5] - 2023-06-10
8
+ - fix: safeguard when `registerMesh` or `registerTexture` are being called with invalid data
9
+ - examples: update vanilla threejs example
10
+
7
11
  ## [1.2.0-alpha.4] - 2023-06-07
8
12
  - add: `useRaycastMeshes` method:
9
13
  ```ts
package/README.md CHANGED
@@ -12,11 +12,17 @@ Support for loading of glTF or GLB files with progressive mesh or texture data f
12
12
 
13
13
  Examples are in the `/examples` directory. Live versions can be found in the links below.
14
14
 
15
- - [Vanilla three.js](https://engine.needle.tools/demos/gltf-progressive/threejs/)
15
+ - [Vanilla three.js](https://engine.needle.tools/demos/gltf-progressive/threejs/) - multiple models and animations
16
16
  - [\<model-viewer\>](https://engine.needle.tools/demos/gltf-progressive/modelviewer)
17
17
  - [React Three Fiber](https://engine.needle.tools/demos/gltf-progressive/r3f/)
18
18
 
19
19
 
20
+ <br/>
21
+ <video width="320" controls autoplay src="https://engine.needle.tools/demos/gltf-progressive/video.mp4">
22
+ <source src="https://engine.needle.tools/demos/gltf-progressive/video.mp4" type="video/mp4">
23
+ </video>
24
+
25
+
20
26
  ## Usage
21
27
 
22
28
  ### react three fiber
@@ -74,11 +80,11 @@ gltfLoader.load(url, gltf => {
74
80
 
75
81
  ### \<model-viewer\>
76
82
 
77
- The full example can be found in `examples/modelviewer.html`
83
+ The example can be found in `examples/modelviewer.html`
78
84
 
79
85
  ```html
80
86
  <head>
81
- <!-- Include the import map and the gltf-progressive package -->
87
+ <!-- Include threejs import map -->
82
88
  <script type="importmap">
83
89
  {
84
90
  "imports": {
@@ -87,14 +93,16 @@ The full example can be found in `examples/modelviewer.html`
87
93
  }
88
94
  }
89
95
  </script>
96
+ <!-- Include gltf-progressive -->
90
97
  <script type="module" src="https://www.unpkg.com/@needle-tools/gltf-progressive@latest"></script>
98
+ <!-- Include model-viewer -->
91
99
  <script type="module" src="https://ajax.googleapis.com/ajax/libs/model-viewer/3.4.0/model-viewer.min.js"></script>
92
100
  </head>
93
101
  <body>
94
102
 
95
103
  <model-viewer src="https://engine.needle.tools/demos/gltf-progressive/assets/church/model.glb" camera-controls auto-rotate></model-viewer>
96
104
 
97
- ...
105
+ </body>
98
106
  ```
99
107
 
100
108
 
@@ -58,6 +58,7 @@ new EXRLoader().load(environmentTextureUrl, texture => {
58
58
 
59
59
  const modelUrls = [
60
60
  "https://engine.needle.tools/demos/gltf-progressive/assets/putti gruppe/model.glb",
61
+ "https://engine.needle.tools/demos/gltf-progressive/assets/cyberpunk/model.glb",
61
62
  "https://engine.needle.tools/demos/gltf-progressive/assets/robot/model.glb",
62
63
  "https://engine.needle.tools/demos/gltf-progressive/assets/vase/model.glb",
63
64
  "https://engine.needle.tools/demos/gltf-progressive/assets/jupiter_und_ganymed/model.glb",
@@ -67,6 +68,8 @@ let currentUrl = "";
67
68
  /** @type {null | THREE.Scene} */
68
69
  let currentScene = null;
69
70
  let wireframe = false;
71
+ /** @type {null | THREE.AnimationMixer} */
72
+ let animationMixer = null;
70
73
 
71
74
  function loadScene() {
72
75
  let currentIndex = modelUrls.indexOf(currentUrl);
@@ -77,6 +80,10 @@ function loadScene() {
77
80
  const url = modelUrls[currentIndex];
78
81
  currentUrl = url;
79
82
  wireframe = false;
83
+ if (animationMixer) {
84
+ animationMixer.stopAllAction();
85
+ animationMixer = null;
86
+ }
80
87
 
81
88
  // Integrate @needle-tools/gltf-progressive
82
89
  // Create a new GLTFLoader instance
@@ -99,11 +106,33 @@ function loadScene() {
99
106
  if (url.includes("church")) {
100
107
  gltf.scene.scale.multiplyScalar(.1);
101
108
  }
109
+ else if (url.includes("cyberpunk")) {
110
+ gltf.scene.scale.multiplyScalar(15);
111
+ }
112
+
113
+ if (gltf.animations?.length) {
114
+ console.log("Playing animation", gltf.animations)
115
+ animationMixer = new THREE.AnimationMixer(gltf.scene);
116
+ const action = animationMixer.clipAction(gltf.animations[0]);
117
+ action.setLoop(THREE.LoopRepeat);
118
+ action.play();
119
+ }
102
120
  })
103
121
  }
104
122
  loadScene();
105
123
 
106
124
 
125
+ const clock = new THREE.Clock();
126
+ function loop() {
127
+ const dt = clock.getDelta();
128
+ if (animationMixer) {
129
+ animationMixer.update(dt);
130
+ }
131
+ window.requestAnimationFrame(loop);
132
+ }
133
+ window.requestAnimationFrame(loop);
134
+
135
+
107
136
  useRaycastMeshes();
108
137
  const raycaster = new THREE.Raycaster();
109
138
  raycaster.params.Line.threshold = 0;
@@ -115,7 +144,9 @@ window.addEventListener("click", evt => {
115
144
  raycaster.setFromCamera(mousePos, camera);
116
145
  const hits = raycaster.intersectObjects(scene.children, true);
117
146
  if (hits?.length) {
118
- const obj = hits[0].object;
147
+ const hit = hits[0];
148
+ const obj = hit.object;
149
+ console.log("HIT", obj.name, hit)
119
150
  const raycastMesh = getRaycastMesh(obj);
120
151
  if (raycastMesh) {
121
152
  const newMesh = new THREE.Mesh(raycastMesh, new THREE.MeshBasicMaterial({ color: 0xffddff, wireframe: true, transparent: true, opacity: .5, depthTest: false }));
@@ -1,10 +1,10 @@
1
1
  var me = Object.defineProperty;
2
- var Le = (l, e, t) => e in l ? me(l, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : l[e] = t;
3
- var c = (l, e, t) => (Le(l, typeof e != "symbol" ? e + "" : e, t), t);
4
- import { MeshoptDecoder as xe } from "three/examples/jsm/libs/meshopt_decoder.module.js";
2
+ var xe = (l, e, t) => e in l ? me(l, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : l[e] = t;
3
+ var c = (l, e, t) => (xe(l, typeof e != "symbol" ? e + "" : e, t), t);
4
+ import { MeshoptDecoder as Le } from "three/examples/jsm/libs/meshopt_decoder.module.js";
5
5
  import { DRACOLoader as De } from "three/examples/jsm/loaders/DRACOLoader.js";
6
6
  import { KTX2Loader as Me } from "three/examples/jsm/loaders/KTX2Loader.js";
7
- import { BufferGeometry as Y, Mesh as F, Material as Oe, Texture as N, TextureLoader as we, Matrix4 as le, Frustum as _e, Sphere as ve, Box3 as ce, Vector3 as B } from "three";
7
+ import { BufferGeometry as Y, Mesh as F, Material as we, Texture as N, TextureLoader as Oe, Matrix4 as le, Frustum as _e, Sphere as ve, Box3 as ce, Vector3 as k } from "three";
8
8
  import { GLTFLoader as Se } from "three/examples/jsm/loaders/GLTFLoader.js";
9
9
  let Z = "https://www.gstatic.com/draco/versioned/decoders/1.4.1/", oe = "https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";
10
10
  fetch(Z + "draco_decoder.js", { method: "head" }).catch((l) => {
@@ -18,7 +18,7 @@ function We(l) {
18
18
  }
19
19
  let q, ie, X;
20
20
  function he(l) {
21
- q || (q = new De(), q.setDecoderPath(Z), q.setDecoderConfig({ type: "js" })), X || (X = new Me(), X.setTranscoderPath(oe)), ie || (ie = xe), l ? X.detectSupport(l) : console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail");
21
+ q || (q = new De(), q.setDecoderPath(Z), q.setDecoderConfig({ type: "js" })), X || (X = new Me(), X.setTranscoderPath(oe)), ie || (ie = Le), l ? X.detectSupport(l) : console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail");
22
22
  }
23
23
  function ge(l) {
24
24
  l.dracoLoader || l.setDRACOLoader(q), l.ktx2Loader || l.setKTX2Loader(X), l.meshoptDecoder || l.setMeshoptDecoder(ie);
@@ -76,8 +76,8 @@ function Pe(l) {
76
76
  e.setAttribute(t, l.getAttribute(t));
77
77
  return e.setIndex(l.getIndex()), e;
78
78
  }
79
- const I = new Array(), R = "NEEDLE_progressive", w = j("debugprogressive"), se = Symbol("needle-progressive-texture"), V = /* @__PURE__ */ new Map(), ne = /* @__PURE__ */ new Set();
80
- if (w) {
79
+ const I = new Array(), B = "NEEDLE_progressive", O = j("debugprogressive"), se = Symbol("needle-progressive-texture"), V = /* @__PURE__ */ new Map(), ne = /* @__PURE__ */ new Set();
80
+ if (O) {
81
81
  let l = function() {
82
82
  e += 1, console.log("Toggle LOD level", e, V), V.forEach((s, n) => {
83
83
  for (const i of s.keys) {
@@ -100,7 +100,7 @@ if (w) {
100
100
  }
101
101
  function ue(l, e, t) {
102
102
  var s;
103
- if (!w)
103
+ if (!O)
104
104
  return;
105
105
  V.has(l) || V.set(l, { keys: [], sourceId: t });
106
106
  const r = V.get(l);
@@ -115,14 +115,14 @@ const _ = class {
115
115
  var r, s;
116
116
  if (this._isLoadingMesh)
117
117
  return null;
118
- const t = (s = (r = this.parser.json.meshes[e]) == null ? void 0 : r.extensions) == null ? void 0 : s[R];
118
+ const t = (s = (r = this.parser.json.meshes[e]) == null ? void 0 : r.extensions) == null ? void 0 : s[B];
119
119
  return t ? (this._isLoadingMesh = !0, this.parser.getDependency("mesh", e).then((n) => (this._isLoadingMesh = !1, n && _.registerMesh(this.url, t.guid, n, t.lods.length, void 0, t), n))) : null;
120
120
  });
121
- w && console.log("Progressive extension registered for", t), this.parser = e, this.url = t;
121
+ O && console.log("Progressive extension registered for", t), this.parser = e, this.url = t;
122
122
  }
123
123
  /** The name of the extension */
124
124
  get name() {
125
- return R;
125
+ return B;
126
126
  }
127
127
  static getMeshLODInformation(e) {
128
128
  const t = this.getAssignedLODInformation(e);
@@ -141,7 +141,7 @@ const _ = class {
141
141
  this.getMaterialMinMaxLODsCount(o, t);
142
142
  return e[s] = t, t;
143
143
  }
144
- if (w === "verbose" && console.log("getMaterialMinMaxLODsCount", e), e.type === "ShaderMaterial" || e.type === "RawShaderMaterial") {
144
+ if (O === "verbose" && console.log("getMaterialMinMaxLODsCount", e), e.type === "ShaderMaterial" || e.type === "RawShaderMaterial") {
145
145
  const o = e;
146
146
  for (const a of Object.keys(o.uniforms)) {
147
147
  const h = o.uniforms[a].value;
@@ -232,12 +232,12 @@ const _ = class {
232
232
  const o = n.index || 0;
233
233
  i = i[o];
234
234
  }
235
- i && s != i && i instanceof Y && (e.geometry = i, w && ue(e, "geometry", n.url));
235
+ i && s != i && i instanceof Y && (e.geometry = i, O && ue(e, "geometry", n.url));
236
236
  }
237
237
  return i;
238
238
  }).catch((i) => (console.error("Error loading mesh LOD", e, i), null));
239
239
  } else
240
- w && console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh", e);
240
+ O && console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh", e);
241
241
  return Promise.resolve(null);
242
242
  }
243
243
  /** Load a different resolution of a texture (if available)
@@ -250,9 +250,9 @@ const _ = class {
250
250
  static assignTextureLOD(e, t = 0) {
251
251
  if (!e)
252
252
  return Promise.resolve(null);
253
- if (e instanceof Oe || e.isMaterial === !0) {
253
+ if (e instanceof we || e.isMaterial === !0) {
254
254
  const r = e, s = [], n = new Array();
255
- if (w && ne.add(r), r.uniforms && r.isRawShaderMaterial || r.isShaderMaterial === !0) {
255
+ if (O && ne.add(r), r.uniforms && r.isRawShaderMaterial || r.isShaderMaterial === !0) {
256
256
  const i = r;
257
257
  for (const o of Object.keys(i.uniforms)) {
258
258
  const a = i.uniforms[o].value;
@@ -295,26 +295,26 @@ const _ = class {
295
295
  if (i) {
296
296
  const o = this.getAssignedLODInformation(i);
297
297
  if (o && (o == null ? void 0 : o.level) < t)
298
- return w === "verbose" && console.warn("Assigned texture level is already higher: ", o.level, t, r, i, n), null;
298
+ return O === "verbose" && console.warn("Assigned texture level is already higher: ", o.level, t, r, i, n), null;
299
299
  }
300
300
  r[s] = n;
301
301
  }
302
- if (w && s && r) {
302
+ if (O && s && r) {
303
303
  const i = this.getAssignedLODInformation(e);
304
304
  i && ue(r, s, i.url);
305
305
  }
306
306
  }
307
307
  return n;
308
308
  } else
309
- w == "verbose" && console.warn("No LOD found for", e, t);
309
+ O == "verbose" && console.warn("No LOD found for", e, t);
310
310
  return null;
311
311
  }).catch((n) => (console.error("Error loading LOD", e, n), null));
312
312
  }
313
313
  afterRoot(e) {
314
314
  var t, r;
315
- return w && console.log("AFTER", this.url, e), (t = this.parser.json.textures) == null || t.forEach((s, n) => {
315
+ return O && console.log("AFTER", this.url, e), (t = this.parser.json.textures) == null || t.forEach((s, n) => {
316
316
  if (s != null && s.extensions) {
317
- const i = s == null ? void 0 : s.extensions[R];
317
+ const i = s == null ? void 0 : s.extensions[B];
318
318
  if (i) {
319
319
  let o = !1;
320
320
  for (const a of this.parser.associations.keys())
@@ -326,7 +326,7 @@ const _ = class {
326
326
  }
327
327
  }), (r = this.parser.json.meshes) == null || r.forEach((s, n) => {
328
328
  if (s != null && s.extensions) {
329
- const i = s == null ? void 0 : s.extensions[R];
329
+ const i = s == null ? void 0 : s.extensions[B];
330
330
  if (i && i.lods) {
331
331
  for (const o of this.parser.associations.keys())
332
332
  if (o.isMesh) {
@@ -339,7 +339,7 @@ const _ = class {
339
339
  }
340
340
  static async getOrLoadLOD(e, t) {
341
341
  var o, a, h, d;
342
- const r = w == "verbose", s = e.userData.LODS;
342
+ const r = O == "verbose", s = e.userData.LODS;
343
343
  if (!s)
344
344
  return null;
345
345
  const n = s == null ? void 0 : s.key;
@@ -357,7 +357,7 @@ const _ = class {
357
357
  }
358
358
  const g = Array.isArray(i.lods) ? (o = i.lods[t]) == null ? void 0 : o.path : i.lods;
359
359
  if (!g)
360
- return w && !i["missing:uri"] && (i["missing:uri"] = !0, console.warn("Missing uri for progressive asset for LOD " + t, i)), null;
360
+ return O && !i["missing:uri"] && (i["missing:uri"] = !0, console.warn("Missing uri for progressive asset for LOD " + t, i)), null;
361
361
  const f = Te(s.url, g);
362
362
  if (f.endsWith(".glb") || f.endsWith(".gltf")) {
363
363
  if (!i.guid)
@@ -365,14 +365,14 @@ const _ = class {
365
365
  const m = f + "_" + i.guid, D = this.previouslyLoaded.get(m);
366
366
  if (D !== void 0) {
367
367
  r && console.log(`LOD ${t} was already loading/loaded: ${m}`);
368
- let L = await D.catch((z) => (console.error(`Error loading LOD ${t} from ${f}
368
+ let x = await D.catch((z) => (console.error(`Error loading LOD ${t} from ${f}
369
369
  `, z), null)), T = !1;
370
- if (L == null || (L instanceof N && e instanceof N ? (a = L.image) != null && a.data || (h = L.source) != null && h.data ? L = this.copySettings(e, L) : (T = !0, this.previouslyLoaded.delete(m)) : L instanceof Y && e instanceof Y && ((d = L.attributes.position) != null && d.array || (T = !0, this.previouslyLoaded.delete(m)))), !T)
371
- return L;
370
+ if (x == null || (x instanceof N && e instanceof N ? (a = x.image) != null && a.data || (h = x.source) != null && h.data ? x = this.copySettings(e, x) : (T = !0, this.previouslyLoaded.delete(m)) : x instanceof Y && e instanceof Y && ((d = x.attributes.position) != null && d.array || (T = !0, this.previouslyLoaded.delete(m)))), !T)
371
+ return x;
372
372
  }
373
- const M = i, O = new Promise(async (L, T) => {
373
+ const M = i, w = new Promise(async (x, T) => {
374
374
  const z = new Se();
375
- ge(z), w && (await new Promise((p) => setTimeout(p, 1e3)), r && console.warn("Start loading (delayed) " + f, M.guid));
375
+ ge(z), O && (await new Promise((p) => setTimeout(p, 1e3)), r && console.warn("Start loading (delayed) " + f, M.guid));
376
376
  let ee = f;
377
377
  if (M && Array.isArray(M.lods)) {
378
378
  const p = M.lods[t];
@@ -389,8 +389,8 @@ const _ = class {
389
389
  let p = !1;
390
390
  for (const u of E.parser.json.textures) {
391
391
  if (u != null && u.extensions) {
392
- const x = u == null ? void 0 : u.extensions[R];
393
- if (x != null && x.guid && x.guid === M.guid) {
392
+ const L = u == null ? void 0 : u.extensions[B];
393
+ if (L != null && L.guid && L.guid === M.guid) {
394
394
  p = !0;
395
395
  break;
396
396
  }
@@ -399,16 +399,16 @@ const _ = class {
399
399
  }
400
400
  if (p) {
401
401
  let u = await te.getDependency("texture", y);
402
- return u && _.assignLODInformation(s.url, u, n, t, void 0, void 0), r && console.log('change "' + e.name + '" → "' + u.name + '"', f, y, u, m), e instanceof N && (u = this.copySettings(e, u)), u && (u.guid = M.guid), L(u);
402
+ return u && _.assignLODInformation(s.url, u, n, t, void 0, void 0), r && console.log('change "' + e.name + '" → "' + u.name + '"', f, y, u, m), e instanceof N && (u = this.copySettings(e, u)), u && (u.guid = M.guid), x(u);
403
403
  } else
404
- w && console.warn("Could not find texture with guid", M.guid);
404
+ O && console.warn("Could not find texture with guid", M.guid);
405
405
  }
406
406
  if (y = 0, E.parser.json.meshes) {
407
407
  let p = !1;
408
408
  for (const u of E.parser.json.meshes) {
409
409
  if (u != null && u.extensions) {
410
- const x = u == null ? void 0 : u.extensions[R];
411
- if (x != null && x.guid && x.guid === M.guid) {
410
+ const L = u == null ? void 0 : u.extensions[B];
411
+ if (L != null && L.guid && L.guid === M.guid) {
412
412
  p = !0;
413
413
  break;
414
414
  }
@@ -416,33 +416,33 @@ const _ = class {
416
416
  y++;
417
417
  }
418
418
  if (p) {
419
- const u = await te.getDependency("mesh", y), x = M;
419
+ const u = await te.getDependency("mesh", y), L = M;
420
420
  if (r && console.log(`Loaded Mesh "${u.name}"`, f, y, u, m), u.isMesh === !0) {
421
421
  const S = u.geometry;
422
- return _.assignLODInformation(s.url, S, n, t, void 0, x.density), L(S);
422
+ return _.assignLODInformation(s.url, S, n, t, void 0, L.density), x(S);
423
423
  } else {
424
424
  const S = new Array();
425
425
  for (let C = 0; C < u.children.length; C++) {
426
426
  const G = u.children[C];
427
427
  if (G instanceof F) {
428
428
  const $ = G.geometry;
429
- _.assignLODInformation(s.url, $, n, t, C, x.density), S.push($);
429
+ _.assignLODInformation(s.url, $, n, t, C, L.density), S.push($);
430
430
  }
431
431
  }
432
- return L(S);
432
+ return x(S);
433
433
  }
434
434
  }
435
435
  }
436
- return L(null);
436
+ return x(null);
437
437
  });
438
- return this.previouslyLoaded.set(m, O), await O;
438
+ return this.previouslyLoaded.set(m, w), await w;
439
439
  } else if (e instanceof N) {
440
440
  r && console.log("Load texture from uri: " + f);
441
- const D = await new we().loadAsync(f);
442
- return D ? (D.guid = i.guid, D.flipY = !1, D.needsUpdate = !0, D.colorSpace = e.colorSpace, r && console.log(i, D)) : w && console.warn("failed loading", f), D;
441
+ const D = await new Oe().loadAsync(f);
442
+ return D ? (D.guid = i.guid, D.flipY = !1, D.needsUpdate = !0, D.colorSpace = e.colorSpace, r && console.log(i, D)) : O && console.warn("failed loading", f), D;
443
443
  }
444
444
  } else
445
- w && console.warn(`Can not load LOD ${t}: no LOD info found for "${n}" ${e.name}`, e.type);
445
+ O && console.warn(`Can not load LOD ${t}: no LOD info found for "${n}" ${e.name}`, e.type);
446
446
  return null;
447
447
  }
448
448
  static assignLODInformation(e, t, r, s, n, i) {
@@ -458,7 +458,7 @@ const _ = class {
458
458
  }
459
459
  // private static readonly _copiedTextures: WeakMap<Texture, Texture> = new Map();
460
460
  static copySettings(e, t) {
461
- return t = t.clone(), w && console.warn(`Copying texture settings
461
+ return t = t.clone(), O && console.warn(`Copying texture settings
462
462
  `, e.uuid, `
463
463
  `, t.uuid), t.offset = e.offset, t.repeat = e.repeat, t.colorSpace = e.colorSpace, t.magFilter = e.magFilter, t.minFilter = e.minFilter, t.wrapS = e.wrapS, t.wrapT = e.wrapT, t.flipY = e.flipY, t.anisotropy = e.anisotropy, t.mipmaps || (t.generateMipmaps = e.generateMipmaps), t;
464
464
  }
@@ -468,7 +468,11 @@ let v = _;
468
468
  * Register a texture with LOD information
469
469
  */
470
470
  c(v, "registerTexture", (e, t, r, s, n) => {
471
- w && console.log("> Progressive: register texture", s, t.name, t.uuid, t, n), t.source && (t.source[se] = n);
471
+ if (O && console.log("> Progressive: register texture", s, t.name, t.uuid, t, n), !t) {
472
+ O && console.error("gltf-progressive: Register texture without texture");
473
+ return;
474
+ }
475
+ t.source && (t.source[se] = n);
472
476
  const i = n.guid;
473
477
  _.assignLODInformation(e, t, i, r, s, void 0), _.lodInfos.set(i, n), _.lowresCache.set(i, t);
474
478
  }), /**
@@ -476,8 +480,12 @@ c(v, "registerTexture", (e, t, r, s, n) => {
476
480
  */
477
481
  c(v, "registerMesh", (e, t, r, s, n, i) => {
478
482
  var h;
479
- w && console.log("> Progressive: register mesh", n, r.name, i, r.uuid, r);
483
+ O && console.log("> Progressive: register mesh", n, r.name, i, r.uuid, r);
480
484
  const o = r.geometry;
485
+ if (!o) {
486
+ O && console.warn("gltf-progressive: Register mesh without geometry");
487
+ return;
488
+ }
481
489
  o.userData || (o.userData = {}), _.assignLODInformation(e, o, t, s, n, i.density), _.lodInfos.set(t, i);
482
490
  let a = _.lowresCache.get(t);
483
491
  a ? a.push(r.geometry) : a = [r.geometry], _.lowresCache.set(t, a), s > 0 && !ae(r) && be(r, o);
@@ -526,9 +534,9 @@ const U = j("debugprogressive"), Ce = j("noprogressive"), fe = Symbol("Needle:LO
526
534
  c(this, "_tempBox", new ce());
527
535
  c(this, "_tempBox2", new ce());
528
536
  c(this, "tempMatrix", new le());
529
- c(this, "_tempWorldPosition", new B());
530
- c(this, "_tempBoxSize", new B());
531
- c(this, "_tempBox2Size", new B());
537
+ c(this, "_tempWorldPosition", new k());
538
+ c(this, "_tempBoxSize", new k());
539
+ c(this, "_tempBox2Size", new k());
532
540
  this.renderer = e;
533
541
  }
534
542
  /** @internal */
@@ -619,7 +627,7 @@ const U = j("debugprogressive"), Ce = j("noprogressive"), fe = Symbol("Needle:LO
619
627
  var a, h;
620
628
  r.userData || (r.userData = {});
621
629
  let i = r.userData.LOD_state;
622
- if (i || (i = new ke(), r.userData.LOD_state = i), i.frames++ < 2)
630
+ if (i || (i = new Re(), r.userData.LOD_state = i), i.frames++ < 2)
623
631
  return;
624
632
  for (const d of I)
625
633
  (a = d.onBeforeUpdateLOD) == null || a.call(d, this.renderer, e, t, r);
@@ -709,25 +717,25 @@ const U = j("debugprogressive"), Ce = j("noprogressive"), fe = Symbol("Needle:LO
709
717
  }
710
718
  if (this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled && M.fov > 70) {
711
719
  const y = this._tempBox.min, p = this._tempBox.max;
712
- let u = y.x, x = y.y, S = p.x, C = p.y;
720
+ let u = y.x, L = y.y, S = p.x, C = p.y;
713
721
  const G = 2, $ = 1.5, H = (y.x + p.x) * 0.5, J = (y.y + p.y) * 0.5;
714
- u = (u - H) * G + H, x = (x - J) * G + J, S = (S - H) * G + H, C = (C - J) * G + J;
715
- const pe = u < 0 && S > 0 ? 0 : Math.min(Math.abs(y.x), Math.abs(p.x)), ye = x < 0 && C > 0 ? 0 : Math.min(Math.abs(y.y), Math.abs(p.y)), re = Math.max(pe, ye);
722
+ u = (u - H) * G + H, L = (L - J) * G + J, S = (S - H) * G + H, C = (C - J) * G + J;
723
+ const pe = u < 0 && S > 0 ? 0 : Math.min(Math.abs(y.x), Math.abs(p.x)), ye = L < 0 && C > 0 ? 0 : Math.min(Math.abs(y.y), Math.abs(p.y)), re = Math.max(pe, ye);
716
724
  r.lastCentrality = ($ - re) * ($ - re) * ($ - re);
717
725
  } else
718
726
  r.lastCentrality = 1;
719
- const O = this._tempBox.getSize(this._tempBoxSize);
720
- O.multiplyScalar(0.5), screen.availHeight > 0 && O.multiplyScalar(this.renderer.domElement.clientHeight / screen.availHeight), O.x *= M.aspect;
721
- const k = e.matrixWorldInverse, L = this._tempBox2;
722
- L.copy(m), L.applyMatrix4(t.matrixWorld), L.applyMatrix4(k);
723
- const T = L.getSize(this._tempBox2Size), z = Math.max(T.x, T.y);
724
- if (Math.max(O.x, O.y) != 0 && z != 0 && (O.z = T.z / Math.max(T.x, T.y) * Math.max(O.x, O.y)), r.lastScreenCoverage = Math.max(O.x, O.y, O.z), r.lastScreenspaceVolume.copy(O), r.lastScreenCoverage *= r.lastCentrality, U && A.debugDrawLine) {
727
+ const w = this._tempBox.getSize(this._tempBoxSize);
728
+ w.multiplyScalar(0.5), screen.availHeight > 0 && w.multiplyScalar(this.renderer.domElement.clientHeight / screen.availHeight), w.x *= M.aspect;
729
+ const R = e.matrixWorldInverse, x = this._tempBox2;
730
+ x.copy(m), x.applyMatrix4(t.matrixWorld), x.applyMatrix4(R);
731
+ const T = x.getSize(this._tempBox2Size), z = Math.max(T.x, T.y);
732
+ if (Math.max(w.x, w.y) != 0 && z != 0 && (w.z = T.z / Math.max(T.x, T.y) * Math.max(w.x, w.y)), r.lastScreenCoverage = Math.max(w.x, w.y, w.z), r.lastScreenspaceVolume.copy(w), r.lastScreenCoverage *= r.lastCentrality, U && A.debugDrawLine) {
725
733
  const y = this.tempMatrix.copy(this.projectionScreenMatrix);
726
734
  y.invert();
727
- const p = A.corner0, u = A.corner1, x = A.corner2, S = A.corner3;
728
- p.copy(this._tempBox.min), u.copy(this._tempBox.max), u.x = p.x, x.copy(this._tempBox.max), x.y = p.y, S.copy(this._tempBox.max);
735
+ const p = A.corner0, u = A.corner1, L = A.corner2, S = A.corner3;
736
+ p.copy(this._tempBox.min), u.copy(this._tempBox.max), u.x = p.x, L.copy(this._tempBox.max), L.y = p.y, S.copy(this._tempBox.max);
729
737
  const C = (p.z + S.z) * 0.5;
730
- p.z = u.z = x.z = S.z = C, p.applyMatrix4(y), u.applyMatrix4(y), x.applyMatrix4(y), S.applyMatrix4(y), A.debugDrawLine(p, u, 255), A.debugDrawLine(p, x, 255), A.debugDrawLine(u, S, 255), A.debugDrawLine(x, S, 255);
738
+ p.z = u.z = L.z = S.z = C, p.applyMatrix4(y), u.applyMatrix4(y), L.applyMatrix4(y), S.applyMatrix4(y), A.debugDrawLine(p, u, 255), A.debugDrawLine(p, L, 255), A.debugDrawLine(u, S, 255), A.debugDrawLine(L, S, 255);
731
739
  }
732
740
  let E = 999;
733
741
  if (h && r.lastScreenCoverage > 0) {
@@ -746,11 +754,11 @@ const U = j("debugprogressive"), Ce = j("noprogressive"), fe = Symbol("Needle:LO
746
754
  U && console.log(`First Texture LOD ${n.texture_lod} (${M.max_height}px) - ${t.name}`);
747
755
  }
748
756
  } else {
749
- const M = r.lastScreenCoverage * 1.5, k = this.renderer.domElement.clientHeight / window.devicePixelRatio * M;
750
- for (let L = g.lods.length - 1; L >= 0; L--) {
751
- const T = g.lods[L];
752
- if (!(Ae() && T.max_height > 4096) && T.max_height > k) {
753
- n.texture_lod = L, n.texture_lod < r.lastLodLevel_Texture && U && console.log(`Texture LOD changed ${r.lastLodLevel_Texture} → ${n.texture_lod} (${T.max_height}px: ${(100 * r.lastScreenCoverage).toFixed(2)} % = ${k.toFixed(0)}px) - ${t.name}`);
757
+ const M = r.lastScreenCoverage * 1.5, R = this.renderer.domElement.clientHeight / window.devicePixelRatio * M;
758
+ for (let x = g.lods.length - 1; x >= 0; x--) {
759
+ const T = g.lods[x];
760
+ if (!(Ae() && T.max_height > 4096) && T.max_height > R) {
761
+ n.texture_lod = x, n.texture_lod < r.lastLodLevel_Texture && U && console.log(`Texture LOD changed ${r.lastLodLevel_Texture} → ${n.texture_lod} (${T.max_height}px: ${(100 * r.lastScreenCoverage).toFixed(2)} % = ${R.toFixed(0)}px) - ${t.name}`);
754
762
  break;
755
763
  }
756
764
  }
@@ -762,19 +770,19 @@ const U = j("debugprogressive"), Ce = j("noprogressive"), fe = Symbol("Needle:LO
762
770
  let P = A;
763
771
  /** 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.
764
772
  */
765
- c(P, "debugDrawLine"), c(P, "corner0", new B()), c(P, "corner1", new B()), c(P, "corner2", new B()), c(P, "corner3", new B()), c(P, "_tempPtInside", new B());
766
- class ke {
773
+ c(P, "debugDrawLine"), c(P, "corner0", new k()), c(P, "corner1", new k()), c(P, "corner2", new k()), c(P, "corner3", new k()), c(P, "_tempPtInside", new k());
774
+ class Re {
767
775
  constructor() {
768
776
  c(this, "frames", 0);
769
777
  c(this, "lastLodLevel_Mesh", -1);
770
778
  c(this, "lastLodLevel_Texture", -1);
771
779
  c(this, "lastScreenCoverage", 0);
772
- c(this, "lastScreenspaceVolume", new B());
780
+ c(this, "lastScreenspaceVolume", new k());
773
781
  c(this, "lastCentrality", 0);
774
782
  }
775
783
  }
776
784
  const de = Symbol("NEEDLE_mesh_lod"), Q = Symbol("NEEDLE_texture_lod");
777
- function Be(l) {
785
+ function ke(l) {
778
786
  if (!l)
779
787
  return null;
780
788
  let e = null, t = null;
@@ -785,7 +793,7 @@ function Be(l) {
785
793
  if (e) {
786
794
  console.log("Adding Needle LODs to modelviewer");
787
795
  const r = P.get(e);
788
- if (P.addPlugin(new Re(l)), r.enable(), t) {
796
+ if (P.addPlugin(new Be(l)), r.enable(), t) {
789
797
  const s = t.camera || t.traverse((n) => n.type == "PerspectiveCamera")[0];
790
798
  s && e.render(t, s);
791
799
  }
@@ -795,7 +803,7 @@ function Be(l) {
795
803
  }
796
804
  return null;
797
805
  }
798
- class Re {
806
+ class Be {
799
807
  constructor(e) {
800
808
  c(this, "modelviewer");
801
809
  c(this, "_didWarnAboutMissingUrl", !1);
@@ -826,14 +834,14 @@ class Re {
826
834
  for (let f = 0; f < a.length; f++) {
827
835
  const m = a[f], D = o[m];
828
836
  if ((D == null ? void 0 : D.isTexture) === !0) {
829
- const M = (d = (h = D.userData) == null ? void 0 : h.associations) == null ? void 0 : d.textures, O = r.parser.json.textures[M];
830
- if (!O) {
837
+ const M = (d = (h = D.userData) == null ? void 0 : h.associations) == null ? void 0 : d.textures, w = r.parser.json.textures[M];
838
+ if (!w) {
831
839
  console.warn("Texture data not found for texture index " + M);
832
840
  continue;
833
841
  }
834
- if ((g = O == null ? void 0 : O.extensions) != null && g[R]) {
835
- const k = O.extensions[R];
836
- k && s && v.registerTexture(s, D, k.lods.length, M, k);
842
+ if ((g = w == null ? void 0 : w.extensions) != null && g[B]) {
843
+ const R = w.extensions[B];
844
+ R && s && v.registerTexture(s, D, R.lods.length, M, R);
837
845
  }
838
846
  }
839
847
  }
@@ -854,7 +862,7 @@ class Re {
854
862
  const r = this.getUrl();
855
863
  if (!r)
856
864
  return;
857
- const s = (i = (n = t.userData) == null ? void 0 : n.gltfExtensions) == null ? void 0 : i[R];
865
+ const s = (i = (n = t.userData) == null ? void 0 : n.gltfExtensions) == null ? void 0 : i[B];
858
866
  if (s && r) {
859
867
  const o = t.uuid;
860
868
  v.registerMesh(r, o, t, 0, s.lods.length, s);
@@ -867,16 +875,16 @@ function qe(l, e, t, r) {
867
875
  return (r == null ? void 0 : r.enableLODsManager) !== !1 && s.enable(), s;
868
876
  }
869
877
  document.addEventListener("DOMContentLoaded", () => {
870
- Be(document.querySelector("model-viewer"));
878
+ ke(document.querySelector("model-viewer"));
871
879
  });
872
880
  export {
873
- R as EXTENSION_NAME,
881
+ B as EXTENSION_NAME,
874
882
  P as LODsManager,
875
883
  v as NEEDLE_progressive,
876
884
  ge as addDracoAndKTX2Loaders,
877
885
  he as createLoaders,
878
886
  ae as getRaycastMesh,
879
- Be as patchModelViewer,
887
+ ke as patchModelViewer,
880
888
  Ne as setDracoDecoderLocation,
881
889
  We as setKTX2TranscoderLocation,
882
890
  be as setRaycastMesh,
@@ -1,5 +1,5 @@
1
- var me=Object.defineProperty,pe=(t,e,r)=>e in t?me(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,c=(t,e,r)=>(pe(t,typeof e!="symbol"?e+"":e,r),r);import{MeshoptDecoder as xe}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as ye}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as ve}from"three/examples/jsm/loaders/KTX2Loader.js";import{BufferGeometry as $,Mesh as G,Material as De,Texture as z,TextureLoader as Le,Matrix4 as ie,Frustum as Me,Sphere as Oe,Box3 as ae,Vector3 as B}from"three";import{GLTFLoader as _e}from"three/examples/jsm/loaders/GLTFLoader.js";let X="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",ee="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(X+"draco_decoder.js",{method:"head"}).catch(t=>{X="./include/draco/",ee="./include/ktx2/"});function we(t){X=t}function be(t){ee=t}let U,te,q;function re(t){U||(U=new ye,U.setDecoderPath(X),U.setDecoderConfig({type:"js"})),q||(q=new ve,q.setTranscoderPath(ee)),te||(te=xe),t?q.detectSupport(t):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function se(t){t.dracoLoader||t.setDRACOLoader(U),t.ktx2Loader||t.setKTX2Loader(q),t.meshoptDecoder||t.setMeshoptDecoder(te)}function H(t){const e=new URL(window.location.href).searchParams.get(t);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function Se(t,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||t===void 0)return e;const r=t.lastIndexOf("/");if(r>=0){const n=t.substring(0,r+1);for(;n.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return n+e}return e}let Y;function Te(){return Y!==void 0||(Y=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),H("debugprogressive")&&console.log("isMobileDevice",Y)),Y}function J(t){var e;return((e=t?.userData)==null?void 0:e["needle:raycast-mesh"])instanceof $?t.userData["needle:raycast-mesh"]:null}function le(t,e){if((t.type==="Mesh"||t.type==="SkinnedMesh")&&!J(t)){const r=Ae(e);r.userData={isRaycastMesh:!0},t.userData||(t.userData={}),t.userData["needle:raycast-mesh"]=r}}function Ee(t=!0){if(t){if(V)return;const e=V=G.prototype.raycast;G.prototype.raycast=function(r,n){const o=this,s=J(o);let i;s&&o.isMesh&&(i=o.geometry,o.geometry=s),e.call(this,r,n),i&&(o.geometry=i)}}else{if(!V)return;G.prototype.raycast=V,V=null}}let V=null;function Ae(t){const e=new $;for(const r in t.attributes)e.setAttribute(r,t.getAttribute(r));return e.setIndex(t.getIndex()),e}const k=new Array,P="NEEDLE_progressive",v=H("debugprogressive"),oe=Symbol("needle-progressive-texture"),K=new Map,ne=new Set;if(v){let t=function(){e+=1,console.log("Toggle LOD level",e,K),K.forEach((o,s)=>{for(const i of o.keys){const a=s[i];if(a.isBufferGeometry===!0){const u=_.getMeshLODInformation(a),l=u?Math.min(e,u.lods.length):0;s["DEBUG:LOD"]=e,_.assignMeshLOD(s,l),u&&(r=Math.max(r,u.lods.length-1))}else if(s.isMaterial===!0){s["DEBUG:LOD"]=e,_.assignTextureLOD(s,e);break}}}),e>=r&&(e=-1)},e=-1,r=2,n=!1;window.addEventListener("keyup",o=>{o.key==="p"&&t(),o.key==="w"&&(n=!n,ne&&ne.forEach(s=>{s.name!="BackgroundCubeMaterial"&&"wireframe"in s&&(s.wireframe=n)}))})}function ue(t,e,r){var n;if(!v)return;K.has(t)||K.set(t,{keys:[],sourceId:r});const o=K.get(t);((n=o?.keys)==null?void 0:n.includes(e))==!1&&o.keys.push(e)}const M=class{constructor(t,e){c(this,"parser"),c(this,"url"),c(this,"_isLoadingMesh"),c(this,"loadMesh",r=>{var n,o;if(this._isLoadingMesh)return null;const s=(o=(n=this.parser.json.meshes[r])==null?void 0:n.extensions)==null?void 0:o[P];return s?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",r).then(i=>(this._isLoadingMesh=!1,i&&M.registerMesh(this.url,s.guid,i,s.lods.length,void 0,s),i))):null}),v&&console.log("Progressive extension registered for",e),this.parser=t,this.url=e}get name(){return P}static getMeshLODInformation(t){const e=this.getAssignedLODInformation(t);return e!=null&&e.key?this.lodInfos.get(e.key):null}static getMaterialMinMaxLODsCount(t,e){const r=this,n="LODS:minmax",o=t[n];if(o!=null)return o;if(e||(e={min_count:1/0,max_count:0,lods:[]}),Array.isArray(t)){for(const i of t)this.getMaterialMinMaxLODsCount(i,e);return t[n]=e,e}if(v==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const i=t;for(const a of Object.keys(i.uniforms)){const u=i.uniforms[a].value;u?.isTexture===!0&&s(u,e)}}else if(t.isMaterial)for(const i of Object.keys(t)){const a=t[i];a?.isTexture===!0&&s(a,e)}return t[n]=e,e;function s(i,a){const u=r.getAssignedLODInformation(i);if(u){const l=r.lodInfos.get(u.key);if(l&&l.lods){a.min_count=Math.min(a.min_count,l.lods.length),a.max_count=Math.max(a.max_count,l.lods.length);for(let g=0;g<l.lods.length;g++){const d=l.lods[g];d.width&&(a.lods[g]=a.lods[g]||{min_height:1/0,max_height:0},a.lods[g].min_height=Math.min(a.lods[g].min_height,d.height),a.lods[g].max_height=Math.max(a.lods[g].max_height,d.height))}}}}}static hasLODLevelAvailable(t,e){var r;if(Array.isArray(t)){for(const s of t)if(this.hasLODLevelAvailable(s,e))return!0;return!1}if(t.isMaterial===!0){for(const s of Object.keys(t)){const i=t[s];if(i&&i.isTexture&&this.hasLODLevelAvailable(i,e))return!0}return!1}else if(t.isGroup===!0){for(const s of t.children)if(s.isMesh===!0&&this.hasLODLevelAvailable(s,e))return!0}let n,o;if(t.isMesh?n=t.geometry:(t.isBufferGeometry||t.isTexture)&&(n=t),n&&(r=n?.userData)!=null&&r.LODS){const s=n.userData.LODS;if(o=this.lodInfos.get(s.key),e===void 0)return o!=null;if(o)return Array.isArray(o.lods)?e<o.lods.length:e===0}return!1}static assignMeshLOD(t,e){var r;if(!t)return Promise.resolve(null);if(t instanceof G||t.isMesh===!0){const n=t.geometry,o=this.getAssignedLODInformation(n);if(!o)return Promise.resolve(null);for(const s of k)(r=s.onBeforeGetLODMesh)==null||r.call(s,t,e);return t["LOD:requested level"]=e,M.getOrLoadLOD(n,e).then(s=>{if(t["LOD:requested level"]===e){if(delete t["LOD:requested level"],Array.isArray(s)){const i=o.index||0;s=s[i]}s&&n!=s&&s instanceof $&&(t.geometry=s,v&&ue(t,"geometry",o.url))}return s}).catch(s=>(console.error("Error loading mesh LOD",t,s),null))}else v&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",t);return Promise.resolve(null)}static assignTextureLOD(t,e=0){if(!t)return Promise.resolve(null);if(t instanceof De||t.isMaterial===!0){const r=t,n=[],o=new Array;if(v&&ne.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const s=r;for(const i of Object.keys(s.uniforms)){const a=s.uniforms[i].value;if(a?.isTexture===!0){const u=this.assignTextureLODForSlot(a,e,r,i);n.push(u),o.push(i)}}}else for(const s of Object.keys(r)){const i=r[s];if(i?.isTexture===!0){const a=this.assignTextureLODForSlot(i,e,r,s);n.push(a),o.push(s)}}return Promise.all(n).then(s=>{const i=new Array;for(let a=0;a<s.length;a++){const u=s[a],l=o[a];u&&u.isTexture===!0?i.push({material:r,slot:l,texture:u,level:e}):i.push({material:r,slot:l,texture:null,level:e})}return i})}if(t instanceof z||t.isTexture===!0){const r=t;return this.assignTextureLODForSlot(r,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,r,n){return t?.isTexture!==!0?Promise.resolve(null):n==="glyphMap"?Promise.resolve(t):M.getOrLoadLOD(t,e).then(o=>{if(Array.isArray(o))return null;if(o?.isTexture===!0){if(o!=t){if(r&&n){const s=r[n];if(s){const i=this.getAssignedLODInformation(s);if(i&&i?.level<e)return v==="verbose"&&console.warn("Assigned texture level is already higher: ",i.level,e,r,s,o),null}r[n]=o}if(v&&n&&r){const s=this.getAssignedLODInformation(t);s&&ue(r,n,s.url)}}return o}else v=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(o=>(console.error("Error loading LOD",t,o),null))}afterRoot(t){var e,r;return v&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((n,o)=>{if(n!=null&&n.extensions){const s=n?.extensions[P];if(s){let i=!1;for(const a of this.parser.associations.keys())a.isTexture===!0&&this.parser.associations.get(a).textures===o&&(i=!0,M.registerTexture(this.url,a,s.lods.length,o,s));i||this.parser.getDependency("texture",o).then(a=>{a&&M.registerTexture(this.url,a,s.lods.length,o,s)})}}}),(r=this.parser.json.meshes)==null||r.forEach((n,o)=>{if(n!=null&&n.extensions){const s=n?.extensions[P];if(s&&s.lods){for(const i of this.parser.associations.keys())if(i.isMesh){const a=this.parser.associations.get(i);a.meshes===o&&M.registerMesh(this.url,s.guid,i,s.lods.length,a.primitives,s)}}}}),null}static async getOrLoadLOD(t,e){var r,n,o,s;const i=v=="verbose",a=t.userData.LODS;if(!a)return null;const u=a?.key;let l;if(t.isTexture===!0){const g=t;g.source&&g.source[oe]&&(l=g.source[oe])}if(l||(l=M.lodInfos.get(u)),l){if(e>0){let f=!1;const w=Array.isArray(l.lods);if(w&&e>=l.lods.length?f=!0:w||(f=!0),f)return this.lowresCache.get(u)}const g=Array.isArray(l.lods)?(r=l.lods[e])==null?void 0:r.path:l.lods;if(!g)return v&&!l["missing:uri"]&&(l["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,l)),null;const d=Se(a.url,g);if(d.endsWith(".glb")||d.endsWith(".gltf")){if(!l.guid)return console.warn("missing pointer for glb/gltf texture",l),null;const f=d+"_"+l.guid,w=this.previouslyLoaded.get(f);if(w!==void 0){i&&console.log(`LOD ${e} was already loading/loaded: ${f}`);let p=await w.catch(N=>(console.error(`Error loading LOD ${e} from ${d}
2
- `,N),null)),b=!1;if(p==null||(p instanceof z&&t instanceof z?(n=p.image)!=null&&n.data||(o=p.source)!=null&&o.data?p=this.copySettings(t,p):(b=!0,this.previouslyLoaded.delete(f)):p instanceof $&&t instanceof $&&((s=p.attributes.position)!=null&&s.array||(b=!0,this.previouslyLoaded.delete(f)))),!b)return p}const m=l,S=new Promise(async(p,b)=>{const N=new _e;se(N),v&&(await new Promise(y=>setTimeout(y,1e3)),i&&console.warn("Start loading (delayed) "+d,m.guid));let F=d;if(m&&Array.isArray(m.lods)){const y=m.lods[e];y.hash&&(F+="?v="+y.hash)}const x=await N.loadAsync(F).catch(y=>(console.error(`Error loading LOD ${e} from ${d}
3
- `,y),null));if(!x)return null;const D=x.parser;i&&console.log("Loading finished "+d,m.guid);let L=0;if(x.parser.json.textures){let y=!1;for(const h of x.parser.json.textures){if(h!=null&&h.extensions){const O=h?.extensions[P];if(O!=null&&O.guid&&O.guid===m.guid){y=!0;break}}L++}if(y){let h=await D.getDependency("texture",L);return h&&M.assignLODInformation(a.url,h,u,e,void 0,void 0),i&&console.log('change "'+t.name+'" \u2192 "'+h.name+'"',d,L,h,f),t instanceof z&&(h=this.copySettings(t,h)),h&&(h.guid=m.guid),p(h)}else v&&console.warn("Could not find texture with guid",m.guid)}if(L=0,x.parser.json.meshes){let y=!1;for(const h of x.parser.json.meshes){if(h!=null&&h.extensions){const O=h?.extensions[P];if(O!=null&&O.guid&&O.guid===m.guid){y=!0;break}}L++}if(y){const h=await D.getDependency("mesh",L),O=m;if(i&&console.log(`Loaded Mesh "${h.name}"`,d,L,h,f),h.isMesh===!0){const A=h.geometry;return M.assignLODInformation(a.url,A,u,e,void 0,O.density),p(A)}else{const A=new Array;for(let C=0;C<h.children.length;C++){const R=h.children[C];if(R instanceof G){const j=R.geometry;M.assignLODInformation(a.url,j,u,e,C,O.density),A.push(j)}}return p(A)}}}return p(null)});return this.previouslyLoaded.set(f,S),await S}else if(t instanceof z){i&&console.log("Load texture from uri: "+d);const f=await new Le().loadAsync(d);return f?(f.guid=l.guid,f.flipY=!1,f.needsUpdate=!0,f.colorSpace=t.colorSpace,i&&console.log(l,f)):v&&console.warn("failed loading",d),f}}else v&&console.warn(`Can not load LOD ${e}: no LOD info found for "${u}" ${t.name}`,t.type);return null}static assignLODInformation(t,e,r,n,o,s){if(!e)return;e.userData||(e.userData={});const i=new Pe(t,r,n,o,s);e.userData.LODS=i,e.userData.LOD=n}static getAssignedLODInformation(t){var e;return((e=t?.userData)==null?void 0:e.LODS)||null}static copySettings(t,e){return e=e.clone(),v&&console.warn(`Copying texture settings
1
+ var me=Object.defineProperty,pe=(t,e,r)=>e in t?me(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,c=(t,e,r)=>(pe(t,typeof e!="symbol"?e+"":e,r),r);import{MeshoptDecoder as xe}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as ye}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as ve}from"three/examples/jsm/loaders/KTX2Loader.js";import{BufferGeometry as $,Mesh as G,Material as Le,Texture as z,TextureLoader as De,Matrix4 as ie,Frustum as Me,Sphere as _e,Box3 as ae,Vector3 as B}from"three";import{GLTFLoader as Oe}from"three/examples/jsm/loaders/GLTFLoader.js";let X="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",ee="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(X+"draco_decoder.js",{method:"head"}).catch(t=>{X="./include/draco/",ee="./include/ktx2/"});function we(t){X=t}function be(t){ee=t}let U,te,q;function re(t){U||(U=new ye,U.setDecoderPath(X),U.setDecoderConfig({type:"js"})),q||(q=new ve,q.setTranscoderPath(ee)),te||(te=xe),t?q.detectSupport(t):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function se(t){t.dracoLoader||t.setDRACOLoader(U),t.ktx2Loader||t.setKTX2Loader(q),t.meshoptDecoder||t.setMeshoptDecoder(te)}function H(t){const e=new URL(window.location.href).searchParams.get(t);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function Se(t,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||t===void 0)return e;const r=t.lastIndexOf("/");if(r>=0){const n=t.substring(0,r+1);for(;n.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return n+e}return e}let Y;function Te(){return Y!==void 0||(Y=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),H("debugprogressive")&&console.log("isMobileDevice",Y)),Y}function J(t){var e;return((e=t?.userData)==null?void 0:e["needle:raycast-mesh"])instanceof $?t.userData["needle:raycast-mesh"]:null}function le(t,e){if((t.type==="Mesh"||t.type==="SkinnedMesh")&&!J(t)){const r=Ae(e);r.userData={isRaycastMesh:!0},t.userData||(t.userData={}),t.userData["needle:raycast-mesh"]=r}}function Ee(t=!0){if(t){if(V)return;const e=V=G.prototype.raycast;G.prototype.raycast=function(r,n){const o=this,s=J(o);let a;s&&o.isMesh&&(a=o.geometry,o.geometry=s),e.call(this,r,n),a&&(o.geometry=a)}}else{if(!V)return;G.prototype.raycast=V,V=null}}let V=null;function Ae(t){const e=new $;for(const r in t.attributes)e.setAttribute(r,t.getAttribute(r));return e.setIndex(t.getIndex()),e}const R=new Array,P="NEEDLE_progressive",v=H("debugprogressive"),oe=Symbol("needle-progressive-texture"),K=new Map,ne=new Set;if(v){let t=function(){e+=1,console.log("Toggle LOD level",e,K),K.forEach((o,s)=>{for(const a of o.keys){const i=s[a];if(i.isBufferGeometry===!0){const u=O.getMeshLODInformation(i),l=u?Math.min(e,u.lods.length):0;s["DEBUG:LOD"]=e,O.assignMeshLOD(s,l),u&&(r=Math.max(r,u.lods.length-1))}else if(s.isMaterial===!0){s["DEBUG:LOD"]=e,O.assignTextureLOD(s,e);break}}}),e>=r&&(e=-1)},e=-1,r=2,n=!1;window.addEventListener("keyup",o=>{o.key==="p"&&t(),o.key==="w"&&(n=!n,ne&&ne.forEach(s=>{s.name!="BackgroundCubeMaterial"&&"wireframe"in s&&(s.wireframe=n)}))})}function ue(t,e,r){var n;if(!v)return;K.has(t)||K.set(t,{keys:[],sourceId:r});const o=K.get(t);((n=o?.keys)==null?void 0:n.includes(e))==!1&&o.keys.push(e)}const M=class{constructor(t,e){c(this,"parser"),c(this,"url"),c(this,"_isLoadingMesh"),c(this,"loadMesh",r=>{var n,o;if(this._isLoadingMesh)return null;const s=(o=(n=this.parser.json.meshes[r])==null?void 0:n.extensions)==null?void 0:o[P];return s?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",r).then(a=>(this._isLoadingMesh=!1,a&&M.registerMesh(this.url,s.guid,a,s.lods.length,void 0,s),a))):null}),v&&console.log("Progressive extension registered for",e),this.parser=t,this.url=e}get name(){return P}static getMeshLODInformation(t){const e=this.getAssignedLODInformation(t);return e!=null&&e.key?this.lodInfos.get(e.key):null}static getMaterialMinMaxLODsCount(t,e){const r=this,n="LODS:minmax",o=t[n];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[n]=e,e}if(v==="verbose"&&console.log("getMaterialMinMaxLODsCount",t),t.type==="ShaderMaterial"||t.type==="RawShaderMaterial"){const a=t;for(const i of Object.keys(a.uniforms)){const u=a.uniforms[i].value;u?.isTexture===!0&&s(u,e)}}else if(t.isMaterial)for(const a of Object.keys(t)){const i=t[a];i?.isTexture===!0&&s(i,e)}return t[n]=e,e;function s(a,i){const u=r.getAssignedLODInformation(a);if(u){const l=r.lodInfos.get(u.key);if(l&&l.lods){i.min_count=Math.min(i.min_count,l.lods.length),i.max_count=Math.max(i.max_count,l.lods.length);for(let g=0;g<l.lods.length;g++){const d=l.lods[g];d.width&&(i.lods[g]=i.lods[g]||{min_height:1/0,max_height:0},i.lods[g].min_height=Math.min(i.lods[g].min_height,d.height),i.lods[g].max_height=Math.max(i.lods[g].max_height,d.height))}}}}}static hasLODLevelAvailable(t,e){var r;if(Array.isArray(t)){for(const s of t)if(this.hasLODLevelAvailable(s,e))return!0;return!1}if(t.isMaterial===!0){for(const s of Object.keys(t)){const a=t[s];if(a&&a.isTexture&&this.hasLODLevelAvailable(a,e))return!0}return!1}else if(t.isGroup===!0){for(const s of t.children)if(s.isMesh===!0&&this.hasLODLevelAvailable(s,e))return!0}let n,o;if(t.isMesh?n=t.geometry:(t.isBufferGeometry||t.isTexture)&&(n=t),n&&(r=n?.userData)!=null&&r.LODS){const s=n.userData.LODS;if(o=this.lodInfos.get(s.key),e===void 0)return o!=null;if(o)return Array.isArray(o.lods)?e<o.lods.length:e===0}return!1}static assignMeshLOD(t,e){var r;if(!t)return Promise.resolve(null);if(t instanceof G||t.isMesh===!0){const n=t.geometry,o=this.getAssignedLODInformation(n);if(!o)return Promise.resolve(null);for(const s of R)(r=s.onBeforeGetLODMesh)==null||r.call(s,t,e);return t["LOD:requested level"]=e,M.getOrLoadLOD(n,e).then(s=>{if(t["LOD:requested level"]===e){if(delete t["LOD:requested level"],Array.isArray(s)){const a=o.index||0;s=s[a]}s&&n!=s&&s instanceof $&&(t.geometry=s,v&&ue(t,"geometry",o.url))}return s}).catch(s=>(console.error("Error loading mesh LOD",t,s),null))}else v&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",t);return Promise.resolve(null)}static assignTextureLOD(t,e=0){if(!t)return Promise.resolve(null);if(t instanceof Le||t.isMaterial===!0){const r=t,n=[],o=new Array;if(v&&ne.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const s=r;for(const a of Object.keys(s.uniforms)){const i=s.uniforms[a].value;if(i?.isTexture===!0){const u=this.assignTextureLODForSlot(i,e,r,a);n.push(u),o.push(a)}}}else for(const s of Object.keys(r)){const a=r[s];if(a?.isTexture===!0){const i=this.assignTextureLODForSlot(a,e,r,s);n.push(i),o.push(s)}}return Promise.all(n).then(s=>{const a=new Array;for(let i=0;i<s.length;i++){const u=s[i],l=o[i];u&&u.isTexture===!0?a.push({material:r,slot:l,texture:u,level:e}):a.push({material:r,slot:l,texture:null,level:e})}return a})}if(t instanceof z||t.isTexture===!0){const r=t;return this.assignTextureLODForSlot(r,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(t,e,r,n){return t?.isTexture!==!0?Promise.resolve(null):n==="glyphMap"?Promise.resolve(t):M.getOrLoadLOD(t,e).then(o=>{if(Array.isArray(o))return null;if(o?.isTexture===!0){if(o!=t){if(r&&n){const s=r[n];if(s){const a=this.getAssignedLODInformation(s);if(a&&a?.level<e)return v==="verbose"&&console.warn("Assigned texture level is already higher: ",a.level,e,r,s,o),null}r[n]=o}if(v&&n&&r){const s=this.getAssignedLODInformation(t);s&&ue(r,n,s.url)}}return o}else v=="verbose"&&console.warn("No LOD found for",t,e);return null}).catch(o=>(console.error("Error loading LOD",t,o),null))}afterRoot(t){var e,r;return v&&console.log("AFTER",this.url,t),(e=this.parser.json.textures)==null||e.forEach((n,o)=>{if(n!=null&&n.extensions){const s=n?.extensions[P];if(s){let a=!1;for(const i of this.parser.associations.keys())i.isTexture===!0&&this.parser.associations.get(i).textures===o&&(a=!0,M.registerTexture(this.url,i,s.lods.length,o,s));a||this.parser.getDependency("texture",o).then(i=>{i&&M.registerTexture(this.url,i,s.lods.length,o,s)})}}}),(r=this.parser.json.meshes)==null||r.forEach((n,o)=>{if(n!=null&&n.extensions){const s=n?.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===o&&M.registerMesh(this.url,s.guid,a,s.lods.length,i.primitives,s)}}}}),null}static async getOrLoadLOD(t,e){var r,n,o,s;const a=v=="verbose",i=t.userData.LODS;if(!i)return null;const u=i?.key;let l;if(t.isTexture===!0){const g=t;g.source&&g.source[oe]&&(l=g.source[oe])}if(l||(l=M.lodInfos.get(u)),l){if(e>0){let f=!1;const w=Array.isArray(l.lods);if(w&&e>=l.lods.length?f=!0:w||(f=!0),f)return this.lowresCache.get(u)}const g=Array.isArray(l.lods)?(r=l.lods[e])==null?void 0:r.path:l.lods;if(!g)return v&&!l["missing:uri"]&&(l["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,l)),null;const d=Se(i.url,g);if(d.endsWith(".glb")||d.endsWith(".gltf")){if(!l.guid)return console.warn("missing pointer for glb/gltf texture",l),null;const f=d+"_"+l.guid,w=this.previouslyLoaded.get(f);if(w!==void 0){a&&console.log(`LOD ${e} was already loading/loaded: ${f}`);let p=await w.catch(N=>(console.error(`Error loading LOD ${e} from ${d}
2
+ `,N),null)),b=!1;if(p==null||(p instanceof z&&t instanceof z?(n=p.image)!=null&&n.data||(o=p.source)!=null&&o.data?p=this.copySettings(t,p):(b=!0,this.previouslyLoaded.delete(f)):p instanceof $&&t instanceof $&&((s=p.attributes.position)!=null&&s.array||(b=!0,this.previouslyLoaded.delete(f)))),!b)return p}const m=l,S=new Promise(async(p,b)=>{const N=new Oe;se(N),v&&(await new Promise(y=>setTimeout(y,1e3)),a&&console.warn("Start loading (delayed) "+d,m.guid));let F=d;if(m&&Array.isArray(m.lods)){const y=m.lods[e];y.hash&&(F+="?v="+y.hash)}const x=await N.loadAsync(F).catch(y=>(console.error(`Error loading LOD ${e} from ${d}
3
+ `,y),null));if(!x)return null;const L=x.parser;a&&console.log("Loading finished "+d,m.guid);let D=0;if(x.parser.json.textures){let y=!1;for(const h of x.parser.json.textures){if(h!=null&&h.extensions){const _=h?.extensions[P];if(_!=null&&_.guid&&_.guid===m.guid){y=!0;break}}D++}if(y){let h=await L.getDependency("texture",D);return h&&M.assignLODInformation(i.url,h,u,e,void 0,void 0),a&&console.log('change "'+t.name+'" \u2192 "'+h.name+'"',d,D,h,f),t instanceof z&&(h=this.copySettings(t,h)),h&&(h.guid=m.guid),p(h)}else v&&console.warn("Could not find texture with guid",m.guid)}if(D=0,x.parser.json.meshes){let y=!1;for(const h of x.parser.json.meshes){if(h!=null&&h.extensions){const _=h?.extensions[P];if(_!=null&&_.guid&&_.guid===m.guid){y=!0;break}}D++}if(y){const h=await L.getDependency("mesh",D),_=m;if(a&&console.log(`Loaded Mesh "${h.name}"`,d,D,h,f),h.isMesh===!0){const A=h.geometry;return M.assignLODInformation(i.url,A,u,e,void 0,_.density),p(A)}else{const A=new Array;for(let C=0;C<h.children.length;C++){const k=h.children[C];if(k instanceof G){const j=k.geometry;M.assignLODInformation(i.url,j,u,e,C,_.density),A.push(j)}}return p(A)}}}return p(null)});return this.previouslyLoaded.set(f,S),await S}else if(t instanceof z){a&&console.log("Load texture from uri: "+d);const f=await new De().loadAsync(d);return f?(f.guid=l.guid,f.flipY=!1,f.needsUpdate=!0,f.colorSpace=t.colorSpace,a&&console.log(l,f)):v&&console.warn("failed loading",d),f}}else v&&console.warn(`Can not load LOD ${e}: no LOD info found for "${u}" ${t.name}`,t.type);return null}static assignLODInformation(t,e,r,n,o,s){if(!e)return;e.userData||(e.userData={});const a=new Pe(t,r,n,o,s);e.userData.LODS=a,e.userData.LOD=n}static getAssignedLODInformation(t){var e;return((e=t?.userData)==null?void 0:e.LODS)||null}static copySettings(t,e){return e=e.clone(),v&&console.warn(`Copying texture settings
4
4
  `,t.uuid,`
5
- `,e.uuid),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}};let _=M;c(_,"registerTexture",(t,e,r,n,o)=>{v&&console.log("> Progressive: register texture",n,e.name,e.uuid,e,o),e.source&&(e.source[oe]=o);const s=o.guid;M.assignLODInformation(t,e,s,r,n,void 0),M.lodInfos.set(s,o),M.lowresCache.set(s,e)}),c(_,"registerMesh",(t,e,r,n,o,s)=>{var i;v&&console.log("> Progressive: register mesh",o,r.name,s,r.uuid,r);const a=r.geometry;a.userData||(a.userData={}),M.assignLODInformation(t,a,e,n,o,s.density),M.lodInfos.set(e,s);let u=M.lowresCache.get(e);u?u.push(r.geometry):u=[r.geometry],M.lowresCache.set(e,u),n>0&&!J(r)&&le(r,a);for(const l of k)(i=l.onRegisteredNewMesh)==null||i.call(l,r,s)}),c(_,"lodInfos",new Map),c(_,"previouslyLoaded",new Map),c(_,"lowresCache",new Map);class Pe{constructor(e,r,n,o,s){c(this,"url"),c(this,"key"),c(this,"level"),c(this,"index"),c(this,"density"),this.url=e,this.key=r,this.level=n,o!=null&&(this.index=o),s!=null&&(this.density=s)}}const W=H("debugprogressive"),Ie=H("noprogressive"),ce=Symbol("Needle:LODSManager"),E={mesh_lod:-1,texture_lod:-1},T=class{constructor(t){c(this,"renderer"),c(this,"projectionScreenMatrix",new ie),c(this,"cameraFrustrum",new Me),c(this,"targetTriangleDensity",2e5),c(this,"updateInterval",0),c(this,"pause",!1),c(this,"_frame",0),c(this,"_originalRender"),c(this,"_sphere",new Oe),c(this,"_tempBox",new ae),c(this,"_tempBox2",new ae),c(this,"tempMatrix",new ie),c(this,"_tempWorldPosition",new B),c(this,"_tempBoxSize",new B),c(this,"_tempBox2Size",new B),this.renderer=t}static getObjectLODState(t){var e;return(e=t.userData)==null?void 0:e.LOD_state}static addPlugin(t){k.push(t)}static removePlugin(t){const e=k.indexOf(t);e>=0&&k.splice(e,1)}static get(t){return t[ce]?t[ce]:new T(t)}get plugins(){return k}enable(){if(this._originalRender)return;let t=0;this._originalRender=this.renderer.render;const e=this;re(this.renderer),this.renderer.render=function(r,n){e.renderer.getRenderTarget()==null&&(t=0,e._frame+=1);const o=e._frame,s=t++;e.onBeforeRender(r,n,s,o),e._originalRender.call(this,r,n),e.onAfterRender(r,n,s,o)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(t,e,r,n){}onAfterRender(t,e,r,n){var o,s;if(this.pause)return;const i=this.renderer.renderLists.get(t,0),a=i.opaque;let u=!0;if(a.length===1){const l=a[0].material;(l.name==="EffectMaterial"||l.name==="CopyShader")&&(u=!1)}if(e.parent&&e.parent.type==="CubeCamera"&&(u=!1),u){if(Ie||this.updateInterval>0&&n%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const l=this.targetTriangleDensity;for(const d of a){if(d.material&&(((o=d.geometry)==null?void 0:o.type)==="BoxGeometry"||((s=d.geometry)==null?void 0:s.type)==="BufferGeometry")&&(d.material.name==="SphericalGaussianBlur"||d.material.name=="BackgroundCubeMaterial"||d.material.name==="CubemapFromEquirect"||d.material.name==="EquirectangularToCubeUV")){W&&(d.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(d.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",d,d.material.name,d.material.type)));continue}switch(d.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}const f=d.object;(f instanceof G||f.isMesh)&&this.updateLODs(t,e,f,l,n)}const g=i.transparent;for(const d of g){const f=d.object;(f instanceof G||f.isMesh)&&this.updateLODs(t,e,f,l,n)}}}updateLODs(t,e,r,n,o){var s,i;r.userData||(r.userData={});let a=r.userData.LOD_state;if(a||(a=new Be,r.userData.LOD_state=a),a.frames++<2)return;for(const l of k)(s=l.onBeforeUpdateLOD)==null||s.call(l,this.renderer,t,e,r);this.calculateLodLevel(e,r,a,n,E),E.mesh_lod=Math.round(E.mesh_lod),E.texture_lod=Math.round(E.texture_lod),E.mesh_lod>=0&&this.loadProgressiveMeshes(r,E.mesh_lod);let u=E.texture_lod;if(r.material&&u>=0){const l=r["DEBUG:LOD"];l!=null&&(u=l),this.loadProgressiveTextures(r.material,u)}for(const l of k)(i=l.onAfterUpdatedLOD)==null||i.call(l,this.renderer,t,e,r,E);a.lastLodLevel_Mesh=E.mesh_lod,a.lastLodLevel_Texture=E.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const o of t)this.loadProgressiveTextures(o,e);return}const r=t;let n=!1;(r.NEEDLE_LOD==null||e<r.NEEDLE_LOD)&&(n=!0),n&&(r.NEEDLE_LOD=e,_.assignTextureLOD(t,e))}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);if(t.userData||(t.userData={}),t.userData.LOD!==e){t.userData.LOD=e;const r=t.geometry;return _.assignMeshLOD(t,e).then(n=>(n&&t.userData.LOD==e&&r!=t.geometry,n))}return Promise.resolve(null)}static isInside(t,e){const r=t.min,n=t.max,o=(r.x+n.x)*.5,s=(r.y+n.y)*.5;return this._tempPtInside.set(o,s,r.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,r,n,o){var s;if(!e){o.mesh_lod=-1,o.texture_lod=-1;return}if(!t){o.mesh_lod=-1,o.texture_lod=-1;return}let i=10+1;if(W&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const a=_.getMeshLODInformation(e.geometry),u=a?.lods,l=u&&u.length>0,g=_.getMaterialMinMaxLODsCount(e.material),d=g?.min_count!=1/0&&g.min_count>0&&g.max_count>0;if(!l&&!d){o.mesh_lod=0,o.texture_lod=0;return}if(l||(i=0),!((s=this.cameraFrustrum)!=null&&s.intersectsObject(e))){o.mesh_lod=99,o.texture_lod=99;return}const f=e.geometry.boundingBox;if(f&&t.isPerspectiveCamera){const w=t;if(e.geometry.attributes.color&&e.geometry.attributes.color.count<100&&e.geometry.boundingSphere){this._sphere.copy(e.geometry.boundingSphere),this._sphere.applyMatrix4(e.matrixWorld);const x=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(x)){o.mesh_lod=0,o.texture_lod=0;return}}if(this._tempBox.copy(f),this._tempBox.applyMatrix4(e.matrixWorld),T.isInside(this._tempBox,this.projectionScreenMatrix)){o.mesh_lod=0,o.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&w.fov>70){const x=this._tempBox.min,D=this._tempBox.max;let L=x.x,y=x.y,h=D.x,O=D.y;const A=2,C=1.5,R=(x.x+D.x)*.5,j=(x.y+D.y)*.5;L=(L-R)*A+R,y=(y-j)*A+j,h=(h-R)*A+R,O=(O-j)*A+j;const fe=L<0&&h>0?0:Math.min(Math.abs(x.x),Math.abs(D.x)),ge=y<0&&O>0?0:Math.min(Math.abs(x.y),Math.abs(D.y)),Z=Math.max(fe,ge);r.lastCentrality=(C-Z)*(C-Z)*(C-Z)}else r.lastCentrality=1;const m=this._tempBox.getSize(this._tempBoxSize);m.multiplyScalar(.5),screen.availHeight>0&&m.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),m.x*=w.aspect;const S=t.matrixWorldInverse,p=this._tempBox2;p.copy(f),p.applyMatrix4(e.matrixWorld),p.applyMatrix4(S);const b=p.getSize(this._tempBox2Size),N=Math.max(b.x,b.y);if(Math.max(m.x,m.y)!=0&&N!=0&&(m.z=b.z/Math.max(b.x,b.y)*Math.max(m.x,m.y)),r.lastScreenCoverage=Math.max(m.x,m.y,m.z),r.lastScreenspaceVolume.copy(m),r.lastScreenCoverage*=r.lastCentrality,W&&T.debugDrawLine){const x=this.tempMatrix.copy(this.projectionScreenMatrix);x.invert();const D=T.corner0,L=T.corner1,y=T.corner2,h=T.corner3;D.copy(this._tempBox.min),L.copy(this._tempBox.max),L.x=D.x,y.copy(this._tempBox.max),y.y=D.y,h.copy(this._tempBox.max);const O=(D.z+h.z)*.5;D.z=L.z=y.z=h.z=O,D.applyMatrix4(x),L.applyMatrix4(x),y.applyMatrix4(x),h.applyMatrix4(x),T.debugDrawLine(D,L,255),T.debugDrawLine(D,y,255),T.debugDrawLine(L,h,255),T.debugDrawLine(y,h,255)}let F=999;if(u&&r.lastScreenCoverage>0){for(let x=0;x<u.length;x++)if(u[x].density/r.lastScreenCoverage<n){F=x;break}}F<i&&(i=F)}if(o.mesh_lod=i,d)if(r.lastLodLevel_Texture<0){if(o.texture_lod=g.max_count-1,W){const w=g.lods[g.max_count-1];W&&console.log(`First Texture LOD ${o.texture_lod} (${w.max_height}px) - ${e.name}`)}}else{const w=r.lastScreenCoverage*1.5,m=this.renderer.domElement.clientHeight/window.devicePixelRatio*w;for(let S=g.lods.length-1;S>=0;S--){const p=g.lods[S];if(!(Te()&&p.max_height>4096)&&p.max_height>m){o.texture_lod=S,o.texture_lod<r.lastLodLevel_Texture&&W&&console.log(`Texture LOD changed ${r.lastLodLevel_Texture} \u2192 ${o.texture_lod} (${p.max_height}px: ${(100*r.lastScreenCoverage).toFixed(2)} % = ${m.toFixed(0)}px) - ${e.name}`);break}}}else o.texture_lod=0}};let I=T;c(I,"debugDrawLine"),c(I,"corner0",new B),c(I,"corner1",new B),c(I,"corner2",new B),c(I,"corner3",new B),c(I,"_tempPtInside",new B);class Be{constructor(){c(this,"frames",0),c(this,"lastLodLevel_Mesh",-1),c(this,"lastLodLevel_Texture",-1),c(this,"lastScreenCoverage",0),c(this,"lastScreenspaceVolume",new B),c(this,"lastCentrality",0)}}const de=Symbol("NEEDLE_mesh_lod"),Q=Symbol("NEEDLE_texture_lod");function he(t){if(!t)return null;let e=null,r=null;for(let n=t;n!=null;n=Object.getPrototypeOf(n)){const o=Object.getOwnPropertySymbols(n),s=o.find(a=>a.toString()=="Symbol(renderer)"),i=o.find(a=>a.toString()=="Symbol(scene)");!e&&s!=null&&(e=t[s].threeRenderer),!r&&i!=null&&(r=t[i])}if(e){console.log("Adding Needle LODs to modelviewer");const n=I.get(e);if(I.addPlugin(new Ce(t)),n.enable(),r){const o=r.camera||r.traverse(s=>s.type=="PerspectiveCamera")[0];o&&e.render(r,o)}return()=>{n.disable()}}return null}class Ce{constructor(e){c(this,"modelviewer"),c(this,"_didWarnAboutMissingUrl",!1),this.modelviewer=e}onBeforeUpdateLOD(e,r,n,o){this.tryParseMeshLOD(r,o),this.tryParseTextureLOD(r,o)}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,r){if(r[Q]==!0)return;r[Q]=!0;const n=this.tryGetCurrentGLTF(e),o=this.getUrl();if(o&&n&&r.material){let s=function(a){var u,l,g;if(a[Q]==!0)return;a[Q]=!0,a.userData&&(a.userData.LOD=-1);const d=Object.keys(a);for(let f=0;f<d.length;f++){const w=d[f],m=a[w];if(m?.isTexture===!0){const S=(l=(u=m.userData)==null?void 0:u.associations)==null?void 0:l.textures,p=n.parser.json.textures[S];if(!p){console.warn("Texture data not found for texture index "+S);continue}if((g=p?.extensions)!=null&&g[P]){const b=p.extensions[P];b&&o&&_.registerTexture(o,m,b.lods.length,S,b)}}}};const i=r.material;if(Array.isArray(i))for(const a of i)s(a);else s(i)}}tryParseMeshLOD(e,r){var n,o;if(r[de]==!0)return;r[de]=!0;const s=this.getUrl();if(!s)return;const i=(o=(n=r.userData)==null?void 0:n.gltfExtensions)==null?void 0:o[P];if(i&&s){const a=r.uuid;_.registerMesh(s,a,r,0,i.lods.length,i)}}}function ke(t,e,r,n){re(e),se(r),r.register(s=>new _(s,t));const o=I.get(e);return n?.enableLODsManager!==!1&&o.enable(),o}document.addEventListener("DOMContentLoaded",()=>{he(document.querySelector("model-viewer"))});export{P as EXTENSION_NAME,I as LODsManager,_ as NEEDLE_progressive,se as addDracoAndKTX2Loaders,re as createLoaders,J as getRaycastMesh,he as patchModelViewer,we as setDracoDecoderLocation,be as setKTX2TranscoderLocation,le as setRaycastMesh,ke as useNeedleProgressive,Ee as useRaycastMeshes};
5
+ `,e.uuid),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}};let O=M;c(O,"registerTexture",(t,e,r,n,o)=>{if(v&&console.log("> Progressive: register texture",n,e.name,e.uuid,e,o),!e){v&&console.error("gltf-progressive: Register texture without texture");return}e.source&&(e.source[oe]=o);const s=o.guid;M.assignLODInformation(t,e,s,r,n,void 0),M.lodInfos.set(s,o),M.lowresCache.set(s,e)}),c(O,"registerMesh",(t,e,r,n,o,s)=>{var a;v&&console.log("> Progressive: register mesh",o,r.name,s,r.uuid,r);const i=r.geometry;if(!i){v&&console.warn("gltf-progressive: Register mesh without geometry");return}i.userData||(i.userData={}),M.assignLODInformation(t,i,e,n,o,s.density),M.lodInfos.set(e,s);let u=M.lowresCache.get(e);u?u.push(r.geometry):u=[r.geometry],M.lowresCache.set(e,u),n>0&&!J(r)&&le(r,i);for(const l of R)(a=l.onRegisteredNewMesh)==null||a.call(l,r,s)}),c(O,"lodInfos",new Map),c(O,"previouslyLoaded",new Map),c(O,"lowresCache",new Map);class Pe{constructor(e,r,n,o,s){c(this,"url"),c(this,"key"),c(this,"level"),c(this,"index"),c(this,"density"),this.url=e,this.key=r,this.level=n,o!=null&&(this.index=o),s!=null&&(this.density=s)}}const W=H("debugprogressive"),Ie=H("noprogressive"),ce=Symbol("Needle:LODSManager"),E={mesh_lod:-1,texture_lod:-1},T=class{constructor(t){c(this,"renderer"),c(this,"projectionScreenMatrix",new ie),c(this,"cameraFrustrum",new Me),c(this,"targetTriangleDensity",2e5),c(this,"updateInterval",0),c(this,"pause",!1),c(this,"_frame",0),c(this,"_originalRender"),c(this,"_sphere",new _e),c(this,"_tempBox",new ae),c(this,"_tempBox2",new ae),c(this,"tempMatrix",new ie),c(this,"_tempWorldPosition",new B),c(this,"_tempBoxSize",new B),c(this,"_tempBox2Size",new B),this.renderer=t}static getObjectLODState(t){var e;return(e=t.userData)==null?void 0:e.LOD_state}static addPlugin(t){R.push(t)}static removePlugin(t){const e=R.indexOf(t);e>=0&&R.splice(e,1)}static get(t){return t[ce]?t[ce]:new T(t)}get plugins(){return R}enable(){if(this._originalRender)return;let t=0;this._originalRender=this.renderer.render;const e=this;re(this.renderer),this.renderer.render=function(r,n){e.renderer.getRenderTarget()==null&&(t=0,e._frame+=1);const o=e._frame,s=t++;e.onBeforeRender(r,n,s,o),e._originalRender.call(this,r,n),e.onAfterRender(r,n,s,o)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(t,e,r,n){}onAfterRender(t,e,r,n){var o,s;if(this.pause)return;const a=this.renderer.renderLists.get(t,0),i=a.opaque;let u=!0;if(i.length===1){const l=i[0].material;(l.name==="EffectMaterial"||l.name==="CopyShader")&&(u=!1)}if(e.parent&&e.parent.type==="CubeCamera"&&(u=!1),u){if(Ie||this.updateInterval>0&&n%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const l=this.targetTriangleDensity;for(const d of i){if(d.material&&(((o=d.geometry)==null?void 0:o.type)==="BoxGeometry"||((s=d.geometry)==null?void 0:s.type)==="BufferGeometry")&&(d.material.name==="SphericalGaussianBlur"||d.material.name=="BackgroundCubeMaterial"||d.material.name==="CubemapFromEquirect"||d.material.name==="EquirectangularToCubeUV")){W&&(d.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(d.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",d,d.material.name,d.material.type)));continue}switch(d.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}const f=d.object;(f instanceof G||f.isMesh)&&this.updateLODs(t,e,f,l,n)}const g=a.transparent;for(const d of g){const f=d.object;(f instanceof G||f.isMesh)&&this.updateLODs(t,e,f,l,n)}}}updateLODs(t,e,r,n,o){var s,a;r.userData||(r.userData={});let i=r.userData.LOD_state;if(i||(i=new Be,r.userData.LOD_state=i),i.frames++<2)return;for(const l of R)(s=l.onBeforeUpdateLOD)==null||s.call(l,this.renderer,t,e,r);this.calculateLodLevel(e,r,i,n,E),E.mesh_lod=Math.round(E.mesh_lod),E.texture_lod=Math.round(E.texture_lod),E.mesh_lod>=0&&this.loadProgressiveMeshes(r,E.mesh_lod);let u=E.texture_lod;if(r.material&&u>=0){const l=r["DEBUG:LOD"];l!=null&&(u=l),this.loadProgressiveTextures(r.material,u)}for(const l of R)(a=l.onAfterUpdatedLOD)==null||a.call(l,this.renderer,t,e,r,E);i.lastLodLevel_Mesh=E.mesh_lod,i.lastLodLevel_Texture=E.texture_lod}loadProgressiveTextures(t,e){if(!t)return;if(Array.isArray(t)){for(const o of t)this.loadProgressiveTextures(o,e);return}const r=t;let n=!1;(r.NEEDLE_LOD==null||e<r.NEEDLE_LOD)&&(n=!0),n&&(r.NEEDLE_LOD=e,O.assignTextureLOD(t,e))}loadProgressiveMeshes(t,e){if(!t)return Promise.resolve(null);if(t.userData||(t.userData={}),t.userData.LOD!==e){t.userData.LOD=e;const r=t.geometry;return O.assignMeshLOD(t,e).then(n=>(n&&t.userData.LOD==e&&r!=t.geometry,n))}return Promise.resolve(null)}static isInside(t,e){const r=t.min,n=t.max,o=(r.x+n.x)*.5,s=(r.y+n.y)*.5;return this._tempPtInside.set(o,s,r.z).applyMatrix4(e).z<0}calculateLodLevel(t,e,r,n,o){var s;if(!e){o.mesh_lod=-1,o.texture_lod=-1;return}if(!t){o.mesh_lod=-1,o.texture_lod=-1;return}let a=10+1;if(W&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const i=O.getMeshLODInformation(e.geometry),u=i?.lods,l=u&&u.length>0,g=O.getMaterialMinMaxLODsCount(e.material),d=g?.min_count!=1/0&&g.min_count>0&&g.max_count>0;if(!l&&!d){o.mesh_lod=0,o.texture_lod=0;return}if(l||(a=0),!((s=this.cameraFrustrum)!=null&&s.intersectsObject(e))){o.mesh_lod=99,o.texture_lod=99;return}const f=e.geometry.boundingBox;if(f&&t.isPerspectiveCamera){const w=t;if(e.geometry.attributes.color&&e.geometry.attributes.color.count<100&&e.geometry.boundingSphere){this._sphere.copy(e.geometry.boundingSphere),this._sphere.applyMatrix4(e.matrixWorld);const x=t.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(x)){o.mesh_lod=0,o.texture_lod=0;return}}if(this._tempBox.copy(f),this._tempBox.applyMatrix4(e.matrixWorld),T.isInside(this._tempBox,this.projectionScreenMatrix)){o.mesh_lod=0,o.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&w.fov>70){const x=this._tempBox.min,L=this._tempBox.max;let D=x.x,y=x.y,h=L.x,_=L.y;const A=2,C=1.5,k=(x.x+L.x)*.5,j=(x.y+L.y)*.5;D=(D-k)*A+k,y=(y-j)*A+j,h=(h-k)*A+k,_=(_-j)*A+j;const fe=D<0&&h>0?0:Math.min(Math.abs(x.x),Math.abs(L.x)),ge=y<0&&_>0?0:Math.min(Math.abs(x.y),Math.abs(L.y)),Z=Math.max(fe,ge);r.lastCentrality=(C-Z)*(C-Z)*(C-Z)}else r.lastCentrality=1;const m=this._tempBox.getSize(this._tempBoxSize);m.multiplyScalar(.5),screen.availHeight>0&&m.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),m.x*=w.aspect;const S=t.matrixWorldInverse,p=this._tempBox2;p.copy(f),p.applyMatrix4(e.matrixWorld),p.applyMatrix4(S);const b=p.getSize(this._tempBox2Size),N=Math.max(b.x,b.y);if(Math.max(m.x,m.y)!=0&&N!=0&&(m.z=b.z/Math.max(b.x,b.y)*Math.max(m.x,m.y)),r.lastScreenCoverage=Math.max(m.x,m.y,m.z),r.lastScreenspaceVolume.copy(m),r.lastScreenCoverage*=r.lastCentrality,W&&T.debugDrawLine){const x=this.tempMatrix.copy(this.projectionScreenMatrix);x.invert();const L=T.corner0,D=T.corner1,y=T.corner2,h=T.corner3;L.copy(this._tempBox.min),D.copy(this._tempBox.max),D.x=L.x,y.copy(this._tempBox.max),y.y=L.y,h.copy(this._tempBox.max);const _=(L.z+h.z)*.5;L.z=D.z=y.z=h.z=_,L.applyMatrix4(x),D.applyMatrix4(x),y.applyMatrix4(x),h.applyMatrix4(x),T.debugDrawLine(L,D,255),T.debugDrawLine(L,y,255),T.debugDrawLine(D,h,255),T.debugDrawLine(y,h,255)}let F=999;if(u&&r.lastScreenCoverage>0){for(let x=0;x<u.length;x++)if(u[x].density/r.lastScreenCoverage<n){F=x;break}}F<a&&(a=F)}if(o.mesh_lod=a,d)if(r.lastLodLevel_Texture<0){if(o.texture_lod=g.max_count-1,W){const w=g.lods[g.max_count-1];W&&console.log(`First Texture LOD ${o.texture_lod} (${w.max_height}px) - ${e.name}`)}}else{const w=r.lastScreenCoverage*1.5,m=this.renderer.domElement.clientHeight/window.devicePixelRatio*w;for(let S=g.lods.length-1;S>=0;S--){const p=g.lods[S];if(!(Te()&&p.max_height>4096)&&p.max_height>m){o.texture_lod=S,o.texture_lod<r.lastLodLevel_Texture&&W&&console.log(`Texture LOD changed ${r.lastLodLevel_Texture} \u2192 ${o.texture_lod} (${p.max_height}px: ${(100*r.lastScreenCoverage).toFixed(2)} % = ${m.toFixed(0)}px) - ${e.name}`);break}}}else o.texture_lod=0}};let I=T;c(I,"debugDrawLine"),c(I,"corner0",new B),c(I,"corner1",new B),c(I,"corner2",new B),c(I,"corner3",new B),c(I,"_tempPtInside",new B);class Be{constructor(){c(this,"frames",0),c(this,"lastLodLevel_Mesh",-1),c(this,"lastLodLevel_Texture",-1),c(this,"lastScreenCoverage",0),c(this,"lastScreenspaceVolume",new B),c(this,"lastCentrality",0)}}const de=Symbol("NEEDLE_mesh_lod"),Q=Symbol("NEEDLE_texture_lod");function he(t){if(!t)return null;let e=null,r=null;for(let n=t;n!=null;n=Object.getPrototypeOf(n)){const o=Object.getOwnPropertySymbols(n),s=o.find(i=>i.toString()=="Symbol(renderer)"),a=o.find(i=>i.toString()=="Symbol(scene)");!e&&s!=null&&(e=t[s].threeRenderer),!r&&a!=null&&(r=t[a])}if(e){console.log("Adding Needle LODs to modelviewer");const n=I.get(e);if(I.addPlugin(new Ce(t)),n.enable(),r){const o=r.camera||r.traverse(s=>s.type=="PerspectiveCamera")[0];o&&e.render(r,o)}return()=>{n.disable()}}return null}class Ce{constructor(e){c(this,"modelviewer"),c(this,"_didWarnAboutMissingUrl",!1),this.modelviewer=e}onBeforeUpdateLOD(e,r,n,o){this.tryParseMeshLOD(r,o),this.tryParseTextureLOD(r,o)}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,r){if(r[Q]==!0)return;r[Q]=!0;const n=this.tryGetCurrentGLTF(e),o=this.getUrl();if(o&&n&&r.material){let s=function(i){var u,l,g;if(i[Q]==!0)return;i[Q]=!0,i.userData&&(i.userData.LOD=-1);const d=Object.keys(i);for(let f=0;f<d.length;f++){const w=d[f],m=i[w];if(m?.isTexture===!0){const S=(l=(u=m.userData)==null?void 0:u.associations)==null?void 0:l.textures,p=n.parser.json.textures[S];if(!p){console.warn("Texture data not found for texture index "+S);continue}if((g=p?.extensions)!=null&&g[P]){const b=p.extensions[P];b&&o&&O.registerTexture(o,m,b.lods.length,S,b)}}}};const a=r.material;if(Array.isArray(a))for(const i of a)s(i);else s(a)}}tryParseMeshLOD(e,r){var n,o;if(r[de]==!0)return;r[de]=!0;const s=this.getUrl();if(!s)return;const a=(o=(n=r.userData)==null?void 0:n.gltfExtensions)==null?void 0:o[P];if(a&&s){const i=r.uuid;O.registerMesh(s,i,r,0,a.lods.length,a)}}}function Re(t,e,r,n){re(e),se(r),r.register(s=>new O(s,t));const o=I.get(e);return n?.enableLODsManager!==!1&&o.enable(),o}document.addEventListener("DOMContentLoaded",()=>{he(document.querySelector("model-viewer"))});export{P as EXTENSION_NAME,I as LODsManager,O as NEEDLE_progressive,se as addDracoAndKTX2Loaders,re as createLoaders,J as getRaycastMesh,he as patchModelViewer,we as setDracoDecoderLocation,be as setKTX2TranscoderLocation,le as setRaycastMesh,Re as useNeedleProgressive,Ee as useRaycastMeshes};
@@ -1,5 +1,5 @@
1
- "use strict";var ge=Object.defineProperty;var pe=(l,e,t)=>e in l?ge(l,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):l[e]=t;var c=(l,e,t)=>(pe(l,typeof e!="symbol"?e+"":e,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const ye=require("three/examples/jsm/libs/meshopt_decoder.module.js"),Le=require("three/examples/jsm/loaders/DRACOLoader.js"),xe=require("three/examples/jsm/loaders/KTX2Loader.js"),g=require("three"),me=require("three/examples/jsm/loaders/GLTFLoader.js");let H="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",ie="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(H+"draco_decoder.js",{method:"head"}).catch(l=>{H="./include/draco/",ie="./include/ktx2/"});function De(l){H=l}function Me(l){ie=l}let W,re,V;function oe(l){W||(W=new Le.DRACOLoader,W.setDecoderPath(H),W.setDecoderConfig({type:"js"})),V||(V=new xe.KTX2Loader,V.setTranscoderPath(ie)),re||(re=ye.MeshoptDecoder),l?V.detectSupport(l):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function ne(l){l.dracoLoader||l.setDRACOLoader(W),l.ktx2Loader||l.setKTX2Loader(V),l.meshoptDecoder||l.setMeshoptDecoder(re)}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 _e(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}let $;function Oe(){return $!==void 0||($=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),J("debugprogressive")&&console.log("isMobileDevice",$)),$}function Q(l){var e;return((e=l==null?void 0:l.userData)==null?void 0:e["needle:raycast-mesh"])instanceof g.BufferGeometry?l.userData["needle:raycast-mesh"]:null}function ue(l,e){if((l.type==="Mesh"||l.type==="SkinnedMesh")&&!Q(l)){const r=ve(e);r.userData={isRaycastMesh:!0},l.userData||(l.userData={}),l.userData["needle:raycast-mesh"]=r}}function we(l=!0){if(l){if(U)return;const e=U=g.Mesh.prototype.raycast;g.Mesh.prototype.raycast=function(t,r){const s=this,o=Q(s);let i;o&&s.isMesh&&(i=s.geometry,s.geometry=o),e.call(this,t,r),i&&(s.geometry=i)}}else{if(!U)return;g.Mesh.prototype.raycast=U,U=null}}let U=null;function ve(l){const e=new g.BufferGeometry;for(const t in l.attributes)e.setAttribute(t,l.getAttribute(t));return e.setIndex(l.getIndex()),e}const I=new Array,R="NEEDLE_progressive",w=J("debugprogressive"),te=Symbol("needle-progressive-texture"),q=new Map,se=new Set;if(w){let l=function(){e+=1,console.log("Toggle LOD level",e,q),q.forEach((s,o)=>{for(const i of s.keys){const n=o[i];if(n.isBufferGeometry===!0){const a=S.getMeshLODInformation(n),h=a?Math.min(e,a.lods.length):0;o["DEBUG:LOD"]=e,S.assignMeshLOD(o,h),a&&(t=Math.max(t,a.lods.length-1))}else if(o.isMaterial===!0){o["DEBUG:LOD"]=e,S.assignTextureLOD(o,e);break}}}),e>=t&&(e=-1)},e=-1,t=2,r=!1;window.addEventListener("keyup",s=>{s.key==="p"&&l(),s.key==="w"&&(r=!r,se&&se.forEach(o=>{o.name!="BackgroundCubeMaterial"&&"wireframe"in o&&(o.wireframe=r)}))})}function ae(l,e,t){var s;if(!w)return;q.has(l)||q.set(l,{keys:[],sourceId:t});const r=q.get(l);((s=r==null?void 0:r.keys)==null?void 0:s.includes(e))==!1&&r.keys.push(e)}const v=class{constructor(e,t){c(this,"parser");c(this,"url");c(this,"_isLoadingMesh");c(this,"loadMesh",e=>{var r,s;if(this._isLoadingMesh)return null;const t=(s=(r=this.parser.json.meshes[e])==null?void 0:r.extensions)==null?void 0:s[R];return t?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",e).then(o=>(this._isLoadingMesh=!1,o&&v.registerMesh(this.url,t.guid,o,t.lods.length,void 0,t),o))):null});w&&console.log("Progressive extension registered for",t),this.parser=e,this.url=t}get name(){return R}static getMeshLODInformation(e){const t=this.getAssignedLODInformation(e);return t!=null&&t.key?this.lodInfos.get(t.key):null}static getMaterialMinMaxLODsCount(e,t){const r=this,s="LODS:minmax",o=e[s];if(o!=null)return o;if(t||(t={min_count:1/0,max_count:0,lods:[]}),Array.isArray(e)){for(const n of e)this.getMaterialMinMaxLODsCount(n,t);return e[s]=t,t}if(w==="verbose"&&console.log("getMaterialMinMaxLODsCount",e),e.type==="ShaderMaterial"||e.type==="RawShaderMaterial"){const n=e;for(const a of Object.keys(n.uniforms)){const h=n.uniforms[a].value;(h==null?void 0:h.isTexture)===!0&&i(h,t)}}else if(e.isMaterial)for(const n of Object.keys(e)){const a=e[n];(a==null?void 0:a.isTexture)===!0&&i(a,t)}return e[s]=t,t;function i(n,a){const h=r.getAssignedLODInformation(n);if(h){const d=r.lodInfos.get(h.key);if(d&&d.lods){a.min_count=Math.min(a.min_count,d.lods.length),a.max_count=Math.max(a.max_count,d.lods.length);for(let p=0;p<d.lods.length;p++){const f=d.lods[p];f.width&&(a.lods[p]=a.lods[p]||{min_height:1/0,max_height:0},a.lods[p].min_height=Math.min(a.lods[p].min_height,f.height),a.lods[p].max_height=Math.max(a.lods[p].max_height,f.height))}}}}}static hasLODLevelAvailable(e,t){var o;if(Array.isArray(e)){for(const i of e)if(this.hasLODLevelAvailable(i,t))return!0;return!1}if(e.isMaterial===!0){for(const i of Object.keys(e)){const n=e[i];if(n&&n.isTexture&&this.hasLODLevelAvailable(n,t))return!0}return!1}else if(e.isGroup===!0){for(const i of e.children)if(i.isMesh===!0&&this.hasLODLevelAvailable(i,t))return!0}let r,s;if(e.isMesh?r=e.geometry:(e.isBufferGeometry||e.isTexture)&&(r=e),r&&(o=r==null?void 0:r.userData)!=null&&o.LODS){const i=r.userData.LODS;if(s=this.lodInfos.get(i.key),t===void 0)return s!=null;if(s)return Array.isArray(s.lods)?t<s.lods.length:t===0}return!1}static assignMeshLOD(e,t){var r;if(!e)return Promise.resolve(null);if(e instanceof g.Mesh||e.isMesh===!0){const s=e.geometry,o=this.getAssignedLODInformation(s);if(!o)return Promise.resolve(null);for(const i of I)(r=i.onBeforeGetLODMesh)==null||r.call(i,e,t);return e["LOD:requested level"]=t,v.getOrLoadLOD(s,t).then(i=>{if(e["LOD:requested level"]===t){if(delete e["LOD:requested level"],Array.isArray(i)){const n=o.index||0;i=i[n]}i&&s!=i&&i instanceof g.BufferGeometry&&(e.geometry=i,w&&ae(e,"geometry",o.url))}return i}).catch(i=>(console.error("Error loading mesh LOD",e,i),null))}else w&&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 g.Material||e.isMaterial===!0){const r=e,s=[],o=new Array;if(w&&se.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const i=r;for(const n of Object.keys(i.uniforms)){const a=i.uniforms[n].value;if((a==null?void 0:a.isTexture)===!0){const h=this.assignTextureLODForSlot(a,t,r,n);s.push(h),o.push(n)}}}else for(const i of Object.keys(r)){const n=r[i];if((n==null?void 0:n.isTexture)===!0){const a=this.assignTextureLODForSlot(n,t,r,i);s.push(a),o.push(i)}}return Promise.all(s).then(i=>{const n=new Array;for(let a=0;a<i.length;a++){const h=i[a],d=o[a];h&&h.isTexture===!0?n.push({material:r,slot:d,texture:h,level:t}):n.push({material:r,slot:d,texture:null,level:t})}return n})}if(e instanceof g.Texture||e.isTexture===!0){const r=e;return this.assignTextureLODForSlot(r,t,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(e,t,r,s){return(e==null?void 0:e.isTexture)!==!0?Promise.resolve(null):s==="glyphMap"?Promise.resolve(e):v.getOrLoadLOD(e,t).then(o=>{if(Array.isArray(o))return null;if((o==null?void 0:o.isTexture)===!0){if(o!=e){if(r&&s){const i=r[s];if(i){const n=this.getAssignedLODInformation(i);if(n&&(n==null?void 0:n.level)<t)return w==="verbose"&&console.warn("Assigned texture level is already higher: ",n.level,t,r,i,o),null}r[s]=o}if(w&&s&&r){const i=this.getAssignedLODInformation(e);i&&ae(r,s,i.url)}}return o}else w=="verbose"&&console.warn("No LOD found for",e,t);return null}).catch(o=>(console.error("Error loading LOD",e,o),null))}afterRoot(e){var t,r;return w&&console.log("AFTER",this.url,e),(t=this.parser.json.textures)==null||t.forEach((s,o)=>{if(s!=null&&s.extensions){const i=s==null?void 0:s.extensions[R];if(i){let n=!1;for(const a of this.parser.associations.keys())a.isTexture===!0&&this.parser.associations.get(a).textures===o&&(n=!0,v.registerTexture(this.url,a,i.lods.length,o,i));n||this.parser.getDependency("texture",o).then(a=>{a&&v.registerTexture(this.url,a,i.lods.length,o,i)})}}}),(r=this.parser.json.meshes)==null||r.forEach((s,o)=>{if(s!=null&&s.extensions){const i=s==null?void 0:s.extensions[R];if(i&&i.lods){for(const n of this.parser.associations.keys())if(n.isMesh){const a=this.parser.associations.get(n);a.meshes===o&&v.registerMesh(this.url,i.guid,n,i.lods.length,a.primitives,i)}}}}),null}static async getOrLoadLOD(e,t){var n,a,h,d;const r=w=="verbose",s=e.userData.LODS;if(!s)return null;const o=s==null?void 0:s.key;let i;if(e.isTexture===!0){const p=e;p.source&&p.source[te]&&(i=p.source[te])}if(i||(i=v.lodInfos.get(o)),i){if(t>0){let x=!1;const M=Array.isArray(i.lods);if(M&&t>=i.lods.length?x=!0:M||(x=!0),x)return this.lowresCache.get(o)}const p=Array.isArray(i.lods)?(n=i.lods[t])==null?void 0:n.path:i.lods;if(!p)return w&&!i["missing:uri"]&&(i["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+t,i)),null;const f=_e(s.url,p);if(f.endsWith(".glb")||f.endsWith(".gltf")){if(!i.guid)return console.warn("missing pointer for glb/gltf texture",i),null;const x=f+"_"+i.guid,M=this.previouslyLoaded.get(x);if(M!==void 0){r&&console.log(`LOD ${t} was already loading/loaded: ${x}`);let m=await M.catch(F=>(console.error(`Error loading LOD ${t} from ${f}
2
- `,F),null)),A=!1;if(m==null||(m instanceof g.Texture&&e instanceof g.Texture?(a=m.image)!=null&&a.data||(h=m.source)!=null&&h.data?m=this.copySettings(e,m):(A=!0,this.previouslyLoaded.delete(x)):m instanceof g.BufferGeometry&&e instanceof g.BufferGeometry&&((d=m.attributes.position)!=null&&d.array||(A=!0,this.previouslyLoaded.delete(x)))),!A)return m}const _=i,O=new Promise(async(m,A)=>{const F=new me.GLTFLoader;ne(F),w&&(await new Promise(y=>setTimeout(y,1e3)),r&&console.warn("Start loading (delayed) "+f,_.guid));let Z=f;if(_&&Array.isArray(_.lods)){const y=_.lods[t];y.hash&&(Z+="?v="+y.hash)}const B=await F.loadAsync(Z).catch(y=>(console.error(`Error loading LOD ${t} from ${f}
3
- `,y),null));if(!B)return null;const j=B.parser;r&&console.log("Loading finished "+f,_.guid);let L=0;if(B.parser.json.textures){let y=!1;for(const u of B.parser.json.textures){if(u!=null&&u.extensions){const D=u==null?void 0:u.extensions[R];if(D!=null&&D.guid&&D.guid===_.guid){y=!0;break}}L++}if(y){let u=await j.getDependency("texture",L);return u&&v.assignLODInformation(s.url,u,o,t,void 0,void 0),r&&console.log('change "'+e.name+'" → "'+u.name+'"',f,L,u,x),e instanceof g.Texture&&(u=this.copySettings(e,u)),u&&(u.guid=_.guid),m(u)}else w&&console.warn("Could not find texture with guid",_.guid)}if(L=0,B.parser.json.meshes){let y=!1;for(const u of B.parser.json.meshes){if(u!=null&&u.extensions){const D=u==null?void 0:u.extensions[R];if(D!=null&&D.guid&&D.guid===_.guid){y=!0;break}}L++}if(y){const u=await j.getDependency("mesh",L),D=_;if(r&&console.log(`Loaded Mesh "${u.name}"`,f,L,u,x),u.isMesh===!0){const T=u.geometry;return v.assignLODInformation(s.url,T,o,t,void 0,D.density),m(T)}else{const T=new Array;for(let C=0;C<u.children.length;C++){const G=u.children[C];if(G instanceof g.Mesh){const N=G.geometry;v.assignLODInformation(s.url,N,o,t,C,D.density),T.push(N)}}return m(T)}}}return m(null)});return this.previouslyLoaded.set(x,O),await O}else if(e instanceof g.Texture){r&&console.log("Load texture from uri: "+f);const M=await new g.TextureLoader().loadAsync(f);return M?(M.guid=i.guid,M.flipY=!1,M.needsUpdate=!0,M.colorSpace=e.colorSpace,r&&console.log(i,M)):w&&console.warn("failed loading",f),M}}else w&&console.warn(`Can not load LOD ${t}: no LOD info found for "${o}" ${e.name}`,e.type);return null}static assignLODInformation(e,t,r,s,o,i){if(!t)return;t.userData||(t.userData={});const n=new Se(e,r,s,o,i);t.userData.LODS=n,t.userData.LOD=s}static getAssignedLODInformation(e){var t;return((t=e==null?void 0:e.userData)==null?void 0:t.LODS)||null}static copySettings(e,t){return t=t.clone(),w&&console.warn(`Copying texture settings
1
+ "use strict";var ge=Object.defineProperty;var pe=(l,e,t)=>e in l?ge(l,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):l[e]=t;var c=(l,e,t)=>(pe(l,typeof e!="symbol"?e+"":e,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const ye=require("three/examples/jsm/libs/meshopt_decoder.module.js"),Le=require("three/examples/jsm/loaders/DRACOLoader.js"),xe=require("three/examples/jsm/loaders/KTX2Loader.js"),g=require("three"),me=require("three/examples/jsm/loaders/GLTFLoader.js");let H="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",ie="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(H+"draco_decoder.js",{method:"head"}).catch(l=>{H="./include/draco/",ie="./include/ktx2/"});function De(l){H=l}function Me(l){ie=l}let W,re,V;function oe(l){W||(W=new Le.DRACOLoader,W.setDecoderPath(H),W.setDecoderConfig({type:"js"})),V||(V=new xe.KTX2Loader,V.setTranscoderPath(ie)),re||(re=ye.MeshoptDecoder),l?V.detectSupport(l):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function ne(l){l.dracoLoader||l.setDRACOLoader(W),l.ktx2Loader||l.setKTX2Loader(V),l.meshoptDecoder||l.setMeshoptDecoder(re)}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 _e(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}let $;function Oe(){return $!==void 0||($=/iPhone|iPad|iPod|Android|IEMobile/i.test(navigator.userAgent),J("debugprogressive")&&console.log("isMobileDevice",$)),$}function Q(l){var e;return((e=l==null?void 0:l.userData)==null?void 0:e["needle:raycast-mesh"])instanceof g.BufferGeometry?l.userData["needle:raycast-mesh"]:null}function ue(l,e){if((l.type==="Mesh"||l.type==="SkinnedMesh")&&!Q(l)){const r=ve(e);r.userData={isRaycastMesh:!0},l.userData||(l.userData={}),l.userData["needle:raycast-mesh"]=r}}function we(l=!0){if(l){if(U)return;const e=U=g.Mesh.prototype.raycast;g.Mesh.prototype.raycast=function(t,r){const s=this,o=Q(s);let i;o&&s.isMesh&&(i=s.geometry,s.geometry=o),e.call(this,t,r),i&&(s.geometry=i)}}else{if(!U)return;g.Mesh.prototype.raycast=U,U=null}}let U=null;function ve(l){const e=new g.BufferGeometry;for(const t in l.attributes)e.setAttribute(t,l.getAttribute(t));return e.setIndex(l.getIndex()),e}const I=new Array,C="NEEDLE_progressive",w=J("debugprogressive"),te=Symbol("needle-progressive-texture"),q=new Map,se=new Set;if(w){let l=function(){e+=1,console.log("Toggle LOD level",e,q),q.forEach((s,o)=>{for(const i of s.keys){const n=o[i];if(n.isBufferGeometry===!0){const a=S.getMeshLODInformation(n),h=a?Math.min(e,a.lods.length):0;o["DEBUG:LOD"]=e,S.assignMeshLOD(o,h),a&&(t=Math.max(t,a.lods.length-1))}else if(o.isMaterial===!0){o["DEBUG:LOD"]=e,S.assignTextureLOD(o,e);break}}}),e>=t&&(e=-1)},e=-1,t=2,r=!1;window.addEventListener("keyup",s=>{s.key==="p"&&l(),s.key==="w"&&(r=!r,se&&se.forEach(o=>{o.name!="BackgroundCubeMaterial"&&"wireframe"in o&&(o.wireframe=r)}))})}function ae(l,e,t){var s;if(!w)return;q.has(l)||q.set(l,{keys:[],sourceId:t});const r=q.get(l);((s=r==null?void 0:r.keys)==null?void 0:s.includes(e))==!1&&r.keys.push(e)}const v=class{constructor(e,t){c(this,"parser");c(this,"url");c(this,"_isLoadingMesh");c(this,"loadMesh",e=>{var r,s;if(this._isLoadingMesh)return null;const t=(s=(r=this.parser.json.meshes[e])==null?void 0:r.extensions)==null?void 0:s[C];return t?(this._isLoadingMesh=!0,this.parser.getDependency("mesh",e).then(o=>(this._isLoadingMesh=!1,o&&v.registerMesh(this.url,t.guid,o,t.lods.length,void 0,t),o))):null});w&&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 getMaterialMinMaxLODsCount(e,t){const r=this,s="LODS:minmax",o=e[s];if(o!=null)return o;if(t||(t={min_count:1/0,max_count:0,lods:[]}),Array.isArray(e)){for(const n of e)this.getMaterialMinMaxLODsCount(n,t);return e[s]=t,t}if(w==="verbose"&&console.log("getMaterialMinMaxLODsCount",e),e.type==="ShaderMaterial"||e.type==="RawShaderMaterial"){const n=e;for(const a of Object.keys(n.uniforms)){const h=n.uniforms[a].value;(h==null?void 0:h.isTexture)===!0&&i(h,t)}}else if(e.isMaterial)for(const n of Object.keys(e)){const a=e[n];(a==null?void 0:a.isTexture)===!0&&i(a,t)}return e[s]=t,t;function i(n,a){const h=r.getAssignedLODInformation(n);if(h){const d=r.lodInfos.get(h.key);if(d&&d.lods){a.min_count=Math.min(a.min_count,d.lods.length),a.max_count=Math.max(a.max_count,d.lods.length);for(let p=0;p<d.lods.length;p++){const f=d.lods[p];f.width&&(a.lods[p]=a.lods[p]||{min_height:1/0,max_height:0},a.lods[p].min_height=Math.min(a.lods[p].min_height,f.height),a.lods[p].max_height=Math.max(a.lods[p].max_height,f.height))}}}}}static hasLODLevelAvailable(e,t){var o;if(Array.isArray(e)){for(const i of e)if(this.hasLODLevelAvailable(i,t))return!0;return!1}if(e.isMaterial===!0){for(const i of Object.keys(e)){const n=e[i];if(n&&n.isTexture&&this.hasLODLevelAvailable(n,t))return!0}return!1}else if(e.isGroup===!0){for(const i of e.children)if(i.isMesh===!0&&this.hasLODLevelAvailable(i,t))return!0}let r,s;if(e.isMesh?r=e.geometry:(e.isBufferGeometry||e.isTexture)&&(r=e),r&&(o=r==null?void 0:r.userData)!=null&&o.LODS){const i=r.userData.LODS;if(s=this.lodInfos.get(i.key),t===void 0)return s!=null;if(s)return Array.isArray(s.lods)?t<s.lods.length:t===0}return!1}static assignMeshLOD(e,t){var r;if(!e)return Promise.resolve(null);if(e instanceof g.Mesh||e.isMesh===!0){const s=e.geometry,o=this.getAssignedLODInformation(s);if(!o)return Promise.resolve(null);for(const i of I)(r=i.onBeforeGetLODMesh)==null||r.call(i,e,t);return e["LOD:requested level"]=t,v.getOrLoadLOD(s,t).then(i=>{if(e["LOD:requested level"]===t){if(delete e["LOD:requested level"],Array.isArray(i)){const n=o.index||0;i=i[n]}i&&s!=i&&i instanceof g.BufferGeometry&&(e.geometry=i,w&&ae(e,"geometry",o.url))}return i}).catch(i=>(console.error("Error loading mesh LOD",e,i),null))}else w&&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 g.Material||e.isMaterial===!0){const r=e,s=[],o=new Array;if(w&&se.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const i=r;for(const n of Object.keys(i.uniforms)){const a=i.uniforms[n].value;if((a==null?void 0:a.isTexture)===!0){const h=this.assignTextureLODForSlot(a,t,r,n);s.push(h),o.push(n)}}}else for(const i of Object.keys(r)){const n=r[i];if((n==null?void 0:n.isTexture)===!0){const a=this.assignTextureLODForSlot(n,t,r,i);s.push(a),o.push(i)}}return Promise.all(s).then(i=>{const n=new Array;for(let a=0;a<i.length;a++){const h=i[a],d=o[a];h&&h.isTexture===!0?n.push({material:r,slot:d,texture:h,level:t}):n.push({material:r,slot:d,texture:null,level:t})}return n})}if(e instanceof g.Texture||e.isTexture===!0){const r=e;return this.assignTextureLODForSlot(r,t,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(e,t,r,s){return(e==null?void 0:e.isTexture)!==!0?Promise.resolve(null):s==="glyphMap"?Promise.resolve(e):v.getOrLoadLOD(e,t).then(o=>{if(Array.isArray(o))return null;if((o==null?void 0:o.isTexture)===!0){if(o!=e){if(r&&s){const i=r[s];if(i){const n=this.getAssignedLODInformation(i);if(n&&(n==null?void 0:n.level)<t)return w==="verbose"&&console.warn("Assigned texture level is already higher: ",n.level,t,r,i,o),null}r[s]=o}if(w&&s&&r){const i=this.getAssignedLODInformation(e);i&&ae(r,s,i.url)}}return o}else w=="verbose"&&console.warn("No LOD found for",e,t);return null}).catch(o=>(console.error("Error loading LOD",e,o),null))}afterRoot(e){var t,r;return w&&console.log("AFTER",this.url,e),(t=this.parser.json.textures)==null||t.forEach((s,o)=>{if(s!=null&&s.extensions){const i=s==null?void 0:s.extensions[C];if(i){let n=!1;for(const a of this.parser.associations.keys())a.isTexture===!0&&this.parser.associations.get(a).textures===o&&(n=!0,v.registerTexture(this.url,a,i.lods.length,o,i));n||this.parser.getDependency("texture",o).then(a=>{a&&v.registerTexture(this.url,a,i.lods.length,o,i)})}}}),(r=this.parser.json.meshes)==null||r.forEach((s,o)=>{if(s!=null&&s.extensions){const i=s==null?void 0:s.extensions[C];if(i&&i.lods){for(const n of this.parser.associations.keys())if(n.isMesh){const a=this.parser.associations.get(n);a.meshes===o&&v.registerMesh(this.url,i.guid,n,i.lods.length,a.primitives,i)}}}}),null}static async getOrLoadLOD(e,t){var n,a,h,d;const r=w=="verbose",s=e.userData.LODS;if(!s)return null;const o=s==null?void 0:s.key;let i;if(e.isTexture===!0){const p=e;p.source&&p.source[te]&&(i=p.source[te])}if(i||(i=v.lodInfos.get(o)),i){if(t>0){let x=!1;const M=Array.isArray(i.lods);if(M&&t>=i.lods.length?x=!0:M||(x=!0),x)return this.lowresCache.get(o)}const p=Array.isArray(i.lods)?(n=i.lods[t])==null?void 0:n.path:i.lods;if(!p)return w&&!i["missing:uri"]&&(i["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+t,i)),null;const f=_e(s.url,p);if(f.endsWith(".glb")||f.endsWith(".gltf")){if(!i.guid)return console.warn("missing pointer for glb/gltf texture",i),null;const x=f+"_"+i.guid,M=this.previouslyLoaded.get(x);if(M!==void 0){r&&console.log(`LOD ${t} was already loading/loaded: ${x}`);let m=await M.catch(F=>(console.error(`Error loading LOD ${t} from ${f}
2
+ `,F),null)),A=!1;if(m==null||(m instanceof g.Texture&&e instanceof g.Texture?(a=m.image)!=null&&a.data||(h=m.source)!=null&&h.data?m=this.copySettings(e,m):(A=!0,this.previouslyLoaded.delete(x)):m instanceof g.BufferGeometry&&e instanceof g.BufferGeometry&&((d=m.attributes.position)!=null&&d.array||(A=!0,this.previouslyLoaded.delete(x)))),!A)return m}const _=i,O=new Promise(async(m,A)=>{const F=new me.GLTFLoader;ne(F),w&&(await new Promise(y=>setTimeout(y,1e3)),r&&console.warn("Start loading (delayed) "+f,_.guid));let Z=f;if(_&&Array.isArray(_.lods)){const y=_.lods[t];y.hash&&(Z+="?v="+y.hash)}const R=await F.loadAsync(Z).catch(y=>(console.error(`Error loading LOD ${t} from ${f}
3
+ `,y),null));if(!R)return null;const j=R.parser;r&&console.log("Loading finished "+f,_.guid);let L=0;if(R.parser.json.textures){let y=!1;for(const u of R.parser.json.textures){if(u!=null&&u.extensions){const D=u==null?void 0:u.extensions[C];if(D!=null&&D.guid&&D.guid===_.guid){y=!0;break}}L++}if(y){let u=await j.getDependency("texture",L);return u&&v.assignLODInformation(s.url,u,o,t,void 0,void 0),r&&console.log('change "'+e.name+'" → "'+u.name+'"',f,L,u,x),e instanceof g.Texture&&(u=this.copySettings(e,u)),u&&(u.guid=_.guid),m(u)}else w&&console.warn("Could not find texture with guid",_.guid)}if(L=0,R.parser.json.meshes){let y=!1;for(const u of R.parser.json.meshes){if(u!=null&&u.extensions){const D=u==null?void 0:u.extensions[C];if(D!=null&&D.guid&&D.guid===_.guid){y=!0;break}}L++}if(y){const u=await j.getDependency("mesh",L),D=_;if(r&&console.log(`Loaded Mesh "${u.name}"`,f,L,u,x),u.isMesh===!0){const T=u.geometry;return v.assignLODInformation(s.url,T,o,t,void 0,D.density),m(T)}else{const T=new Array;for(let B=0;B<u.children.length;B++){const G=u.children[B];if(G instanceof g.Mesh){const N=G.geometry;v.assignLODInformation(s.url,N,o,t,B,D.density),T.push(N)}}return m(T)}}}return m(null)});return this.previouslyLoaded.set(x,O),await O}else if(e instanceof g.Texture){r&&console.log("Load texture from uri: "+f);const M=await new g.TextureLoader().loadAsync(f);return M?(M.guid=i.guid,M.flipY=!1,M.needsUpdate=!0,M.colorSpace=e.colorSpace,r&&console.log(i,M)):w&&console.warn("failed loading",f),M}}else w&&console.warn(`Can not load LOD ${t}: no LOD info found for "${o}" ${e.name}`,e.type);return null}static assignLODInformation(e,t,r,s,o,i){if(!t)return;t.userData||(t.userData={});const n=new Se(e,r,s,o,i);t.userData.LODS=n,t.userData.LOD=s}static getAssignedLODInformation(e){var t;return((t=e==null?void 0:e.userData)==null?void 0:t.LODS)||null}static copySettings(e,t){return t=t.clone(),w&&console.warn(`Copying texture settings
4
4
  `,e.uuid,`
5
- `,t.uuid),t.offset=e.offset,t.repeat=e.repeat,t.colorSpace=e.colorSpace,t.magFilter=e.magFilter,t.minFilter=e.minFilter,t.wrapS=e.wrapS,t.wrapT=e.wrapT,t.flipY=e.flipY,t.anisotropy=e.anisotropy,t.mipmaps||(t.generateMipmaps=e.generateMipmaps),t}};let S=v;c(S,"registerTexture",(e,t,r,s,o)=>{w&&console.log("> Progressive: register texture",s,t.name,t.uuid,t,o),t.source&&(t.source[te]=o);const i=o.guid;v.assignLODInformation(e,t,i,r,s,void 0),v.lodInfos.set(i,o),v.lowresCache.set(i,t)}),c(S,"registerMesh",(e,t,r,s,o,i)=>{var h;w&&console.log("> Progressive: register mesh",o,r.name,i,r.uuid,r);const n=r.geometry;n.userData||(n.userData={}),v.assignLODInformation(e,n,t,s,o,i.density),v.lodInfos.set(t,i);let a=v.lowresCache.get(t);a?a.push(r.geometry):a=[r.geometry],v.lowresCache.set(t,a),s>0&&!Q(r)&&ue(r,n);for(const d of I)(h=d.onRegisteredNewMesh)==null||h.call(d,r,i)}),c(S,"lodInfos",new Map),c(S,"previouslyLoaded",new Map),c(S,"lowresCache",new Map);class Se{constructor(e,t,r,s,o){c(this,"url");c(this,"key");c(this,"level");c(this,"index");c(this,"density");this.url=e,this.key=t,this.level=r,s!=null&&(this.index=s),o!=null&&(this.density=o)}}const z=J("debugprogressive"),Te=J("noprogressive"),le=Symbol("Needle:LODSManager"),E={mesh_lod:-1,texture_lod:-1},b=class{constructor(e){c(this,"renderer");c(this,"projectionScreenMatrix",new g.Matrix4);c(this,"cameraFrustrum",new g.Frustum);c(this,"targetTriangleDensity",2e5);c(this,"updateInterval",0);c(this,"pause",!1);c(this,"_frame",0);c(this,"_originalRender");c(this,"_sphere",new g.Sphere);c(this,"_tempBox",new g.Box3);c(this,"_tempBox2",new g.Box3);c(this,"tempMatrix",new g.Matrix4);c(this,"_tempWorldPosition",new g.Vector3);c(this,"_tempBoxSize",new g.Vector3);c(this,"_tempBox2Size",new g.Vector3);this.renderer=e}static getObjectLODState(e){var t;return(t=e.userData)==null?void 0:t.LOD_state}static addPlugin(e){I.push(e)}static removePlugin(e){const t=I.indexOf(e);t>=0&&I.splice(t,1)}static get(e){return e[le]?e[le]:new b(e)}get plugins(){return I}enable(){if(this._originalRender)return;let e=0;this._originalRender=this.renderer.render;const t=this;oe(this.renderer),this.renderer.render=function(r,s){t.renderer.getRenderTarget()==null&&(e=0,t._frame+=1);const i=t._frame,n=e++;t.onBeforeRender(r,s,n,i),t._originalRender.call(this,r,s),t.onAfterRender(r,s,n,i)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(e,t,r,s){}onAfterRender(e,t,r,s){var a,h;if(this.pause)return;const o=this.renderer.renderLists.get(e,0),i=o.opaque;let n=!0;if(i.length===1){const d=i[0].material;(d.name==="EffectMaterial"||d.name==="CopyShader")&&(n=!1)}if(t.parent&&t.parent.type==="CubeCamera"&&(n=!1),n){if(Te||this.updateInterval>0&&s%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const d=this.targetTriangleDensity;for(const f of i){if(f.material&&(((a=f.geometry)==null?void 0:a.type)==="BoxGeometry"||((h=f.geometry)==null?void 0:h.type)==="BufferGeometry")&&(f.material.name==="SphericalGaussianBlur"||f.material.name=="BackgroundCubeMaterial"||f.material.name==="CubemapFromEquirect"||f.material.name==="EquirectangularToCubeUV")){z&&(f.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(f.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",f,f.material.name,f.material.type)));continue}switch(f.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}const x=f.object;(x instanceof g.Mesh||x.isMesh)&&this.updateLODs(e,t,x,d,s)}const p=o.transparent;for(const f of p){const x=f.object;(x instanceof g.Mesh||x.isMesh)&&this.updateLODs(e,t,x,d,s)}}}updateLODs(e,t,r,s,o){var a,h;r.userData||(r.userData={});let i=r.userData.LOD_state;if(i||(i=new Ae,r.userData.LOD_state=i),i.frames++<2)return;for(const d of I)(a=d.onBeforeUpdateLOD)==null||a.call(d,this.renderer,e,t,r);this.calculateLodLevel(t,r,i,s,E),E.mesh_lod=Math.round(E.mesh_lod),E.texture_lod=Math.round(E.texture_lod),E.mesh_lod>=0&&this.loadProgressiveMeshes(r,E.mesh_lod);let n=E.texture_lod;if(r.material&&n>=0){const d=r["DEBUG:LOD"];d!=null&&(n=d),this.loadProgressiveTextures(r.material,n)}for(const d of I)(h=d.onAfterUpdatedLOD)==null||h.call(d,this.renderer,e,t,r,E);i.lastLodLevel_Mesh=E.mesh_lod,i.lastLodLevel_Texture=E.texture_lod}loadProgressiveTextures(e,t){if(!e)return;if(Array.isArray(e)){for(const o of e)this.loadProgressiveTextures(o,t);return}const r=e;let s=!1;(r.NEEDLE_LOD==null||t<r.NEEDLE_LOD)&&(s=!0),s&&(r.NEEDLE_LOD=t,S.assignTextureLOD(e,t))}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 S.assignMeshLOD(e,t).then(s=>(s&&e.userData.LOD==t&&r!=e.geometry,s))}return Promise.resolve(null)}static isInside(e,t){const r=e.min,s=e.max,o=(r.x+s.x)*.5,i=(r.y+s.y)*.5;return this._tempPtInside.set(o,i,r.z).applyMatrix4(t).z<0}calculateLodLevel(e,t,r,s,o){var M;if(!t){o.mesh_lod=-1,o.texture_lod=-1;return}if(!e){o.mesh_lod=-1,o.texture_lod=-1;return}let n=10+1;if(z&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const a=S.getMeshLODInformation(t.geometry),h=a==null?void 0:a.lods,d=h&&h.length>0,p=S.getMaterialMinMaxLODsCount(t.material),f=(p==null?void 0:p.min_count)!=1/0&&p.min_count>0&&p.max_count>0;if(!d&&!f){o.mesh_lod=0,o.texture_lod=0;return}if(d||(n=0),!((M=this.cameraFrustrum)!=null&&M.intersectsObject(t))){o.mesh_lod=99,o.texture_lod=99;return}const x=t.geometry.boundingBox;if(x&&e.isPerspectiveCamera){const _=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 L=e.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(L)){o.mesh_lod=0,o.texture_lod=0;return}}if(this._tempBox.copy(x),this._tempBox.applyMatrix4(t.matrixWorld),b.isInside(this._tempBox,this.projectionScreenMatrix)){o.mesh_lod=0,o.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&_.fov>70){const L=this._tempBox.min,y=this._tempBox.max;let u=L.x,D=L.y,T=y.x,C=y.y;const G=2,N=1.5,K=(L.x+y.x)*.5,X=(L.y+y.y)*.5;u=(u-K)*G+K,D=(D-X)*G+X,T=(T-K)*G+K,C=(C-X)*G+X;const de=u<0&&T>0?0:Math.min(Math.abs(L.x),Math.abs(y.x)),he=D<0&&C>0?0:Math.min(Math.abs(L.y),Math.abs(y.y)),ee=Math.max(de,he);r.lastCentrality=(N-ee)*(N-ee)*(N-ee)}else r.lastCentrality=1;const O=this._tempBox.getSize(this._tempBoxSize);O.multiplyScalar(.5),screen.availHeight>0&&O.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),O.x*=_.aspect;const k=e.matrixWorldInverse,m=this._tempBox2;m.copy(x),m.applyMatrix4(t.matrixWorld),m.applyMatrix4(k);const A=m.getSize(this._tempBox2Size),F=Math.max(A.x,A.y);if(Math.max(O.x,O.y)!=0&&F!=0&&(O.z=A.z/Math.max(A.x,A.y)*Math.max(O.x,O.y)),r.lastScreenCoverage=Math.max(O.x,O.y,O.z),r.lastScreenspaceVolume.copy(O),r.lastScreenCoverage*=r.lastCentrality,z&&b.debugDrawLine){const L=this.tempMatrix.copy(this.projectionScreenMatrix);L.invert();const y=b.corner0,u=b.corner1,D=b.corner2,T=b.corner3;y.copy(this._tempBox.min),u.copy(this._tempBox.max),u.x=y.x,D.copy(this._tempBox.max),D.y=y.y,T.copy(this._tempBox.max);const C=(y.z+T.z)*.5;y.z=u.z=D.z=T.z=C,y.applyMatrix4(L),u.applyMatrix4(L),D.applyMatrix4(L),T.applyMatrix4(L),b.debugDrawLine(y,u,255),b.debugDrawLine(y,D,255),b.debugDrawLine(u,T,255),b.debugDrawLine(D,T,255)}let B=999;if(h&&r.lastScreenCoverage>0){for(let L=0;L<h.length;L++)if(h[L].density/r.lastScreenCoverage<s){B=L;break}}B<n&&(n=B)}if(o.mesh_lod=n,f)if(r.lastLodLevel_Texture<0){if(o.texture_lod=p.max_count-1,z){const _=p.lods[p.max_count-1];z&&console.log(`First Texture LOD ${o.texture_lod} (${_.max_height}px) - ${t.name}`)}}else{const _=r.lastScreenCoverage*1.5,k=this.renderer.domElement.clientHeight/window.devicePixelRatio*_;for(let m=p.lods.length-1;m>=0;m--){const A=p.lods[m];if(!(Oe()&&A.max_height>4096)&&A.max_height>k){o.texture_lod=m,o.texture_lod<r.lastLodLevel_Texture&&z&&console.log(`Texture LOD changed ${r.lastLodLevel_Texture} → ${o.texture_lod} (${A.max_height}px: ${(100*r.lastScreenCoverage).toFixed(2)} % = ${k.toFixed(0)}px) - ${t.name}`);break}}}else o.texture_lod=0}};let P=b;c(P,"debugDrawLine"),c(P,"corner0",new g.Vector3),c(P,"corner1",new g.Vector3),c(P,"corner2",new g.Vector3),c(P,"corner3",new g.Vector3),c(P,"_tempPtInside",new g.Vector3);class Ae{constructor(){c(this,"frames",0);c(this,"lastLodLevel_Mesh",-1);c(this,"lastLodLevel_Texture",-1);c(this,"lastScreenCoverage",0);c(this,"lastScreenspaceVolume",new g.Vector3);c(this,"lastCentrality",0)}}const ce=Symbol("NEEDLE_mesh_lod"),Y=Symbol("NEEDLE_texture_lod");function fe(l){if(!l)return null;let e=null,t=null;for(let r=l;r!=null;r=Object.getPrototypeOf(r)){const s=Object.getOwnPropertySymbols(r),o=s.find(n=>n.toString()=="Symbol(renderer)"),i=s.find(n=>n.toString()=="Symbol(scene)");!e&&o!=null&&(e=l[o].threeRenderer),!t&&i!=null&&(t=l[i])}if(e){console.log("Adding Needle LODs to modelviewer");const r=P.get(e);if(P.addPlugin(new be(l)),r.enable(),t){const s=t.camera||t.traverse(o=>o.type=="PerspectiveCamera")[0];s&&e.render(t,s)}return()=>{r.disable()}}return null}class be{constructor(e){c(this,"modelviewer");c(this,"_didWarnAboutMissingUrl",!1);this.modelviewer=e}onBeforeUpdateLOD(e,t,r,s){this.tryParseMeshLOD(t,s),this.tryParseTextureLOD(t,s)}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[Y]==!0)return;t[Y]=!0;const r=this.tryGetCurrentGLTF(e),s=this.getUrl();if(s&&r&&t.material){let o=function(n){var h,d,p;if(n[Y]==!0)return;n[Y]=!0,n.userData&&(n.userData.LOD=-1);const a=Object.keys(n);for(let f=0;f<a.length;f++){const x=a[f],M=n[x];if((M==null?void 0:M.isTexture)===!0){const _=(d=(h=M.userData)==null?void 0:h.associations)==null?void 0:d.textures,O=r.parser.json.textures[_];if(!O){console.warn("Texture data not found for texture index "+_);continue}if((p=O==null?void 0:O.extensions)!=null&&p[R]){const k=O.extensions[R];k&&s&&S.registerTexture(s,M,k.lods.length,_,k)}}}};const i=t.material;if(Array.isArray(i))for(const n of i)o(n);else o(i)}}tryParseMeshLOD(e,t){var o,i;if(t[ce]==!0)return;t[ce]=!0;const r=this.getUrl();if(!r)return;const s=(i=(o=t.userData)==null?void 0:o.gltfExtensions)==null?void 0:i[R];if(s&&r){const n=t.uuid;S.registerMesh(r,n,t,0,s.lods.length,s)}}}function Pe(l,e,t,r){oe(e),ne(t),t.register(o=>new S(o,l));const s=P.get(e);return(r==null?void 0:r.enableLODsManager)!==!1&&s.enable(),s}document.addEventListener("DOMContentLoaded",()=>{fe(document.querySelector("model-viewer"))});exports.EXTENSION_NAME=R;exports.LODsManager=P;exports.NEEDLE_progressive=S;exports.addDracoAndKTX2Loaders=ne;exports.createLoaders=oe;exports.getRaycastMesh=Q;exports.patchModelViewer=fe;exports.setDracoDecoderLocation=De;exports.setKTX2TranscoderLocation=Me;exports.setRaycastMesh=ue;exports.useNeedleProgressive=Pe;exports.useRaycastMeshes=we;
5
+ `,t.uuid),t.offset=e.offset,t.repeat=e.repeat,t.colorSpace=e.colorSpace,t.magFilter=e.magFilter,t.minFilter=e.minFilter,t.wrapS=e.wrapS,t.wrapT=e.wrapT,t.flipY=e.flipY,t.anisotropy=e.anisotropy,t.mipmaps||(t.generateMipmaps=e.generateMipmaps),t}};let S=v;c(S,"registerTexture",(e,t,r,s,o)=>{if(w&&console.log("> Progressive: register texture",s,t.name,t.uuid,t,o),!t){w&&console.error("gltf-progressive: Register texture without texture");return}t.source&&(t.source[te]=o);const i=o.guid;v.assignLODInformation(e,t,i,r,s,void 0),v.lodInfos.set(i,o),v.lowresCache.set(i,t)}),c(S,"registerMesh",(e,t,r,s,o,i)=>{var h;w&&console.log("> Progressive: register mesh",o,r.name,i,r.uuid,r);const n=r.geometry;if(!n){w&&console.warn("gltf-progressive: Register mesh without geometry");return}n.userData||(n.userData={}),v.assignLODInformation(e,n,t,s,o,i.density),v.lodInfos.set(t,i);let a=v.lowresCache.get(t);a?a.push(r.geometry):a=[r.geometry],v.lowresCache.set(t,a),s>0&&!Q(r)&&ue(r,n);for(const d of I)(h=d.onRegisteredNewMesh)==null||h.call(d,r,i)}),c(S,"lodInfos",new Map),c(S,"previouslyLoaded",new Map),c(S,"lowresCache",new Map);class Se{constructor(e,t,r,s,o){c(this,"url");c(this,"key");c(this,"level");c(this,"index");c(this,"density");this.url=e,this.key=t,this.level=r,s!=null&&(this.index=s),o!=null&&(this.density=o)}}const z=J("debugprogressive"),Te=J("noprogressive"),le=Symbol("Needle:LODSManager"),E={mesh_lod:-1,texture_lod:-1},b=class{constructor(e){c(this,"renderer");c(this,"projectionScreenMatrix",new g.Matrix4);c(this,"cameraFrustrum",new g.Frustum);c(this,"targetTriangleDensity",2e5);c(this,"updateInterval",0);c(this,"pause",!1);c(this,"_frame",0);c(this,"_originalRender");c(this,"_sphere",new g.Sphere);c(this,"_tempBox",new g.Box3);c(this,"_tempBox2",new g.Box3);c(this,"tempMatrix",new g.Matrix4);c(this,"_tempWorldPosition",new g.Vector3);c(this,"_tempBoxSize",new g.Vector3);c(this,"_tempBox2Size",new g.Vector3);this.renderer=e}static getObjectLODState(e){var t;return(t=e.userData)==null?void 0:t.LOD_state}static addPlugin(e){I.push(e)}static removePlugin(e){const t=I.indexOf(e);t>=0&&I.splice(t,1)}static get(e){return e[le]?e[le]:new b(e)}get plugins(){return I}enable(){if(this._originalRender)return;let e=0;this._originalRender=this.renderer.render;const t=this;oe(this.renderer),this.renderer.render=function(r,s){t.renderer.getRenderTarget()==null&&(e=0,t._frame+=1);const i=t._frame,n=e++;t.onBeforeRender(r,s,n,i),t._originalRender.call(this,r,s),t.onAfterRender(r,s,n,i)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(e,t,r,s){}onAfterRender(e,t,r,s){var a,h;if(this.pause)return;const o=this.renderer.renderLists.get(e,0),i=o.opaque;let n=!0;if(i.length===1){const d=i[0].material;(d.name==="EffectMaterial"||d.name==="CopyShader")&&(n=!1)}if(t.parent&&t.parent.type==="CubeCamera"&&(n=!1),n){if(Te||this.updateInterval>0&&s%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const d=this.targetTriangleDensity;for(const f of i){if(f.material&&(((a=f.geometry)==null?void 0:a.type)==="BoxGeometry"||((h=f.geometry)==null?void 0:h.type)==="BufferGeometry")&&(f.material.name==="SphericalGaussianBlur"||f.material.name=="BackgroundCubeMaterial"||f.material.name==="CubemapFromEquirect"||f.material.name==="EquirectangularToCubeUV")){z&&(f.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(f.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",f,f.material.name,f.material.type)));continue}switch(f.material.type){case"LineBasicMaterial":case"LineDashedMaterial":case"PointsMaterial":case"ShadowMaterial":case"MeshDistanceMaterial":case"MeshDepthMaterial":continue}const x=f.object;(x instanceof g.Mesh||x.isMesh)&&this.updateLODs(e,t,x,d,s)}const p=o.transparent;for(const f of p){const x=f.object;(x instanceof g.Mesh||x.isMesh)&&this.updateLODs(e,t,x,d,s)}}}updateLODs(e,t,r,s,o){var a,h;r.userData||(r.userData={});let i=r.userData.LOD_state;if(i||(i=new Ae,r.userData.LOD_state=i),i.frames++<2)return;for(const d of I)(a=d.onBeforeUpdateLOD)==null||a.call(d,this.renderer,e,t,r);this.calculateLodLevel(t,r,i,s,E),E.mesh_lod=Math.round(E.mesh_lod),E.texture_lod=Math.round(E.texture_lod),E.mesh_lod>=0&&this.loadProgressiveMeshes(r,E.mesh_lod);let n=E.texture_lod;if(r.material&&n>=0){const d=r["DEBUG:LOD"];d!=null&&(n=d),this.loadProgressiveTextures(r.material,n)}for(const d of I)(h=d.onAfterUpdatedLOD)==null||h.call(d,this.renderer,e,t,r,E);i.lastLodLevel_Mesh=E.mesh_lod,i.lastLodLevel_Texture=E.texture_lod}loadProgressiveTextures(e,t){if(!e)return;if(Array.isArray(e)){for(const o of e)this.loadProgressiveTextures(o,t);return}const r=e;let s=!1;(r.NEEDLE_LOD==null||t<r.NEEDLE_LOD)&&(s=!0),s&&(r.NEEDLE_LOD=t,S.assignTextureLOD(e,t))}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 S.assignMeshLOD(e,t).then(s=>(s&&e.userData.LOD==t&&r!=e.geometry,s))}return Promise.resolve(null)}static isInside(e,t){const r=e.min,s=e.max,o=(r.x+s.x)*.5,i=(r.y+s.y)*.5;return this._tempPtInside.set(o,i,r.z).applyMatrix4(t).z<0}calculateLodLevel(e,t,r,s,o){var M;if(!t){o.mesh_lod=-1,o.texture_lod=-1;return}if(!e){o.mesh_lod=-1,o.texture_lod=-1;return}let n=10+1;if(z&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const a=S.getMeshLODInformation(t.geometry),h=a==null?void 0:a.lods,d=h&&h.length>0,p=S.getMaterialMinMaxLODsCount(t.material),f=(p==null?void 0:p.min_count)!=1/0&&p.min_count>0&&p.max_count>0;if(!d&&!f){o.mesh_lod=0,o.texture_lod=0;return}if(d||(n=0),!((M=this.cameraFrustrum)!=null&&M.intersectsObject(t))){o.mesh_lod=99,o.texture_lod=99;return}const x=t.geometry.boundingBox;if(x&&e.isPerspectiveCamera){const _=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 L=e.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(L)){o.mesh_lod=0,o.texture_lod=0;return}}if(this._tempBox.copy(x),this._tempBox.applyMatrix4(t.matrixWorld),b.isInside(this._tempBox,this.projectionScreenMatrix)){o.mesh_lod=0,o.texture_lod=0;return}if(this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&_.fov>70){const L=this._tempBox.min,y=this._tempBox.max;let u=L.x,D=L.y,T=y.x,B=y.y;const G=2,N=1.5,K=(L.x+y.x)*.5,X=(L.y+y.y)*.5;u=(u-K)*G+K,D=(D-X)*G+X,T=(T-K)*G+K,B=(B-X)*G+X;const de=u<0&&T>0?0:Math.min(Math.abs(L.x),Math.abs(y.x)),he=D<0&&B>0?0:Math.min(Math.abs(L.y),Math.abs(y.y)),ee=Math.max(de,he);r.lastCentrality=(N-ee)*(N-ee)*(N-ee)}else r.lastCentrality=1;const O=this._tempBox.getSize(this._tempBoxSize);O.multiplyScalar(.5),screen.availHeight>0&&O.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),O.x*=_.aspect;const k=e.matrixWorldInverse,m=this._tempBox2;m.copy(x),m.applyMatrix4(t.matrixWorld),m.applyMatrix4(k);const A=m.getSize(this._tempBox2Size),F=Math.max(A.x,A.y);if(Math.max(O.x,O.y)!=0&&F!=0&&(O.z=A.z/Math.max(A.x,A.y)*Math.max(O.x,O.y)),r.lastScreenCoverage=Math.max(O.x,O.y,O.z),r.lastScreenspaceVolume.copy(O),r.lastScreenCoverage*=r.lastCentrality,z&&b.debugDrawLine){const L=this.tempMatrix.copy(this.projectionScreenMatrix);L.invert();const y=b.corner0,u=b.corner1,D=b.corner2,T=b.corner3;y.copy(this._tempBox.min),u.copy(this._tempBox.max),u.x=y.x,D.copy(this._tempBox.max),D.y=y.y,T.copy(this._tempBox.max);const B=(y.z+T.z)*.5;y.z=u.z=D.z=T.z=B,y.applyMatrix4(L),u.applyMatrix4(L),D.applyMatrix4(L),T.applyMatrix4(L),b.debugDrawLine(y,u,255),b.debugDrawLine(y,D,255),b.debugDrawLine(u,T,255),b.debugDrawLine(D,T,255)}let R=999;if(h&&r.lastScreenCoverage>0){for(let L=0;L<h.length;L++)if(h[L].density/r.lastScreenCoverage<s){R=L;break}}R<n&&(n=R)}if(o.mesh_lod=n,f)if(r.lastLodLevel_Texture<0){if(o.texture_lod=p.max_count-1,z){const _=p.lods[p.max_count-1];z&&console.log(`First Texture LOD ${o.texture_lod} (${_.max_height}px) - ${t.name}`)}}else{const _=r.lastScreenCoverage*1.5,k=this.renderer.domElement.clientHeight/window.devicePixelRatio*_;for(let m=p.lods.length-1;m>=0;m--){const A=p.lods[m];if(!(Oe()&&A.max_height>4096)&&A.max_height>k){o.texture_lod=m,o.texture_lod<r.lastLodLevel_Texture&&z&&console.log(`Texture LOD changed ${r.lastLodLevel_Texture} → ${o.texture_lod} (${A.max_height}px: ${(100*r.lastScreenCoverage).toFixed(2)} % = ${k.toFixed(0)}px) - ${t.name}`);break}}}else o.texture_lod=0}};let P=b;c(P,"debugDrawLine"),c(P,"corner0",new g.Vector3),c(P,"corner1",new g.Vector3),c(P,"corner2",new g.Vector3),c(P,"corner3",new g.Vector3),c(P,"_tempPtInside",new g.Vector3);class Ae{constructor(){c(this,"frames",0);c(this,"lastLodLevel_Mesh",-1);c(this,"lastLodLevel_Texture",-1);c(this,"lastScreenCoverage",0);c(this,"lastScreenspaceVolume",new g.Vector3);c(this,"lastCentrality",0)}}const ce=Symbol("NEEDLE_mesh_lod"),Y=Symbol("NEEDLE_texture_lod");function fe(l){if(!l)return null;let e=null,t=null;for(let r=l;r!=null;r=Object.getPrototypeOf(r)){const s=Object.getOwnPropertySymbols(r),o=s.find(n=>n.toString()=="Symbol(renderer)"),i=s.find(n=>n.toString()=="Symbol(scene)");!e&&o!=null&&(e=l[o].threeRenderer),!t&&i!=null&&(t=l[i])}if(e){console.log("Adding Needle LODs to modelviewer");const r=P.get(e);if(P.addPlugin(new be(l)),r.enable(),t){const s=t.camera||t.traverse(o=>o.type=="PerspectiveCamera")[0];s&&e.render(t,s)}return()=>{r.disable()}}return null}class be{constructor(e){c(this,"modelviewer");c(this,"_didWarnAboutMissingUrl",!1);this.modelviewer=e}onBeforeUpdateLOD(e,t,r,s){this.tryParseMeshLOD(t,s),this.tryParseTextureLOD(t,s)}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[Y]==!0)return;t[Y]=!0;const r=this.tryGetCurrentGLTF(e),s=this.getUrl();if(s&&r&&t.material){let o=function(n){var h,d,p;if(n[Y]==!0)return;n[Y]=!0,n.userData&&(n.userData.LOD=-1);const a=Object.keys(n);for(let f=0;f<a.length;f++){const x=a[f],M=n[x];if((M==null?void 0:M.isTexture)===!0){const _=(d=(h=M.userData)==null?void 0:h.associations)==null?void 0:d.textures,O=r.parser.json.textures[_];if(!O){console.warn("Texture data not found for texture index "+_);continue}if((p=O==null?void 0:O.extensions)!=null&&p[C]){const k=O.extensions[C];k&&s&&S.registerTexture(s,M,k.lods.length,_,k)}}}};const i=t.material;if(Array.isArray(i))for(const n of i)o(n);else o(i)}}tryParseMeshLOD(e,t){var o,i;if(t[ce]==!0)return;t[ce]=!0;const r=this.getUrl();if(!r)return;const s=(i=(o=t.userData)==null?void 0:o.gltfExtensions)==null?void 0:i[C];if(s&&r){const n=t.uuid;S.registerMesh(r,n,t,0,s.lods.length,s)}}}function Pe(l,e,t,r){oe(e),ne(t),t.register(o=>new S(o,l));const s=P.get(e);return(r==null?void 0:r.enableLODsManager)!==!1&&s.enable(),s}document.addEventListener("DOMContentLoaded",()=>{fe(document.querySelector("model-viewer"))});exports.EXTENSION_NAME=C;exports.LODsManager=P;exports.NEEDLE_progressive=S;exports.addDracoAndKTX2Loaders=ne;exports.createLoaders=oe;exports.getRaycastMesh=Q;exports.patchModelViewer=fe;exports.setDracoDecoderLocation=De;exports.setKTX2TranscoderLocation=Me;exports.setRaycastMesh=ue;exports.useNeedleProgressive=Pe;exports.useRaycastMeshes=we;
package/lib/extension.js CHANGED
@@ -473,6 +473,11 @@ export class NEEDLE_progressive {
473
473
  static registerTexture = (url, tex, level, index, ext) => {
474
474
  if (debug)
475
475
  console.log("> Progressive: register texture", index, tex.name, tex.uuid, tex, ext);
476
+ if (!tex) {
477
+ if (debug)
478
+ console.error("gltf-progressive: Register texture without texture");
479
+ return;
480
+ }
476
481
  // Put the extension info into the source (seems like tiled textures are cloned and the userdata etc is not properly copied BUT the source of course is not cloned)
477
482
  // see https://github.com/needle-tools/needle-engine-support/issues/133
478
483
  if (tex.source)
@@ -489,6 +494,11 @@ export class NEEDLE_progressive {
489
494
  if (debug)
490
495
  console.log("> Progressive: register mesh", index, mesh.name, ext, mesh.uuid, mesh);
491
496
  const geometry = mesh.geometry;
497
+ if (!geometry) {
498
+ if (debug)
499
+ console.warn("gltf-progressive: Register mesh without geometry");
500
+ return;
501
+ }
492
502
  if (!geometry.userData)
493
503
  geometry.userData = {};
494
504
  NEEDLE_progressive.assignLODInformation(url, geometry, key, level, index, ext.density);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/gltf-progressive",
3
- "version": "1.2.0-alpha.4",
3
+ "version": "1.2.0-alpha.5",
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": {