@preference-sl/pref-viewer 2.10.0-beta.11 → 2.10.0-beta.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/package.json +1 -1
- package/src/index.js +192 -10
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* =============================================================================
|
|
3
|
-
* PrefViewer Web Component (JavaScript)
|
|
3
|
+
* PrefViewer Web Component (JavaScript) — con logging opcional por atributo
|
|
4
4
|
* =============================================================================
|
|
5
5
|
*
|
|
6
6
|
* Overview
|
|
@@ -49,6 +49,76 @@ import { initDb, loadModel } from "./gltf-storage.js";
|
|
|
49
49
|
class PrefViewer extends HTMLElement {
|
|
50
50
|
#initialized = false;
|
|
51
51
|
|
|
52
|
+
// --- Logging -------------------------------------------------------------
|
|
53
|
+
#debugEnabled = false;
|
|
54
|
+
#logPrefix = "PrefViewer";
|
|
55
|
+
#timers = new Map();
|
|
56
|
+
#log = {
|
|
57
|
+
debug: () => {},
|
|
58
|
+
info: () => {},
|
|
59
|
+
warn: () => {},
|
|
60
|
+
error: () => {},
|
|
61
|
+
time: () => {},
|
|
62
|
+
timeEnd: () => {},
|
|
63
|
+
group: () => {},
|
|
64
|
+
groupEnd: () => {},
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
#enableDebug(enable) {
|
|
68
|
+
const on = !!enable;
|
|
69
|
+
this.#debugEnabled = on;
|
|
70
|
+
if (!on) {
|
|
71
|
+
this.#log = {
|
|
72
|
+
debug: () => {},
|
|
73
|
+
info: () => {},
|
|
74
|
+
warn: () => {},
|
|
75
|
+
error: () => {},
|
|
76
|
+
time: () => {},
|
|
77
|
+
timeEnd: () => {},
|
|
78
|
+
group: () => {},
|
|
79
|
+
groupEnd: () => {},
|
|
80
|
+
};
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const tag = (lvl, args) => {
|
|
84
|
+
if (!args || !args.length) return [`${this.#logPrefix}:`];
|
|
85
|
+
const [first, ...rest] = args;
|
|
86
|
+
if (typeof first === "string") return [`${this.#logPrefix} [${lvl}] ${first}`, ...rest];
|
|
87
|
+
return [`${this.#logPrefix} [${lvl}]`, first, ...rest];
|
|
88
|
+
};
|
|
89
|
+
this.#log = {
|
|
90
|
+
debug: (...a) => console.debug(...tag("debug", a)),
|
|
91
|
+
info: (...a) => console.info(...tag("info", a)),
|
|
92
|
+
warn: (...a) => console.warn(...tag("warn", a)),
|
|
93
|
+
error: (...a) => console.error(...tag("error", a)),
|
|
94
|
+
time: (label) => {
|
|
95
|
+
const key = `${label}`;
|
|
96
|
+
this.#timers.set(key, performance.now());
|
|
97
|
+
console.debug(`${this.#logPrefix} [time] ${key} start`);
|
|
98
|
+
},
|
|
99
|
+
timeEnd: (label) => {
|
|
100
|
+
const key = `${label}`;
|
|
101
|
+
if (this.#timers.has(key)) {
|
|
102
|
+
const delta = (performance.now() - this.#timers.get(key)).toFixed(2);
|
|
103
|
+
console.debug(`${this.#logPrefix} [time] ${key} ${delta}ms`);
|
|
104
|
+
this.#timers.delete(key);
|
|
105
|
+
} else {
|
|
106
|
+
console.debug(`${this.#logPrefix} [time] ${key} (no start)`);
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
group: (title) => console.group?.(`${this.#logPrefix} ${title}`),
|
|
110
|
+
groupEnd: () => console.groupEnd?.(),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
#readDebugAttribute() {
|
|
115
|
+
const v = (this.getAttribute("debug") || "").trim().toLowerCase();
|
|
116
|
+
// true/1/yes/on
|
|
117
|
+
const enabled = v === "true" || v === "1" || v === "yes" || v === "on" || v === "debug";
|
|
118
|
+
this.#enableDebug(enabled);
|
|
119
|
+
}
|
|
120
|
+
// ------------------------------------------------------------------------
|
|
121
|
+
|
|
52
122
|
#data = {
|
|
53
123
|
containers: {
|
|
54
124
|
model: {
|
|
@@ -130,6 +200,8 @@ class PrefViewer extends HTMLElement {
|
|
|
130
200
|
constructor() {
|
|
131
201
|
super();
|
|
132
202
|
this.attachShadow({ mode: "open" });
|
|
203
|
+
this.#readDebugAttribute();
|
|
204
|
+
this.#log.info("constructor()");
|
|
133
205
|
this.#createCanvas();
|
|
134
206
|
this.#wrapCanvas();
|
|
135
207
|
// Point to whichever version you packaged or want to use:
|
|
@@ -142,13 +214,24 @@ class PrefViewer extends HTMLElement {
|
|
|
142
214
|
// JS fallback if WASM isn’t available
|
|
143
215
|
fallbackUrl: `${DRACO_BASE}/draco_decoder_gltf.js`,
|
|
144
216
|
};
|
|
217
|
+
this.#log.debug("Draco decoder configured", DracoCompression.Configuration.decoder);
|
|
145
218
|
}
|
|
146
219
|
|
|
147
220
|
static get observedAttributes() {
|
|
148
|
-
|
|
221
|
+
// Añadimos "debug" como atributo observable
|
|
222
|
+
return ["config", "model", "scene", "show-model", "show-scene", "debug"];
|
|
149
223
|
}
|
|
150
224
|
|
|
151
225
|
attributeChangedCallback(name, _old, value) {
|
|
226
|
+
// Nota: el cambio de "debug" debe ocurrir antes de loguear otras cosas.
|
|
227
|
+
if (name === "debug") {
|
|
228
|
+
this.#enableDebug((value || "").toLowerCase() === "true" || value === "1" || value === "yes" || value === "on" || value === "debug");
|
|
229
|
+
this.#log.info(`attributeChanged: debug -> ${this.#debugEnabled}`);
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
this.#log.debug("attributeChangedCallback()", { name, oldValue: _old, value });
|
|
234
|
+
|
|
152
235
|
let data = null;
|
|
153
236
|
switch (name) {
|
|
154
237
|
case "config":
|
|
@@ -163,6 +246,7 @@ class PrefViewer extends HTMLElement {
|
|
|
163
246
|
case "show-model":
|
|
164
247
|
data = value.toLowerCase?.() === "true";
|
|
165
248
|
if (this.#initialized) {
|
|
249
|
+
this.#log.info(`attr show-model -> ${data}`);
|
|
166
250
|
data ? this.showModel() : this.hideModel();
|
|
167
251
|
} else {
|
|
168
252
|
this.#data.containers.model.show = data;
|
|
@@ -171,6 +255,7 @@ class PrefViewer extends HTMLElement {
|
|
|
171
255
|
case "show-scene":
|
|
172
256
|
data = value.toLowerCase?.() === "true";
|
|
173
257
|
if (this.#initialized) {
|
|
258
|
+
this.#log.info(`attr show-scene -> ${data}`);
|
|
174
259
|
data ? this.showScene() : this.hideScene();
|
|
175
260
|
} else {
|
|
176
261
|
this.#data.containers.environment.show = data;
|
|
@@ -180,6 +265,7 @@ class PrefViewer extends HTMLElement {
|
|
|
180
265
|
}
|
|
181
266
|
|
|
182
267
|
connectedCallback() {
|
|
268
|
+
this.#log.info("connectedCallback()");
|
|
183
269
|
if (!this.hasAttribute("config")) {
|
|
184
270
|
const error = 'PrefViewer: provide "models" as array of model and environment';
|
|
185
271
|
console.error(error);
|
|
@@ -196,15 +282,18 @@ class PrefViewer extends HTMLElement {
|
|
|
196
282
|
this.#initializeBabylon();
|
|
197
283
|
this.#loadContainers(true, true, true);
|
|
198
284
|
this.#initialized = true;
|
|
285
|
+
this.#log.info("initialized = true");
|
|
199
286
|
}
|
|
200
287
|
|
|
201
288
|
disconnectedCallback() {
|
|
289
|
+
this.#log.info("disconnectedCallback()");
|
|
202
290
|
this.#disposeEngine();
|
|
203
291
|
this.#canvasResizeObserver.disconnect();
|
|
204
292
|
}
|
|
205
293
|
|
|
206
294
|
// Web Component
|
|
207
295
|
#createCanvas() {
|
|
296
|
+
this.#log.debug("#createCanvas()");
|
|
208
297
|
this.#canvas = document.createElement("canvas");
|
|
209
298
|
Object.assign(this.#canvas.style, {
|
|
210
299
|
width: "100%",
|
|
@@ -215,6 +304,7 @@ class PrefViewer extends HTMLElement {
|
|
|
215
304
|
}
|
|
216
305
|
|
|
217
306
|
#wrapCanvas() {
|
|
307
|
+
this.#log.debug("#wrapCanvas()");
|
|
218
308
|
this.#wrapper = document.createElement("div");
|
|
219
309
|
Object.assign(this.#wrapper.style, {
|
|
220
310
|
width: "100%",
|
|
@@ -230,8 +320,10 @@ class PrefViewer extends HTMLElement {
|
|
|
230
320
|
if (!options || !options.camera) {
|
|
231
321
|
return false;
|
|
232
322
|
}
|
|
233
|
-
|
|
234
|
-
this.#data.options.camera.
|
|
323
|
+
const prev = this.#data.options.camera.value;
|
|
324
|
+
this.#data.options.camera.changed = options.camera && options.camera !== prev ? true : false;
|
|
325
|
+
this.#data.options.camera.value = this.#data.options.camera.changed ? options.camera : prev;
|
|
326
|
+
this.#log.debug("#checkCameraChanged()", { prev, next: this.#data.options.camera.value, changed: this.#data.options.camera.changed });
|
|
235
327
|
return this.#data.options.camera.changed;
|
|
236
328
|
}
|
|
237
329
|
|
|
@@ -242,19 +334,23 @@ class PrefViewer extends HTMLElement {
|
|
|
242
334
|
let someChanged = false;
|
|
243
335
|
Object.keys(this.#data.options.materials).forEach((material) => {
|
|
244
336
|
const key = `${material}Material`;
|
|
245
|
-
|
|
246
|
-
this.#data.options.materials[material].
|
|
337
|
+
const prev = this.#data.options.materials[material].value;
|
|
338
|
+
this.#data.options.materials[material].changed = options[key] && options[key] !== prev ? true : false;
|
|
339
|
+
this.#data.options.materials[material].value = this.#data.options.materials[material].changed ? options[key] : prev;
|
|
247
340
|
someChanged = someChanged || this.#data.options.materials[material].changed;
|
|
248
341
|
});
|
|
342
|
+
this.#log.debug("#checkMaterialsChanged()", { someChanged, values: this.#data.options.materials });
|
|
249
343
|
return someChanged;
|
|
250
344
|
}
|
|
251
345
|
|
|
252
346
|
#storeChangedFlagsForContainer(container) {
|
|
347
|
+
this.#log.debug("#storeChangedFlagsForContainer()", { name: container.name, changed: container.changed });
|
|
253
348
|
container.timestamp = container.changed.timestamp;
|
|
254
349
|
container.size = container.changed.size;
|
|
255
350
|
}
|
|
256
351
|
|
|
257
352
|
#resetChangedFlags() {
|
|
353
|
+
this.#log.debug("#resetChangedFlags()");
|
|
258
354
|
Object.values(this.#data.containers).forEach((container) => (container.changed = false));
|
|
259
355
|
Object.values(this.#data.options.materials).forEach((material) => (material.changed = false));
|
|
260
356
|
this.#data.options.camera.changed = false;
|
|
@@ -262,6 +358,8 @@ class PrefViewer extends HTMLElement {
|
|
|
262
358
|
|
|
263
359
|
// Babylon.js
|
|
264
360
|
async #initializeBabylon() {
|
|
361
|
+
this.#log.group("#initializeBabylon()");
|
|
362
|
+
this.#log.time("babylon:init");
|
|
265
363
|
this.#engine = new Engine(this.#canvas, true, { alpha: true });
|
|
266
364
|
this.#scene = new Scene(this.#engine);
|
|
267
365
|
this.#scene.clearColor = new Color4(1, 1, 1, 1);
|
|
@@ -273,9 +371,12 @@ class PrefViewer extends HTMLElement {
|
|
|
273
371
|
this.#canvasResizeObserver.observe(this.#canvas);
|
|
274
372
|
|
|
275
373
|
await this.#createXRExperience();
|
|
374
|
+
this.#log.timeEnd("babylon:init");
|
|
375
|
+
this.#log.groupEnd();
|
|
276
376
|
}
|
|
277
377
|
|
|
278
378
|
addStylesToARButton() {
|
|
379
|
+
this.#log.debug("addStylesToARButton()");
|
|
279
380
|
const css = '.babylonVRicon { color: #868686; border-color: #868686; border-style: solid; margin-left: 10px; height: 50px; width: 80px; background-color: rgba(51,51,51,0.7); background-image: url(data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%222048%22%20height%3D%221152%22%20viewBox%3D%220%200%202048%201152%22%20version%3D%221.1%22%3E%3Cpath%20transform%3D%22rotate%28180%201024%2C576.0000000000001%29%22%20d%3D%22m1109%2C896q17%2C0%2030%2C-12t13%2C-30t-12.5%2C-30.5t-30.5%2C-12.5l-170%2C0q-18%2C0%20-30.5%2C12.5t-12.5%2C30.5t13%2C30t30%2C12l170%2C0zm-85%2C256q59%2C0%20132.5%2C-1.5t154.5%2C-5.5t164.5%2C-11.5t163%2C-20t150%2C-30t124.5%2C-41.5q23%2C-11%2042%2C-24t38%2C-30q27%2C-25%2041%2C-61.5t14%2C-72.5l0%2C-257q0%2C-123%20-47%2C-232t-128%2C-190t-190%2C-128t-232%2C-47l-81%2C0q-37%2C0%20-68.5%2C14t-60.5%2C34.5t-55.5%2C45t-53%2C45t-53%2C34.5t-55.5%2C14t-55.5%2C-14t-53%2C-34.5t-53%2C-45t-55.5%2C-45t-60.5%2C-34.5t-68.5%2C-14l-81%2C0q-123%2C0%20-232%2C47t-190%2C128t-128%2C190t-47%2C232l0%2C257q0%2C68%2038%2C115t97%2C73q54%2C24%20124.5%2C41.5t150%2C30t163%2C20t164.5%2C11.5t154.5%2C5.5t132.5%2C1.5zm939%2C-298q0%2C39%20-24.5%2C67t-58.5%2C42q-54%2C23%20-122%2C39.5t-143.5%2C28t-155.5%2C19t-157%2C11t-148.5%2C5t-129.5%2C1.5q-59%2C0%20-130%2C-1.5t-148%2C-5t-157%2C-11t-155.5%2C-19t-143.5%2C-28t-122%2C-39.5q-34%2C-14%20-58.5%2C-42t-24.5%2C-67l0%2C-257q0%2C-106%2040.5%2C-199t110%2C-162.5t162.5%2C-109.5t199%2C-40l81%2C0q27%2C0%2052%2C14t50%2C34.5t51%2C44.5t55.5%2C44.5t63.5%2C34.5t74%2C14t74%2C-14t63.5%2C-34.5t55.5%2C-44.5t51%2C-44.5t50%2C-34.5t52%2C-14l14%2C0q37%2C0%2070%2C0.5t64.5%2C4.5t63.5%2C12t68%2C23q71%2C30%20128.5%2C78.5t98.5%2C110t63.5%2C133.5t22.5%2C149l0%2C257z%22%20fill%3D%22white%22%20/%3E%3C/svg%3E%0A); background-size: 80%; background-repeat:no-repeat; background-position: center; border: none; outline: none; transition: transform 0.125s ease-out } .babylonVRicon:hover { transform: scale(1.05) } .babylonVRicon:active {background-color: rgba(51,51,51,1) } .babylonVRicon:focus {background-color: rgba(51,51,51,1) }.babylonVRicon.vrdisplaypresenting { background-image: none;} .vrdisplaypresenting::after { content: "EXIT"} .xr-error::after { content: "ERROR"}';
|
|
280
381
|
const style = document.createElement("style");
|
|
281
382
|
style.appendChild(document.createTextNode(css));
|
|
@@ -288,6 +389,7 @@ class PrefViewer extends HTMLElement {
|
|
|
288
389
|
}
|
|
289
390
|
|
|
290
391
|
const sessionMode = "immersive-ar";
|
|
392
|
+
this.#log.info("#createXRExperience()", { sessionMode });
|
|
291
393
|
const sessionSupported = await WebXRSessionManager.IsSessionSupportedAsync(sessionMode);
|
|
292
394
|
if (!sessionSupported) {
|
|
293
395
|
console.info("PrefViewer: WebXR in mode AR is not supported");
|
|
@@ -295,6 +397,7 @@ class PrefViewer extends HTMLElement {
|
|
|
295
397
|
}
|
|
296
398
|
|
|
297
399
|
try {
|
|
400
|
+
this.#log.time("xr:create");
|
|
298
401
|
const ground = MeshBuilder.CreateGround("ground", { width: 1000, height: 1000 }, this.#scene);
|
|
299
402
|
ground.isVisible = false;
|
|
300
403
|
|
|
@@ -318,6 +421,7 @@ class PrefViewer extends HTMLElement {
|
|
|
318
421
|
});
|
|
319
422
|
|
|
320
423
|
this.#XRExperience.baseExperience.sessionManager.onXRReady.add(() => {
|
|
424
|
+
this.#log.info("XR onXRReady");
|
|
321
425
|
// Set the initial position of xrCamera: use nonVRCamera, which contains a copy of the original this.#scene.activeCamera before entering XR
|
|
322
426
|
this.#XRExperience.baseExperience.camera.setTransformationFromNonVRCamera(this.#XRExperience.baseExperience._nonVRCamera);
|
|
323
427
|
this.#XRExperience.baseExperience.camera.setTarget(Vector3.Zero());
|
|
@@ -325,15 +429,21 @@ class PrefViewer extends HTMLElement {
|
|
|
325
429
|
});
|
|
326
430
|
|
|
327
431
|
this.addStylesToARButton();
|
|
432
|
+
this.#log.timeEnd("xr:create");
|
|
328
433
|
} catch (error) {
|
|
329
434
|
console.warn("PrefViewer: failed to create WebXR experience", error);
|
|
435
|
+
this.#log.error("XR creation failed", error);
|
|
330
436
|
this.#XRExperience = null;
|
|
331
437
|
}
|
|
332
438
|
}
|
|
333
439
|
|
|
334
|
-
#canvasResizeObserver = new ResizeObserver(() =>
|
|
440
|
+
#canvasResizeObserver = new ResizeObserver(() => {
|
|
441
|
+
this.#log.debug("ResizeObserver -> engine.resize()");
|
|
442
|
+
this.#engine && this.#engine.resize();
|
|
443
|
+
});
|
|
335
444
|
|
|
336
445
|
#createCamera() {
|
|
446
|
+
this.#log.debug("#createCamera()");
|
|
337
447
|
this.#camera = new ArcRotateCamera("camera", (3 * Math.PI) / 2, Math.PI * 0.47, 10, Vector3.Zero(), this.#scene);
|
|
338
448
|
this.#camera.upperBetaLimit = Math.PI * 0.48;
|
|
339
449
|
this.#camera.lowerBetaLimit = Math.PI * 0.25;
|
|
@@ -345,6 +455,7 @@ class PrefViewer extends HTMLElement {
|
|
|
345
455
|
}
|
|
346
456
|
|
|
347
457
|
#createLights() {
|
|
458
|
+
this.#log.debug("#createLights()");
|
|
348
459
|
// 1) Stronger ambient fill
|
|
349
460
|
this.#hemiLight = new HemisphericLight("hemiLight", new Vector3(-10, 10, -10), this.#scene);
|
|
350
461
|
this.#hemiLight.intensity = 0.6;
|
|
@@ -367,12 +478,11 @@ class PrefViewer extends HTMLElement {
|
|
|
367
478
|
}
|
|
368
479
|
|
|
369
480
|
#setupInteraction() {
|
|
481
|
+
this.#log.debug("#setupInteraction()");
|
|
370
482
|
this.#canvas.addEventListener("wheel", (event) => {
|
|
371
483
|
if (!this.#scene || !this.#camera) {
|
|
372
484
|
return false;
|
|
373
485
|
}
|
|
374
|
-
//const pick = this.#scene.pick(this.#scene.pointerX, this.#scene.pointerY);
|
|
375
|
-
//this.#camera.target = pick.hit ? pick.pickedPoint.clone() : this.#camera.target;
|
|
376
486
|
if (!this.#scene.activeCamera.metadata?.locked) {
|
|
377
487
|
this.#scene.activeCamera.inertialRadiusOffset -= event.deltaY * this.#scene.activeCamera.wheelPrecision * 0.001;
|
|
378
488
|
}
|
|
@@ -382,6 +492,7 @@ class PrefViewer extends HTMLElement {
|
|
|
382
492
|
|
|
383
493
|
#disposeEngine() {
|
|
384
494
|
if (!this.#engine) return;
|
|
495
|
+
this.#log.info("#disposeEngine()");
|
|
385
496
|
this.#engine.dispose();
|
|
386
497
|
this.#engine = this.#scene = this.#camera = null;
|
|
387
498
|
this.#hemiLight = this.#dirLight = this.#cameraLight = null;
|
|
@@ -390,6 +501,7 @@ class PrefViewer extends HTMLElement {
|
|
|
390
501
|
|
|
391
502
|
// Utility methods for loading gltf/glb
|
|
392
503
|
async #getServerFileDataHeader(uri) {
|
|
504
|
+
this.#log.debug("#getServerFileDataHeader()", { uri });
|
|
393
505
|
return new Promise((resolve) => {
|
|
394
506
|
const xhr = new XMLHttpRequest();
|
|
395
507
|
xhr.open("HEAD", uri, true);
|
|
@@ -398,12 +510,15 @@ class PrefViewer extends HTMLElement {
|
|
|
398
510
|
if (xhr.status === 200) {
|
|
399
511
|
const size = parseInt(xhr.getResponseHeader("Content-Length"));
|
|
400
512
|
const timestamp = new Date(xhr.getResponseHeader("Last-Modified")).toISOString();
|
|
513
|
+
this.#log.debug("HEAD ok", { size, timestamp });
|
|
401
514
|
resolve(size, timestamp);
|
|
402
515
|
} else {
|
|
516
|
+
this.#log.warn("HEAD failed", { status: xhr.status });
|
|
403
517
|
resolve(0, null);
|
|
404
518
|
}
|
|
405
519
|
};
|
|
406
520
|
xhr.onerror = () => {
|
|
521
|
+
this.#log.error("HEAD network error");
|
|
407
522
|
resolve(0, null);
|
|
408
523
|
};
|
|
409
524
|
xhr.send();
|
|
@@ -411,12 +526,14 @@ class PrefViewer extends HTMLElement {
|
|
|
411
526
|
}
|
|
412
527
|
|
|
413
528
|
#transformUrl(url) {
|
|
529
|
+
this.#log.debug("#transformUrl()", { url });
|
|
414
530
|
return new Promise((resolve) => {
|
|
415
531
|
resolve(url.replace(/^blob:[^/]+\//i, "").replace(/\\/g, "/"));
|
|
416
532
|
});
|
|
417
533
|
}
|
|
418
534
|
|
|
419
535
|
#decodeBase64(base64) {
|
|
536
|
+
this.#log.debug("#decodeBase64()", { length: (base64 || "").length });
|
|
420
537
|
const [, payload] = base64.split(",");
|
|
421
538
|
const raw = payload || base64;
|
|
422
539
|
let decoded = "";
|
|
@@ -426,6 +543,7 @@ class PrefViewer extends HTMLElement {
|
|
|
426
543
|
try {
|
|
427
544
|
decoded = atob(raw);
|
|
428
545
|
} catch {
|
|
546
|
+
this.#log.warn("atob failed (not base64?)");
|
|
429
547
|
return { blob, extension, size };
|
|
430
548
|
}
|
|
431
549
|
let isJson = false;
|
|
@@ -441,6 +559,7 @@ class PrefViewer extends HTMLElement {
|
|
|
441
559
|
}
|
|
442
560
|
|
|
443
561
|
async #initStorage(db, table) {
|
|
562
|
+
this.#log.debug("#initStorage()", { db, table });
|
|
444
563
|
if (window.gltfDB && window.gltfDB.name === db && window.gltfDB.objectStoreNames.contains(table)) {
|
|
445
564
|
return true;
|
|
446
565
|
}
|
|
@@ -449,6 +568,7 @@ class PrefViewer extends HTMLElement {
|
|
|
449
568
|
|
|
450
569
|
// Methods for managing Asset Containers
|
|
451
570
|
#setVisibilityOfWallAndFloorInModel(show) {
|
|
571
|
+
this.#log.debug("#setVisibilityOfWallAndFloorInModel()", { show });
|
|
452
572
|
if (!this.#data.containers.model.assetContainer || !this.#data.containers.model.visible) {
|
|
453
573
|
return false;
|
|
454
574
|
}
|
|
@@ -461,9 +581,11 @@ class PrefViewer extends HTMLElement {
|
|
|
461
581
|
if (!optionMaterial || !optionMaterial.prefix || !optionMaterial.value) {
|
|
462
582
|
return false;
|
|
463
583
|
}
|
|
584
|
+
this.#log.debug("#setOptionsMaterial()", optionMaterial);
|
|
464
585
|
|
|
465
586
|
const material = this.#data.containers.materials.assetContainer?.materials.find((mat) => mat.name === optionMaterial.value) || null;
|
|
466
587
|
if (!material) {
|
|
588
|
+
this.#log.warn("material not found", { wanted: optionMaterial.value });
|
|
467
589
|
return false;
|
|
468
590
|
}
|
|
469
591
|
|
|
@@ -492,6 +614,7 @@ class PrefViewer extends HTMLElement {
|
|
|
492
614
|
}
|
|
493
615
|
|
|
494
616
|
#setOptionsMaterials() {
|
|
617
|
+
this.#log.debug("#setOptionsMaterials()");
|
|
495
618
|
let someSetted = false;
|
|
496
619
|
Object.values(this.#data.options.materials).forEach((material) => {
|
|
497
620
|
let settedMaterial = this.#setOptionsMaterial(material);
|
|
@@ -501,12 +624,14 @@ class PrefViewer extends HTMLElement {
|
|
|
501
624
|
}
|
|
502
625
|
|
|
503
626
|
#setOptionsCamera() {
|
|
627
|
+
this.#log.debug("#setOptionsCamera()", this.#data.options.camera);
|
|
504
628
|
if (!this.#data.options.camera.value || (!this.#data.options.camera.changed && !this.#data.containers.model.assetContainer.changed)) {
|
|
505
629
|
return false;
|
|
506
630
|
}
|
|
507
631
|
|
|
508
632
|
let camera = this.#data.containers.model.assetContainer?.cameras.find((cam) => cam.name === this.#data.options.camera.value) || null;
|
|
509
633
|
if (!camera) {
|
|
634
|
+
this.#log.warn("camera not found", { wanted: this.#data.options.camera.value });
|
|
510
635
|
return false;
|
|
511
636
|
}
|
|
512
637
|
|
|
@@ -521,6 +646,7 @@ class PrefViewer extends HTMLElement {
|
|
|
521
646
|
|
|
522
647
|
#addContainer(container) {
|
|
523
648
|
if (container.assetContainer && !container.visible && container.show) {
|
|
649
|
+
this.#log.debug("#addContainer()", { name: container.name });
|
|
524
650
|
container.assetContainer.addAllToScene();
|
|
525
651
|
container.visible = true;
|
|
526
652
|
}
|
|
@@ -528,12 +654,14 @@ class PrefViewer extends HTMLElement {
|
|
|
528
654
|
|
|
529
655
|
#removeContainer(container) {
|
|
530
656
|
if (container.assetContainer && container.visible) {
|
|
657
|
+
this.#log.debug("#removeContainer()", { name: container.name });
|
|
531
658
|
container.assetContainer.removeAllFromScene();
|
|
532
659
|
container.visible = false;
|
|
533
660
|
}
|
|
534
661
|
}
|
|
535
662
|
|
|
536
663
|
#replaceContainer(container, newAssetContainer) {
|
|
664
|
+
this.#log.debug("#replaceContainer()", { name: container.name });
|
|
537
665
|
this.#removeContainer(container);
|
|
538
666
|
container.assetContainer = newAssetContainer;
|
|
539
667
|
container.assetContainer.meshes.forEach((mesh) => {
|
|
@@ -544,9 +672,12 @@ class PrefViewer extends HTMLElement {
|
|
|
544
672
|
}
|
|
545
673
|
|
|
546
674
|
async #loadAssetContainer(container) {
|
|
675
|
+
this.#log.group(`#loadAssetContainer(${container?.name})`);
|
|
547
676
|
let storage = container?.storage;
|
|
548
677
|
|
|
549
678
|
if (!storage) {
|
|
679
|
+
this.#log.warn("no storage provided");
|
|
680
|
+
this.#log.groupEnd();
|
|
550
681
|
return false;
|
|
551
682
|
}
|
|
552
683
|
|
|
@@ -557,6 +688,8 @@ class PrefViewer extends HTMLElement {
|
|
|
557
688
|
const object = await loadModel(storage.id, storage.table);
|
|
558
689
|
source = object.data;
|
|
559
690
|
if (object.timestamp === container.timestamp) {
|
|
691
|
+
this.#log.info("no change from IndexedDB (timestamp match)");
|
|
692
|
+
this.#log.groupEnd();
|
|
560
693
|
return false;
|
|
561
694
|
} else {
|
|
562
695
|
container.changed = { timestamp: object.timestamp, size: object.size };
|
|
@@ -564,6 +697,8 @@ class PrefViewer extends HTMLElement {
|
|
|
564
697
|
}
|
|
565
698
|
|
|
566
699
|
if (!source) {
|
|
700
|
+
this.#log.warn("no source URL or data");
|
|
701
|
+
this.#log.groupEnd();
|
|
567
702
|
return false;
|
|
568
703
|
}
|
|
569
704
|
|
|
@@ -571,11 +706,14 @@ class PrefViewer extends HTMLElement {
|
|
|
571
706
|
|
|
572
707
|
let { blob, extension, size } = this.#decodeBase64(source);
|
|
573
708
|
if (blob && extension) {
|
|
709
|
+
this.#log.debug("source is base64", { extension, size });
|
|
574
710
|
file = new File([blob], `${container.name}${extension}`, {
|
|
575
711
|
type: blob.type,
|
|
576
712
|
});
|
|
577
713
|
if (!container.changed) {
|
|
578
714
|
if (container.timestamp === null && container.size === size) {
|
|
715
|
+
this.#log.info("no change (base64 size match)");
|
|
716
|
+
this.#log.groupEnd();
|
|
579
717
|
return false;
|
|
580
718
|
} else {
|
|
581
719
|
container.changed = { timestamp: null, size: size };
|
|
@@ -586,6 +724,8 @@ class PrefViewer extends HTMLElement {
|
|
|
586
724
|
extension = extMatch ? `.${extMatch[1].toLowerCase()}` : ".gltf";
|
|
587
725
|
const { fileSize, fileTimestamp } = await this.#getServerFileDataHeader(source);
|
|
588
726
|
if (container.timestamp === fileTimestamp && container.size === fileSize) {
|
|
727
|
+
this.#log.info("no change (remote HEAD match)");
|
|
728
|
+
this.#log.groupEnd();
|
|
589
729
|
return false;
|
|
590
730
|
} else {
|
|
591
731
|
container.changed = { timestamp: fileTimestamp, size: fileSize };
|
|
@@ -602,10 +742,15 @@ class PrefViewer extends HTMLElement {
|
|
|
602
742
|
},
|
|
603
743
|
};
|
|
604
744
|
|
|
605
|
-
|
|
745
|
+
this.#log.time(`babylon:LoadAssetContainerAsync:${container.name}`);
|
|
746
|
+
const res = LoadAssetContainerAsync(file || source, this.#scene, options);
|
|
747
|
+
this.#log.groupEnd();
|
|
748
|
+
return res;
|
|
606
749
|
}
|
|
607
750
|
|
|
608
751
|
async #loadContainers(loadModel = true, loadEnvironment = true, loadMaterials = true) {
|
|
752
|
+
this.#log.group("#loadContainers()");
|
|
753
|
+
this.#log.debug("flags", { loadModel, loadEnvironment, loadMaterials });
|
|
609
754
|
const promiseArray = [];
|
|
610
755
|
promiseArray.push(loadModel ? this.#loadAssetContainer(this.#data.containers.model) : false);
|
|
611
756
|
promiseArray.push(loadEnvironment ? this.#loadAssetContainer(this.#data.containers.environment) : false);
|
|
@@ -618,22 +763,29 @@ class PrefViewer extends HTMLElement {
|
|
|
618
763
|
const materialsContainer = values[2];
|
|
619
764
|
|
|
620
765
|
if (modelContainer.status === "fulfilled" && modelContainer.value) {
|
|
766
|
+
this.#log.timeEnd(`babylon:LoadAssetContainerAsync:model`);
|
|
621
767
|
this.#replaceContainer(this.#data.containers.model, modelContainer.value);
|
|
622
768
|
this.#storeChangedFlagsForContainer(this.#data.containers.model);
|
|
623
769
|
} else {
|
|
770
|
+
this.#log.debug("model container unchanged / not loaded");
|
|
624
771
|
this.#data.containers.model.show ? this.#addContainer(this.#data.containers.model) : this.#removeContainer(this.#data.containers.model);
|
|
625
772
|
}
|
|
626
773
|
|
|
627
774
|
if (environmentContainer.status === "fulfilled" && environmentContainer.value) {
|
|
775
|
+
this.#log.timeEnd(`babylon:LoadAssetContainerAsync:environment`);
|
|
628
776
|
this.#replaceContainer(this.#data.containers.environment, environmentContainer.value);
|
|
629
777
|
this.#storeChangedFlagsForContainer(this.#data.containers.environment);
|
|
630
778
|
} else {
|
|
779
|
+
this.#log.debug("environment container unchanged / not loaded");
|
|
631
780
|
this.#data.containers.environment.show ? this.#addContainer(this.#data.containers.environment) : this.#removeContainer(this.#data.containers.environment);
|
|
632
781
|
}
|
|
633
782
|
|
|
634
783
|
if (materialsContainer.status === "fulfilled" && materialsContainer.value) {
|
|
784
|
+
this.#log.timeEnd(`babylon:LoadAssetContainerAsync:materials`);
|
|
635
785
|
this.#replaceContainer(this.#data.containers.materials, materialsContainer.value);
|
|
636
786
|
this.#storeChangedFlagsForContainer(this.#data.containers.materials);
|
|
787
|
+
} else if (loadMaterials) {
|
|
788
|
+
this.#log.debug("materials container unchanged / not loaded");
|
|
637
789
|
}
|
|
638
790
|
|
|
639
791
|
this.#setOptionsMaterials();
|
|
@@ -642,6 +794,7 @@ class PrefViewer extends HTMLElement {
|
|
|
642
794
|
|
|
643
795
|
this.#resetChangedFlags();
|
|
644
796
|
|
|
797
|
+
this.#log.info("dispatch: model-loaded");
|
|
645
798
|
this.dispatchEvent(
|
|
646
799
|
new CustomEvent("model-loaded", {
|
|
647
800
|
detail: { success: "" },
|
|
@@ -649,9 +802,11 @@ class PrefViewer extends HTMLElement {
|
|
|
649
802
|
composed: true,
|
|
650
803
|
})
|
|
651
804
|
);
|
|
805
|
+
this.#log.groupEnd();
|
|
652
806
|
})
|
|
653
807
|
.catch((error) => {
|
|
654
808
|
console.error("PrefViewer: failed to load model", error);
|
|
809
|
+
this.#log.error("failed to load model", error);
|
|
655
810
|
this.dispatchEvent(
|
|
656
811
|
new CustomEvent("model-error", {
|
|
657
812
|
detail: { error: error },
|
|
@@ -659,13 +814,17 @@ class PrefViewer extends HTMLElement {
|
|
|
659
814
|
composed: true,
|
|
660
815
|
})
|
|
661
816
|
);
|
|
817
|
+
this.#log.groupEnd();
|
|
662
818
|
});
|
|
663
819
|
}
|
|
664
820
|
|
|
665
821
|
// Public Methods
|
|
666
822
|
loadConfig(config) {
|
|
823
|
+
this.#log.group("loadConfig()");
|
|
667
824
|
config = typeof config === "string" ? JSON.parse(config) : config;
|
|
668
825
|
if (!config) {
|
|
826
|
+
this.#log.warn("no config");
|
|
827
|
+
this.#log.groupEnd();
|
|
669
828
|
return false;
|
|
670
829
|
}
|
|
671
830
|
|
|
@@ -682,11 +841,16 @@ class PrefViewer extends HTMLElement {
|
|
|
682
841
|
this.#checkMaterialsChanged(config.options);
|
|
683
842
|
}
|
|
684
843
|
|
|
844
|
+
this.#log.debug("config applied", { containers: this.#data.containers, options: this.#data.options });
|
|
685
845
|
this.#initialized && this.#loadContainers(true, true, true);
|
|
846
|
+
this.#log.groupEnd();
|
|
686
847
|
}
|
|
687
848
|
|
|
688
849
|
setOptions(options) {
|
|
850
|
+
this.#log.group("setOptions()");
|
|
689
851
|
if (!options) {
|
|
852
|
+
this.#log.warn("no options");
|
|
853
|
+
this.#log.groupEnd();
|
|
690
854
|
return false;
|
|
691
855
|
}
|
|
692
856
|
let someSetted = false;
|
|
@@ -698,57 +862,73 @@ class PrefViewer extends HTMLElement {
|
|
|
698
862
|
}
|
|
699
863
|
this.#resetChangedFlags();
|
|
700
864
|
debugger;
|
|
865
|
+
this.#log.debug("setOptions result", { someSetted });
|
|
866
|
+
this.#log.groupEnd();
|
|
701
867
|
return someSetted;
|
|
702
868
|
}
|
|
703
869
|
|
|
704
870
|
loadModel(model) {
|
|
871
|
+
this.#log.group("loadModel()");
|
|
705
872
|
model = typeof model === "string" ? JSON.parse(model) : model;
|
|
706
873
|
if (!model) {
|
|
874
|
+
this.#log.warn("no model");
|
|
875
|
+
this.#log.groupEnd();
|
|
707
876
|
return false;
|
|
708
877
|
}
|
|
709
878
|
this.#data.containers.model.storage = model.storage || null;
|
|
710
879
|
this.#data.containers.model.show = model.visible !== undefined ? model.visible : this.#data.containers.model.show;
|
|
711
880
|
this.#initialized && this.#loadContainers(true, false, false);
|
|
881
|
+
this.#log.groupEnd();
|
|
712
882
|
}
|
|
713
883
|
|
|
714
884
|
loadScene(scene) {
|
|
885
|
+
this.#log.group("loadScene()");
|
|
715
886
|
scene = typeof scene === "string" ? JSON.parse(scene) : scene;
|
|
716
887
|
if (!scene) {
|
|
888
|
+
this.#log.warn("no scene");
|
|
889
|
+
this.#log.groupEnd();
|
|
717
890
|
return false;
|
|
718
891
|
}
|
|
719
892
|
this.#data.containers.environment.storage = scene.storage || null;
|
|
720
893
|
this.#data.containers.environment.show = scene.visible !== undefined ? scene.visible : this.#data.containers.environment.show;
|
|
721
894
|
this.#initialized && this.#loadContainers(false, true, false);
|
|
895
|
+
this.#log.groupEnd();
|
|
722
896
|
}
|
|
723
897
|
|
|
724
898
|
showModel() {
|
|
899
|
+
this.#log.info("showModel()");
|
|
725
900
|
this.#data.containers.model.show = true;
|
|
726
901
|
this.#addContainer(this.#data.containers.model);
|
|
727
902
|
}
|
|
728
903
|
|
|
729
904
|
hideModel() {
|
|
905
|
+
this.#log.info("hideModel()");
|
|
730
906
|
this.#data.containers.model.show = false;
|
|
731
907
|
this.#removeContainer(this.#data.containers.model);
|
|
732
908
|
}
|
|
733
909
|
|
|
734
910
|
showScene() {
|
|
911
|
+
this.#log.info("showScene()");
|
|
735
912
|
this.#data.containers.environment.show = true;
|
|
736
913
|
this.#addContainer(this.#data.containers.environment);
|
|
737
914
|
this.#setVisibilityOfWallAndFloorInModel();
|
|
738
915
|
}
|
|
739
916
|
|
|
740
917
|
hideScene() {
|
|
918
|
+
this.#log.info("hideScene()");
|
|
741
919
|
this.#data.containers.environment.show = false;
|
|
742
920
|
this.#removeContainer(this.#data.containers.environment);
|
|
743
921
|
this.#setVisibilityOfWallAndFloorInModel();
|
|
744
922
|
}
|
|
745
923
|
|
|
746
924
|
downloadModelGLB() {
|
|
925
|
+
this.#log.info("downloadModelGLB()");
|
|
747
926
|
const fileName = "model";
|
|
748
927
|
GLTF2Export.GLBAsync(this.#data.containers.model.assetContainer, fileName, { exportWithoutWaitingForScene: true }).then((glb) => glb.downloadFiles());
|
|
749
928
|
}
|
|
750
929
|
|
|
751
930
|
downloadModelUSDZ() {
|
|
931
|
+
this.#log.info("downloadModelUSDZ()");
|
|
752
932
|
const fileName = "model";
|
|
753
933
|
USDZExportAsync(this.#data.containers.model.assetContainer).then((response) => {
|
|
754
934
|
if (response) {
|
|
@@ -758,6 +938,7 @@ class PrefViewer extends HTMLElement {
|
|
|
758
938
|
}
|
|
759
939
|
|
|
760
940
|
downloadModelAndSceneUSDZ() {
|
|
941
|
+
this.#log.info("downloadModelAndSceneUSDZ()");
|
|
761
942
|
const fileName = "scene";
|
|
762
943
|
USDZExportAsync(this.#scene).then((response) => {
|
|
763
944
|
if (response) {
|
|
@@ -767,6 +948,7 @@ class PrefViewer extends HTMLElement {
|
|
|
767
948
|
}
|
|
768
949
|
|
|
769
950
|
downloadModelAndSceneGLB() {
|
|
951
|
+
this.#log.info("downloadModelAndSceneGLB()");
|
|
770
952
|
const fileName = "scene";
|
|
771
953
|
GLTF2Export.GLBAsync(this.#scene, fileName, { exportWithoutWaitingForScene: true }).then((glb) => glb.downloadFiles());
|
|
772
954
|
}
|