@preference-sl/pref-viewer 2.10.0-beta.20 → 2.10.0-beta.22
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 +123 -4
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -131,11 +131,13 @@ class PrefViewer extends HTMLElement {
|
|
|
131
131
|
|
|
132
132
|
constructor() {
|
|
133
133
|
super();
|
|
134
|
+
console.log("PrefViewer: constructor()");
|
|
134
135
|
this.attachShadow({ mode: "open" });
|
|
135
136
|
this.#createCanvas();
|
|
136
137
|
this.#wrapCanvas();
|
|
137
138
|
// Point to whichever version you packaged or want to use:
|
|
138
139
|
const DRACO_BASE = "https://www.gstatic.com/draco/versioned/decoders/1.5.7";
|
|
140
|
+
console.log("PrefViewer: DRACO config base =", DRACO_BASE);
|
|
139
141
|
DracoCompression.Configuration.decoder = {
|
|
140
142
|
// loader for the “wrapper” that pulls in the real WASM
|
|
141
143
|
wasmUrl: `${DRACO_BASE}/draco_wasm_wrapper_gltf.js`,
|
|
@@ -151,6 +153,7 @@ class PrefViewer extends HTMLElement {
|
|
|
151
153
|
}
|
|
152
154
|
|
|
153
155
|
attributeChangedCallback(name, _old, value) {
|
|
156
|
+
console.log("PrefViewer: attributeChangedCallback()", { name, old: _old, value });
|
|
154
157
|
let data = null;
|
|
155
158
|
switch (name) {
|
|
156
159
|
case "config":
|
|
@@ -165,6 +168,7 @@ class PrefViewer extends HTMLElement {
|
|
|
165
168
|
case "show-model":
|
|
166
169
|
data = value.toLowerCase?.() === "true";
|
|
167
170
|
if (this.initialized) {
|
|
171
|
+
console.log("PrefViewer: toggling model visibility (attr)", data);
|
|
168
172
|
data ? this.showModel() : this.hideModel();
|
|
169
173
|
} else {
|
|
170
174
|
this.#data.containers.model.show = data;
|
|
@@ -173,6 +177,7 @@ class PrefViewer extends HTMLElement {
|
|
|
173
177
|
case "show-scene":
|
|
174
178
|
data = value.toLowerCase?.() === "true";
|
|
175
179
|
if (this.initialized) {
|
|
180
|
+
console.log("PrefViewer: toggling scene visibility (attr)", data);
|
|
176
181
|
data ? this.showScene() : this.hideScene();
|
|
177
182
|
} else {
|
|
178
183
|
this.#data.containers.environment.show = data;
|
|
@@ -182,6 +187,7 @@ class PrefViewer extends HTMLElement {
|
|
|
182
187
|
}
|
|
183
188
|
|
|
184
189
|
connectedCallback() {
|
|
190
|
+
console.log("PrefViewer: connectedCallback()");
|
|
185
191
|
if (!this.hasAttribute("config")) {
|
|
186
192
|
const error = 'PrefViewer: provide "models" as array of model and environment';
|
|
187
193
|
console.error(error);
|
|
@@ -198,16 +204,19 @@ class PrefViewer extends HTMLElement {
|
|
|
198
204
|
|
|
199
205
|
this.#initializeBabylon();
|
|
200
206
|
this.initialized = true;
|
|
207
|
+
console.log("PrefViewer: initialized = true, loading containers…");
|
|
201
208
|
this.#loadContainers(true, true, true);
|
|
202
209
|
}
|
|
203
210
|
|
|
204
211
|
disconnectedCallback() {
|
|
212
|
+
console.log("PrefViewer: disconnectedCallback()");
|
|
205
213
|
this.#disposeEngine();
|
|
206
214
|
this.#canvasResizeObserver.disconnect();
|
|
207
215
|
}
|
|
208
216
|
|
|
209
217
|
// Web Component
|
|
210
218
|
#createCanvas() {
|
|
219
|
+
console.log("PrefViewer: #createCanvas()");
|
|
211
220
|
this.#canvas = document.createElement("canvas");
|
|
212
221
|
Object.assign(this.#canvas.style, {
|
|
213
222
|
width: "100%",
|
|
@@ -218,6 +227,7 @@ class PrefViewer extends HTMLElement {
|
|
|
218
227
|
}
|
|
219
228
|
|
|
220
229
|
#wrapCanvas() {
|
|
230
|
+
console.log("PrefViewer: #wrapCanvas()");
|
|
221
231
|
this.#wrapper = document.createElement("div");
|
|
222
232
|
Object.assign(this.#wrapper.style, {
|
|
223
233
|
width: "100%",
|
|
@@ -229,6 +239,7 @@ class PrefViewer extends HTMLElement {
|
|
|
229
239
|
}
|
|
230
240
|
|
|
231
241
|
#setStatusSceneLoading() {
|
|
242
|
+
console.log("PrefViewer: #setStatusSceneLoading()");
|
|
232
243
|
this.loaded = false;
|
|
233
244
|
this.loading = true;
|
|
234
245
|
if (this.hasAttribute("loaded")) {
|
|
@@ -245,6 +256,7 @@ class PrefViewer extends HTMLElement {
|
|
|
245
256
|
}
|
|
246
257
|
|
|
247
258
|
#setStatusSceneLoaded() {
|
|
259
|
+
console.log("PrefViewer: #setStatusSceneLoaded()");
|
|
248
260
|
this.loaded = true;
|
|
249
261
|
this.loading = false;
|
|
250
262
|
|
|
@@ -286,9 +298,11 @@ class PrefViewer extends HTMLElement {
|
|
|
286
298
|
detail: detail,
|
|
287
299
|
})
|
|
288
300
|
);
|
|
301
|
+
console.log("PrefViewer: scene-loaded detail =", detail);
|
|
289
302
|
}
|
|
290
303
|
|
|
291
304
|
#setStatusOptionsLoading() {
|
|
305
|
+
console.log("PrefViewer: #setStatusOptionsLoading()");
|
|
292
306
|
this.dispatchEvent(
|
|
293
307
|
new CustomEvent("options-loading", {
|
|
294
308
|
bubbles: true,
|
|
@@ -299,6 +313,7 @@ class PrefViewer extends HTMLElement {
|
|
|
299
313
|
}
|
|
300
314
|
|
|
301
315
|
#setStatusOptionsLoaded() {
|
|
316
|
+
console.log("PrefViewer: #setStatusOptionsLoaded()");
|
|
302
317
|
const toLoadDetail = {
|
|
303
318
|
innerWallMaterial: !!this.#data.options.materials.innerWall.changed,
|
|
304
319
|
outerWallMaterial: !!this.#data.options.materials.outerWall.changed,
|
|
@@ -325,6 +340,7 @@ class PrefViewer extends HTMLElement {
|
|
|
325
340
|
detail: detail,
|
|
326
341
|
})
|
|
327
342
|
);
|
|
343
|
+
console.log("PrefViewer: options-loaded detail =", detail);
|
|
328
344
|
}
|
|
329
345
|
|
|
330
346
|
// Data
|
|
@@ -332,8 +348,8 @@ class PrefViewer extends HTMLElement {
|
|
|
332
348
|
if (!options || !options.camera) {
|
|
333
349
|
return false;
|
|
334
350
|
}
|
|
335
|
-
|
|
336
351
|
const changed = options.camera !== this.#data.options.camera.value;
|
|
352
|
+
console.log("PrefViewer: #checkCameraChanged()", { incoming: options.camera, previous: this.#data.options.camera.value, changed });
|
|
337
353
|
this.#data.options.camera.changed = changed ? { oldValue: this.#data.options.camera.value, oldLocked: this.#data.options.camera.locked, success: false } : false;
|
|
338
354
|
if (changed) this.#data.options.camera.value = options.camera;
|
|
339
355
|
|
|
@@ -348,6 +364,7 @@ class PrefViewer extends HTMLElement {
|
|
|
348
364
|
Object.keys(this.#data.options.materials).forEach((material) => {
|
|
349
365
|
const key = `${material}Material`;
|
|
350
366
|
const materialChanged = options[key] && options[key] !== this.#data.options.materials[material].value ? true : false;
|
|
367
|
+
console.log("PrefViewer: #checkMaterialsChanged()", { key, incoming: options[key], previous: this.#data.options.materials[material].value, materialChanged });
|
|
351
368
|
this.#data.options.materials[material].changed = materialChanged ? { oldValue: this.#data.options.materials[material].value, success: false } : false;
|
|
352
369
|
this.#data.options.materials[material].value = materialChanged ? options[key] : this.#data.options.materials[material].value;
|
|
353
370
|
someChanged = someChanged || this.#data.options.materials[material].changed;
|
|
@@ -356,12 +373,14 @@ class PrefViewer extends HTMLElement {
|
|
|
356
373
|
}
|
|
357
374
|
|
|
358
375
|
#storeChangedFlagsForContainer(container) {
|
|
376
|
+
console.log("PrefViewer: #storeChangedFlagsForContainer()", { name: container.name, changed: container.changed });
|
|
359
377
|
container.timeStamp = container.changed.timeStamp;
|
|
360
378
|
container.size = container.changed.size;
|
|
361
379
|
container.changed.success = true;
|
|
362
380
|
}
|
|
363
381
|
|
|
364
382
|
#resetChangedFlags() {
|
|
383
|
+
console.log("PrefViewer: #resetChangedFlags()");
|
|
365
384
|
Object.values(this.#data.containers).forEach((container) => (container.changed = false));
|
|
366
385
|
Object.values(this.#data.options.materials).forEach((material) => (material.changed = false));
|
|
367
386
|
this.#data.options.camera.changed = false;
|
|
@@ -369,22 +388,30 @@ class PrefViewer extends HTMLElement {
|
|
|
369
388
|
|
|
370
389
|
// Babylon.js
|
|
371
390
|
async #initializeBabylon() {
|
|
391
|
+
console.log("PrefViewer: #initializeBabylon() START");
|
|
372
392
|
this.#engine = new Engine(this.#canvas, true, { alpha: true });
|
|
373
393
|
this.#engine.disableUniformBuffers = true; // <- evita el límite de GL_MAX_*_UNIFORM_BUFFERS // PROVISIONAL, YA QUE ESTO ES UN POCO OVERKILL
|
|
394
|
+
console.log("PrefViewer: Engine created", { disableUBO: this.#engine.disableUniformBuffers });
|
|
374
395
|
|
|
375
396
|
this.#scene = new Scene(this.#engine);
|
|
376
397
|
this.#scene.clearColor = new Color4(1, 1, 1, 1);
|
|
398
|
+
console.log("PrefViewer: Scene created, clearColor set to white");
|
|
399
|
+
|
|
377
400
|
this.#createCamera();
|
|
378
401
|
this.#createLights();
|
|
379
402
|
this.#setupInteraction();
|
|
380
403
|
|
|
381
404
|
this.#engine.runRenderLoop(() => this.#scene && this.#scene.render());
|
|
405
|
+
console.log("PrefViewer: runRenderLoop started");
|
|
382
406
|
this.#canvasResizeObserver.observe(this.#canvas);
|
|
407
|
+
console.log("PrefViewer: ResizeObserver attached");
|
|
383
408
|
|
|
384
409
|
await this.#createXRExperience();
|
|
410
|
+
console.log("PrefViewer: #initializeBabylon() END");
|
|
385
411
|
}
|
|
386
412
|
|
|
387
413
|
addStylesToARButton() {
|
|
414
|
+
console.log("PrefViewer: addStylesToARButton()");
|
|
388
415
|
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"}';
|
|
389
416
|
const style = document.createElement("style");
|
|
390
417
|
style.appendChild(document.createTextNode(css));
|
|
@@ -392,12 +419,15 @@ class PrefViewer extends HTMLElement {
|
|
|
392
419
|
}
|
|
393
420
|
|
|
394
421
|
async #createXRExperience() {
|
|
422
|
+
console.log("PrefViewer: #createXRExperience() START");
|
|
395
423
|
if (this.#XRExperience) {
|
|
424
|
+
console.log("PrefViewer: XR already exists, skipping.");
|
|
396
425
|
return true;
|
|
397
426
|
}
|
|
398
427
|
|
|
399
428
|
const sessionMode = "immersive-ar";
|
|
400
429
|
const sessionSupported = await WebXRSessionManager.IsSessionSupportedAsync(sessionMode);
|
|
430
|
+
console.log("PrefViewer: WebXR session supported =", sessionSupported);
|
|
401
431
|
if (!sessionSupported) {
|
|
402
432
|
console.info("PrefViewer: WebXR in mode AR is not supported");
|
|
403
433
|
return false;
|
|
@@ -418,6 +448,7 @@ class PrefViewer extends HTMLElement {
|
|
|
418
448
|
};
|
|
419
449
|
|
|
420
450
|
this.#XRExperience = await WebXRDefaultExperience.CreateAsync(this.#scene, options);
|
|
451
|
+
console.log("PrefViewer: XR experience created");
|
|
421
452
|
|
|
422
453
|
const featuresManager = this.#XRExperience.baseExperience.featuresManager;
|
|
423
454
|
featuresManager.enableFeature(WebXRFeatureName.TELEPORTATION, "stable", {
|
|
@@ -427,6 +458,7 @@ class PrefViewer extends HTMLElement {
|
|
|
427
458
|
});
|
|
428
459
|
|
|
429
460
|
this.#XRExperience.baseExperience.sessionManager.onXRReady.add(() => {
|
|
461
|
+
console.log("PrefViewer: onXRReady - syncing camera pose");
|
|
430
462
|
// Set the initial position of xrCamera: use nonVRCamera, which contains a copy of the original this.#scene.activeCamera before entering XR
|
|
431
463
|
this.#XRExperience.baseExperience.camera.setTransformationFromNonVRCamera(this.#XRExperience.baseExperience._nonVRCamera);
|
|
432
464
|
this.#XRExperience.baseExperience.camera.setTarget(Vector3.Zero());
|
|
@@ -438,11 +470,13 @@ class PrefViewer extends HTMLElement {
|
|
|
438
470
|
console.warn("PrefViewer: failed to create WebXR experience", error);
|
|
439
471
|
this.#XRExperience = null;
|
|
440
472
|
}
|
|
473
|
+
console.log("PrefViewer: #createXRExperience() END");
|
|
441
474
|
}
|
|
442
475
|
|
|
443
476
|
#canvasResizeObserver = new ResizeObserver(() => this.#engine && this.#engine.resize());
|
|
444
477
|
|
|
445
478
|
#createCamera() {
|
|
479
|
+
console.log("PrefViewer: #createCamera()");
|
|
446
480
|
this.#camera = new ArcRotateCamera("camera", (3 * Math.PI) / 2, Math.PI * 0.47, 10, Vector3.Zero(), this.#scene);
|
|
447
481
|
this.#camera.upperBetaLimit = Math.PI * 0.48;
|
|
448
482
|
this.#camera.lowerBetaLimit = Math.PI * 0.25;
|
|
@@ -451,9 +485,16 @@ class PrefViewer extends HTMLElement {
|
|
|
451
485
|
this.#camera.metadata = { locked: false }
|
|
452
486
|
this.#camera.attachControl(this.#canvas, true);
|
|
453
487
|
this.#scene.activeCamera = this.#camera;
|
|
488
|
+
console.log("PrefViewer: camera configured", {
|
|
489
|
+
upperBetaLimit: this.#camera.upperBetaLimit,
|
|
490
|
+
lowerBetaLimit: this.#camera.lowerBetaLimit,
|
|
491
|
+
lowerRadiusLimit: this.#camera.lowerRadiusLimit,
|
|
492
|
+
upperRadiusLimit: this.#camera.upperRadiusLimit
|
|
493
|
+
});
|
|
454
494
|
}
|
|
455
495
|
|
|
456
496
|
#createLights() {
|
|
497
|
+
console.log("PrefViewer: #createLights()");
|
|
457
498
|
// 1) Stronger ambient fill
|
|
458
499
|
this.#hemiLight = new HemisphericLight("hemiLight", new Vector3(-10, 10, -10), this.#scene);
|
|
459
500
|
this.#hemiLight.intensity = 0.6;
|
|
@@ -473,15 +514,21 @@ class PrefViewer extends HTMLElement {
|
|
|
473
514
|
this.#cameraLight = new PointLight("pl", this.#camera.position, this.#scene);
|
|
474
515
|
this.#cameraLight.parent = this.#camera;
|
|
475
516
|
this.#cameraLight.intensity = 0.3;
|
|
517
|
+
|
|
518
|
+
console.log("PrefViewer: lights created", {
|
|
519
|
+
hemiIntensity: this.#hemiLight.intensity,
|
|
520
|
+
dirIntensity: this.#dirLight.intensity,
|
|
521
|
+
shadowMapSize: 1024,
|
|
522
|
+
pointIntensity: this.#cameraLight.intensity
|
|
523
|
+
});
|
|
476
524
|
}
|
|
477
525
|
|
|
478
526
|
#setupInteraction() {
|
|
527
|
+
console.log("PrefViewer: #setupInteraction()");
|
|
479
528
|
this.#canvas.addEventListener("wheel", (event) => {
|
|
480
529
|
if (!this.#scene || !this.#camera) {
|
|
481
530
|
return false;
|
|
482
531
|
}
|
|
483
|
-
//const pick = this.#scene.pick(this.#scene.pointerX, this.#scene.pointerY);
|
|
484
|
-
//this.#camera.target = pick.hit ? pick.pickedPoint.clone() : this.#camera.target;
|
|
485
532
|
if (!this.#scene.activeCamera.metadata?.locked) {
|
|
486
533
|
this.#scene.activeCamera.inertialRadiusOffset -= event.deltaY * this.#scene.activeCamera.wheelPrecision * 0.001;
|
|
487
534
|
}
|
|
@@ -490,6 +537,7 @@ class PrefViewer extends HTMLElement {
|
|
|
490
537
|
}
|
|
491
538
|
|
|
492
539
|
#disposeEngine() {
|
|
540
|
+
console.log("PrefViewer: #disposeEngine()");
|
|
493
541
|
if (!this.#engine) return;
|
|
494
542
|
this.#shadowGen?.dispose();
|
|
495
543
|
this.#scene?.lights?.slice().forEach(l => l.dispose());
|
|
@@ -501,6 +549,7 @@ class PrefViewer extends HTMLElement {
|
|
|
501
549
|
|
|
502
550
|
// Utility methods for loading gltf/glb
|
|
503
551
|
async #getServerFileDataHeader(uri) {
|
|
552
|
+
console.log("PrefViewer: #getServerFileDataHeader()", uri);
|
|
504
553
|
return new Promise((resolve) => {
|
|
505
554
|
const xhr = new XMLHttpRequest();
|
|
506
555
|
xhr.open("HEAD", uri, true);
|
|
@@ -509,12 +558,15 @@ class PrefViewer extends HTMLElement {
|
|
|
509
558
|
if (xhr.status === 200) {
|
|
510
559
|
const size = parseInt(xhr.getResponseHeader("Content-Length"));
|
|
511
560
|
const timeStamp = new Date(xhr.getResponseHeader("Last-Modified")).toISOString();
|
|
561
|
+
console.log("PrefViewer: HEAD ok", { size, timeStamp });
|
|
512
562
|
resolve([size, timeStamp]);
|
|
513
563
|
} else {
|
|
564
|
+
console.warn("PrefViewer: HEAD failed", xhr.status);
|
|
514
565
|
resolve([0, null]);
|
|
515
566
|
}
|
|
516
567
|
};
|
|
517
568
|
xhr.onerror = () => {
|
|
569
|
+
console.warn("PrefViewer: HEAD network error");
|
|
518
570
|
resolve([0, null]);
|
|
519
571
|
};
|
|
520
572
|
xhr.send();
|
|
@@ -523,11 +575,14 @@ class PrefViewer extends HTMLElement {
|
|
|
523
575
|
|
|
524
576
|
#transformUrl(url) {
|
|
525
577
|
return new Promise((resolve) => {
|
|
526
|
-
|
|
578
|
+
const transformed = url.replace(/^blob:[^/]+\//i, "").replace(/\\/g, "/");
|
|
579
|
+
console.log("PrefViewer: #transformUrl()", { in: url, out: transformed });
|
|
580
|
+
resolve(transformed);
|
|
527
581
|
});
|
|
528
582
|
}
|
|
529
583
|
|
|
530
584
|
#decodeBase64(base64) {
|
|
585
|
+
console.log("PrefViewer: #decodeBase64() START");
|
|
531
586
|
const [, payload] = base64.split(",");
|
|
532
587
|
const raw = payload || base64;
|
|
533
588
|
let decoded = "";
|
|
@@ -537,6 +592,7 @@ class PrefViewer extends HTMLElement {
|
|
|
537
592
|
try {
|
|
538
593
|
decoded = atob(raw);
|
|
539
594
|
} catch {
|
|
595
|
+
console.warn("PrefViewer: base64 decode failed (not base64?)");
|
|
540
596
|
return { blob, extension, size };
|
|
541
597
|
}
|
|
542
598
|
let isJson = false;
|
|
@@ -548,33 +604,43 @@ class PrefViewer extends HTMLElement {
|
|
|
548
604
|
const type = isJson ? "model/gltf+json" : "model/gltf-binary";
|
|
549
605
|
const array = Uint8Array.from(decoded, (c) => c.charCodeAt(0));
|
|
550
606
|
blob = new Blob([array], { type });
|
|
607
|
+
console.log("PrefViewer: #decodeBase64() END", { extension, size, type });
|
|
551
608
|
return { blob, extension, size };
|
|
552
609
|
}
|
|
553
610
|
|
|
554
611
|
async #initStorage(db, table) {
|
|
612
|
+
console.log("PrefViewer: #initStorage()", { db, table });
|
|
555
613
|
if (window.gltfDB && window.gltfDB.name === db && window.gltfDB.objectStoreNames.contains(table)) {
|
|
614
|
+
console.log("PrefViewer: existing DB connection reused");
|
|
556
615
|
return true;
|
|
557
616
|
}
|
|
558
617
|
await initDb(db, table);
|
|
618
|
+
console.log("PrefViewer: DB initialized");
|
|
559
619
|
}
|
|
560
620
|
|
|
561
621
|
// Methods for managing Asset Containers
|
|
562
622
|
#setVisibilityOfWallAndFloorInModel(show) {
|
|
623
|
+
console.log("PrefViewer: #setVisibilityOfWallAndFloorInModel()", { incomingShow: show });
|
|
563
624
|
if (!this.#data.containers.model.assetContainer || !this.#data.containers.model.visible) {
|
|
625
|
+
console.log("PrefViewer: no model assetContainer or not visible, skip visibility set");
|
|
564
626
|
return false;
|
|
565
627
|
}
|
|
566
628
|
show = show !== undefined ? show : this.#data.containers.environment.visible;
|
|
567
629
|
const prefixes = Object.values(this.#data.options.materials).map((material) => material.prefix);
|
|
630
|
+
console.log("PrefViewer: toggling meshes with prefixes", prefixes, "->", show);
|
|
568
631
|
this.#data.containers.model.assetContainer.meshes.filter((meshToFilter) => prefixes.some((prefix) => meshToFilter.name.startsWith(prefix))).forEach((mesh) => mesh.setEnabled(show));
|
|
569
632
|
}
|
|
570
633
|
|
|
571
634
|
#setOptionsMaterial(optionMaterial) {
|
|
635
|
+
console.log("PrefViewer: #setOptionsMaterial()", { optionMaterial });
|
|
572
636
|
if (!optionMaterial || !optionMaterial.prefix || !optionMaterial.value) {
|
|
637
|
+
console.log("PrefViewer: optionMaterial incomplete, skipping");
|
|
573
638
|
return false;
|
|
574
639
|
}
|
|
575
640
|
|
|
576
641
|
const material = this.#data.containers.materials.assetContainer?.materials.find((mat) => mat.name === optionMaterial.value) || null;
|
|
577
642
|
if (!material) {
|
|
643
|
+
console.warn("PrefViewer: material not found", optionMaterial.value);
|
|
578
644
|
return false;
|
|
579
645
|
}
|
|
580
646
|
|
|
@@ -586,6 +652,7 @@ class PrefViewer extends HTMLElement {
|
|
|
586
652
|
containers.push(this.#data.containers.environment.assetContainer);
|
|
587
653
|
}
|
|
588
654
|
if (containers.length === 0) {
|
|
655
|
+
console.log("PrefViewer: no containers require material update");
|
|
589
656
|
return false;
|
|
590
657
|
}
|
|
591
658
|
|
|
@@ -599,6 +666,8 @@ class PrefViewer extends HTMLElement {
|
|
|
599
666
|
})
|
|
600
667
|
);
|
|
601
668
|
|
|
669
|
+
console.log("PrefViewer: material assignment result", { prefix: optionMaterial.prefix, material: optionMaterial.value, someSetted });
|
|
670
|
+
|
|
602
671
|
if (someSetted) {
|
|
603
672
|
optionMaterial.changed.success = true;
|
|
604
673
|
} else {
|
|
@@ -609,15 +678,23 @@ class PrefViewer extends HTMLElement {
|
|
|
609
678
|
}
|
|
610
679
|
|
|
611
680
|
#setOptionsMaterials() {
|
|
681
|
+
console.log("PrefViewer: #setOptionsMaterials() START");
|
|
612
682
|
let someSetted = false;
|
|
613
683
|
Object.values(this.#data.options.materials).forEach((material) => {
|
|
614
684
|
let settedMaterial = this.#setOptionsMaterial(material);
|
|
615
685
|
someSetted = someSetted || settedMaterial;
|
|
616
686
|
});
|
|
687
|
+
console.log("PrefViewer: #setOptionsMaterials() END", { someSetted });
|
|
617
688
|
return someSetted;
|
|
618
689
|
}
|
|
619
690
|
|
|
620
691
|
#setOptionsCamera() {
|
|
692
|
+
console.log("PrefViewer: #setOptionsCamera()", {
|
|
693
|
+
requested: this.#data.options.camera.value,
|
|
694
|
+
changed: this.#data.options.camera.changed,
|
|
695
|
+
modelChanged: this.#data.containers.model.changed,
|
|
696
|
+
envChanged: this.#data.containers.environment.changed
|
|
697
|
+
});
|
|
621
698
|
if (!this.#data.options.camera.value || (!this.#data.options.camera.changed && !this.#data.containers.model.changed && !this.#data.containers.environment.changed)) {
|
|
622
699
|
return false;
|
|
623
700
|
}
|
|
@@ -644,29 +721,36 @@ class PrefViewer extends HTMLElement {
|
|
|
644
721
|
camera.attachControl(this.#canvas, true);
|
|
645
722
|
}
|
|
646
723
|
this.#scene.activeCamera = camera;
|
|
724
|
+
console.log("PrefViewer: active camera set", { name: camera.name, locked: camera.metadata?.locked });
|
|
647
725
|
return true;
|
|
648
726
|
}
|
|
649
727
|
|
|
650
728
|
#addContainer(container) {
|
|
729
|
+
console.log("PrefViewer: #addContainer()", { name: container.name, hasContainer: !!container.assetContainer, visible: container.visible, show: container.show });
|
|
651
730
|
if (container.assetContainer && !container.visible && container.show) {
|
|
652
731
|
container.assetContainer.addAllToScene();
|
|
653
732
|
container.visible = true;
|
|
733
|
+
console.log("PrefViewer: container added to scene", container.name);
|
|
654
734
|
}
|
|
655
735
|
}
|
|
656
736
|
|
|
657
737
|
#removeContainer(container) {
|
|
738
|
+
console.log("PrefViewer: #removeContainer()", { name: container.name, hasContainer: !!container.assetContainer, visible: container.visible });
|
|
658
739
|
if (container.assetContainer && container.visible) {
|
|
659
740
|
container.assetContainer.removeAllFromScene();
|
|
660
741
|
container.visible = false;
|
|
742
|
+
console.log("PrefViewer: container removed from scene", container.name);
|
|
661
743
|
}
|
|
662
744
|
}
|
|
663
745
|
|
|
664
746
|
#replaceContainer(container, newAssetContainer) {
|
|
747
|
+
console.log("PrefViewer: #replaceContainer()", { name: container.name, hadContainer: !!container.assetContainer });
|
|
665
748
|
// 1) quita y destruye el anterior si existía
|
|
666
749
|
const old = container.assetContainer;
|
|
667
750
|
if (old) {
|
|
668
751
|
if (container.visible) { old.removeAllFromScene(); }
|
|
669
752
|
old.dispose(); // <- importante
|
|
753
|
+
console.log("PrefViewer: old container disposed", container.name);
|
|
670
754
|
}
|
|
671
755
|
|
|
672
756
|
// 2) asigna el nuevo y prepara
|
|
@@ -690,12 +774,15 @@ class PrefViewer extends HTMLElement {
|
|
|
690
774
|
|
|
691
775
|
// 5) fuerza recompilación con defines correctos del nuevo estado
|
|
692
776
|
this.#scene.getEngine().releaseEffects();
|
|
777
|
+
console.log("PrefViewer: container replaced and effects released", container.name);
|
|
693
778
|
}
|
|
694
779
|
|
|
695
780
|
async #loadAssetContainer(container) {
|
|
781
|
+
console.log("PrefViewer: #loadAssetContainer() START", { name: container?.name, storage: container?.storage });
|
|
696
782
|
let storage = container?.storage;
|
|
697
783
|
|
|
698
784
|
if (!storage) {
|
|
785
|
+
console.log("PrefViewer: no storage, skipping", container?.name);
|
|
699
786
|
return false;
|
|
700
787
|
}
|
|
701
788
|
|
|
@@ -706,13 +793,16 @@ class PrefViewer extends HTMLElement {
|
|
|
706
793
|
const object = await loadModel(storage.id, storage.table);
|
|
707
794
|
source = object.data;
|
|
708
795
|
if (object.timeStamp === container.timeStamp) {
|
|
796
|
+
console.log("PrefViewer: DB entry unchanged, skipping", container.name);
|
|
709
797
|
return false;
|
|
710
798
|
} else {
|
|
711
799
|
container.changed = { timeStamp: object.timeStamp, size: object.size, success: false };
|
|
800
|
+
console.log("PrefViewer: DB entry changed", container.changed);
|
|
712
801
|
}
|
|
713
802
|
}
|
|
714
803
|
|
|
715
804
|
if (!source) {
|
|
805
|
+
console.log("PrefViewer: no source after storage resolution", container.name);
|
|
716
806
|
return false;
|
|
717
807
|
}
|
|
718
808
|
|
|
@@ -725,19 +815,23 @@ class PrefViewer extends HTMLElement {
|
|
|
725
815
|
});
|
|
726
816
|
if (!container.changed) {
|
|
727
817
|
if (container.timeStamp === null && container.size === size) {
|
|
818
|
+
console.log("PrefViewer: same base64 size and null timestamp, skipping", container.name);
|
|
728
819
|
return false;
|
|
729
820
|
} else {
|
|
730
821
|
container.changed = { timeStamp: null, size: size, success: false };
|
|
731
822
|
}
|
|
732
823
|
}
|
|
824
|
+
console.log("PrefViewer: prepared File from base64", { name: file.name, size: file.size, type: file.type });
|
|
733
825
|
} else {
|
|
734
826
|
const extMatch = source.match(/\.(gltf|glb)(\?|#|$)/i);
|
|
735
827
|
extension = extMatch ? `.${extMatch[1].toLowerCase()}` : ".gltf";
|
|
736
828
|
const [fileSize, fileTimeStamp] = await this.#getServerFileDataHeader(source);
|
|
737
829
|
if (container.size === fileSize && container.timeStamp === fileTimeStamp) {
|
|
830
|
+
console.log("PrefViewer: remote file unchanged, skipping", container.name);
|
|
738
831
|
return false;
|
|
739
832
|
} else {
|
|
740
833
|
container.changed = { timeStamp: fileTimeStamp, size: fileSize, success: false };
|
|
834
|
+
console.log("PrefViewer: remote file changed", container.changed);
|
|
741
835
|
}
|
|
742
836
|
}
|
|
743
837
|
|
|
@@ -751,10 +845,12 @@ class PrefViewer extends HTMLElement {
|
|
|
751
845
|
},
|
|
752
846
|
};
|
|
753
847
|
|
|
848
|
+
console.log("PrefViewer: calling LoadAssetContainerAsync()", { extension });
|
|
754
849
|
return LoadAssetContainerAsync(file || source, this.#scene, options);
|
|
755
850
|
}
|
|
756
851
|
|
|
757
852
|
async #loadContainers(loadModel = true, loadEnvironment = true, loadMaterials = true) {
|
|
853
|
+
console.log("PrefViewer: #loadContainers()", { loadModel, loadEnvironment, loadMaterials });
|
|
758
854
|
const promiseArray = [];
|
|
759
855
|
promiseArray.push(loadModel ? this.#loadAssetContainer(this.#data.containers.model) : false);
|
|
760
856
|
promiseArray.push(loadEnvironment ? this.#loadAssetContainer(this.#data.containers.environment) : false);
|
|
@@ -764,27 +860,33 @@ class PrefViewer extends HTMLElement {
|
|
|
764
860
|
|
|
765
861
|
Promise.allSettled(promiseArray)
|
|
766
862
|
.then(async (values) => {
|
|
863
|
+
console.log("PrefViewer: Promise.allSettled results", values);
|
|
767
864
|
const modelContainer = values[0];
|
|
768
865
|
const environmentContainer = values[1];
|
|
769
866
|
const materialsContainer = values[2];
|
|
770
867
|
|
|
771
868
|
if (modelContainer.status === "fulfilled" && modelContainer.value) {
|
|
869
|
+
console.log("PrefViewer: model container fulfilled, applying");
|
|
772
870
|
this.#stripImportedLights(modelContainer.value);
|
|
773
871
|
this.#replaceContainer(this.#data.containers.model, modelContainer.value);
|
|
774
872
|
this.#storeChangedFlagsForContainer(this.#data.containers.model);
|
|
775
873
|
} else {
|
|
874
|
+
console.log("PrefViewer: model container not fulfilled or unchanged; ensuring visibility state");
|
|
776
875
|
this.#data.containers.model.show ? this.#addContainer(this.#data.containers.model) : this.#removeContainer(this.#data.containers.model);
|
|
777
876
|
}
|
|
778
877
|
|
|
779
878
|
if (environmentContainer.status === "fulfilled" && environmentContainer.value) {
|
|
879
|
+
console.log("PrefViewer: environment container fulfilled, applying");
|
|
780
880
|
this.#stripImportedLights(environmentContainer.value);
|
|
781
881
|
this.#replaceContainer(this.#data.containers.environment, environmentContainer.value);
|
|
782
882
|
this.#storeChangedFlagsForContainer(this.#data.containers.environment);
|
|
783
883
|
} else {
|
|
884
|
+
console.log("PrefViewer: environment container not fulfilled or unchanged; ensuring visibility state");
|
|
784
885
|
this.#data.containers.environment.show ? this.#addContainer(this.#data.containers.environment) : this.#removeContainer(this.#data.containers.environment);
|
|
785
886
|
}
|
|
786
887
|
|
|
787
888
|
if (materialsContainer.status === "fulfilled" && materialsContainer.value) {
|
|
889
|
+
console.log("PrefViewer: materials container fulfilled, applying");
|
|
788
890
|
this.#stripImportedLights(materialsContainer.value);
|
|
789
891
|
this.#replaceContainer(this.#data.containers.materials, materialsContainer.value);
|
|
790
892
|
this.#storeChangedFlagsForContainer(this.#data.containers.materials);
|
|
@@ -811,17 +913,21 @@ class PrefViewer extends HTMLElement {
|
|
|
811
913
|
}
|
|
812
914
|
|
|
813
915
|
#stripImportedLights(container) {
|
|
916
|
+
console.log("PrefViewer: #stripImportedLights()", { lights: container?.lights?.length || 0 });
|
|
814
917
|
// El glTF puede traer KHR_lights_punctual: bórralas antes de añadir a la escena
|
|
815
918
|
if (container?.lights?.length) {
|
|
816
919
|
// Clonar para no mutar mientras iteras
|
|
817
920
|
container.lights.slice().forEach(l => l.dispose());
|
|
921
|
+
console.log("PrefViewer: stripped punctual lights from imported asset");
|
|
818
922
|
}
|
|
819
923
|
}
|
|
820
924
|
|
|
821
925
|
// Public Methods
|
|
822
926
|
loadConfig(config) {
|
|
927
|
+
console.log("PrefViewer: loadConfig()", config);
|
|
823
928
|
config = typeof config === "string" ? JSON.parse(config) : config;
|
|
824
929
|
if (!config) {
|
|
930
|
+
console.warn("PrefViewer: loadConfig() no config provided");
|
|
825
931
|
return false;
|
|
826
932
|
}
|
|
827
933
|
|
|
@@ -842,6 +948,7 @@ class PrefViewer extends HTMLElement {
|
|
|
842
948
|
}
|
|
843
949
|
|
|
844
950
|
setOptions(options) {
|
|
951
|
+
console.log("PrefViewer: setOptions()", options);
|
|
845
952
|
if (!options) {
|
|
846
953
|
return false;
|
|
847
954
|
}
|
|
@@ -863,8 +970,10 @@ class PrefViewer extends HTMLElement {
|
|
|
863
970
|
}
|
|
864
971
|
|
|
865
972
|
loadModel(model) {
|
|
973
|
+
console.log("PrefViewer: loadModel()", model);
|
|
866
974
|
model = typeof model === "string" ? JSON.parse(model) : model;
|
|
867
975
|
if (!model) {
|
|
976
|
+
console.warn("PrefViewer: loadModel() no model provided");
|
|
868
977
|
return false;
|
|
869
978
|
}
|
|
870
979
|
this.#data.containers.model.storage = model.storage || null;
|
|
@@ -873,8 +982,10 @@ class PrefViewer extends HTMLElement {
|
|
|
873
982
|
}
|
|
874
983
|
|
|
875
984
|
loadScene(scene) {
|
|
985
|
+
console.log("PrefViewer: loadScene()", scene);
|
|
876
986
|
scene = typeof scene === "string" ? JSON.parse(scene) : scene;
|
|
877
987
|
if (!scene) {
|
|
988
|
+
console.warn("PrefViewer: loadScene() no scene provided");
|
|
878
989
|
return false;
|
|
879
990
|
}
|
|
880
991
|
this.#data.containers.environment.storage = scene.storage || null;
|
|
@@ -883,33 +994,39 @@ class PrefViewer extends HTMLElement {
|
|
|
883
994
|
}
|
|
884
995
|
|
|
885
996
|
showModel() {
|
|
997
|
+
console.log("PrefViewer: showModel()");
|
|
886
998
|
this.#data.containers.model.show = true;
|
|
887
999
|
this.#addContainer(this.#data.containers.model);
|
|
888
1000
|
}
|
|
889
1001
|
|
|
890
1002
|
hideModel() {
|
|
1003
|
+
console.log("PrefViewer: hideModel()");
|
|
891
1004
|
this.#data.containers.model.show = false;
|
|
892
1005
|
this.#removeContainer(this.#data.containers.model);
|
|
893
1006
|
}
|
|
894
1007
|
|
|
895
1008
|
showScene() {
|
|
1009
|
+
console.log("PrefViewer: showScene()");
|
|
896
1010
|
this.#data.containers.environment.show = true;
|
|
897
1011
|
this.#addContainer(this.#data.containers.environment);
|
|
898
1012
|
this.#setVisibilityOfWallAndFloorInModel();
|
|
899
1013
|
}
|
|
900
1014
|
|
|
901
1015
|
hideScene() {
|
|
1016
|
+
console.log("PrefViewer: hideScene()");
|
|
902
1017
|
this.#data.containers.environment.show = false;
|
|
903
1018
|
this.#removeContainer(this.#data.containers.environment);
|
|
904
1019
|
this.#setVisibilityOfWallAndFloorInModel();
|
|
905
1020
|
}
|
|
906
1021
|
|
|
907
1022
|
downloadModelGLB() {
|
|
1023
|
+
console.log("PrefViewer: downloadModelGLB()");
|
|
908
1024
|
const fileName = "model";
|
|
909
1025
|
GLTF2Export.GLBAsync(this.#data.containers.model.assetContainer, fileName, { exportWithoutWaitingForScene: true }).then((glb) => glb.downloadFiles());
|
|
910
1026
|
}
|
|
911
1027
|
|
|
912
1028
|
downloadModelUSDZ() {
|
|
1029
|
+
console.log("PrefViewer: downloadModelUSDZ()");
|
|
913
1030
|
const fileName = "model";
|
|
914
1031
|
USDZExportAsync(this.#data.containers.model.assetContainer).then((response) => {
|
|
915
1032
|
if (response) {
|
|
@@ -919,6 +1036,7 @@ class PrefViewer extends HTMLElement {
|
|
|
919
1036
|
}
|
|
920
1037
|
|
|
921
1038
|
downloadModelAndSceneUSDZ() {
|
|
1039
|
+
console.log("PrefViewer: downloadModelAndSceneUSDZ()");
|
|
922
1040
|
const fileName = "scene";
|
|
923
1041
|
USDZExportAsync(this.#scene).then((response) => {
|
|
924
1042
|
if (response) {
|
|
@@ -928,6 +1046,7 @@ class PrefViewer extends HTMLElement {
|
|
|
928
1046
|
}
|
|
929
1047
|
|
|
930
1048
|
downloadModelAndSceneGLB() {
|
|
1049
|
+
console.log("PrefViewer: downloadModelAndSceneGLB()");
|
|
931
1050
|
const fileName = "scene";
|
|
932
1051
|
GLTF2Export.GLBAsync(this.#scene, fileName, { exportWithoutWaitingForScene: true }).then((glb) => glb.downloadFiles());
|
|
933
1052
|
}
|