@needle-tools/gltf-progressive 1.0.0-alpha.10 → 1.0.0-alpha.12

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,13 @@ All notable changes to this package will be documented in this file.
4
4
  The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5
5
  and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [1.0.0-alpha.12] - 2023-05-19
8
+ - fix: update LODs when using postprocessing
9
+
10
+ ## [1.0.0-alpha.11] - 2023-05-17
11
+ - add: expose `setDracoDecoderLocation` and `setKTX2TranscoderLocation`
12
+ - fix: allow using draco decoder and ktx2 transcoder from local filepath
13
+
7
14
  ## [1.0.0-alpha.10] - 2023-05-07
8
15
  - fix: progressive assets are now only updated during the main canvas render call and not e.g. when rendering to a texture
9
16
 
@@ -1,20 +1,29 @@
1
- var oe = Object.defineProperty;
2
- var ae = (l, e, t) => e in l ? oe(l, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : l[e] = t;
3
- var u = (l, e, t) => (ae(l, typeof e != "symbol" ? e + "" : e, t), t);
4
- import { Mesh as q, BufferGeometry as X, Material as le, Texture as U, TextureLoader as ue, Matrix4 as j, Frustum as ce, Sphere as fe, Box3 as ee, Vector3 as R } from "three";
5
- import { GLTFLoader as de } from "three/examples/jsm/loaders/GLTFLoader.js";
6
- import { MeshoptDecoder as ge } from "three/examples/jsm/libs/meshopt_decoder.module.js";
7
- import { DRACOLoader as he } from "three/examples/jsm/loaders/DRACOLoader.js";
8
- import { KTX2Loader as pe } from "three/examples/jsm/loaders/KTX2Loader.js";
9
- const ye = "https://www.gstatic.com/draco/versioned/decoders/1.4.1/", me = "https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";
10
- let F, H, W;
11
- function se(l) {
12
- F || (F = new he(), F.setDecoderPath(ye), F.setDecoderConfig({ type: "js" })), W || (W = new pe(), W.setTranscoderPath(me)), H || (H = ge), l ? W.detectSupport(l) : console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail");
1
+ var le = Object.defineProperty;
2
+ var ue = (l, e, t) => e in l ? le(l, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : l[e] = t;
3
+ var c = (l, e, t) => (ue(l, typeof e != "symbol" ? e + "" : e, t), t);
4
+ import { Mesh as q, BufferGeometry as V, Material as ce, Texture as U, TextureLoader as fe, Matrix4 as te, Frustum as de, Sphere as ge, Box3 as re, Vector3 as C } from "three";
5
+ import { GLTFLoader as he } from "three/examples/jsm/loaders/GLTFLoader.js";
6
+ import { MeshoptDecoder as pe } from "three/examples/jsm/libs/meshopt_decoder.module.js";
7
+ import { DRACOLoader as ye } from "three/examples/jsm/loaders/DRACOLoader.js";
8
+ import { KTX2Loader as me } from "three/examples/jsm/loaders/KTX2Loader.js";
9
+ let K = "https://www.gstatic.com/draco/versioned/decoders/1.4.1/", j = "https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";
10
+ fetch(K + "draco_decoder.js", { method: "head" }).catch((l) => {
11
+ K = "./include/draco/", j = "./include/ktx2/";
12
+ });
13
+ function _e(l) {
14
+ K = l;
15
+ }
16
+ function Be(l) {
17
+ j = l;
18
+ }
19
+ let F, J, W;
20
+ function ne(l) {
21
+ F || (F = new ye(), F.setDecoderPath(K), F.setDecoderConfig({ type: "js" })), W || (W = new me(), W.setTranscoderPath(j)), J || (J = pe), l ? W.detectSupport(l) : console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail");
13
22
  }
14
- function ie(l) {
15
- l.dracoLoader || l.setDRACOLoader(F), l.ktx2Loader || l.setKTX2Loader(W), l.meshoptDecoder || l.setMeshoptDecoder(H);
23
+ function oe(l) {
24
+ l.dracoLoader || l.setDRACOLoader(F), l.ktx2Loader || l.setKTX2Loader(W), l.meshoptDecoder || l.setMeshoptDecoder(J);
16
25
  }
17
- function Z(l) {
26
+ function ee(l) {
18
27
  const t = new URL(window.location.href).searchParams.get(l);
19
28
  return t == null || t === "0" || t === "false" ? !1 : t === "" ? !0 : t;
20
29
  }
@@ -30,19 +39,19 @@ function Le(l, e) {
30
39
  }
31
40
  return e;
32
41
  }
33
- const J = new Array();
34
- function _e(l) {
35
- J.push(l);
42
+ const Q = new Array();
43
+ function ke(l) {
44
+ Q.push(l);
36
45
  }
37
- const k = "NEEDLE_progressive", S = Z("debugprogressive"), V = Symbol("needle-progressive-texture"), z = /* @__PURE__ */ new Map(), Q = /* @__PURE__ */ new Set();
46
+ const R = "NEEDLE_progressive", S = ee("debugprogressive"), Y = Symbol("needle-progressive-texture"), z = /* @__PURE__ */ new Map(), Z = /* @__PURE__ */ new Set();
38
47
  if (S) {
39
48
  let l = function() {
40
49
  e += 1, console.log("Toggle LOD level", e, z), z.forEach((i, n) => {
41
50
  for (const s of i.keys) {
42
51
  const o = n[s];
43
52
  if (o.isBufferGeometry === !0) {
44
- const a = v.getMeshLODInformation(o), h = a ? Math.min(e, a.lods.length) : 0;
45
- n["DEBUG:LOD"] = e, v.assignMeshLOD(n, h), a && (t = Math.max(t, a.lods.length - 1));
53
+ const a = v.getMeshLODInformation(o), g = a ? Math.min(e, a.lods.length) : 0;
54
+ n["DEBUG:LOD"] = e, v.assignMeshLOD(n, g), a && (t = Math.max(t, a.lods.length - 1));
46
55
  } else if (n.isMaterial === !0) {
47
56
  n["DEBUG:LOD"] = e, v.assignTextureLOD(n, e);
48
57
  break;
@@ -51,12 +60,12 @@ if (S) {
51
60
  }), e >= t && (e = -1);
52
61
  }, e = -1, t = 2, r = !1;
53
62
  window.addEventListener("keyup", (i) => {
54
- i.key === "p" && l(), i.key === "w" && (r = !r, Q && Q.forEach((n) => {
63
+ i.key === "p" && l(), i.key === "w" && (r = !r, Z && Z.forEach((n) => {
55
64
  n.name != "BackgroundCubeMaterial" && "wireframe" in n && (n.wireframe = r);
56
65
  }));
57
66
  });
58
67
  }
59
- function te(l, e, t) {
68
+ function se(l, e, t) {
60
69
  var i;
61
70
  if (!S)
62
71
  return;
@@ -66,13 +75,13 @@ function te(l, e, t) {
66
75
  }
67
76
  const M = class {
68
77
  constructor(e, t) {
69
- u(this, "parser");
70
- u(this, "url");
78
+ c(this, "parser");
79
+ c(this, "url");
71
80
  S && console.log("Progressive extension registered for", t), this.parser = e, this.url = t;
72
81
  }
73
82
  /** The name of the extension */
74
83
  get name() {
75
- return k;
84
+ return R;
76
85
  }
77
86
  static getMeshLODInformation(e) {
78
87
  const t = this.getAssignedLODInformation(e);
@@ -129,7 +138,7 @@ const M = class {
129
138
  const i = e.geometry, n = this.getAssignedLODInformation(i);
130
139
  if (!n)
131
140
  return Promise.resolve(null);
132
- for (const s of J)
141
+ for (const s of Q)
133
142
  (r = s.onBeforeGetLODMesh) == null || r.call(s, e, t);
134
143
  return e["LOD:requested level"] = t, M.getOrLoadLOD(i, t).then((s) => {
135
144
  if (e["LOD:requested level"] === t) {
@@ -137,7 +146,7 @@ const M = class {
137
146
  const o = n.index || 0;
138
147
  s = s[o];
139
148
  }
140
- s && i != s && s instanceof X && (e.geometry = s, S && te(e, "geometry", n.url));
149
+ s && i != s && s instanceof V && (e.geometry = s, S && se(e, "geometry", n.url));
141
150
  }
142
151
  return s;
143
152
  }).catch((s) => (console.error("Error loading mesh LOD", e, s), null));
@@ -155,15 +164,15 @@ const M = class {
155
164
  static assignTextureLOD(e, t = 0) {
156
165
  if (!e)
157
166
  return Promise.resolve(null);
158
- if (e instanceof le || e.isMaterial === !0) {
167
+ if (e instanceof ce || e.isMaterial === !0) {
159
168
  const r = e, i = [], n = new Array();
160
- if (S && Q.add(r), r.uniforms && r.isRawShaderMaterial || r.isShaderMaterial === !0) {
169
+ if (S && Z.add(r), r.uniforms && r.isRawShaderMaterial || r.isShaderMaterial === !0) {
161
170
  const s = r;
162
171
  for (const o of Object.keys(s.uniforms)) {
163
172
  const a = s.uniforms[o].value;
164
173
  if ((a == null ? void 0 : a.isTexture) === !0) {
165
- const h = this.assignTextureLODForSlot(a, t, r, o);
166
- i.push(h), n.push(o);
174
+ const g = this.assignTextureLODForSlot(a, t, r, o);
175
+ i.push(g), n.push(o);
167
176
  }
168
177
  }
169
178
  } else
@@ -177,8 +186,8 @@ const M = class {
177
186
  return Promise.all(i).then((s) => {
178
187
  const o = new Array();
179
188
  for (let a = 0; a < s.length; a++) {
180
- const h = s[a], g = n[a];
181
- h && h.isTexture === !0 ? o.push({ material: r, slot: g, texture: h, level: t }) : o.push({ material: r, slot: g, texture: null, level: t });
189
+ const g = s[a], f = n[a];
190
+ g && g.isTexture === !0 ? o.push({ material: r, slot: f, texture: g, level: t }) : o.push({ material: r, slot: f, texture: null, level: t });
182
191
  }
183
192
  return o;
184
193
  });
@@ -196,7 +205,7 @@ const M = class {
196
205
  if ((n == null ? void 0 : n.isTexture) === !0) {
197
206
  if (n != e && (r && i && (r[i] = n), S && i && r)) {
198
207
  const s = this.getAssignedLODInformation(e);
199
- s && te(r, i, s.url);
208
+ s && se(r, i, s.url);
200
209
  }
201
210
  return n;
202
211
  } else
@@ -208,7 +217,7 @@ const M = class {
208
217
  var t, r;
209
218
  return S && console.log("AFTER", this.url, e), (t = this.parser.json.textures) == null || t.forEach((i, n) => {
210
219
  if (i != null && i.extensions) {
211
- const s = i == null ? void 0 : i.extensions[k];
220
+ const s = i == null ? void 0 : i.extensions[R];
212
221
  if (s) {
213
222
  let o = !1;
214
223
  for (const a of this.parser.associations.keys())
@@ -220,7 +229,7 @@ const M = class {
220
229
  }
221
230
  }), (r = this.parser.json.meshes) == null || r.forEach((i, n) => {
222
231
  if (i != null && i.extensions) {
223
- const s = i == null ? void 0 : i.extensions[k];
232
+ const s = i == null ? void 0 : i.extensions[R];
224
233
  if (s && s.lods) {
225
234
  for (const o of this.parser.associations.keys())
226
235
  if (o.isMesh) {
@@ -232,107 +241,107 @@ const M = class {
232
241
  }), null;
233
242
  }
234
243
  static async getOrLoadLOD(e, t) {
235
- var o, a, h;
244
+ var o, a, g;
236
245
  const r = S == "verbose", i = e.userData.LODS;
237
246
  if (!i)
238
247
  return null;
239
248
  const n = i == null ? void 0 : i.key;
240
249
  let s;
241
250
  if (e.isTexture === !0) {
242
- const g = e;
243
- g.source && g.source[V] && (s = g.source[V]);
251
+ const f = e;
252
+ f.source && f.source[Y] && (s = f.source[Y]);
244
253
  }
245
254
  if (s || (s = M.lodInfos.get(n)), s) {
246
255
  if (t > 0) {
247
- let f = !1;
248
- const w = Array.isArray(s.lods);
249
- if (w && t >= s.lods.length ? f = !0 : w || (f = !0), f)
256
+ let u = !1;
257
+ const h = Array.isArray(s.lods);
258
+ if (h && t >= s.lods.length ? u = !0 : h || (u = !0), u)
250
259
  return this.lowresCache.get(n);
251
260
  }
252
- const g = Array.isArray(s.lods) ? s.lods[t].path : s.lods;
253
- if (!g)
261
+ const f = Array.isArray(s.lods) ? s.lods[t].path : s.lods;
262
+ if (!f)
254
263
  return S && !s["missing:uri"] && (s["missing:uri"] = !0, console.warn("Missing uri for progressive asset for LOD " + t, s)), null;
255
- const c = Le(i.url, g);
256
- if (c.endsWith(".glb") || c.endsWith(".gltf")) {
264
+ const p = Le(i.url, f);
265
+ if (p.endsWith(".glb") || p.endsWith(".gltf")) {
257
266
  if (!s.guid)
258
267
  return console.warn("missing pointer for glb/gltf texture", s), null;
259
- const f = c + "_" + s.guid, w = this.previouslyLoaded.get(f);
260
- if (w !== void 0) {
261
- r && console.log(`LOD ${t} was already loading/loaded: ${f}`);
262
- let D = await w.catch((I) => (console.error(`Error loading LOD ${t} from ${c}
263
- `, I), null)), C = !1;
264
- if (D == null || (D instanceof U && e instanceof U ? (o = D.image) != null && o.data || (a = D.source) != null && a.data ? D = this.copySettings(e, D) : (C = !0, this.previouslyLoaded.delete(f)) : D instanceof X && e instanceof X && ((h = D.attributes.position) != null && h.array || (C = !0, this.previouslyLoaded.delete(f)))), !C)
265
- return D;
268
+ const u = p + "_" + s.guid, h = this.previouslyLoaded.get(u);
269
+ if (h !== void 0) {
270
+ r && console.log(`LOD ${t} was already loading/loaded: ${u}`);
271
+ let x = await h.catch((I) => (console.error(`Error loading LOD ${t} from ${p}
272
+ `, I), null)), k = !1;
273
+ if (x == null || (x instanceof U && e instanceof U ? (o = x.image) != null && o.data || (a = x.source) != null && a.data ? x = this.copySettings(e, x) : (k = !0, this.previouslyLoaded.delete(u)) : x instanceof V && e instanceof V && ((g = x.attributes.position) != null && g.array || (k = !0, this.previouslyLoaded.delete(u)))), !k)
274
+ return x;
266
275
  }
267
- const L = s, A = new Promise(async (D, C) => {
268
- const I = new de();
269
- ie(I), S && (await new Promise((y) => setTimeout(y, 1e3)), r && console.warn("Start loading (delayed) " + c, L.guid));
270
- let m = c;
271
- if (L && Array.isArray(L.lods)) {
272
- const y = L.lods[t];
273
- y.hash && (m += "?v=" + y.hash);
276
+ const D = s, A = new Promise(async (x, k) => {
277
+ const I = new he();
278
+ oe(I), S && (await new Promise((m) => setTimeout(m, 1e3)), r && console.warn("Start loading (delayed) " + p, D.guid));
279
+ let L = p;
280
+ if (D && Array.isArray(D.lods)) {
281
+ const m = D.lods[t];
282
+ m.hash && (L += "?v=" + m.hash);
274
283
  }
275
- const p = await I.loadAsync(m).catch((y) => (console.error(`Error loading LOD ${t} from ${c}
276
- `, y), null));
277
- if (!p)
284
+ const y = await I.loadAsync(L).catch((m) => (console.error(`Error loading LOD ${t} from ${p}
285
+ `, m), null));
286
+ if (!y)
278
287
  return null;
279
- const b = p.parser;
280
- r && console.log("Loading finished " + c, L.guid);
281
- let x = 0;
282
- if (p.parser.json.textures) {
283
- let y = !1;
284
- for (const d of p.parser.json.textures) {
288
+ const T = y.parser;
289
+ r && console.log("Loading finished " + p, D.guid);
290
+ let O = 0;
291
+ if (y.parser.json.textures) {
292
+ let m = !1;
293
+ for (const d of y.parser.json.textures) {
285
294
  if (d != null && d.extensions) {
286
- const O = d == null ? void 0 : d.extensions[k];
287
- if (O != null && O.guid && O.guid === L.guid) {
288
- y = !0;
295
+ const w = d == null ? void 0 : d.extensions[R];
296
+ if (w != null && w.guid && w.guid === D.guid) {
297
+ m = !0;
289
298
  break;
290
299
  }
291
300
  }
292
- x++;
301
+ O++;
293
302
  }
294
- if (y) {
295
- let d = await b.getDependency("texture", x);
296
- return r && console.log('change "' + e.name + '" → "' + d.name + '"', c, x, d, f), e instanceof U && (d = this.copySettings(e, d)), d && (d.guid = L.guid), D(d);
303
+ if (m) {
304
+ let d = await T.getDependency("texture", O);
305
+ return r && console.log('change "' + e.name + '" → "' + d.name + '"', p, O, d, u), e instanceof U && (d = this.copySettings(e, d)), d && (d.guid = D.guid), x(d);
297
306
  }
298
307
  }
299
- if (x = 0, p.parser.json.meshes) {
300
- let y = !1;
301
- for (const d of p.parser.json.meshes) {
308
+ if (O = 0, y.parser.json.meshes) {
309
+ let m = !1;
310
+ for (const d of y.parser.json.meshes) {
302
311
  if (d != null && d.extensions) {
303
- const O = d == null ? void 0 : d.extensions[k];
304
- if (O != null && O.guid && O.guid === L.guid) {
305
- y = !0;
312
+ const w = d == null ? void 0 : d.extensions[R];
313
+ if (w != null && w.guid && w.guid === D.guid) {
314
+ m = !0;
306
315
  break;
307
316
  }
308
317
  }
309
- x++;
318
+ O++;
310
319
  }
311
- if (y) {
312
- const d = await b.getDependency("mesh", x), O = L;
313
- if (r && console.log(`Loaded Mesh "${d.name}"`, c, x, d, f), d.isMesh === !0) {
320
+ if (m) {
321
+ const d = await T.getDependency("mesh", O), w = D;
322
+ if (r && console.log(`Loaded Mesh "${d.name}"`, p, O, d, u), d.isMesh === !0) {
314
323
  const P = d.geometry;
315
- return M.assignLODInformation(i.url, P, n, t, void 0, O.density), D(P);
324
+ return M.assignLODInformation(i.url, P, n, t, void 0, w.density), x(P);
316
325
  } else {
317
326
  const P = new Array();
318
327
  for (let _ = 0; _ < d.children.length; _++) {
319
328
  const E = d.children[_];
320
329
  if (E instanceof q) {
321
330
  const N = E.geometry;
322
- M.assignLODInformation(i.url, N, n, t, _, O.density), P.push(N);
331
+ M.assignLODInformation(i.url, N, n, t, _, w.density), P.push(N);
323
332
  }
324
333
  }
325
- return D(P);
334
+ return x(P);
326
335
  }
327
336
  }
328
337
  }
329
- return D(null);
338
+ return x(null);
330
339
  });
331
- return this.previouslyLoaded.set(f, A), await A;
340
+ return this.previouslyLoaded.set(u, A), await A;
332
341
  } else if (e instanceof U) {
333
- r && console.log("Load texture from uri: " + c);
334
- const w = await new ue().loadAsync(c);
335
- return w ? (w.guid = s.guid, w.flipY = !1, w.needsUpdate = !0, w.colorSpace = e.colorSpace, r && console.log(s, w)) : S && console.warn("failed loading", c), w;
342
+ r && console.log("Load texture from uri: " + p);
343
+ const h = await new fe().loadAsync(p);
344
+ return h ? (h.guid = s.guid, h.flipY = !1, h.needsUpdate = !0, h.colorSpace = e.colorSpace, r && console.log(s, h)) : S && console.warn("failed loading", p), h;
336
345
  }
337
346
  } else
338
347
  S && console.warn(`Can not load LOD ${t}: no LOD info found for "${n}" ${e.name}`, e.type);
@@ -358,62 +367,62 @@ let v = M;
358
367
  /**
359
368
  * Register a texture with LOD information
360
369
  */
361
- u(v, "registerTexture", (e, t, r, i) => {
362
- S && console.log("> Progressive: register texture", r, t.name, t.uuid, t, i), t.source && (t.source[V] = i);
370
+ c(v, "registerTexture", (e, t, r, i) => {
371
+ S && console.log("> Progressive: register texture", r, t.name, t.uuid, t, i), t.source && (t.source[Y] = i);
363
372
  const n = i.guid;
364
373
  M.assignLODInformation(e, t, n, 0, 0, void 0), M.lodInfos.set(n, i), M.lowresCache.set(n, t);
365
374
  }), /**
366
375
  * Register a mesh with LOD information
367
376
  */
368
- u(v, "registerMesh", (e, t, r, i, n, s) => {
369
- var h;
377
+ c(v, "registerMesh", (e, t, r, i, n, s) => {
378
+ var g;
370
379
  S && console.log("> Progressive: register mesh", n, r.name, s, r.uuid, r);
371
380
  const o = r.geometry;
372
381
  o.userData || (o.userData = {}), M.assignLODInformation(e, o, t, i, n, s.density), M.lodInfos.set(t, s);
373
382
  let a = M.lowresCache.get(t);
374
383
  a ? a.push(r.geometry) : a = [r.geometry], M.lowresCache.set(t, a);
375
- for (const g of J)
376
- (h = g.onRegisteredNewMesh) == null || h.call(g, r, s);
384
+ for (const f of Q)
385
+ (g = f.onRegisteredNewMesh) == null || g.call(f, r, s);
377
386
  }), /** A map of key = asset uuid and value = LOD information */
378
- u(v, "lodInfos", /* @__PURE__ */ new Map()), /** cache of already loaded mesh lods */
379
- u(v, "previouslyLoaded", /* @__PURE__ */ new Map()), /** this contains the geometry/textures that were originally loaded */
380
- u(v, "lowresCache", /* @__PURE__ */ new Map()), u(v, "_copiedTextures", /* @__PURE__ */ new Map());
387
+ c(v, "lodInfos", /* @__PURE__ */ new Map()), /** cache of already loaded mesh lods */
388
+ c(v, "previouslyLoaded", /* @__PURE__ */ new Map()), /** this contains the geometry/textures that were originally loaded */
389
+ c(v, "lowresCache", /* @__PURE__ */ new Map()), c(v, "_copiedTextures", /* @__PURE__ */ new Map());
381
390
  class De {
382
391
  constructor(e, t, r, i, n) {
383
- u(this, "url");
392
+ c(this, "url");
384
393
  /** the key to lookup the LOD information */
385
- u(this, "key");
386
- u(this, "level");
394
+ c(this, "key");
395
+ c(this, "level");
387
396
  /** For multi objects (e.g. a group of meshes) this is the index of the object */
388
- u(this, "index");
397
+ c(this, "index");
389
398
  /** the mesh density */
390
- u(this, "density");
399
+ c(this, "density");
391
400
  this.url = e, this.key = t, this.level = r, i != null && (this.index = i), n != null && (this.density = n);
392
401
  }
393
402
  }
394
- const Y = Z("debugprogressive"), xe = Z("noprogressive"), T = class {
403
+ const H = ee("debugprogressive"), xe = ee("noprogressive"), b = class {
395
404
  constructor(e) {
396
- u(this, "renderer");
397
- u(this, "projectionScreenMatrix", new j());
398
- u(this, "cameraFrustrum", new ce());
405
+ c(this, "renderer");
406
+ c(this, "projectionScreenMatrix", new te());
407
+ c(this, "cameraFrustrum", new de());
399
408
  /**
400
409
  * The update interval in frames. If set to 0, the LODs will be updated every frame. If set to 1, the LODs will be updated every second frame, etc.
401
410
  */
402
- u(this, "updateInterval", 0);
411
+ c(this, "updateInterval", 0);
403
412
  /**
404
413
  * If set to true, the LODsManager will not update the LODs.
405
414
  */
406
- u(this, "pause", !1);
407
- u(this, "plugins", []);
408
- u(this, "_frame", 0);
409
- u(this, "_originalRender");
415
+ c(this, "pause", !1);
416
+ c(this, "plugins", []);
417
+ c(this, "_frame", 0);
418
+ c(this, "_originalRender");
410
419
  // private testIfLODLevelsAreAvailable() {
411
- u(this, "_sphere", new fe());
412
- u(this, "_tempBox", new ee());
413
- u(this, "tempMatrix", new j());
414
- u(this, "_tempWorldPosition", new R());
415
- u(this, "_tempBoxSize", new R());
416
- u(this, "_tempBox2Size", new R());
420
+ c(this, "_sphere", new ge());
421
+ c(this, "_tempBox", new re());
422
+ c(this, "tempMatrix", new te());
423
+ c(this, "_tempWorldPosition", new C());
424
+ c(this, "_tempBoxSize", new C());
425
+ c(this, "_tempBox2Size", new C());
417
426
  this.renderer = e;
418
427
  }
419
428
  /** @internal */
@@ -430,7 +439,7 @@ const Y = Z("debugprogressive"), xe = Z("noprogressive"), T = class {
430
439
  let e = 0;
431
440
  this._originalRender = this.renderer.render;
432
441
  const t = this;
433
- se(this.renderer), this.renderer.render = function(r, i) {
442
+ ne(this.renderer), this.renderer.render = function(r, i) {
434
443
  t.renderer.getRenderTarget() == null && (e = 0, t._frame += 1);
435
444
  const s = t._frame, o = e++;
436
445
  t.onBeforeRender(r, i, o, s), t._originalRender.call(this, r, i), t.onAfterRender(r, i, o, s);
@@ -442,47 +451,55 @@ const Y = Z("debugprogressive"), xe = Z("noprogressive"), T = class {
442
451
  onBeforeRender(e, t, r, i) {
443
452
  }
444
453
  onAfterRender(e, t, r, i) {
445
- var n, s;
446
- if (!this.pause && r == 0) {
454
+ var a, g;
455
+ if (this.pause)
456
+ return;
457
+ const n = this.renderer.renderLists.get(e, 0), s = n.opaque;
458
+ let o = !0;
459
+ if (s.length === 1) {
460
+ const f = s[0].material;
461
+ (f.name === "EffectMaterial" || f.name === "CopyShader") && (o = !1);
462
+ }
463
+ if (o) {
447
464
  if (xe || this.updateInterval > 0 && i % this.updateInterval != 0)
448
465
  return;
449
466
  this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix, t.matrixWorldInverse), this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix, this.renderer.coordinateSystem);
450
- const o = 1e5, a = this.renderer.renderLists.get(e, r), h = a.opaque;
451
- for (const c of h) {
452
- if (c.material && (((n = c.geometry) == null ? void 0 : n.type) === "BoxGeometry" || ((s = c.geometry) == null ? void 0 : s.type) === "BufferGeometry") && (c.material.name === "SphericalGaussianBlur" || c.material.name == "BackgroundCubeMaterial" || c.material.name === "CubemapFromEquirect" || c.material.name === "EquirectangularToCubeUV")) {
453
- Y && (c.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"] || (c.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"] = !0, console.warn("Ignoring skybox or BLIT object", c, c.material.name, c.material.type)));
467
+ const f = 1e5;
468
+ for (const u of s) {
469
+ if (u.material && (((a = u.geometry) == null ? void 0 : a.type) === "BoxGeometry" || ((g = u.geometry) == null ? void 0 : g.type) === "BufferGeometry") && (u.material.name === "SphericalGaussianBlur" || u.material.name == "BackgroundCubeMaterial" || u.material.name === "CubemapFromEquirect" || u.material.name === "EquirectangularToCubeUV")) {
470
+ H && (u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"] || (u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"] = !0, console.warn("Ignoring skybox or BLIT object", u, u.material.name, u.material.type)));
454
471
  continue;
455
472
  }
456
- const f = c.object;
457
- (f instanceof q || f.isMesh) && this.updateLODs(e, t, f, o);
473
+ const h = u.object;
474
+ (h instanceof q || h.isMesh) && this.updateLODs(e, t, h, f);
458
475
  }
459
- const g = a.transparent;
460
- for (const c of g) {
461
- const f = c.object;
462
- (f instanceof q || f.isMesh) && this.updateLODs(e, t, f, o);
476
+ const p = n.transparent;
477
+ for (const u of p) {
478
+ const h = u.object;
479
+ (h instanceof q || h.isMesh) && this.updateLODs(e, t, h, f);
463
480
  }
464
481
  }
465
482
  }
466
483
  /** Update the LOD levels for the renderer. */
467
484
  updateLODs(e, t, r, i) {
468
- var a, h;
469
- for (const g of this.plugins)
470
- (a = g.onBeforeUpdateLOD) == null || a.call(g, this.renderer, e, t, r);
485
+ var a, g;
486
+ for (const f of this.plugins)
487
+ (a = f.onBeforeUpdateLOD) == null || a.call(f, this.renderer, e, t, r);
471
488
  let n = r.userData.LOD_state;
472
- n || (n = new we(), r.userData.LOD_state = n);
489
+ n || (n = new Oe(), r.userData.LOD_state = n);
473
490
  let s = this.calculateLodLevel(t, r, n, i);
474
491
  s = Math.round(s), s >= 0 && this.loadProgressiveMeshes(r, s);
475
492
  let o = 0;
476
493
  if (r.material) {
477
- const g = r["DEBUG:LOD"];
478
- if (g != null && (o = g), Array.isArray(r.material))
479
- for (const c of r.material)
480
- this.loadProgressiveTextures(c, o);
494
+ const f = r["DEBUG:LOD"];
495
+ if (f != null && (o = f), Array.isArray(r.material))
496
+ for (const p of r.material)
497
+ this.loadProgressiveTextures(p, o);
481
498
  else
482
499
  this.loadProgressiveTextures(r.material, o);
483
500
  }
484
- for (const g of this.plugins)
485
- (h = g.onAfterUpdatedLOD) == null || h.call(g, this.renderer, e, t, r, s);
501
+ for (const f of this.plugins)
502
+ (g = f.onAfterUpdatedLOD) == null || g.call(f, this.renderer, e, t, r, s);
486
503
  n.lastLodLevel = s;
487
504
  }
488
505
  /** Load progressive textures for the given material
@@ -515,70 +532,70 @@ const Y = Z("debugprogressive"), xe = Z("noprogressive"), T = class {
515
532
  return -1;
516
533
  let s = 10 + 1;
517
534
  if (e) {
518
- if (Y && t["DEBUG:LOD"] != null)
535
+ if (H && t["DEBUG:LOD"] != null)
519
536
  return t["DEBUG:LOD"];
520
- const a = v.getMeshLODInformation(t.geometry), h = a == null ? void 0 : a.lods;
521
- if (!h || h.length <= 0 || !((o = this.cameraFrustrum) != null && o.intersectsObject(t)))
537
+ const a = v.getMeshLODInformation(t.geometry), g = a == null ? void 0 : a.lods;
538
+ if (!g || g.length <= 0 || !((o = this.cameraFrustrum) != null && o.intersectsObject(t)))
522
539
  return 99;
523
- const g = t.geometry.boundingBox;
524
- if (g && e.isPerspectiveCamera) {
525
- const c = e;
540
+ const f = t.geometry.boundingBox;
541
+ if (f && e.isPerspectiveCamera) {
542
+ const p = e;
526
543
  if (t.geometry.attributes.color && t.geometry.attributes.color.count < 100 && t.geometry.boundingSphere) {
527
544
  this._sphere.copy(t.geometry.boundingSphere), this._sphere.applyMatrix4(t.matrixWorld);
528
- const m = e.getWorldPosition(this._tempWorldPosition);
529
- if (this._sphere.containsPoint(m))
545
+ const L = e.getWorldPosition(this._tempWorldPosition);
546
+ if (this._sphere.containsPoint(L))
530
547
  return 0;
531
548
  }
532
- if (this._tempBox.copy(g), this._tempBox.applyMatrix4(t.matrixWorld), this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled && c.fov > 70) {
533
- const m = this._tempBox.min, p = this._tempBox.max;
534
- let b = m.x, x = m.y, y = p.x, d = p.y;
535
- const O = 2, P = 1.5, _ = (m.x + p.x) * 0.5, E = (m.y + p.y) * 0.5;
536
- b = (b - _) * O + _, x = (x - E) * O + E, y = (y - _) * O + _, d = (d - E) * O + E;
537
- const N = b < 0 && y > 0 ? 0 : Math.min(Math.abs(m.x), Math.abs(p.x)), ne = x < 0 && d > 0 ? 0 : Math.min(Math.abs(m.y), Math.abs(p.y)), K = Math.max(N, ne);
538
- r.lastCentrality = (P - K) * (P - K) * (P - K);
549
+ if (this._tempBox.copy(f), this._tempBox.applyMatrix4(t.matrixWorld), this._tempBox.applyMatrix4(this.projectionScreenMatrix), this.renderer.xr.enabled && p.fov > 70) {
550
+ const L = this._tempBox.min, y = this._tempBox.max;
551
+ let T = L.x, O = L.y, m = y.x, d = y.y;
552
+ const w = 2, P = 1.5, _ = (L.x + y.x) * 0.5, E = (L.y + y.y) * 0.5;
553
+ T = (T - _) * w + _, O = (O - E) * w + E, m = (m - _) * w + _, d = (d - E) * w + E;
554
+ const N = T < 0 && m > 0 ? 0 : Math.min(Math.abs(L.x), Math.abs(y.x)), ae = O < 0 && d > 0 ? 0 : Math.min(Math.abs(L.y), Math.abs(y.y)), X = Math.max(N, ae);
555
+ r.lastCentrality = (P - X) * (P - X) * (P - X);
539
556
  } else
540
557
  r.lastCentrality = 1;
541
- const f = this._tempBox.getSize(this._tempBoxSize);
542
- f.multiplyScalar(0.5), screen.availHeight > 0 && f.multiplyScalar(this.renderer.domElement.clientHeight / screen.availHeight), f.x *= c.aspect;
543
- const w = e.matrixWorldInverse, L = new ee();
544
- L.copy(g), L.applyMatrix4(t.matrixWorld), L.applyMatrix4(w);
545
- const A = L.getSize(this._tempBox2Size), G = Math.max(A.x, A.y);
546
- if (Math.max(f.x, f.y) != 0 && G != 0 && (f.z = A.z / Math.max(A.x, A.y) * Math.max(f.x, f.y)), r.lastScreenCoverage = Math.max(f.x, f.y, f.z), r.lastScreenspaceVolume.copy(f), r.lastScreenCoverage *= r.lastCentrality, Y && T.debugDrawLine) {
547
- const m = this.tempMatrix.copy(this.projectionScreenMatrix);
548
- m.invert();
549
- const p = T.corner0, b = T.corner1, x = T.corner2, y = T.corner3;
550
- p.copy(this._tempBox.min), b.copy(this._tempBox.max), b.x = p.x, x.copy(this._tempBox.max), x.y = p.y, y.copy(this._tempBox.max);
551
- const d = (p.z + y.z) * 0.5;
552
- p.z = b.z = x.z = y.z = d, p.applyMatrix4(m), b.applyMatrix4(m), x.applyMatrix4(m), y.applyMatrix4(m), T.debugDrawLine(p, b, 255), T.debugDrawLine(p, x, 255), T.debugDrawLine(b, y, 255), T.debugDrawLine(x, y, 255);
558
+ const u = this._tempBox.getSize(this._tempBoxSize);
559
+ u.multiplyScalar(0.5), screen.availHeight > 0 && u.multiplyScalar(this.renderer.domElement.clientHeight / screen.availHeight), u.x *= p.aspect;
560
+ const h = e.matrixWorldInverse, D = new re();
561
+ D.copy(f), D.applyMatrix4(t.matrixWorld), D.applyMatrix4(h);
562
+ const A = D.getSize(this._tempBox2Size), G = Math.max(A.x, A.y);
563
+ if (Math.max(u.x, u.y) != 0 && G != 0 && (u.z = A.z / Math.max(A.x, A.y) * Math.max(u.x, u.y)), r.lastScreenCoverage = Math.max(u.x, u.y, u.z), r.lastScreenspaceVolume.copy(u), r.lastScreenCoverage *= r.lastCentrality, H && b.debugDrawLine) {
564
+ const L = this.tempMatrix.copy(this.projectionScreenMatrix);
565
+ L.invert();
566
+ const y = b.corner0, T = b.corner1, O = b.corner2, m = b.corner3;
567
+ y.copy(this._tempBox.min), T.copy(this._tempBox.max), T.x = y.x, O.copy(this._tempBox.max), O.y = y.y, m.copy(this._tempBox.max);
568
+ const d = (y.z + m.z) * 0.5;
569
+ y.z = T.z = O.z = m.z = d, y.applyMatrix4(L), T.applyMatrix4(L), O.applyMatrix4(L), m.applyMatrix4(L), b.debugDrawLine(y, T, 255), b.debugDrawLine(y, O, 255), b.debugDrawLine(T, m, 255), b.debugDrawLine(O, m, 255);
553
570
  }
554
- let C = 999;
555
- if (h && r.lastScreenCoverage > 0) {
556
- for (let m = 0; m < h.length; m++)
557
- if (h[m].density / r.lastScreenCoverage < i) {
558
- C = m;
571
+ let k = 999;
572
+ if (g && r.lastScreenCoverage > 0) {
573
+ for (let L = 0; L < g.length; L++)
574
+ if (g[L].density / r.lastScreenCoverage < i) {
575
+ k = L;
559
576
  break;
560
577
  }
561
578
  }
562
- C < s && (s = C);
579
+ k < s && (s = k);
563
580
  }
564
581
  }
565
582
  return s;
566
583
  }
567
584
  };
568
- let B = T;
585
+ let B = b;
569
586
  /** Assign a function to draw debug lines for the LODs. This function will be called with the start and end position of the line and the color of the line when the `debugprogressive` query parameter is set.
570
587
  */
571
- u(B, "debugDrawLine"), u(B, "corner0", new R()), u(B, "corner1", new R()), u(B, "corner2", new R()), u(B, "corner3", new R());
572
- class we {
588
+ c(B, "debugDrawLine"), c(B, "corner0", new C()), c(B, "corner1", new C()), c(B, "corner2", new C()), c(B, "corner3", new C());
589
+ class Oe {
573
590
  constructor() {
574
- u(this, "lastLodLevel", 0);
575
- u(this, "lastScreenCoverage", 0);
576
- u(this, "lastScreenspaceVolume", new R());
577
- u(this, "lastCentrality", 0);
591
+ c(this, "lastLodLevel", 0);
592
+ c(this, "lastScreenCoverage", 0);
593
+ c(this, "lastScreenspaceVolume", new C());
594
+ c(this, "lastCentrality", 0);
578
595
  }
579
596
  }
580
- const re = Symbol("NEEDLE_mesh_lod"), $ = Symbol("NEEDLE_texture_lod");
581
- function Oe(l) {
597
+ const ie = Symbol("NEEDLE_mesh_lod"), $ = Symbol("NEEDLE_texture_lod");
598
+ function we(l) {
582
599
  if (!l)
583
600
  return null;
584
601
  let e = null, t = null;
@@ -601,8 +618,8 @@ function Oe(l) {
601
618
  }
602
619
  class Me {
603
620
  constructor(e) {
604
- u(this, "modelviewer");
605
- u(this, "_didWarnAboutMissingUrl", !1);
621
+ c(this, "modelviewer");
622
+ c(this, "_didWarnAboutMissingUrl", !1);
606
623
  this.modelviewer = e;
607
624
  }
608
625
  onBeforeUpdateLOD(e, t, r, i) {
@@ -622,18 +639,18 @@ class Me {
622
639
  const r = this.tryGetCurrentGLTF(e), i = this.getUrl();
623
640
  if (i && r && t.material) {
624
641
  let n = function(o) {
625
- var h, g, c;
642
+ var g, f, p;
626
643
  if (o[$] == !0)
627
644
  return;
628
645
  o[$] = !0, o.userData && (o.userData.LOD = -1);
629
646
  const a = Object.keys(o);
630
- for (let f = 0; f < a.length; f++) {
631
- const w = a[f], L = o[w];
632
- if ((L == null ? void 0 : L.isTexture) === !0) {
633
- const A = (g = (h = L.userData) == null ? void 0 : h.associations) == null ? void 0 : g.textures, G = r.parser.json.textures[A];
634
- if ((c = G.extensions) != null && c[k]) {
635
- const D = G.extensions[k];
636
- D && i && v.registerTexture(i, L, D.lods.length, D);
647
+ for (let u = 0; u < a.length; u++) {
648
+ const h = a[u], D = o[h];
649
+ if ((D == null ? void 0 : D.isTexture) === !0) {
650
+ const A = (f = (g = D.userData) == null ? void 0 : g.associations) == null ? void 0 : f.textures, G = r.parser.json.textures[A];
651
+ if ((p = G.extensions) != null && p[R]) {
652
+ const x = G.extensions[R];
653
+ x && i && v.registerTexture(i, D, x.lods.length, x);
637
654
  }
638
655
  }
639
656
  }
@@ -648,32 +665,34 @@ class Me {
648
665
  }
649
666
  tryParseMeshLOD(e, t) {
650
667
  var n, s;
651
- if (t[re] == !0)
668
+ if (t[ie] == !0)
652
669
  return;
653
- t[re] = !0;
670
+ t[ie] = !0;
654
671
  const r = this.getUrl();
655
672
  if (!r)
656
673
  return;
657
- const i = (s = (n = t.userData) == null ? void 0 : n.gltfExtensions) == null ? void 0 : s[k];
674
+ const i = (s = (n = t.userData) == null ? void 0 : n.gltfExtensions) == null ? void 0 : s[R];
658
675
  if (i && r) {
659
676
  const o = t.uuid;
660
677
  v.registerMesh(r, o, t, 0, i.lods.length, i);
661
678
  }
662
679
  }
663
680
  }
664
- function Be(l, e, t, r) {
665
- se(e), ie(t), t.register((n) => new v(n, l));
681
+ function Ce(l, e, t, r) {
682
+ ne(e), oe(t), t.register((n) => new v(n, l));
666
683
  const i = new B(e);
667
684
  return (r == null ? void 0 : r.enableLODsManager) !== !1 && i.enable(), i;
668
685
  }
669
686
  document.addEventListener("DOMContentLoaded", () => {
670
- Oe(document.querySelector("model-viewer"));
687
+ we(document.querySelector("model-viewer"));
671
688
  });
672
689
  export {
673
- k as EXTENSION_NAME,
690
+ R as EXTENSION_NAME,
674
691
  B as LODsManager,
675
692
  v as NEEDLE_progressive,
676
- Oe as patchModelViewer,
677
- _e as registerPlugin,
678
- Be as useNeedleProgressive
693
+ we as patchModelViewer,
694
+ ke as registerPlugin,
695
+ _e as setDracoDecoderLocation,
696
+ Be as setKTX2TranscoderLocation,
697
+ Ce as useNeedleProgressive
679
698
  };
@@ -1,3 +1,3 @@
1
- var se=Object.defineProperty,oe=(r,e,t)=>e in r?se(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t,c=(r,e,t)=>(oe(r,typeof e!="symbol"?e+"":e,t),t);import{Mesh as U,BufferGeometry as F,Material as ne,Texture as j,TextureLoader as ie,Matrix4 as Y,Frustum as ae,Sphere as le,Box3 as J,Vector3 as B}from"three";import{GLTFLoader as ue}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as ce}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as de}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as he}from"three/examples/jsm/loaders/KTX2Loader.js";const fe="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",ge="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";let k,$,G;function Q(r){k||(k=new de,k.setDecoderPath(fe),k.setDecoderConfig({type:"js"})),G||(G=new he,G.setTranscoderPath(ge)),$||($=ce),r?G.detectSupport(r):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function Z(r){r.dracoLoader||r.setDRACOLoader(k),r.ktx2Loader||r.setKTX2Loader(G),r.meshoptDecoder||r.setMeshoptDecoder($)}function q(r){const e=new URL(window.location.href).searchParams.get(r);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function me(r,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||r===void 0)return e;const t=r.lastIndexOf("/");if(t>=0){const o=r.substring(0,t+1);for(;o.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return o+e}return e}const V=new Array;function pe(r){V.push(r)}const P="NEEDLE_progressive",L=q("debugprogressive"),X=Symbol("needle-progressive-texture"),N=new Map,H=new Set;if(L){let r=function(){e+=1,console.log("Toggle LOD level",e,N),N.forEach((n,s)=>{for(const a of n.keys){const i=s[a];if(i.isBufferGeometry===!0){const l=O.getMeshLODInformation(i),h=l?Math.min(e,l.lods.length):0;s["DEBUG:LOD"]=e,O.assignMeshLOD(s,h),l&&(t=Math.max(t,l.lods.length-1))}else if(s.isMaterial===!0){s["DEBUG:LOD"]=e,O.assignTextureLOD(s,e);break}}}),e>=t&&(e=-1)},e=-1,t=2,o=!1;window.addEventListener("keyup",n=>{n.key==="p"&&r(),n.key==="w"&&(o=!o,H&&H.forEach(s=>{s.name!="BackgroundCubeMaterial"&&"wireframe"in s&&(s.wireframe=o)}))})}function ee(r,e,t){var o;if(!L)return;N.has(r)||N.set(r,{keys:[],sourceId:t});const n=N.get(r);((o=n?.keys)==null?void 0:o.includes(e))==!1&&n.keys.push(e)}const D=class{constructor(r,e){c(this,"parser"),c(this,"url"),L&&console.log("Progressive extension registered for",e),this.parser=r,this.url=e}get name(){return P}static getMeshLODInformation(r){const e=this.getAssignedLODInformation(r);return e!=null&&e.key?this.lodInfos.get(e.key):null}static hasLODLevelAvailable(r,e){var t;if(r.isMaterial===!0){for(const s of Object.keys(r)){const a=r[s];if(a.isTexture&&this.hasLODLevelAvailable(a,e))return!0}return!1}else if(r.isGroup===!0){for(const s of r.children)if(s.isMesh===!0&&this.hasLODLevelAvailable(s,e))return!0}let o,n;if(r.isMesh?o=r.geometry:(r.isBufferGeometry||r.isTexture)&&(o=r),o&&(t=o?.userData)!=null&&t.LODS){const s=o.userData.LODS;if(n=this.lodInfos.get(s.key),e===void 0)return n!=null;if(n)return Array.isArray(n.lods)?e<n.lods.length:e===0}return!1}static assignMeshLOD(r,e){var t;if(!r)return Promise.resolve(null);if(r instanceof U||r.isMesh===!0){const o=r.geometry,n=this.getAssignedLODInformation(o);if(!n)return Promise.resolve(null);for(const s of V)(t=s.onBeforeGetLODMesh)==null||t.call(s,r,e);return r["LOD:requested level"]=e,D.getOrLoadLOD(o,e).then(s=>{if(r["LOD:requested level"]===e){if(delete r["LOD:requested level"],Array.isArray(s)){const a=n.index||0;s=s[a]}s&&o!=s&&s instanceof F&&(r.geometry=s,L&&ee(r,"geometry",n.url))}return s}).catch(s=>(console.error("Error loading mesh LOD",r,s),null))}else L&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",r);return Promise.resolve(null)}static assignTextureLOD(r,e=0){if(!r)return Promise.resolve(null);if(r instanceof ne||r.isMaterial===!0){const t=r,o=[],n=new Array;if(L&&H.add(t),t.uniforms&&t.isRawShaderMaterial||t.isShaderMaterial===!0){const s=t;for(const a of Object.keys(s.uniforms)){const i=s.uniforms[a].value;if(i?.isTexture===!0){const l=this.assignTextureLODForSlot(i,e,t,a);o.push(l),n.push(a)}}}else for(const s of Object.keys(t)){const a=t[s];if(a?.isTexture===!0){const i=this.assignTextureLODForSlot(a,e,t,s);o.push(i),n.push(s)}}return Promise.all(o).then(s=>{const a=new Array;for(let i=0;i<s.length;i++){const l=s[i],h=n[i];l&&l.isTexture===!0?a.push({material:t,slot:h,texture:l,level:e}):a.push({material:t,slot:h,texture:null,level:e})}return a})}if(r instanceof j||r.isTexture===!0){const t=r;return this.assignTextureLODForSlot(t,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(r,e,t,o){return r?.isTexture!==!0?Promise.resolve(null):D.getOrLoadLOD(r,e).then(n=>{if(Array.isArray(n))return null;if(n?.isTexture===!0){if(n!=r&&(t&&o&&(t[o]=n),L&&o&&t)){const s=this.getAssignedLODInformation(r);s&&ee(t,o,s.url)}return n}else L=="verbose"&&console.warn("No LOD found for",r,e);return null}).catch(n=>(console.error("Error loading LOD",r,n),null))}afterRoot(r){var e,t;return L&&console.log("AFTER",this.url,r),(e=this.parser.json.textures)==null||e.forEach((o,n)=>{if(o!=null&&o.extensions){const s=o?.extensions[P];if(s){let a=!1;for(const i of this.parser.associations.keys())i.isTexture===!0&&this.parser.associations.get(i).textures===n&&(a=!0,D.registerTexture(this.url,i,n,s));a||this.parser.getDependency("texture",n).then(i=>{i&&D.registerTexture(this.url,i,n,s)})}}}),(t=this.parser.json.meshes)==null||t.forEach((o,n)=>{if(o!=null&&o.extensions){const s=o?.extensions[P];if(s&&s.lods){for(const a of this.parser.associations.keys())if(a.isMesh){const i=this.parser.associations.get(a);i.meshes===n&&D.registerMesh(this.url,s.guid,a,s.lods.length,i.primitives,s)}}}}),null}static async getOrLoadLOD(r,e){var t,o,n;const s=L=="verbose",a=r.userData.LODS;if(!a)return null;const i=a?.key;let l;if(r.isTexture===!0){const h=r;h.source&&h.source[X]&&(l=h.source[X])}if(l||(l=D.lodInfos.get(i)),l){if(e>0){let d=!1;const M=Array.isArray(l.lods);if(M&&e>=l.lods.length?d=!0:M||(d=!0),d)return this.lowresCache.get(i)}const h=Array.isArray(l.lods)?l.lods[e].path:l.lods;if(!h)return L&&!l["missing:uri"]&&(l["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,l)),null;const u=me(a.url,h);if(u.endsWith(".glb")||u.endsWith(".gltf")){if(!l.guid)return console.warn("missing pointer for glb/gltf texture",l),null;const d=u+"_"+l.guid,M=this.previouslyLoaded.get(d);if(M!==void 0){s&&console.log(`LOD ${e} was already loading/loaded: ${d}`);let p=await M.catch(m=>(console.error(`Error loading LOD ${e} from ${u}
2
- `,m),null)),g=!1;if(p==null||(p instanceof j&&r instanceof j?(t=p.image)!=null&&t.data||(o=p.source)!=null&&o.data?p=this.copySettings(r,p):(g=!0,this.previouslyLoaded.delete(d)):p instanceof F&&r instanceof F&&((n=p.attributes.position)!=null&&n.array||(g=!0,this.previouslyLoaded.delete(d)))),!g)return p}const y=l,A=new Promise(async(p,g)=>{const m=new ue;Z(m),L&&(await new Promise(v=>setTimeout(v,1e3)),s&&console.warn("Start loading (delayed) "+u,y.guid));let b=u;if(y&&Array.isArray(y.lods)){const v=y.lods[e];v.hash&&(b+="?v="+v.hash)}const x=await m.loadAsync(b).catch(v=>(console.error(`Error loading LOD ${e} from ${u}
3
- `,v),null));if(!x)return null;const S=x.parser;s&&console.log("Loading finished "+u,y.guid);let _=0;if(x.parser.json.textures){let v=!1;for(const f of x.parser.json.textures){if(f!=null&&f.extensions){const w=f?.extensions[P];if(w!=null&&w.guid&&w.guid===y.guid){v=!0;break}}_++}if(v){let f=await S.getDependency("texture",_);return s&&console.log('change "'+r.name+'" \u2192 "'+f.name+'"',u,_,f,d),r instanceof j&&(f=this.copySettings(r,f)),f&&(f.guid=y.guid),p(f)}}if(_=0,x.parser.json.meshes){let v=!1;for(const f of x.parser.json.meshes){if(f!=null&&f.extensions){const w=f?.extensions[P];if(w!=null&&w.guid&&w.guid===y.guid){v=!0;break}}_++}if(v){const f=await S.getDependency("mesh",_),w=y;if(s&&console.log(`Loaded Mesh "${f.name}"`,u,_,f,d),f.isMesh===!0){const E=f.geometry;return D.assignLODInformation(a.url,E,i,e,void 0,w.density),p(E)}else{const E=new Array;for(let C=0;C<f.children.length;C++){const W=f.children[C];if(W instanceof U){const R=W.geometry;D.assignLODInformation(a.url,R,i,e,C,w.density),E.push(R)}}return p(E)}}}return p(null)});return this.previouslyLoaded.set(d,A),await A}else if(r instanceof j){s&&console.log("Load texture from uri: "+u);const d=await new ie().loadAsync(u);return d?(d.guid=l.guid,d.flipY=!1,d.needsUpdate=!0,d.colorSpace=r.colorSpace,s&&console.log(l,d)):L&&console.warn("failed loading",u),d}}else L&&console.warn(`Can not load LOD ${e}: no LOD info found for "${i}" ${r.name}`,r.type);return null}static assignLODInformation(r,e,t,o,n,s){if(!e)return;e.userData||(e.userData={});const a=new ye(r,t,o,n,s);e.userData.LODS=a,e.userData.LOD=o}static getAssignedLODInformation(r){var e;return((e=r?.userData)==null?void 0:e.LODS)||null}static copySettings(r,e){return this._copiedTextures.get(r)||(e=e.clone(),this._copiedTextures.set(r,e),e.offset=r.offset,e.repeat=r.repeat,e.colorSpace=r.colorSpace,e)}};let O=D;c(O,"registerTexture",(r,e,t,o)=>{L&&console.log("> Progressive: register texture",t,e.name,e.uuid,e,o),e.source&&(e.source[X]=o);const n=o.guid;D.assignLODInformation(r,e,n,0,0,void 0),D.lodInfos.set(n,o),D.lowresCache.set(n,e)}),c(O,"registerMesh",(r,e,t,o,n,s)=>{var a;L&&console.log("> Progressive: register mesh",n,t.name,s,t.uuid,t);const i=t.geometry;i.userData||(i.userData={}),D.assignLODInformation(r,i,e,o,n,s.density),D.lodInfos.set(e,s);let l=D.lowresCache.get(e);l?l.push(t.geometry):l=[t.geometry],D.lowresCache.set(e,l);for(const h of V)(a=h.onRegisteredNewMesh)==null||a.call(h,t,s)}),c(O,"lodInfos",new Map),c(O,"previouslyLoaded",new Map),c(O,"lowresCache",new Map),c(O,"_copiedTextures",new Map);class ye{constructor(e,t,o,n,s){c(this,"url"),c(this,"key"),c(this,"level"),c(this,"index"),c(this,"density"),this.url=e,this.key=t,this.level=o,n!=null&&(this.index=n),s!=null&&(this.density=s)}}const K=q("debugprogressive"),xe=q("noprogressive"),T=class{constructor(r){c(this,"renderer"),c(this,"projectionScreenMatrix",new Y),c(this,"cameraFrustrum",new ae),c(this,"updateInterval",0),c(this,"pause",!1),c(this,"plugins",[]),c(this,"_frame",0),c(this,"_originalRender"),c(this,"_sphere",new le),c(this,"_tempBox",new J),c(this,"tempMatrix",new Y),c(this,"_tempWorldPosition",new B),c(this,"_tempBoxSize",new B),c(this,"_tempBox2Size",new B),this.renderer=r}static getObjectLODState(r){var e;return(e=r.userData)==null?void 0:e.LOD_state}enable(){if(this._originalRender)return;let r=0;this._originalRender=this.renderer.render;const e=this;Q(this.renderer),this.renderer.render=function(t,o){e.renderer.getRenderTarget()==null&&(r=0,e._frame+=1);const n=e._frame,s=r++;e.onBeforeRender(t,o,s,n),e._originalRender.call(this,t,o),e.onAfterRender(t,o,s,n)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(r,e,t,o){}onAfterRender(r,e,t,o){var n,s;if(!this.pause&&t==0){if(xe||this.updateInterval>0&&o%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const a=1e5,i=this.renderer.renderLists.get(r,t),l=i.opaque;for(const u of l){if(u.material&&(((n=u.geometry)==null?void 0:n.type)==="BoxGeometry"||((s=u.geometry)==null?void 0:s.type)==="BufferGeometry")&&(u.material.name==="SphericalGaussianBlur"||u.material.name=="BackgroundCubeMaterial"||u.material.name==="CubemapFromEquirect"||u.material.name==="EquirectangularToCubeUV")){K&&(u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",u,u.material.name,u.material.type)));continue}const d=u.object;(d instanceof U||d.isMesh)&&this.updateLODs(r,e,d,a)}const h=i.transparent;for(const u of h){const d=u.object;(d instanceof U||d.isMesh)&&this.updateLODs(r,e,d,a)}}}updateLODs(r,e,t,o){var n,s;for(const h of this.plugins)(n=h.onBeforeUpdateLOD)==null||n.call(h,this.renderer,r,e,t);let a=t.userData.LOD_state;a||(a=new ve,t.userData.LOD_state=a);let i=this.calculateLodLevel(e,t,a,o);i=Math.round(i),i>=0&&this.loadProgressiveMeshes(t,i);let l=0;if(t.material){const h=t["DEBUG:LOD"];if(h!=null&&(l=h),Array.isArray(t.material))for(const u of t.material)this.loadProgressiveTextures(u,l);else this.loadProgressiveTextures(t.material,l)}for(const h of this.plugins)(s=h.onAfterUpdatedLOD)==null||s.call(h,this.renderer,r,e,t,i);a.lastLodLevel=i}loadProgressiveTextures(r,e){return r&&r.userData&&r.userData.LOD!==e?(r.userData.LOD=e,O.assignTextureLOD(r,e)):Promise.resolve(null)}loadProgressiveMeshes(r,e){if(!r)return Promise.resolve(null);if(r.userData||(r.userData={}),r.userData.LOD!==e){r.userData.LOD=e;const t=r.geometry;return O.assignMeshLOD(r,e).then(o=>(o&&r.userData.LOD==e&&t!=r.geometry,o))}return Promise.resolve(null)}calculateLodLevel(r,e,t,o){var n;if(!e)return-1;let s=10+1;if(r){if(K&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const a=O.getMeshLODInformation(e.geometry),i=a?.lods;if(!i||i.length<=0||!((n=this.cameraFrustrum)!=null&&n.intersectsObject(e)))return 99;const l=e.geometry.boundingBox;if(l&&r.isPerspectiveCamera){const h=r;if(e.geometry.attributes.color&&e.geometry.attributes.color.count<100&&e.geometry.boundingSphere){this._sphere.copy(e.geometry.boundingSphere),this._sphere.applyMatrix4(e.matrixWorld);const g=r.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(g))return 0}if(this._tempBox.copy(l),this._tempBox.applyMatrix4(e.matrixWorld),this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&h.fov>70){const g=this._tempBox.min,m=this._tempBox.max;let b=g.x,x=g.y,S=m.x,_=m.y;const v=2,f=1.5,w=(g.x+m.x)*.5,E=(g.y+m.y)*.5;b=(b-w)*v+w,x=(x-E)*v+E,S=(S-w)*v+w,_=(_-E)*v+E;const C=b<0&&S>0?0:Math.min(Math.abs(g.x),Math.abs(m.x)),W=x<0&&_>0?0:Math.min(Math.abs(g.y),Math.abs(m.y)),R=Math.max(C,W);t.lastCentrality=(f-R)*(f-R)*(f-R)}else t.lastCentrality=1;const u=this._tempBox.getSize(this._tempBoxSize);u.multiplyScalar(.5),screen.availHeight>0&&u.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),u.x*=h.aspect;const d=r.matrixWorldInverse,M=new J;M.copy(l),M.applyMatrix4(e.matrixWorld),M.applyMatrix4(d);const y=M.getSize(this._tempBox2Size),A=Math.max(y.x,y.y);if(Math.max(u.x,u.y)!=0&&A!=0&&(u.z=y.z/Math.max(y.x,y.y)*Math.max(u.x,u.y)),t.lastScreenCoverage=Math.max(u.x,u.y,u.z),t.lastScreenspaceVolume.copy(u),t.lastScreenCoverage*=t.lastCentrality,K&&T.debugDrawLine){const g=this.tempMatrix.copy(this.projectionScreenMatrix);g.invert();const m=T.corner0,b=T.corner1,x=T.corner2,S=T.corner3;m.copy(this._tempBox.min),b.copy(this._tempBox.max),b.x=m.x,x.copy(this._tempBox.max),x.y=m.y,S.copy(this._tempBox.max);const _=(m.z+S.z)*.5;m.z=b.z=x.z=S.z=_,m.applyMatrix4(g),b.applyMatrix4(g),x.applyMatrix4(g),S.applyMatrix4(g),T.debugDrawLine(m,b,255),T.debugDrawLine(m,x,255),T.debugDrawLine(b,S,255),T.debugDrawLine(x,S,255)}let p=999;if(i&&t.lastScreenCoverage>0){for(let g=0;g<i.length;g++)if(i[g].density/t.lastScreenCoverage<o){p=g;break}}p<s&&(s=p)}}return s}};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);class ve{constructor(){c(this,"lastLodLevel",0),c(this,"lastScreenCoverage",0),c(this,"lastScreenspaceVolume",new B),c(this,"lastCentrality",0)}}const re=Symbol("NEEDLE_mesh_lod"),z=Symbol("NEEDLE_texture_lod");function te(r){if(!r)return null;let e=null,t=null;for(let o=r;o!=null;o=Object.getPrototypeOf(o)){const n=Object.getOwnPropertySymbols(o),s=n.find(i=>i.toString()=="Symbol(renderer)"),a=n.find(i=>i.toString()=="Symbol(scene)");!e&&s!=null&&(e=r[s].threeRenderer),!t&&a!=null&&(t=r[a])}if(e){console.log("Adding Needle LODs to modelviewer");const o=new I(e);if(o.plugins.push(new Le(r)),o.enable(),t){const n=t.camera||t.traverse(s=>s.type=="PerspectiveCamera")[0];n&&e.render(t,n)}return()=>{o.disable()}}return null}class Le{constructor(e){c(this,"modelviewer"),c(this,"_didWarnAboutMissingUrl",!1),this.modelviewer=e}onBeforeUpdateLOD(e,t,o,n){this.tryParseMeshLOD(t,n),this.tryParseTextureLOD(t,n)}getUrl(){let e=this.modelviewer.getAttribute("src");return e||(e=this.modelviewer.src),e||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",this.modelviewer),this._didWarnAboutMissingUrl=!0),e}tryGetCurrentGLTF(e){return e._currentGLTF}tryParseTextureLOD(e,t){if(t[z]==!0)return;t[z]=!0;const o=this.tryGetCurrentGLTF(e),n=this.getUrl();if(n&&o&&t.material){let s=function(i){var l,h,u;if(i[z]==!0)return;i[z]=!0,i.userData&&(i.userData.LOD=-1);const d=Object.keys(i);for(let M=0;M<d.length;M++){const y=d[M],A=i[y];if(A?.isTexture===!0){const p=(h=(l=A.userData)==null?void 0:l.associations)==null?void 0:h.textures,g=o.parser.json.textures[p];if((u=g.extensions)!=null&&u[P]){const m=g.extensions[P];m&&n&&O.registerTexture(n,A,m.lods.length,m)}}}};const a=t.material;if(Array.isArray(a))for(const i of a)s(i);else s(a)}}tryParseMeshLOD(e,t){var o,n;if(t[re]==!0)return;t[re]=!0;const s=this.getUrl();if(!s)return;const a=(n=(o=t.userData)==null?void 0:o.gltfExtensions)==null?void 0:n[P];if(a&&s){const i=t.uuid;O.registerMesh(s,i,t,0,a.lods.length,a)}}}function De(r,e,t,o){Q(e),Z(t),t.register(s=>new O(s,r));const n=new I(e);return o?.enableLODsManager!==!1&&n.enable(),n}document.addEventListener("DOMContentLoaded",()=>{te(document.querySelector("model-viewer"))});export{P as EXTENSION_NAME,I as LODsManager,O as NEEDLE_progressive,te as patchModelViewer,pe as registerPlugin,De as useNeedleProgressive};
1
+ var ne=Object.defineProperty,ie=(r,e,t)=>e in r?ne(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t,c=(r,e,t)=>(ie(r,typeof e!="symbol"?e+"":e,t),t);import{Mesh as U,BufferGeometry as $,Material as ae,Texture as C,TextureLoader as le,Matrix4 as Q,Frustum as ue,Sphere as ce,Box3 as Z,Vector3 as B}from"three";import{GLTFLoader as de}from"three/examples/jsm/loaders/GLTFLoader.js";import{MeshoptDecoder as he}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{DRACOLoader as fe}from"three/examples/jsm/loaders/DRACOLoader.js";import{KTX2Loader as ge}from"three/examples/jsm/loaders/KTX2Loader.js";let z="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",q="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(z+"draco_decoder.js",{method:"head"}).catch(r=>{z="./include/draco/",q="./include/ktx2/"});function me(r){z=r}function pe(r){q=r}let R,V,G;function ee(r){R||(R=new fe,R.setDecoderPath(z),R.setDecoderConfig({type:"js"})),G||(G=new ge,G.setTranscoderPath(q)),V||(V=he),r?G.detectSupport(r):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function re(r){r.dracoLoader||r.setDRACOLoader(R),r.ktx2Loader||r.setKTX2Loader(G),r.meshoptDecoder||r.setMeshoptDecoder(V)}function X(r){const e=new URL(window.location.href).searchParams.get(r);return e==null||e==="0"||e==="false"?!1:e===""?!0:e}function ye(r,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||r===void 0)return e;const t=r.lastIndexOf("/");if(t>=0){const o=r.substring(0,t+1);for(;o.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return o+e}return e}const K=new Array;function Le(r){K.push(r)}const P="NEEDLE_progressive",v=X("debugprogressive"),H=Symbol("needle-progressive-texture"),N=new Map,Y=new Set;if(v){let r=function(){e+=1,console.log("Toggle LOD level",e,N),N.forEach((n,s)=>{for(const a of n.keys){const i=s[a];if(i.isBufferGeometry===!0){const l=w.getMeshLODInformation(i),d=l?Math.min(e,l.lods.length):0;s["DEBUG:LOD"]=e,w.assignMeshLOD(s,d),l&&(t=Math.max(t,l.lods.length-1))}else if(s.isMaterial===!0){s["DEBUG:LOD"]=e,w.assignTextureLOD(s,e);break}}}),e>=t&&(e=-1)},e=-1,t=2,o=!1;window.addEventListener("keyup",n=>{n.key==="p"&&r(),n.key==="w"&&(o=!o,Y&&Y.forEach(s=>{s.name!="BackgroundCubeMaterial"&&"wireframe"in s&&(s.wireframe=o)}))})}function te(r,e,t){var o;if(!v)return;N.has(r)||N.set(r,{keys:[],sourceId:t});const n=N.get(r);((o=n?.keys)==null?void 0:o.includes(e))==!1&&n.keys.push(e)}const O=class{constructor(r,e){c(this,"parser"),c(this,"url"),v&&console.log("Progressive extension registered for",e),this.parser=r,this.url=e}get name(){return P}static getMeshLODInformation(r){const e=this.getAssignedLODInformation(r);return e!=null&&e.key?this.lodInfos.get(e.key):null}static hasLODLevelAvailable(r,e){var t;if(r.isMaterial===!0){for(const s of Object.keys(r)){const a=r[s];if(a.isTexture&&this.hasLODLevelAvailable(a,e))return!0}return!1}else if(r.isGroup===!0){for(const s of r.children)if(s.isMesh===!0&&this.hasLODLevelAvailable(s,e))return!0}let o,n;if(r.isMesh?o=r.geometry:(r.isBufferGeometry||r.isTexture)&&(o=r),o&&(t=o?.userData)!=null&&t.LODS){const s=o.userData.LODS;if(n=this.lodInfos.get(s.key),e===void 0)return n!=null;if(n)return Array.isArray(n.lods)?e<n.lods.length:e===0}return!1}static assignMeshLOD(r,e){var t;if(!r)return Promise.resolve(null);if(r instanceof U||r.isMesh===!0){const o=r.geometry,n=this.getAssignedLODInformation(o);if(!n)return Promise.resolve(null);for(const s of K)(t=s.onBeforeGetLODMesh)==null||t.call(s,r,e);return r["LOD:requested level"]=e,O.getOrLoadLOD(o,e).then(s=>{if(r["LOD:requested level"]===e){if(delete r["LOD:requested level"],Array.isArray(s)){const a=n.index||0;s=s[a]}s&&o!=s&&s instanceof $&&(r.geometry=s,v&&te(r,"geometry",n.url))}return s}).catch(s=>(console.error("Error loading mesh LOD",r,s),null))}else v&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",r);return Promise.resolve(null)}static assignTextureLOD(r,e=0){if(!r)return Promise.resolve(null);if(r instanceof ae||r.isMaterial===!0){const t=r,o=[],n=new Array;if(v&&Y.add(t),t.uniforms&&t.isRawShaderMaterial||t.isShaderMaterial===!0){const s=t;for(const a of Object.keys(s.uniforms)){const i=s.uniforms[a].value;if(i?.isTexture===!0){const l=this.assignTextureLODForSlot(i,e,t,a);o.push(l),n.push(a)}}}else for(const s of Object.keys(t)){const a=t[s];if(a?.isTexture===!0){const i=this.assignTextureLODForSlot(a,e,t,s);o.push(i),n.push(s)}}return Promise.all(o).then(s=>{const a=new Array;for(let i=0;i<s.length;i++){const l=s[i],d=n[i];l&&l.isTexture===!0?a.push({material:t,slot:d,texture:l,level:e}):a.push({material:t,slot:d,texture:null,level:e})}return a})}if(r instanceof C||r.isTexture===!0){const t=r;return this.assignTextureLODForSlot(t,e,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(r,e,t,o){return r?.isTexture!==!0?Promise.resolve(null):O.getOrLoadLOD(r,e).then(n=>{if(Array.isArray(n))return null;if(n?.isTexture===!0){if(n!=r&&(t&&o&&(t[o]=n),v&&o&&t)){const s=this.getAssignedLODInformation(r);s&&te(t,o,s.url)}return n}else v=="verbose"&&console.warn("No LOD found for",r,e);return null}).catch(n=>(console.error("Error loading LOD",r,n),null))}afterRoot(r){var e,t;return v&&console.log("AFTER",this.url,r),(e=this.parser.json.textures)==null||e.forEach((o,n)=>{if(o!=null&&o.extensions){const s=o?.extensions[P];if(s){let a=!1;for(const i of this.parser.associations.keys())i.isTexture===!0&&this.parser.associations.get(i).textures===n&&(a=!0,O.registerTexture(this.url,i,n,s));a||this.parser.getDependency("texture",n).then(i=>{i&&O.registerTexture(this.url,i,n,s)})}}}),(t=this.parser.json.meshes)==null||t.forEach((o,n)=>{if(o!=null&&o.extensions){const s=o?.extensions[P];if(s&&s.lods){for(const a of this.parser.associations.keys())if(a.isMesh){const i=this.parser.associations.get(a);i.meshes===n&&O.registerMesh(this.url,s.guid,a,s.lods.length,i.primitives,s)}}}}),null}static async getOrLoadLOD(r,e){var t,o,n;const s=v=="verbose",a=r.userData.LODS;if(!a)return null;const i=a?.key;let l;if(r.isTexture===!0){const d=r;d.source&&d.source[H]&&(l=d.source[H])}if(l||(l=O.lodInfos.get(i)),l){if(e>0){let u=!1;const p=Array.isArray(l.lods);if(p&&e>=l.lods.length?u=!0:p||(u=!0),u)return this.lowresCache.get(i)}const d=Array.isArray(l.lods)?l.lods[e].path:l.lods;if(!d)return v&&!l["missing:uri"]&&(l["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+e,l)),null;const h=ye(a.url,d);if(h.endsWith(".glb")||h.endsWith(".gltf")){if(!l.guid)return console.warn("missing pointer for glb/gltf texture",l),null;const u=h+"_"+l.guid,p=this.previouslyLoaded.get(u);if(p!==void 0){s&&console.log(`LOD ${e} was already loading/loaded: ${u}`);let y=await p.catch(m=>(console.error(`Error loading LOD ${e} from ${h}
2
+ `,m),null)),g=!1;if(y==null||(y instanceof C&&r instanceof C?(t=y.image)!=null&&t.data||(o=y.source)!=null&&o.data?y=this.copySettings(r,y):(g=!0,this.previouslyLoaded.delete(u)):y instanceof $&&r instanceof $&&((n=y.attributes.position)!=null&&n.array||(g=!0,this.previouslyLoaded.delete(u)))),!g)return y}const L=l,A=new Promise(async(y,g)=>{const m=new de;re(m),v&&(await new Promise(D=>setTimeout(D,1e3)),s&&console.warn("Start loading (delayed) "+h,L.guid));let b=h;if(L&&Array.isArray(L.lods)){const D=L.lods[e];D.hash&&(b+="?v="+D.hash)}const x=await m.loadAsync(b).catch(D=>(console.error(`Error loading LOD ${e} from ${h}
3
+ `,D),null));if(!x)return null;const S=x.parser;s&&console.log("Loading finished "+h,L.guid);let _=0;if(x.parser.json.textures){let D=!1;for(const f of x.parser.json.textures){if(f!=null&&f.extensions){const M=f?.extensions[P];if(M!=null&&M.guid&&M.guid===L.guid){D=!0;break}}_++}if(D){let f=await S.getDependency("texture",_);return s&&console.log('change "'+r.name+'" \u2192 "'+f.name+'"',h,_,f,u),r instanceof C&&(f=this.copySettings(r,f)),f&&(f.guid=L.guid),y(f)}}if(_=0,x.parser.json.meshes){let D=!1;for(const f of x.parser.json.meshes){if(f!=null&&f.extensions){const M=f?.extensions[P];if(M!=null&&M.guid&&M.guid===L.guid){D=!0;break}}_++}if(D){const f=await S.getDependency("mesh",_),M=L;if(s&&console.log(`Loaded Mesh "${f.name}"`,h,_,f,u),f.isMesh===!0){const T=f.geometry;return O.assignLODInformation(a.url,T,i,e,void 0,M.density),y(T)}else{const T=new Array;for(let k=0;k<f.children.length;k++){const W=f.children[k];if(W instanceof U){const j=W.geometry;O.assignLODInformation(a.url,j,i,e,k,M.density),T.push(j)}}return y(T)}}}return y(null)});return this.previouslyLoaded.set(u,A),await A}else if(r instanceof C){s&&console.log("Load texture from uri: "+h);const u=await new le().loadAsync(h);return u?(u.guid=l.guid,u.flipY=!1,u.needsUpdate=!0,u.colorSpace=r.colorSpace,s&&console.log(l,u)):v&&console.warn("failed loading",h),u}}else v&&console.warn(`Can not load LOD ${e}: no LOD info found for "${i}" ${r.name}`,r.type);return null}static assignLODInformation(r,e,t,o,n,s){if(!e)return;e.userData||(e.userData={});const a=new xe(r,t,o,n,s);e.userData.LODS=a,e.userData.LOD=o}static getAssignedLODInformation(r){var e;return((e=r?.userData)==null?void 0:e.LODS)||null}static copySettings(r,e){return this._copiedTextures.get(r)||(e=e.clone(),this._copiedTextures.set(r,e),e.offset=r.offset,e.repeat=r.repeat,e.colorSpace=r.colorSpace,e)}};let w=O;c(w,"registerTexture",(r,e,t,o)=>{v&&console.log("> Progressive: register texture",t,e.name,e.uuid,e,o),e.source&&(e.source[H]=o);const n=o.guid;O.assignLODInformation(r,e,n,0,0,void 0),O.lodInfos.set(n,o),O.lowresCache.set(n,e)}),c(w,"registerMesh",(r,e,t,o,n,s)=>{var a;v&&console.log("> Progressive: register mesh",n,t.name,s,t.uuid,t);const i=t.geometry;i.userData||(i.userData={}),O.assignLODInformation(r,i,e,o,n,s.density),O.lodInfos.set(e,s);let l=O.lowresCache.get(e);l?l.push(t.geometry):l=[t.geometry],O.lowresCache.set(e,l);for(const d of K)(a=d.onRegisteredNewMesh)==null||a.call(d,t,s)}),c(w,"lodInfos",new Map),c(w,"previouslyLoaded",new Map),c(w,"lowresCache",new Map),c(w,"_copiedTextures",new Map);class xe{constructor(e,t,o,n,s){c(this,"url"),c(this,"key"),c(this,"level"),c(this,"index"),c(this,"density"),this.url=e,this.key=t,this.level=o,n!=null&&(this.index=n),s!=null&&(this.density=s)}}const J=X("debugprogressive"),De=X("noprogressive"),E=class{constructor(r){c(this,"renderer"),c(this,"projectionScreenMatrix",new Q),c(this,"cameraFrustrum",new ue),c(this,"updateInterval",0),c(this,"pause",!1),c(this,"plugins",[]),c(this,"_frame",0),c(this,"_originalRender"),c(this,"_sphere",new ce),c(this,"_tempBox",new Z),c(this,"tempMatrix",new Q),c(this,"_tempWorldPosition",new B),c(this,"_tempBoxSize",new B),c(this,"_tempBox2Size",new B),this.renderer=r}static getObjectLODState(r){var e;return(e=r.userData)==null?void 0:e.LOD_state}enable(){if(this._originalRender)return;let r=0;this._originalRender=this.renderer.render;const e=this;ee(this.renderer),this.renderer.render=function(t,o){e.renderer.getRenderTarget()==null&&(r=0,e._frame+=1);const n=e._frame,s=r++;e.onBeforeRender(t,o,s,n),e._originalRender.call(this,t,o),e.onAfterRender(t,o,s,n)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(r,e,t,o){}onAfterRender(r,e,t,o){var n,s;if(this.pause)return;const a=this.renderer.renderLists.get(r,0),i=a.opaque;let l=!0;if(i.length===1){const d=i[0].material;(d.name==="EffectMaterial"||d.name==="CopyShader")&&(l=!1)}if(l){if(De||this.updateInterval>0&&o%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const d=1e5;for(const u of i){if(u.material&&(((n=u.geometry)==null?void 0:n.type)==="BoxGeometry"||((s=u.geometry)==null?void 0:s.type)==="BufferGeometry")&&(u.material.name==="SphericalGaussianBlur"||u.material.name=="BackgroundCubeMaterial"||u.material.name==="CubemapFromEquirect"||u.material.name==="EquirectangularToCubeUV")){J&&(u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",u,u.material.name,u.material.type)));continue}const p=u.object;(p instanceof U||p.isMesh)&&this.updateLODs(r,e,p,d)}const h=a.transparent;for(const u of h){const p=u.object;(p instanceof U||p.isMesh)&&this.updateLODs(r,e,p,d)}}}updateLODs(r,e,t,o){var n,s;for(const d of this.plugins)(n=d.onBeforeUpdateLOD)==null||n.call(d,this.renderer,r,e,t);let a=t.userData.LOD_state;a||(a=new ve,t.userData.LOD_state=a);let i=this.calculateLodLevel(e,t,a,o);i=Math.round(i),i>=0&&this.loadProgressiveMeshes(t,i);let l=0;if(t.material){const d=t["DEBUG:LOD"];if(d!=null&&(l=d),Array.isArray(t.material))for(const h of t.material)this.loadProgressiveTextures(h,l);else this.loadProgressiveTextures(t.material,l)}for(const d of this.plugins)(s=d.onAfterUpdatedLOD)==null||s.call(d,this.renderer,r,e,t,i);a.lastLodLevel=i}loadProgressiveTextures(r,e){return r&&r.userData&&r.userData.LOD!==e?(r.userData.LOD=e,w.assignTextureLOD(r,e)):Promise.resolve(null)}loadProgressiveMeshes(r,e){if(!r)return Promise.resolve(null);if(r.userData||(r.userData={}),r.userData.LOD!==e){r.userData.LOD=e;const t=r.geometry;return w.assignMeshLOD(r,e).then(o=>(o&&r.userData.LOD==e&&t!=r.geometry,o))}return Promise.resolve(null)}calculateLodLevel(r,e,t,o){var n;if(!e)return-1;let s=10+1;if(r){if(J&&e["DEBUG:LOD"]!=null)return e["DEBUG:LOD"];const a=w.getMeshLODInformation(e.geometry),i=a?.lods;if(!i||i.length<=0||!((n=this.cameraFrustrum)!=null&&n.intersectsObject(e)))return 99;const l=e.geometry.boundingBox;if(l&&r.isPerspectiveCamera){const d=r;if(e.geometry.attributes.color&&e.geometry.attributes.color.count<100&&e.geometry.boundingSphere){this._sphere.copy(e.geometry.boundingSphere),this._sphere.applyMatrix4(e.matrixWorld);const g=r.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(g))return 0}if(this._tempBox.copy(l),this._tempBox.applyMatrix4(e.matrixWorld),this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&d.fov>70){const g=this._tempBox.min,m=this._tempBox.max;let b=g.x,x=g.y,S=m.x,_=m.y;const D=2,f=1.5,M=(g.x+m.x)*.5,T=(g.y+m.y)*.5;b=(b-M)*D+M,x=(x-T)*D+T,S=(S-M)*D+M,_=(_-T)*D+T;const k=b<0&&S>0?0:Math.min(Math.abs(g.x),Math.abs(m.x)),W=x<0&&_>0?0:Math.min(Math.abs(g.y),Math.abs(m.y)),j=Math.max(k,W);t.lastCentrality=(f-j)*(f-j)*(f-j)}else t.lastCentrality=1;const h=this._tempBox.getSize(this._tempBoxSize);h.multiplyScalar(.5),screen.availHeight>0&&h.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),h.x*=d.aspect;const u=r.matrixWorldInverse,p=new Z;p.copy(l),p.applyMatrix4(e.matrixWorld),p.applyMatrix4(u);const L=p.getSize(this._tempBox2Size),A=Math.max(L.x,L.y);if(Math.max(h.x,h.y)!=0&&A!=0&&(h.z=L.z/Math.max(L.x,L.y)*Math.max(h.x,h.y)),t.lastScreenCoverage=Math.max(h.x,h.y,h.z),t.lastScreenspaceVolume.copy(h),t.lastScreenCoverage*=t.lastCentrality,J&&E.debugDrawLine){const g=this.tempMatrix.copy(this.projectionScreenMatrix);g.invert();const m=E.corner0,b=E.corner1,x=E.corner2,S=E.corner3;m.copy(this._tempBox.min),b.copy(this._tempBox.max),b.x=m.x,x.copy(this._tempBox.max),x.y=m.y,S.copy(this._tempBox.max);const _=(m.z+S.z)*.5;m.z=b.z=x.z=S.z=_,m.applyMatrix4(g),b.applyMatrix4(g),x.applyMatrix4(g),S.applyMatrix4(g),E.debugDrawLine(m,b,255),E.debugDrawLine(m,x,255),E.debugDrawLine(b,S,255),E.debugDrawLine(x,S,255)}let y=999;if(i&&t.lastScreenCoverage>0){for(let g=0;g<i.length;g++)if(i[g].density/t.lastScreenCoverage<o){y=g;break}}y<s&&(s=y)}}return s}};let I=E;c(I,"debugDrawLine"),c(I,"corner0",new B),c(I,"corner1",new B),c(I,"corner2",new B),c(I,"corner3",new B);class ve{constructor(){c(this,"lastLodLevel",0),c(this,"lastScreenCoverage",0),c(this,"lastScreenspaceVolume",new B),c(this,"lastCentrality",0)}}const se=Symbol("NEEDLE_mesh_lod"),F=Symbol("NEEDLE_texture_lod");function oe(r){if(!r)return null;let e=null,t=null;for(let o=r;o!=null;o=Object.getPrototypeOf(o)){const n=Object.getOwnPropertySymbols(o),s=n.find(i=>i.toString()=="Symbol(renderer)"),a=n.find(i=>i.toString()=="Symbol(scene)");!e&&s!=null&&(e=r[s].threeRenderer),!t&&a!=null&&(t=r[a])}if(e){console.log("Adding Needle LODs to modelviewer");const o=new I(e);if(o.plugins.push(new Oe(r)),o.enable(),t){const n=t.camera||t.traverse(s=>s.type=="PerspectiveCamera")[0];n&&e.render(t,n)}return()=>{o.disable()}}return null}class Oe{constructor(e){c(this,"modelviewer"),c(this,"_didWarnAboutMissingUrl",!1),this.modelviewer=e}onBeforeUpdateLOD(e,t,o,n){this.tryParseMeshLOD(t,n),this.tryParseTextureLOD(t,n)}getUrl(){let e=this.modelviewer.getAttribute("src");return e||(e=this.modelviewer.src),e||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",this.modelviewer),this._didWarnAboutMissingUrl=!0),e}tryGetCurrentGLTF(e){return e._currentGLTF}tryParseTextureLOD(e,t){if(t[F]==!0)return;t[F]=!0;const o=this.tryGetCurrentGLTF(e),n=this.getUrl();if(n&&o&&t.material){let s=function(i){var l,d,h;if(i[F]==!0)return;i[F]=!0,i.userData&&(i.userData.LOD=-1);const u=Object.keys(i);for(let p=0;p<u.length;p++){const L=u[p],A=i[L];if(A?.isTexture===!0){const y=(d=(l=A.userData)==null?void 0:l.associations)==null?void 0:d.textures,g=o.parser.json.textures[y];if((h=g.extensions)!=null&&h[P]){const m=g.extensions[P];m&&n&&w.registerTexture(n,A,m.lods.length,m)}}}};const a=t.material;if(Array.isArray(a))for(const i of a)s(i);else s(a)}}tryParseMeshLOD(e,t){var o,n;if(t[se]==!0)return;t[se]=!0;const s=this.getUrl();if(!s)return;const a=(n=(o=t.userData)==null?void 0:o.gltfExtensions)==null?void 0:n[P];if(a&&s){const i=t.uuid;w.registerMesh(s,i,t,0,a.lods.length,a)}}}function we(r,e,t,o){ee(e),re(t),t.register(s=>new w(s,r));const n=new I(e);return o?.enableLODsManager!==!1&&n.enable(),n}document.addEventListener("DOMContentLoaded",()=>{oe(document.querySelector("model-viewer"))});export{P as EXTENSION_NAME,I as LODsManager,w as NEEDLE_progressive,oe as patchModelViewer,Le as registerPlugin,me as setDracoDecoderLocation,pe as setKTX2TranscoderLocation,we as useNeedleProgressive};
@@ -1,3 +1,3 @@
1
- "use strict";var re=Object.defineProperty;var se=(l,e,t)=>e in l?re(l,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):l[e]=t;var u=(l,e,t)=>(se(l,typeof e!="symbol"?e+"":e,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const p=require("three"),ie=require("three/examples/jsm/loaders/GLTFLoader.js"),oe=require("three/examples/jsm/libs/meshopt_decoder.module.js"),ne=require("three/examples/jsm/loaders/DRACOLoader.js"),ae=require("three/examples/jsm/loaders/KTX2Loader.js"),le="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",ue="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";let F,X,U;function Z(l){F||(F=new ne.DRACOLoader,F.setDecoderPath(le),F.setDecoderConfig({type:"js"})),U||(U=new ae.KTX2Loader,U.setTranscoderPath(ue)),X||(X=oe.MeshoptDecoder),l?U.detectSupport(l):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function j(l){l.dracoLoader||l.setDRACOLoader(F),l.ktx2Loader||l.setKTX2Loader(U),l.meshoptDecoder||l.setMeshoptDecoder(X)}function H(l){const t=new URL(window.location.href).searchParams.get(l);return t==null||t==="0"||t==="false"?!1:t===""?!0:t}function ce(l,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||l===void 0)return e;const t=l.lastIndexOf("/");if(t>=0){const r=l.substring(0,t+1);for(;r.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return r+e}return e}const K=new Array;function fe(l){K.push(l)}const C="NEEDLE_progressive",T=H("debugprogressive"),q=Symbol("needle-progressive-texture"),N=new Map,Y=new Set;if(T){let l=function(){e+=1,console.log("Toggle LOD level",e,N),N.forEach((i,o)=>{for(const s of i.keys){const n=o[s];if(n.isBufferGeometry===!0){const a=w.getMeshLODInformation(n),h=a?Math.min(e,a.lods.length):0;o["DEBUG:LOD"]=e,w.assignMeshLOD(o,h),a&&(t=Math.max(t,a.lods.length-1))}else if(o.isMaterial===!0){o["DEBUG:LOD"]=e,w.assignTextureLOD(o,e);break}}}),e>=t&&(e=-1)},e=-1,t=2,r=!1;window.addEventListener("keyup",i=>{i.key==="p"&&l(),i.key==="w"&&(r=!r,Y&&Y.forEach(o=>{o.name!="BackgroundCubeMaterial"&&"wireframe"in o&&(o.wireframe=r)}))})}function J(l,e,t){var i;if(!T)return;N.has(l)||N.set(l,{keys:[],sourceId:t});const r=N.get(l);((i=r==null?void 0:r.keys)==null?void 0:i.includes(e))==!1&&r.keys.push(e)}const S=class{constructor(e,t){u(this,"parser");u(this,"url");T&&console.log("Progressive extension registered for",t),this.parser=e,this.url=t}get name(){return C}static getMeshLODInformation(e){const t=this.getAssignedLODInformation(e);return t!=null&&t.key?this.lodInfos.get(t.key):null}static hasLODLevelAvailable(e,t){var o;if(e.isMaterial===!0){for(const s of Object.keys(e)){const n=e[s];if(n.isTexture&&this.hasLODLevelAvailable(n,t))return!0}return!1}else if(e.isGroup===!0){for(const s of e.children)if(s.isMesh===!0&&this.hasLODLevelAvailable(s,t))return!0}let r,i;if(e.isMesh?r=e.geometry:(e.isBufferGeometry||e.isTexture)&&(r=e),r&&(o=r==null?void 0:r.userData)!=null&&o.LODS){const s=r.userData.LODS;if(i=this.lodInfos.get(s.key),t===void 0)return i!=null;if(i)return Array.isArray(i.lods)?t<i.lods.length:t===0}return!1}static assignMeshLOD(e,t){var r;if(!e)return Promise.resolve(null);if(e instanceof p.Mesh||e.isMesh===!0){const i=e.geometry,o=this.getAssignedLODInformation(i);if(!o)return Promise.resolve(null);for(const s of K)(r=s.onBeforeGetLODMesh)==null||r.call(s,e,t);return e["LOD:requested level"]=t,S.getOrLoadLOD(i,t).then(s=>{if(e["LOD:requested level"]===t){if(delete e["LOD:requested level"],Array.isArray(s)){const n=o.index||0;s=s[n]}s&&i!=s&&s instanceof p.BufferGeometry&&(e.geometry=s,T&&J(e,"geometry",o.url))}return s}).catch(s=>(console.error("Error loading mesh LOD",e,s),null))}else T&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",e);return Promise.resolve(null)}static assignTextureLOD(e,t=0){if(!e)return Promise.resolve(null);if(e instanceof p.Material||e.isMaterial===!0){const r=e,i=[],o=new Array;if(T&&Y.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const s=r;for(const n of Object.keys(s.uniforms)){const a=s.uniforms[n].value;if((a==null?void 0:a.isTexture)===!0){const h=this.assignTextureLODForSlot(a,t,r,n);i.push(h),o.push(n)}}}else for(const s of Object.keys(r)){const n=r[s];if((n==null?void 0:n.isTexture)===!0){const a=this.assignTextureLODForSlot(n,t,r,s);i.push(a),o.push(s)}}return Promise.all(i).then(s=>{const n=new Array;for(let a=0;a<s.length;a++){const h=s[a],g=o[a];h&&h.isTexture===!0?n.push({material:r,slot:g,texture:h,level:t}):n.push({material:r,slot:g,texture:null,level:t})}return n})}if(e instanceof p.Texture||e.isTexture===!0){const r=e;return this.assignTextureLODForSlot(r,t,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(e,t,r,i){return(e==null?void 0:e.isTexture)!==!0?Promise.resolve(null):S.getOrLoadLOD(e,t).then(o=>{if(Array.isArray(o))return null;if((o==null?void 0:o.isTexture)===!0){if(o!=e&&(r&&i&&(r[i]=o),T&&i&&r)){const s=this.getAssignedLODInformation(e);s&&J(r,i,s.url)}return o}else T=="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 T&&console.log("AFTER",this.url,e),(t=this.parser.json.textures)==null||t.forEach((i,o)=>{if(i!=null&&i.extensions){const s=i==null?void 0:i.extensions[C];if(s){let n=!1;for(const a of this.parser.associations.keys())a.isTexture===!0&&this.parser.associations.get(a).textures===o&&(n=!0,S.registerTexture(this.url,a,o,s));n||this.parser.getDependency("texture",o).then(a=>{a&&S.registerTexture(this.url,a,o,s)})}}}),(r=this.parser.json.meshes)==null||r.forEach((i,o)=>{if(i!=null&&i.extensions){const s=i==null?void 0:i.extensions[C];if(s&&s.lods){for(const n of this.parser.associations.keys())if(n.isMesh){const a=this.parser.associations.get(n);a.meshes===o&&S.registerMesh(this.url,s.guid,n,s.lods.length,a.primitives,s)}}}}),null}static async getOrLoadLOD(e,t){var n,a,h;const r=T=="verbose",i=e.userData.LODS;if(!i)return null;const o=i==null?void 0:i.key;let s;if(e.isTexture===!0){const g=e;g.source&&g.source[q]&&(s=g.source[q])}if(s||(s=S.lodInfos.get(o)),s){if(t>0){let f=!1;const M=Array.isArray(s.lods);if(M&&t>=s.lods.length?f=!0:M||(f=!0),f)return this.lowresCache.get(o)}const g=Array.isArray(s.lods)?s.lods[t].path:s.lods;if(!g)return T&&!s["missing:uri"]&&(s["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+t,s)),null;const c=ce(i.url,g);if(c.endsWith(".glb")||c.endsWith(".gltf")){if(!s.guid)return console.warn("missing pointer for glb/gltf texture",s),null;const f=c+"_"+s.guid,M=this.previouslyLoaded.get(f);if(M!==void 0){r&&console.log(`LOD ${t} was already loading/loaded: ${f}`);let x=await M.catch(I=>(console.error(`Error loading LOD ${t} from ${c}
2
- `,I),null)),R=!1;if(x==null||(x instanceof p.Texture&&e instanceof p.Texture?(n=x.image)!=null&&n.data||(a=x.source)!=null&&a.data?x=this.copySettings(e,x):(R=!0,this.previouslyLoaded.delete(f)):x instanceof p.BufferGeometry&&e instanceof p.BufferGeometry&&((h=x.attributes.position)!=null&&h.array||(R=!0,this.previouslyLoaded.delete(f)))),!R)return x}const D=s,P=new Promise(async(x,R)=>{const I=new ie.GLTFLoader;j(I),T&&(await new Promise(L=>setTimeout(L,1e3)),r&&console.warn("Start loading (delayed) "+c,D.guid));let m=c;if(D&&Array.isArray(D.lods)){const L=D.lods[t];L.hash&&(m+="?v="+L.hash)}const y=await I.loadAsync(m).catch(L=>(console.error(`Error loading LOD ${t} from ${c}
3
- `,L),null));if(!y)return null;const b=y.parser;r&&console.log("Loading finished "+c,D.guid);let O=0;if(y.parser.json.textures){let L=!1;for(const d of y.parser.json.textures){if(d!=null&&d.extensions){const v=d==null?void 0:d.extensions[C];if(v!=null&&v.guid&&v.guid===D.guid){L=!0;break}}O++}if(L){let d=await b.getDependency("texture",O);return r&&console.log('change "'+e.name+'" → "'+d.name+'"',c,O,d,f),e instanceof p.Texture&&(d=this.copySettings(e,d)),d&&(d.guid=D.guid),x(d)}}if(O=0,y.parser.json.meshes){let L=!1;for(const d of y.parser.json.meshes){if(d!=null&&d.extensions){const v=d==null?void 0:d.extensions[C];if(v!=null&&v.guid&&v.guid===D.guid){L=!0;break}}O++}if(L){const d=await b.getDependency("mesh",O),v=D;if(r&&console.log(`Loaded Mesh "${d.name}"`,c,O,d,f),d.isMesh===!0){const B=d.geometry;return S.assignLODInformation(i.url,B,o,t,void 0,v.density),x(B)}else{const B=new Array;for(let E=0;E<d.children.length;E++){const k=d.children[E];if(k instanceof p.Mesh){const W=k.geometry;S.assignLODInformation(i.url,W,o,t,E,v.density),B.push(W)}}return x(B)}}}return x(null)});return this.previouslyLoaded.set(f,P),await P}else if(e instanceof p.Texture){r&&console.log("Load texture from uri: "+c);const M=await new p.TextureLoader().loadAsync(c);return M?(M.guid=s.guid,M.flipY=!1,M.needsUpdate=!0,M.colorSpace=e.colorSpace,r&&console.log(s,M)):T&&console.warn("failed loading",c),M}}else T&&console.warn(`Can not load LOD ${t}: no LOD info found for "${o}" ${e.name}`,e.type);return null}static assignLODInformation(e,t,r,i,o,s){if(!t)return;t.userData||(t.userData={});const n=new de(e,r,i,o,s);t.userData.LODS=n,t.userData.LOD=i}static getAssignedLODInformation(e){var t;return((t=e==null?void 0:e.userData)==null?void 0:t.LODS)||null}static copySettings(e,t){const r=this._copiedTextures.get(e);return r||(t=t.clone(),this._copiedTextures.set(e,t),t.offset=e.offset,t.repeat=e.repeat,t.colorSpace=e.colorSpace,t)}};let w=S;u(w,"registerTexture",(e,t,r,i)=>{T&&console.log("> Progressive: register texture",r,t.name,t.uuid,t,i),t.source&&(t.source[q]=i);const o=i.guid;S.assignLODInformation(e,t,o,0,0,void 0),S.lodInfos.set(o,i),S.lowresCache.set(o,t)}),u(w,"registerMesh",(e,t,r,i,o,s)=>{var h;T&&console.log("> Progressive: register mesh",o,r.name,s,r.uuid,r);const n=r.geometry;n.userData||(n.userData={}),S.assignLODInformation(e,n,t,i,o,s.density),S.lodInfos.set(t,s);let a=S.lowresCache.get(t);a?a.push(r.geometry):a=[r.geometry],S.lowresCache.set(t,a);for(const g of K)(h=g.onRegisteredNewMesh)==null||h.call(g,r,s)}),u(w,"lodInfos",new Map),u(w,"previouslyLoaded",new Map),u(w,"lowresCache",new Map),u(w,"_copiedTextures",new Map);class de{constructor(e,t,r,i,o){u(this,"url");u(this,"key");u(this,"level");u(this,"index");u(this,"density");this.url=e,this.key=t,this.level=r,i!=null&&(this.index=i),o!=null&&(this.density=o)}}const $=H("debugprogressive"),ge=H("noprogressive"),A=class{constructor(e){u(this,"renderer");u(this,"projectionScreenMatrix",new p.Matrix4);u(this,"cameraFrustrum",new p.Frustum);u(this,"updateInterval",0);u(this,"pause",!1);u(this,"plugins",[]);u(this,"_frame",0);u(this,"_originalRender");u(this,"_sphere",new p.Sphere);u(this,"_tempBox",new p.Box3);u(this,"tempMatrix",new p.Matrix4);u(this,"_tempWorldPosition",new p.Vector3);u(this,"_tempBoxSize",new p.Vector3);u(this,"_tempBox2Size",new p.Vector3);this.renderer=e}static getObjectLODState(e){var t;return(t=e.userData)==null?void 0:t.LOD_state}enable(){if(this._originalRender)return;let e=0;this._originalRender=this.renderer.render;const t=this;Z(this.renderer),this.renderer.render=function(r,i){t.renderer.getRenderTarget()==null&&(e=0,t._frame+=1);const s=t._frame,n=e++;t.onBeforeRender(r,i,n,s),t._originalRender.call(this,r,i),t.onAfterRender(r,i,n,s)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(e,t,r,i){}onAfterRender(e,t,r,i){var o,s;if(!this.pause&&r==0){if(ge||this.updateInterval>0&&i%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const n=1e5,a=this.renderer.renderLists.get(e,r),h=a.opaque;for(const c of h){if(c.material&&(((o=c.geometry)==null?void 0:o.type)==="BoxGeometry"||((s=c.geometry)==null?void 0:s.type)==="BufferGeometry")&&(c.material.name==="SphericalGaussianBlur"||c.material.name=="BackgroundCubeMaterial"||c.material.name==="CubemapFromEquirect"||c.material.name==="EquirectangularToCubeUV")){$&&(c.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(c.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",c,c.material.name,c.material.type)));continue}const f=c.object;(f instanceof p.Mesh||f.isMesh)&&this.updateLODs(e,t,f,n)}const g=a.transparent;for(const c of g){const f=c.object;(f instanceof p.Mesh||f.isMesh)&&this.updateLODs(e,t,f,n)}}}updateLODs(e,t,r,i){var a,h;for(const g of this.plugins)(a=g.onBeforeUpdateLOD)==null||a.call(g,this.renderer,e,t,r);let o=r.userData.LOD_state;o||(o=new he,r.userData.LOD_state=o);let s=this.calculateLodLevel(t,r,o,i);s=Math.round(s),s>=0&&this.loadProgressiveMeshes(r,s);let n=0;if(r.material){const g=r["DEBUG:LOD"];if(g!=null&&(n=g),Array.isArray(r.material))for(const c of r.material)this.loadProgressiveTextures(c,n);else this.loadProgressiveTextures(r.material,n)}for(const g of this.plugins)(h=g.onAfterUpdatedLOD)==null||h.call(g,this.renderer,e,t,r,s);o.lastLodLevel=s}loadProgressiveTextures(e,t){return e&&e.userData&&e.userData.LOD!==t?(e.userData.LOD=t,w.assignTextureLOD(e,t)):Promise.resolve(null)}loadProgressiveMeshes(e,t){if(!e)return Promise.resolve(null);if(e.userData||(e.userData={}),e.userData.LOD!==t){e.userData.LOD=t;const r=e.geometry;return w.assignMeshLOD(e,t).then(i=>(i&&e.userData.LOD==t&&r!=e.geometry,i))}return Promise.resolve(null)}calculateLodLevel(e,t,r,i){var n;if(!t)return-1;let s=10+1;if(e){if($&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const a=w.getMeshLODInformation(t.geometry),h=a==null?void 0:a.lods;if(!h||h.length<=0||!((n=this.cameraFrustrum)!=null&&n.intersectsObject(t)))return 99;const g=t.geometry.boundingBox;if(g&&e.isPerspectiveCamera){const c=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 m=e.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(m))return 0}if(this._tempBox.copy(g),this._tempBox.applyMatrix4(t.matrixWorld),this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&c.fov>70){const m=this._tempBox.min,y=this._tempBox.max;let b=m.x,O=m.y,L=y.x,d=y.y;const v=2,B=1.5,E=(m.x+y.x)*.5,k=(m.y+y.y)*.5;b=(b-E)*v+E,O=(O-k)*v+k,L=(L-E)*v+E,d=(d-k)*v+k;const W=b<0&&L>0?0:Math.min(Math.abs(m.x),Math.abs(y.x)),te=O<0&&d>0?0:Math.min(Math.abs(m.y),Math.abs(y.y)),V=Math.max(W,te);r.lastCentrality=(B-V)*(B-V)*(B-V)}else r.lastCentrality=1;const f=this._tempBox.getSize(this._tempBoxSize);f.multiplyScalar(.5),screen.availHeight>0&&f.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),f.x*=c.aspect;const M=e.matrixWorldInverse,D=new p.Box3;D.copy(g),D.applyMatrix4(t.matrixWorld),D.applyMatrix4(M);const P=D.getSize(this._tempBox2Size),G=Math.max(P.x,P.y);if(Math.max(f.x,f.y)!=0&&G!=0&&(f.z=P.z/Math.max(P.x,P.y)*Math.max(f.x,f.y)),r.lastScreenCoverage=Math.max(f.x,f.y,f.z),r.lastScreenspaceVolume.copy(f),r.lastScreenCoverage*=r.lastCentrality,$&&A.debugDrawLine){const m=this.tempMatrix.copy(this.projectionScreenMatrix);m.invert();const y=A.corner0,b=A.corner1,O=A.corner2,L=A.corner3;y.copy(this._tempBox.min),b.copy(this._tempBox.max),b.x=y.x,O.copy(this._tempBox.max),O.y=y.y,L.copy(this._tempBox.max);const d=(y.z+L.z)*.5;y.z=b.z=O.z=L.z=d,y.applyMatrix4(m),b.applyMatrix4(m),O.applyMatrix4(m),L.applyMatrix4(m),A.debugDrawLine(y,b,255),A.debugDrawLine(y,O,255),A.debugDrawLine(b,L,255),A.debugDrawLine(O,L,255)}let R=999;if(h&&r.lastScreenCoverage>0){for(let m=0;m<h.length;m++)if(h[m].density/r.lastScreenCoverage<i){R=m;break}}R<s&&(s=R)}}return s}};let _=A;u(_,"debugDrawLine"),u(_,"corner0",new p.Vector3),u(_,"corner1",new p.Vector3),u(_,"corner2",new p.Vector3),u(_,"corner3",new p.Vector3);class he{constructor(){u(this,"lastLodLevel",0);u(this,"lastScreenCoverage",0);u(this,"lastScreenspaceVolume",new p.Vector3);u(this,"lastCentrality",0)}}const Q=Symbol("NEEDLE_mesh_lod"),z=Symbol("NEEDLE_texture_lod");function ee(l){if(!l)return null;let e=null,t=null;for(let r=l;r!=null;r=Object.getPrototypeOf(r)){const i=Object.getOwnPropertySymbols(r),o=i.find(n=>n.toString()=="Symbol(renderer)"),s=i.find(n=>n.toString()=="Symbol(scene)");!e&&o!=null&&(e=l[o].threeRenderer),!t&&s!=null&&(t=l[s])}if(e){console.log("Adding Needle LODs to modelviewer");const r=new _(e);if(r.plugins.push(new pe(l)),r.enable(),t){const i=t.camera||t.traverse(o=>o.type=="PerspectiveCamera")[0];i&&e.render(t,i)}return()=>{r.disable()}}return null}class pe{constructor(e){u(this,"modelviewer");u(this,"_didWarnAboutMissingUrl",!1);this.modelviewer=e}onBeforeUpdateLOD(e,t,r,i){this.tryParseMeshLOD(t,i),this.tryParseTextureLOD(t,i)}getUrl(){let e=this.modelviewer.getAttribute("src");return e||(e=this.modelviewer.src),e||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",this.modelviewer),this._didWarnAboutMissingUrl=!0),e}tryGetCurrentGLTF(e){return e._currentGLTF}tryParseTextureLOD(e,t){if(t[z]==!0)return;t[z]=!0;const r=this.tryGetCurrentGLTF(e),i=this.getUrl();if(i&&r&&t.material){let o=function(n){var h,g,c;if(n[z]==!0)return;n[z]=!0,n.userData&&(n.userData.LOD=-1);const a=Object.keys(n);for(let f=0;f<a.length;f++){const M=a[f],D=n[M];if((D==null?void 0:D.isTexture)===!0){const P=(g=(h=D.userData)==null?void 0:h.associations)==null?void 0:g.textures,G=r.parser.json.textures[P];if((c=G.extensions)!=null&&c[C]){const x=G.extensions[C];x&&i&&w.registerTexture(i,D,x.lods.length,x)}}}};const s=t.material;if(Array.isArray(s))for(const n of s)o(n);else o(s)}}tryParseMeshLOD(e,t){var o,s;if(t[Q]==!0)return;t[Q]=!0;const r=this.getUrl();if(!r)return;const i=(s=(o=t.userData)==null?void 0:o.gltfExtensions)==null?void 0:s[C];if(i&&r){const n=t.uuid;w.registerMesh(r,n,t,0,i.lods.length,i)}}}function ye(l,e,t,r){Z(e),j(t),t.register(o=>new w(o,l));const i=new _(e);return(r==null?void 0:r.enableLODsManager)!==!1&&i.enable(),i}document.addEventListener("DOMContentLoaded",()=>{ee(document.querySelector("model-viewer"))});exports.EXTENSION_NAME=C;exports.LODsManager=_;exports.NEEDLE_progressive=w;exports.patchModelViewer=ee;exports.registerPlugin=fe;exports.useNeedleProgressive=ye;
1
+ "use strict";var ie=Object.defineProperty;var oe=(l,e,t)=>e in l?ie(l,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):l[e]=t;var c=(l,e,t)=>(oe(l,typeof e!="symbol"?e+"":e,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const h=require("three"),ne=require("three/examples/jsm/loaders/GLTFLoader.js"),ae=require("three/examples/jsm/libs/meshopt_decoder.module.js"),le=require("three/examples/jsm/loaders/DRACOLoader.js"),ue=require("three/examples/jsm/loaders/KTX2Loader.js");let V="https://www.gstatic.com/draco/versioned/decoders/1.4.1/",J="https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/";fetch(V+"draco_decoder.js",{method:"head"}).catch(l=>{V="./include/draco/",J="./include/ktx2/"});function ce(l){V=l}function fe(l){J=l}let F,K,U;function ee(l){F||(F=new le.DRACOLoader,F.setDecoderPath(V),F.setDecoderConfig({type:"js"})),U||(U=new ue.KTX2Loader,U.setTranscoderPath(J)),K||(K=ae.MeshoptDecoder),l?U.detectSupport(l):console.warn("No renderer provided to detect ktx2 support - loading KTX2 textures will probably fail")}function te(l){l.dracoLoader||l.setDRACOLoader(F),l.ktx2Loader||l.setKTX2Loader(U),l.meshoptDecoder||l.setMeshoptDecoder(K)}function Q(l){const t=new URL(window.location.href).searchParams.get(l);return t==null||t==="0"||t==="false"?!1:t===""?!0:t}function de(l,e){if(e===void 0||e.startsWith("./")||e.startsWith("http")||l===void 0)return e;const t=l.lastIndexOf("/");if(t>=0){const r=l.substring(0,t+1);for(;r.endsWith("/")&&e.startsWith("/");)e=e.substring(1);return r+e}return e}const Y=new Array;function ge(l){Y.push(l)}const C="NEEDLE_progressive",T=Q("debugprogressive"),X=Symbol("needle-progressive-texture"),N=new Map,H=new Set;if(T){let l=function(){e+=1,console.log("Toggle LOD level",e,N),N.forEach((i,o)=>{for(const s of i.keys){const n=o[s];if(n.isBufferGeometry===!0){const a=M.getMeshLODInformation(n),g=a?Math.min(e,a.lods.length):0;o["DEBUG:LOD"]=e,M.assignMeshLOD(o,g),a&&(t=Math.max(t,a.lods.length-1))}else if(o.isMaterial===!0){o["DEBUG:LOD"]=e,M.assignTextureLOD(o,e);break}}}),e>=t&&(e=-1)},e=-1,t=2,r=!1;window.addEventListener("keyup",i=>{i.key==="p"&&l(),i.key==="w"&&(r=!r,H&&H.forEach(o=>{o.name!="BackgroundCubeMaterial"&&"wireframe"in o&&(o.wireframe=r)}))})}function Z(l,e,t){var i;if(!T)return;N.has(l)||N.set(l,{keys:[],sourceId:t});const r=N.get(l);((i=r==null?void 0:r.keys)==null?void 0:i.includes(e))==!1&&r.keys.push(e)}const S=class{constructor(e,t){c(this,"parser");c(this,"url");T&&console.log("Progressive extension registered for",t),this.parser=e,this.url=t}get name(){return C}static getMeshLODInformation(e){const t=this.getAssignedLODInformation(e);return t!=null&&t.key?this.lodInfos.get(t.key):null}static hasLODLevelAvailable(e,t){var o;if(e.isMaterial===!0){for(const s of Object.keys(e)){const n=e[s];if(n.isTexture&&this.hasLODLevelAvailable(n,t))return!0}return!1}else if(e.isGroup===!0){for(const s of e.children)if(s.isMesh===!0&&this.hasLODLevelAvailable(s,t))return!0}let r,i;if(e.isMesh?r=e.geometry:(e.isBufferGeometry||e.isTexture)&&(r=e),r&&(o=r==null?void 0:r.userData)!=null&&o.LODS){const s=r.userData.LODS;if(i=this.lodInfos.get(s.key),t===void 0)return i!=null;if(i)return Array.isArray(i.lods)?t<i.lods.length:t===0}return!1}static assignMeshLOD(e,t){var r;if(!e)return Promise.resolve(null);if(e instanceof h.Mesh||e.isMesh===!0){const i=e.geometry,o=this.getAssignedLODInformation(i);if(!o)return Promise.resolve(null);for(const s of Y)(r=s.onBeforeGetLODMesh)==null||r.call(s,e,t);return e["LOD:requested level"]=t,S.getOrLoadLOD(i,t).then(s=>{if(e["LOD:requested level"]===t){if(delete e["LOD:requested level"],Array.isArray(s)){const n=o.index||0;s=s[n]}s&&i!=s&&s instanceof h.BufferGeometry&&(e.geometry=s,T&&Z(e,"geometry",o.url))}return s}).catch(s=>(console.error("Error loading mesh LOD",e,s),null))}else T&&console.error("Invalid call to assignMeshLOD: Request mesh LOD but the object is not a mesh",e);return Promise.resolve(null)}static assignTextureLOD(e,t=0){if(!e)return Promise.resolve(null);if(e instanceof h.Material||e.isMaterial===!0){const r=e,i=[],o=new Array;if(T&&H.add(r),r.uniforms&&r.isRawShaderMaterial||r.isShaderMaterial===!0){const s=r;for(const n of Object.keys(s.uniforms)){const a=s.uniforms[n].value;if((a==null?void 0:a.isTexture)===!0){const g=this.assignTextureLODForSlot(a,t,r,n);i.push(g),o.push(n)}}}else for(const s of Object.keys(r)){const n=r[s];if((n==null?void 0:n.isTexture)===!0){const a=this.assignTextureLODForSlot(n,t,r,s);i.push(a),o.push(s)}}return Promise.all(i).then(s=>{const n=new Array;for(let a=0;a<s.length;a++){const g=s[a],f=o[a];g&&g.isTexture===!0?n.push({material:r,slot:f,texture:g,level:t}):n.push({material:r,slot:f,texture:null,level:t})}return n})}if(e instanceof h.Texture||e.isTexture===!0){const r=e;return this.assignTextureLODForSlot(r,t,null,null)}return Promise.resolve(null)}static assignTextureLODForSlot(e,t,r,i){return(e==null?void 0:e.isTexture)!==!0?Promise.resolve(null):S.getOrLoadLOD(e,t).then(o=>{if(Array.isArray(o))return null;if((o==null?void 0:o.isTexture)===!0){if(o!=e&&(r&&i&&(r[i]=o),T&&i&&r)){const s=this.getAssignedLODInformation(e);s&&Z(r,i,s.url)}return o}else T=="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 T&&console.log("AFTER",this.url,e),(t=this.parser.json.textures)==null||t.forEach((i,o)=>{if(i!=null&&i.extensions){const s=i==null?void 0:i.extensions[C];if(s){let n=!1;for(const a of this.parser.associations.keys())a.isTexture===!0&&this.parser.associations.get(a).textures===o&&(n=!0,S.registerTexture(this.url,a,o,s));n||this.parser.getDependency("texture",o).then(a=>{a&&S.registerTexture(this.url,a,o,s)})}}}),(r=this.parser.json.meshes)==null||r.forEach((i,o)=>{if(i!=null&&i.extensions){const s=i==null?void 0:i.extensions[C];if(s&&s.lods){for(const n of this.parser.associations.keys())if(n.isMesh){const a=this.parser.associations.get(n);a.meshes===o&&S.registerMesh(this.url,s.guid,n,s.lods.length,a.primitives,s)}}}}),null}static async getOrLoadLOD(e,t){var n,a,g;const r=T=="verbose",i=e.userData.LODS;if(!i)return null;const o=i==null?void 0:i.key;let s;if(e.isTexture===!0){const f=e;f.source&&f.source[X]&&(s=f.source[X])}if(s||(s=S.lodInfos.get(o)),s){if(t>0){let u=!1;const p=Array.isArray(s.lods);if(p&&t>=s.lods.length?u=!0:p||(u=!0),u)return this.lowresCache.get(o)}const f=Array.isArray(s.lods)?s.lods[t].path:s.lods;if(!f)return T&&!s["missing:uri"]&&(s["missing:uri"]=!0,console.warn("Missing uri for progressive asset for LOD "+t,s)),null;const y=de(i.url,f);if(y.endsWith(".glb")||y.endsWith(".gltf")){if(!s.guid)return console.warn("missing pointer for glb/gltf texture",s),null;const u=y+"_"+s.guid,p=this.previouslyLoaded.get(u);if(p!==void 0){r&&console.log(`LOD ${t} was already loading/loaded: ${u}`);let O=await p.catch(I=>(console.error(`Error loading LOD ${t} from ${y}
2
+ `,I),null)),k=!1;if(O==null||(O instanceof h.Texture&&e instanceof h.Texture?(n=O.image)!=null&&n.data||(a=O.source)!=null&&a.data?O=this.copySettings(e,O):(k=!0,this.previouslyLoaded.delete(u)):O instanceof h.BufferGeometry&&e instanceof h.BufferGeometry&&((g=O.attributes.position)!=null&&g.array||(k=!0,this.previouslyLoaded.delete(u)))),!k)return O}const x=s,P=new Promise(async(O,k)=>{const I=new ne.GLTFLoader;te(I),T&&(await new Promise(m=>setTimeout(m,1e3)),r&&console.warn("Start loading (delayed) "+y,x.guid));let D=y;if(x&&Array.isArray(x.lods)){const m=x.lods[t];m.hash&&(D+="?v="+m.hash)}const L=await I.loadAsync(D).catch(m=>(console.error(`Error loading LOD ${t} from ${y}
3
+ `,m),null));if(!L)return null;const b=L.parser;r&&console.log("Loading finished "+y,x.guid);let w=0;if(L.parser.json.textures){let m=!1;for(const d of L.parser.json.textures){if(d!=null&&d.extensions){const v=d==null?void 0:d.extensions[C];if(v!=null&&v.guid&&v.guid===x.guid){m=!0;break}}w++}if(m){let d=await b.getDependency("texture",w);return r&&console.log('change "'+e.name+'" → "'+d.name+'"',y,w,d,u),e instanceof h.Texture&&(d=this.copySettings(e,d)),d&&(d.guid=x.guid),O(d)}}if(w=0,L.parser.json.meshes){let m=!1;for(const d of L.parser.json.meshes){if(d!=null&&d.extensions){const v=d==null?void 0:d.extensions[C];if(v!=null&&v.guid&&v.guid===x.guid){m=!0;break}}w++}if(m){const d=await b.getDependency("mesh",w),v=x;if(r&&console.log(`Loaded Mesh "${d.name}"`,y,w,d,u),d.isMesh===!0){const B=d.geometry;return S.assignLODInformation(i.url,B,o,t,void 0,v.density),O(B)}else{const B=new Array;for(let E=0;E<d.children.length;E++){const R=d.children[E];if(R instanceof h.Mesh){const W=R.geometry;S.assignLODInformation(i.url,W,o,t,E,v.density),B.push(W)}}return O(B)}}}return O(null)});return this.previouslyLoaded.set(u,P),await P}else if(e instanceof h.Texture){r&&console.log("Load texture from uri: "+y);const p=await new h.TextureLoader().loadAsync(y);return p?(p.guid=s.guid,p.flipY=!1,p.needsUpdate=!0,p.colorSpace=e.colorSpace,r&&console.log(s,p)):T&&console.warn("failed loading",y),p}}else T&&console.warn(`Can not load LOD ${t}: no LOD info found for "${o}" ${e.name}`,e.type);return null}static assignLODInformation(e,t,r,i,o,s){if(!t)return;t.userData||(t.userData={});const n=new he(e,r,i,o,s);t.userData.LODS=n,t.userData.LOD=i}static getAssignedLODInformation(e){var t;return((t=e==null?void 0:e.userData)==null?void 0:t.LODS)||null}static copySettings(e,t){const r=this._copiedTextures.get(e);return r||(t=t.clone(),this._copiedTextures.set(e,t),t.offset=e.offset,t.repeat=e.repeat,t.colorSpace=e.colorSpace,t)}};let M=S;c(M,"registerTexture",(e,t,r,i)=>{T&&console.log("> Progressive: register texture",r,t.name,t.uuid,t,i),t.source&&(t.source[X]=i);const o=i.guid;S.assignLODInformation(e,t,o,0,0,void 0),S.lodInfos.set(o,i),S.lowresCache.set(o,t)}),c(M,"registerMesh",(e,t,r,i,o,s)=>{var g;T&&console.log("> Progressive: register mesh",o,r.name,s,r.uuid,r);const n=r.geometry;n.userData||(n.userData={}),S.assignLODInformation(e,n,t,i,o,s.density),S.lodInfos.set(t,s);let a=S.lowresCache.get(t);a?a.push(r.geometry):a=[r.geometry],S.lowresCache.set(t,a);for(const f of Y)(g=f.onRegisteredNewMesh)==null||g.call(f,r,s)}),c(M,"lodInfos",new Map),c(M,"previouslyLoaded",new Map),c(M,"lowresCache",new Map),c(M,"_copiedTextures",new Map);class he{constructor(e,t,r,i,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,i!=null&&(this.index=i),o!=null&&(this.density=o)}}const $=Q("debugprogressive"),pe=Q("noprogressive"),A=class{constructor(e){c(this,"renderer");c(this,"projectionScreenMatrix",new h.Matrix4);c(this,"cameraFrustrum",new h.Frustum);c(this,"updateInterval",0);c(this,"pause",!1);c(this,"plugins",[]);c(this,"_frame",0);c(this,"_originalRender");c(this,"_sphere",new h.Sphere);c(this,"_tempBox",new h.Box3);c(this,"tempMatrix",new h.Matrix4);c(this,"_tempWorldPosition",new h.Vector3);c(this,"_tempBoxSize",new h.Vector3);c(this,"_tempBox2Size",new h.Vector3);this.renderer=e}static getObjectLODState(e){var t;return(t=e.userData)==null?void 0:t.LOD_state}enable(){if(this._originalRender)return;let e=0;this._originalRender=this.renderer.render;const t=this;ee(this.renderer),this.renderer.render=function(r,i){t.renderer.getRenderTarget()==null&&(e=0,t._frame+=1);const s=t._frame,n=e++;t.onBeforeRender(r,i,n,s),t._originalRender.call(this,r,i),t.onAfterRender(r,i,n,s)}}disable(){this._originalRender&&(this.renderer.render=this._originalRender,this._originalRender=void 0)}onBeforeRender(e,t,r,i){}onAfterRender(e,t,r,i){var a,g;if(this.pause)return;const o=this.renderer.renderLists.get(e,0),s=o.opaque;let n=!0;if(s.length===1){const f=s[0].material;(f.name==="EffectMaterial"||f.name==="CopyShader")&&(n=!1)}if(n){if(pe||this.updateInterval>0&&i%this.updateInterval!=0)return;this.projectionScreenMatrix.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse),this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix,this.renderer.coordinateSystem);const f=1e5;for(const u of s){if(u.material&&(((a=u.geometry)==null?void 0:a.type)==="BoxGeometry"||((g=u.geometry)==null?void 0:g.type)==="BufferGeometry")&&(u.material.name==="SphericalGaussianBlur"||u.material.name=="BackgroundCubeMaterial"||u.material.name==="CubemapFromEquirect"||u.material.name==="EquirectangularToCubeUV")){$&&(u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]||(u.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]=!0,console.warn("Ignoring skybox or BLIT object",u,u.material.name,u.material.type)));continue}const p=u.object;(p instanceof h.Mesh||p.isMesh)&&this.updateLODs(e,t,p,f)}const y=o.transparent;for(const u of y){const p=u.object;(p instanceof h.Mesh||p.isMesh)&&this.updateLODs(e,t,p,f)}}}updateLODs(e,t,r,i){var a,g;for(const f of this.plugins)(a=f.onBeforeUpdateLOD)==null||a.call(f,this.renderer,e,t,r);let o=r.userData.LOD_state;o||(o=new ye,r.userData.LOD_state=o);let s=this.calculateLodLevel(t,r,o,i);s=Math.round(s),s>=0&&this.loadProgressiveMeshes(r,s);let n=0;if(r.material){const f=r["DEBUG:LOD"];if(f!=null&&(n=f),Array.isArray(r.material))for(const y of r.material)this.loadProgressiveTextures(y,n);else this.loadProgressiveTextures(r.material,n)}for(const f of this.plugins)(g=f.onAfterUpdatedLOD)==null||g.call(f,this.renderer,e,t,r,s);o.lastLodLevel=s}loadProgressiveTextures(e,t){return e&&e.userData&&e.userData.LOD!==t?(e.userData.LOD=t,M.assignTextureLOD(e,t)):Promise.resolve(null)}loadProgressiveMeshes(e,t){if(!e)return Promise.resolve(null);if(e.userData||(e.userData={}),e.userData.LOD!==t){e.userData.LOD=t;const r=e.geometry;return M.assignMeshLOD(e,t).then(i=>(i&&e.userData.LOD==t&&r!=e.geometry,i))}return Promise.resolve(null)}calculateLodLevel(e,t,r,i){var n;if(!t)return-1;let s=10+1;if(e){if($&&t["DEBUG:LOD"]!=null)return t["DEBUG:LOD"];const a=M.getMeshLODInformation(t.geometry),g=a==null?void 0:a.lods;if(!g||g.length<=0||!((n=this.cameraFrustrum)!=null&&n.intersectsObject(t)))return 99;const f=t.geometry.boundingBox;if(f&&e.isPerspectiveCamera){const y=e;if(t.geometry.attributes.color&&t.geometry.attributes.color.count<100&&t.geometry.boundingSphere){this._sphere.copy(t.geometry.boundingSphere),this._sphere.applyMatrix4(t.matrixWorld);const D=e.getWorldPosition(this._tempWorldPosition);if(this._sphere.containsPoint(D))return 0}if(this._tempBox.copy(f),this._tempBox.applyMatrix4(t.matrixWorld),this._tempBox.applyMatrix4(this.projectionScreenMatrix),this.renderer.xr.enabled&&y.fov>70){const D=this._tempBox.min,L=this._tempBox.max;let b=D.x,w=D.y,m=L.x,d=L.y;const v=2,B=1.5,E=(D.x+L.x)*.5,R=(D.y+L.y)*.5;b=(b-E)*v+E,w=(w-R)*v+R,m=(m-E)*v+E,d=(d-R)*v+R;const W=b<0&&m>0?0:Math.min(Math.abs(D.x),Math.abs(L.x)),se=w<0&&d>0?0:Math.min(Math.abs(D.y),Math.abs(L.y)),q=Math.max(W,se);r.lastCentrality=(B-q)*(B-q)*(B-q)}else r.lastCentrality=1;const u=this._tempBox.getSize(this._tempBoxSize);u.multiplyScalar(.5),screen.availHeight>0&&u.multiplyScalar(this.renderer.domElement.clientHeight/screen.availHeight),u.x*=y.aspect;const p=e.matrixWorldInverse,x=new h.Box3;x.copy(f),x.applyMatrix4(t.matrixWorld),x.applyMatrix4(p);const P=x.getSize(this._tempBox2Size),G=Math.max(P.x,P.y);if(Math.max(u.x,u.y)!=0&&G!=0&&(u.z=P.z/Math.max(P.x,P.y)*Math.max(u.x,u.y)),r.lastScreenCoverage=Math.max(u.x,u.y,u.z),r.lastScreenspaceVolume.copy(u),r.lastScreenCoverage*=r.lastCentrality,$&&A.debugDrawLine){const D=this.tempMatrix.copy(this.projectionScreenMatrix);D.invert();const L=A.corner0,b=A.corner1,w=A.corner2,m=A.corner3;L.copy(this._tempBox.min),b.copy(this._tempBox.max),b.x=L.x,w.copy(this._tempBox.max),w.y=L.y,m.copy(this._tempBox.max);const d=(L.z+m.z)*.5;L.z=b.z=w.z=m.z=d,L.applyMatrix4(D),b.applyMatrix4(D),w.applyMatrix4(D),m.applyMatrix4(D),A.debugDrawLine(L,b,255),A.debugDrawLine(L,w,255),A.debugDrawLine(b,m,255),A.debugDrawLine(w,m,255)}let k=999;if(g&&r.lastScreenCoverage>0){for(let D=0;D<g.length;D++)if(g[D].density/r.lastScreenCoverage<i){k=D;break}}k<s&&(s=k)}}return s}};let _=A;c(_,"debugDrawLine"),c(_,"corner0",new h.Vector3),c(_,"corner1",new h.Vector3),c(_,"corner2",new h.Vector3),c(_,"corner3",new h.Vector3);class ye{constructor(){c(this,"lastLodLevel",0);c(this,"lastScreenCoverage",0);c(this,"lastScreenspaceVolume",new h.Vector3);c(this,"lastCentrality",0)}}const j=Symbol("NEEDLE_mesh_lod"),z=Symbol("NEEDLE_texture_lod");function re(l){if(!l)return null;let e=null,t=null;for(let r=l;r!=null;r=Object.getPrototypeOf(r)){const i=Object.getOwnPropertySymbols(r),o=i.find(n=>n.toString()=="Symbol(renderer)"),s=i.find(n=>n.toString()=="Symbol(scene)");!e&&o!=null&&(e=l[o].threeRenderer),!t&&s!=null&&(t=l[s])}if(e){console.log("Adding Needle LODs to modelviewer");const r=new _(e);if(r.plugins.push(new Le(l)),r.enable(),t){const i=t.camera||t.traverse(o=>o.type=="PerspectiveCamera")[0];i&&e.render(t,i)}return()=>{r.disable()}}return null}class Le{constructor(e){c(this,"modelviewer");c(this,"_didWarnAboutMissingUrl",!1);this.modelviewer=e}onBeforeUpdateLOD(e,t,r,i){this.tryParseMeshLOD(t,i),this.tryParseTextureLOD(t,i)}getUrl(){let e=this.modelviewer.getAttribute("src");return e||(e=this.modelviewer.src),e||(this._didWarnAboutMissingUrl||console.warn("No url found in modelviewer",this.modelviewer),this._didWarnAboutMissingUrl=!0),e}tryGetCurrentGLTF(e){return e._currentGLTF}tryParseTextureLOD(e,t){if(t[z]==!0)return;t[z]=!0;const r=this.tryGetCurrentGLTF(e),i=this.getUrl();if(i&&r&&t.material){let o=function(n){var g,f,y;if(n[z]==!0)return;n[z]=!0,n.userData&&(n.userData.LOD=-1);const a=Object.keys(n);for(let u=0;u<a.length;u++){const p=a[u],x=n[p];if((x==null?void 0:x.isTexture)===!0){const P=(f=(g=x.userData)==null?void 0:g.associations)==null?void 0:f.textures,G=r.parser.json.textures[P];if((y=G.extensions)!=null&&y[C]){const O=G.extensions[C];O&&i&&M.registerTexture(i,x,O.lods.length,O)}}}};const s=t.material;if(Array.isArray(s))for(const n of s)o(n);else o(s)}}tryParseMeshLOD(e,t){var o,s;if(t[j]==!0)return;t[j]=!0;const r=this.getUrl();if(!r)return;const i=(s=(o=t.userData)==null?void 0:o.gltfExtensions)==null?void 0:s[C];if(i&&r){const n=t.uuid;M.registerMesh(r,n,t,0,i.lods.length,i)}}}function me(l,e,t,r){ee(e),te(t),t.register(o=>new M(o,l));const i=new _(e);return(r==null?void 0:r.enableLODsManager)!==!1&&i.enable(),i}document.addEventListener("DOMContentLoaded",()=>{re(document.querySelector("model-viewer"))});exports.EXTENSION_NAME=C;exports.LODsManager=_;exports.NEEDLE_progressive=M;exports.patchModelViewer=re;exports.registerPlugin=ge;exports.setDracoDecoderLocation=ce;exports.setKTX2TranscoderLocation=fe;exports.useNeedleProgressive=me;
package/lib/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from "./extension.js";
2
2
  export * from "./plugins/index.js";
3
3
  export { LODsManager } from "./lods_manager.js";
4
+ export { setDracoDecoderLocation, setKTX2TranscoderLocation } from "./loaders.js";
4
5
  import { WebGLRenderer } from "three";
5
6
  import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
6
7
  import { LODsManager } from "./lods_manager.js";
package/lib/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from "./extension.js";
2
2
  export * from "./plugins/index.js";
3
3
  export { LODsManager } from "./lods_manager.js";
4
+ export { setDracoDecoderLocation, setKTX2TranscoderLocation } from "./loaders.js";
4
5
  import { addDracoAndKTX2Loaders, createLoaders } from "./loaders.js";
5
6
  import { NEEDLE_progressive } from "./extension.js";
6
7
  import { LODsManager } from "./lods_manager.js";
package/lib/loaders.d.ts CHANGED
@@ -1,4 +1,14 @@
1
1
  import { WebGLRenderer } from 'three';
2
2
  import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
3
+ /**
4
+ * Set the location of the Draco decoder.
5
+ * @default 'https://www.gstatic.com/draco/versioned/decoders/1.4.1/'
6
+ */
7
+ export declare function setDracoDecoderLocation(location: string): void;
8
+ /**
9
+ * Set the location of the KTX2 transcoder.
10
+ * @default 'https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/'
11
+ */
12
+ export declare function setKTX2TranscoderLocation(location: string): void;
3
13
  export declare function createLoaders(renderer: WebGLRenderer): void;
4
14
  export declare function addDracoAndKTX2Loaders(loader: GLTFLoader): void;
package/lib/loaders.js CHANGED
@@ -1,8 +1,27 @@
1
1
  import { MeshoptDecoder } from 'three/examples/jsm/libs/meshopt_decoder.module.js';
2
2
  import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
3
3
  import { KTX2Loader } from 'three/examples/jsm/loaders/KTX2Loader.js';
4
- const DEFAULT_DRACO_DECODER_LOCATION = 'https://www.gstatic.com/draco/versioned/decoders/1.4.1/';
5
- const DEFAULT_KTX2_TRANSCODER_LOCATION = 'https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/';
4
+ let DEFAULT_DRACO_DECODER_LOCATION = 'https://www.gstatic.com/draco/versioned/decoders/1.4.1/';
5
+ let DEFAULT_KTX2_TRANSCODER_LOCATION = 'https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/';
6
+ fetch(DEFAULT_DRACO_DECODER_LOCATION + "draco_decoder.js", { method: "head" })
7
+ .catch(_ => {
8
+ DEFAULT_DRACO_DECODER_LOCATION = "./include/draco/";
9
+ DEFAULT_KTX2_TRANSCODER_LOCATION = "./include/ktx2/";
10
+ });
11
+ /**
12
+ * Set the location of the Draco decoder.
13
+ * @default 'https://www.gstatic.com/draco/versioned/decoders/1.4.1/'
14
+ */
15
+ export function setDracoDecoderLocation(location) {
16
+ DEFAULT_DRACO_DECODER_LOCATION = location;
17
+ }
18
+ /**
19
+ * Set the location of the KTX2 transcoder.
20
+ * @default 'https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/'
21
+ */
22
+ export function setKTX2TranscoderLocation(location) {
23
+ DEFAULT_KTX2_TRANSCODER_LOCATION = location;
24
+ }
6
25
  let dracoLoader;
7
26
  let meshoptDecoder;
8
27
  let ktx2Loader;
@@ -70,11 +70,25 @@ export class LODsManager {
70
70
  }
71
71
  onBeforeRender(_scene, _camera, _stack, _frame) {
72
72
  }
73
- onAfterRender(scene, camera, stack, frame) {
73
+ onAfterRender(scene, camera, _stack, frame) {
74
74
  if (this.pause)
75
75
  return;
76
- // we only want to update LODs during the main render call
77
- if (stack == 0) {
76
+ const renderList = this.renderer.renderLists.get(scene, 0);
77
+ const opaque = renderList.opaque;
78
+ let updateLODs = true;
79
+ // check if we're rendering a postprocessing pass
80
+ if (opaque.length === 1) {
81
+ const material = opaque[0].material;
82
+ // pmndrs postprocessing
83
+ if (material.name === "EffectMaterial") {
84
+ updateLODs = false;
85
+ }
86
+ // builtin three postprocessing
87
+ else if (material.name === "CopyShader") {
88
+ updateLODs = false;
89
+ }
90
+ }
91
+ if (updateLODs) {
78
92
  if (suppressProgressiveLoading)
79
93
  return;
80
94
  if (this.updateInterval > 0 && frame % this.updateInterval != 0)
@@ -92,8 +106,6 @@ export class LODsManager {
92
106
  currentAllowedDensity *= 1.25;
93
107
  }
94
108
  */
95
- const renderList = this.renderer.renderLists.get(scene, stack);
96
- const opaque = renderList.opaque;
97
109
  for (const entry of opaque) {
98
110
  if (entry.material && (entry.geometry?.type === "BoxGeometry" || entry.geometry?.type === "BufferGeometry")) {
99
111
  // Ignore the skybox
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/gltf-progressive",
3
- "version": "1.0.0-alpha.10",
3
+ "version": "1.0.0-alpha.12",
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": {