@preference-sl/pref-viewer 2.10.0-beta.3 → 2.10.0-beta.4
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 +286 -80
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -49,18 +49,68 @@ import { initDb, loadModel } from "./gltf-storage.js";
|
|
|
49
49
|
class PrefViewer extends HTMLElement {
|
|
50
50
|
#initialized = false;
|
|
51
51
|
|
|
52
|
-
#
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
52
|
+
#data = {
|
|
53
|
+
containers: {
|
|
54
|
+
model: {
|
|
55
|
+
name: "model",
|
|
56
|
+
container: null,
|
|
57
|
+
show: true,
|
|
58
|
+
storage: null,
|
|
59
|
+
visible: false,
|
|
60
|
+
size: null,
|
|
61
|
+
timestamp: null,
|
|
62
|
+
changed: false,
|
|
63
|
+
},
|
|
64
|
+
environment: {
|
|
65
|
+
name: "environment",
|
|
66
|
+
container: null,
|
|
67
|
+
show: true,
|
|
68
|
+
storage: null,
|
|
69
|
+
visible: false,
|
|
70
|
+
size: null,
|
|
71
|
+
timestamp: null,
|
|
72
|
+
changed: false,
|
|
73
|
+
},
|
|
74
|
+
materials: {
|
|
75
|
+
name: "materials",
|
|
76
|
+
container: null,
|
|
77
|
+
storage: null,
|
|
78
|
+
show: true,
|
|
79
|
+
visible: false,
|
|
80
|
+
size: null,
|
|
81
|
+
timestamp: null,
|
|
82
|
+
changed: false,
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
options: {
|
|
86
|
+
camera: {
|
|
87
|
+
value: null,
|
|
88
|
+
locked: true,
|
|
89
|
+
changed: false,
|
|
90
|
+
},
|
|
91
|
+
materials: {
|
|
92
|
+
innerWall: {
|
|
93
|
+
value: null,
|
|
94
|
+
prefix: "innerWall",
|
|
95
|
+
changed: false,
|
|
96
|
+
},
|
|
97
|
+
outerWall: {
|
|
98
|
+
value: null,
|
|
99
|
+
prefix: "outerWall",
|
|
100
|
+
changed: false,
|
|
101
|
+
},
|
|
102
|
+
innerFloor: {
|
|
103
|
+
value: null,
|
|
104
|
+
prefix: "innerFloor",
|
|
105
|
+
changed: false,
|
|
106
|
+
},
|
|
107
|
+
outerFloor: {
|
|
108
|
+
value: null,
|
|
109
|
+
prefix: "outerFloor",
|
|
110
|
+
changed: false,
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
},
|
|
64
114
|
};
|
|
65
115
|
|
|
66
116
|
// DOM elements
|
|
@@ -115,7 +165,7 @@ class PrefViewer extends HTMLElement {
|
|
|
115
165
|
if (this.#initialized) {
|
|
116
166
|
data ? this.showModel() : this.hideModel();
|
|
117
167
|
} else {
|
|
118
|
-
this.#model.show = data;
|
|
168
|
+
this.#data.containers.model.show = data;
|
|
119
169
|
}
|
|
120
170
|
break;
|
|
121
171
|
case "show-scene":
|
|
@@ -123,7 +173,7 @@ class PrefViewer extends HTMLElement {
|
|
|
123
173
|
if (this.#initialized) {
|
|
124
174
|
data ? this.showScene() : this.hideScene();
|
|
125
175
|
} else {
|
|
126
|
-
this.#environment.show = data;
|
|
176
|
+
this.#data.containers.environment.show = data;
|
|
127
177
|
}
|
|
128
178
|
break;
|
|
129
179
|
}
|
|
@@ -144,7 +194,7 @@ class PrefViewer extends HTMLElement {
|
|
|
144
194
|
}
|
|
145
195
|
|
|
146
196
|
this.#initializeBabylon();
|
|
147
|
-
this.#loadContainers(true, true);
|
|
197
|
+
this.#loadContainers(true, true, true);
|
|
148
198
|
this.#initialized = true;
|
|
149
199
|
}
|
|
150
200
|
|
|
@@ -174,8 +224,39 @@ class PrefViewer extends HTMLElement {
|
|
|
174
224
|
this.#wrapper.appendChild(this.#canvas);
|
|
175
225
|
this.shadowRoot.append(this.#wrapper);
|
|
176
226
|
}
|
|
177
|
-
|
|
178
|
-
//
|
|
227
|
+
|
|
228
|
+
// Data
|
|
229
|
+
#checkCameraChanged(options) {
|
|
230
|
+
if (!options || !options.camera) {
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
this.#data.options.camera.changed = options.camera && options.camera !== this.#data.options.camera.value ? true : false;
|
|
234
|
+
this.#data.options.camera.value = this.#data.options.camera.changed ? options.camera : this.#data.options.camera.value;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
#checkMaterialsChanged(options) {
|
|
238
|
+
if (!options) {
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
Object.keys(this.#data.options.materials).forEach((material) => {
|
|
242
|
+
const key = `${material}Material`;
|
|
243
|
+
this.#data.options.materials[material].changed = options[key] && options[key] !== this.#data.options.materials[material].value ? true : false;
|
|
244
|
+
this.#data.options.materials[material].value = this.#data.options.materials[material].changed ? options[key] : this.#data.options.materials[material].value;
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
#storeChangedFlagsForContainer(container) {
|
|
249
|
+
container.timestamp = container.changed.timestamp;
|
|
250
|
+
container.size = container.changed.size;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
#resetChangedFlags() {
|
|
254
|
+
Object.values(this.#data.containers).forEach((container) => (container.changed = false));
|
|
255
|
+
Object.values(this.#data.options.materials).forEach((material) => (material.changed = false));
|
|
256
|
+
this.#data.options.camera.changed = false;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Babylon.js
|
|
179
260
|
async #initializeBabylon() {
|
|
180
261
|
this.#engine = new Engine(this.#canvas, true, { alpha: true });
|
|
181
262
|
this.#scene = new Scene(this.#engine);
|
|
@@ -183,15 +264,14 @@ class PrefViewer extends HTMLElement {
|
|
|
183
264
|
this.#createCamera();
|
|
184
265
|
this.#createLights();
|
|
185
266
|
this.#setupInteraction();
|
|
186
|
-
|
|
267
|
+
|
|
187
268
|
this.#engine.runRenderLoop(() => this.#scene && this.#scene.render());
|
|
188
269
|
this.#canvasResizeObserver.observe(this.#canvas);
|
|
189
270
|
|
|
190
271
|
await this.#createXRExperience();
|
|
191
|
-
|
|
192
272
|
}
|
|
193
273
|
|
|
194
|
-
addStylesToARButton(){
|
|
274
|
+
addStylesToARButton() {
|
|
195
275
|
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"}';
|
|
196
276
|
const style = document.createElement("style");
|
|
197
277
|
style.appendChild(document.createTextNode(css));
|
|
@@ -202,14 +282,14 @@ class PrefViewer extends HTMLElement {
|
|
|
202
282
|
if (this.#XRExperience) {
|
|
203
283
|
return true;
|
|
204
284
|
}
|
|
205
|
-
|
|
285
|
+
|
|
206
286
|
const sessionMode = "immersive-ar";
|
|
207
287
|
const sessionSupported = await WebXRSessionManager.IsSessionSupportedAsync(sessionMode);
|
|
208
288
|
if (!sessionSupported) {
|
|
209
289
|
console.info("PrefViewer: WebXR in mode AR is not supported");
|
|
210
290
|
return false;
|
|
211
291
|
}
|
|
212
|
-
|
|
292
|
+
|
|
213
293
|
try {
|
|
214
294
|
const ground = MeshBuilder.CreateGround("ground", { width: 1000, height: 1000 }, this.#scene);
|
|
215
295
|
ground.isVisible = false;
|
|
@@ -231,7 +311,6 @@ class PrefViewer extends HTMLElement {
|
|
|
231
311
|
xrInput: this.#XRExperience.input,
|
|
232
312
|
floorMeshes: [ground],
|
|
233
313
|
timeToTeleport: 1500,
|
|
234
|
-
useMainComponentOnly: true,
|
|
235
314
|
});
|
|
236
315
|
|
|
237
316
|
this.#XRExperience.baseExperience.sessionManager.onXRReady.add(() => {
|
|
@@ -251,11 +330,13 @@ class PrefViewer extends HTMLElement {
|
|
|
251
330
|
#canvasResizeObserver = new ResizeObserver(() => this.#engine && this.#engine.resize());
|
|
252
331
|
|
|
253
332
|
#createCamera() {
|
|
254
|
-
this.#camera = new ArcRotateCamera("camera", 3 * Math.PI / 2, Math.PI * 0.47, 10, Vector3.Zero(), this.#scene);
|
|
333
|
+
this.#camera = new ArcRotateCamera("camera", (3 * Math.PI) / 2, Math.PI * 0.47, 10, Vector3.Zero(), this.#scene);
|
|
255
334
|
this.#camera.upperBetaLimit = Math.PI * 0.48;
|
|
256
335
|
this.#camera.lowerBetaLimit = Math.PI * 0.25;
|
|
257
336
|
this.#camera.lowerRadiusLimit = 5;
|
|
258
337
|
this.#camera.upperRadiusLimit = 20;
|
|
338
|
+
this.#camera.metadata = { locked: false }
|
|
339
|
+
this.#camera = this.#camera;
|
|
259
340
|
this.#camera.attachControl(this.#canvas, true);
|
|
260
341
|
}
|
|
261
342
|
|
|
@@ -283,10 +364,14 @@ class PrefViewer extends HTMLElement {
|
|
|
283
364
|
|
|
284
365
|
#setupInteraction() {
|
|
285
366
|
this.#canvas.addEventListener("wheel", (event) => {
|
|
286
|
-
if (!this.#scene || !this.#camera)
|
|
287
|
-
|
|
367
|
+
if (!this.#scene || !this.#camera) {
|
|
368
|
+
return false;
|
|
369
|
+
}
|
|
370
|
+
//const pick = this.#scene.pick(this.#scene.pointerX, this.#scene.pointerY);
|
|
288
371
|
//this.#camera.target = pick.hit ? pick.pickedPoint.clone() : this.#camera.target;
|
|
289
|
-
this.#
|
|
372
|
+
if (!this.#scene.activeCamera.metadata?.locked) {
|
|
373
|
+
this.#scene.activeCamera.inertialRadiusOffset -= event.deltaY * this.#scene.activeCamera.wheelPrecision * 0.001;
|
|
374
|
+
}
|
|
290
375
|
event.preventDefault();
|
|
291
376
|
});
|
|
292
377
|
}
|
|
@@ -300,6 +385,27 @@ class PrefViewer extends HTMLElement {
|
|
|
300
385
|
}
|
|
301
386
|
|
|
302
387
|
// Utility methods for loading gltf/glb
|
|
388
|
+
async #getServerFileDataHeader(uri) {
|
|
389
|
+
return new Promise((resolve) => {
|
|
390
|
+
const xhr = new XMLHttpRequest();
|
|
391
|
+
xhr.open("HEAD", uri, true);
|
|
392
|
+
xhr.responseType = "blob";
|
|
393
|
+
xhr.onload = () => {
|
|
394
|
+
if (xhr.status === 200) {
|
|
395
|
+
const size = parseInt(xhr.getResponseHeader("Content-Length"));
|
|
396
|
+
const timestamp = new Date(xhr.getResponseHeader("Last-Modified")).toISOString();
|
|
397
|
+
resolve(size, timestamp);
|
|
398
|
+
} else {
|
|
399
|
+
resolve(0, null);
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
xhr.onerror = () => {
|
|
403
|
+
resolve(0, null);
|
|
404
|
+
};
|
|
405
|
+
xhr.send();
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
|
|
303
409
|
#transformUrl(url) {
|
|
304
410
|
return new Promise((resolve) => {
|
|
305
411
|
resolve(url.replace(/^blob:[^/]+\//i, "").replace(/\\/g, "/"));
|
|
@@ -312,10 +418,11 @@ class PrefViewer extends HTMLElement {
|
|
|
312
418
|
let decoded = "";
|
|
313
419
|
let blob = null;
|
|
314
420
|
let extension = null;
|
|
421
|
+
let size = raw.length;
|
|
315
422
|
try {
|
|
316
423
|
decoded = atob(raw);
|
|
317
424
|
} catch {
|
|
318
|
-
return { blob, extension };
|
|
425
|
+
return { blob, extension, size };
|
|
319
426
|
}
|
|
320
427
|
let isJson = false;
|
|
321
428
|
try {
|
|
@@ -326,7 +433,7 @@ class PrefViewer extends HTMLElement {
|
|
|
326
433
|
const type = isJson ? "model/gltf+json" : "model/gltf-binary";
|
|
327
434
|
const array = Uint8Array.from(decoded, (c) => c.charCodeAt(0));
|
|
328
435
|
blob = new Blob([array], { type });
|
|
329
|
-
return { blob, extension };
|
|
436
|
+
return { blob, extension, size };
|
|
330
437
|
}
|
|
331
438
|
|
|
332
439
|
async #initStorage(db, table) {
|
|
@@ -338,41 +445,95 @@ class PrefViewer extends HTMLElement {
|
|
|
338
445
|
|
|
339
446
|
// Methods for managing Asset Containers
|
|
340
447
|
#setVisibilityOfWallAndFloorInModel(show) {
|
|
341
|
-
if (this.#model.
|
|
342
|
-
|
|
343
|
-
const nodes = this.#model.container.getNodes();
|
|
344
|
-
this.#model.container
|
|
345
|
-
.getNodes()
|
|
346
|
-
.filter((filter) => names.includes(filter.name))
|
|
347
|
-
.forEach((node) => node.setEnabled(show !== undefined ? show : this.#environment.show));
|
|
448
|
+
if (!this.#data.containers.model.assetContainer || !this.#data.containers.model.visible) {
|
|
449
|
+
return false;
|
|
348
450
|
}
|
|
451
|
+
show = show !== undefined ? show : this.#data.containers.environment.visible;
|
|
452
|
+
const prefixes = Object.values(this.#data.options.materials).map((material) => material.prefix);
|
|
453
|
+
this.#data.containers.model.assetContainer.meshes.filter((meshToFilter) => prefixes.some((prefix) => meshToFilter.name.startsWith(prefix))).forEach((mesh) => mesh.setEnabled(show));
|
|
349
454
|
}
|
|
350
455
|
|
|
351
|
-
#
|
|
352
|
-
if (
|
|
353
|
-
|
|
354
|
-
group.visible = true;
|
|
456
|
+
#setOptionsMaterial(optionMaterial) {
|
|
457
|
+
if (!optionMaterial || !optionMaterial.prefix || !optionMaterial.value) {
|
|
458
|
+
return false;
|
|
355
459
|
}
|
|
460
|
+
|
|
461
|
+
const material = this.#data.containers.materials.assetContainer?.materials.find((mat) => mat.name === optionMaterial.value) || null;
|
|
462
|
+
if (!material) {
|
|
463
|
+
return false;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
const containers = [];
|
|
467
|
+
if (this.#data.containers.model.assetContainer && (this.#data.containers.model.assetContainer.changed || optionMaterial.changed)) {
|
|
468
|
+
containers.push(this.#data.containers.model.assetContainer);
|
|
469
|
+
}
|
|
470
|
+
if (this.#data.containers.environment.assetContainer && (this.#data.containers.environment.assetContainer.changed || optionMaterial.changed)) {
|
|
471
|
+
containers.push(this.#data.containers.environment.assetContainer);
|
|
472
|
+
}
|
|
473
|
+
if (containers.length === 0) {
|
|
474
|
+
return false;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
containers.forEach((container) => {
|
|
478
|
+
container.meshes.filter((meshToFilter) => meshToFilter.name.startsWith(optionMaterial.prefix)).forEach((mesh) => {
|
|
479
|
+
if (mesh.material) {
|
|
480
|
+
mesh.material.dispose();
|
|
481
|
+
}
|
|
482
|
+
mesh.material = material;
|
|
483
|
+
});
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
return true;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
#setOptionsMaterials() {
|
|
490
|
+
Object.values(this.#data.options.materials).forEach((material) => this.#setOptionsMaterial(material));
|
|
356
491
|
}
|
|
357
492
|
|
|
358
|
-
#
|
|
359
|
-
if (
|
|
360
|
-
|
|
361
|
-
|
|
493
|
+
#setOptionsCamera() {
|
|
494
|
+
if (!this.#data.options.camera.value || (!this.#data.options.camera.changed && !this.#data.containers.model.assetContainer.changed)) {
|
|
495
|
+
return false;
|
|
496
|
+
}
|
|
497
|
+
let camera = this.#data.containers.model.assetContainer?.cameras.find((cam) => cam.name === this.#data.options.camera.value) || null;
|
|
498
|
+
if (!camera) {
|
|
499
|
+
camera = this.#camera;
|
|
500
|
+
} else {
|
|
501
|
+
camera.metadata = { locked: this.#data.options.camera.locked };
|
|
502
|
+
if (!this.#data.options.camera.locked) {
|
|
503
|
+
camera.attachControl(this.#canvas, true);
|
|
504
|
+
}
|
|
362
505
|
}
|
|
506
|
+
|
|
507
|
+
this.#scene.activeCamera = camera;
|
|
363
508
|
}
|
|
364
509
|
|
|
365
|
-
#
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
510
|
+
#addContainer(container) {
|
|
511
|
+
if (container.assetContainer && !container.visible && container.show) {
|
|
512
|
+
container.assetContainer.addAllToScene();
|
|
513
|
+
container.visible = true;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
#removeContainer(container) {
|
|
518
|
+
if (container.assetContainer && container.visible) {
|
|
519
|
+
container.assetContainer.removeAllFromScene();
|
|
520
|
+
container.visible = false;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
#replaceContainer(container, newAssetContainer) {
|
|
525
|
+
this.#removeContainer(container);
|
|
526
|
+
container.assetContainer = newAssetContainer;
|
|
527
|
+
container.assetContainer.meshes.forEach((mesh) => {
|
|
369
528
|
mesh.receiveShadows = true;
|
|
370
529
|
this.#shadowGen.addShadowCaster(mesh, true);
|
|
371
530
|
});
|
|
372
|
-
this.#addContainer(
|
|
531
|
+
this.#addContainer(container);
|
|
373
532
|
}
|
|
374
533
|
|
|
375
|
-
async #loadAssetContainer(
|
|
534
|
+
async #loadAssetContainer(container) {
|
|
535
|
+
let storage = container?.storage;
|
|
536
|
+
|
|
376
537
|
if (!storage) {
|
|
377
538
|
return false;
|
|
378
539
|
}
|
|
@@ -383,6 +544,11 @@ class PrefViewer extends HTMLElement {
|
|
|
383
544
|
await this.#initStorage(storage.db, storage.table);
|
|
384
545
|
const object = await loadModel(storage.id, storage.table);
|
|
385
546
|
source = object.data;
|
|
547
|
+
if (object.timestamp === container.timestamp) {
|
|
548
|
+
return false;
|
|
549
|
+
} else {
|
|
550
|
+
container.changed = { timestamp: object.timestamp, size: object.size };
|
|
551
|
+
}
|
|
386
552
|
}
|
|
387
553
|
|
|
388
554
|
if (!source) {
|
|
@@ -391,20 +557,34 @@ class PrefViewer extends HTMLElement {
|
|
|
391
557
|
|
|
392
558
|
let file = null;
|
|
393
559
|
|
|
394
|
-
let { blob, extension } = this.#decodeBase64(source);
|
|
560
|
+
let { blob, extension, size } = this.#decodeBase64(source);
|
|
395
561
|
if (blob && extension) {
|
|
396
|
-
file = new File([blob],
|
|
562
|
+
file = new File([blob], `${container.name}${extension}`, {
|
|
397
563
|
type: blob.type,
|
|
398
564
|
});
|
|
565
|
+
if (!container.changed) {
|
|
566
|
+
if (container.timestamp === null && container.size === size) {
|
|
567
|
+
return false;
|
|
568
|
+
} else {
|
|
569
|
+
container.changed = { timestamp: null, size: size };
|
|
570
|
+
}
|
|
571
|
+
}
|
|
399
572
|
} else {
|
|
400
573
|
const extMatch = source.match(/\.(gltf|glb)(\?|#|$)/i);
|
|
401
574
|
extension = extMatch ? `.${extMatch[1].toLowerCase()}` : ".gltf";
|
|
575
|
+
const { fileSize, fileTimestamp } = await this.#getServerFileDataHeader(source);
|
|
576
|
+
if (container.timestamp === fileTimestamp && container.size === fileSize) {
|
|
577
|
+
return false;
|
|
578
|
+
} else {
|
|
579
|
+
container.changed = { timestamp: fileTimestamp, size: fileSize };
|
|
580
|
+
}
|
|
402
581
|
}
|
|
403
582
|
|
|
404
583
|
let options = {
|
|
405
584
|
pluginExtension: extension,
|
|
406
585
|
pluginOptions: {
|
|
407
586
|
gltf: {
|
|
587
|
+
loadAllMaterials: true,
|
|
408
588
|
preprocessUrlAsync: this.#transformUrl,
|
|
409
589
|
},
|
|
410
590
|
},
|
|
@@ -413,27 +593,43 @@ class PrefViewer extends HTMLElement {
|
|
|
413
593
|
return LoadAssetContainerAsync(file || source, this.#scene, options);
|
|
414
594
|
}
|
|
415
595
|
|
|
416
|
-
async #loadContainers(loadModel = true, loadEnvironment = true) {
|
|
596
|
+
async #loadContainers(loadModel = true, loadEnvironment = true, loadMaterials = true) {
|
|
417
597
|
const promiseArray = [];
|
|
418
|
-
|
|
419
|
-
promiseArray.push(
|
|
420
|
-
promiseArray.push(
|
|
598
|
+
promiseArray.push(loadModel ? this.#loadAssetContainer(this.#data.containers.model) : false);
|
|
599
|
+
promiseArray.push(loadEnvironment ? this.#loadAssetContainer(this.#data.containers.environment) : false);
|
|
600
|
+
promiseArray.push(loadMaterials ? this.#loadAssetContainer(this.#data.containers.materials) : false);
|
|
421
601
|
|
|
422
602
|
Promise.allSettled(promiseArray)
|
|
423
603
|
.then(async (values) => {
|
|
424
604
|
const modelContainer = values[0];
|
|
425
605
|
const environmentContainer = values[1];
|
|
606
|
+
const materialsContainer = values[2];
|
|
426
607
|
|
|
427
608
|
if (modelContainer.status === "fulfilled" && modelContainer.value) {
|
|
428
|
-
this.#replaceContainer(this.#model, modelContainer.value);
|
|
609
|
+
this.#replaceContainer(this.#data.containers.model, modelContainer.value);
|
|
610
|
+
this.#storeChangedFlagsForContainer(this.#data.containers.model);
|
|
611
|
+
} else {
|
|
612
|
+
this.#data.containers.model.show ? this.#addContainer(this.#data.containers.model) : this.#removeContainer(this.#data.containers.model);
|
|
429
613
|
}
|
|
430
614
|
|
|
431
615
|
if (environmentContainer.status === "fulfilled" && environmentContainer.value) {
|
|
432
|
-
this.#replaceContainer(this.#environment, environmentContainer.value);
|
|
616
|
+
this.#replaceContainer(this.#data.containers.environment, environmentContainer.value);
|
|
617
|
+
this.#storeChangedFlagsForContainer(this.#data.containers.environment);
|
|
618
|
+
} else {
|
|
619
|
+
this.#data.containers.environment.show ? this.#addContainer(this.#data.containers.environment) : this.#removeContainer(this.#data.containers.environment);
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
if (materialsContainer.status === "fulfilled" && materialsContainer.value) {
|
|
623
|
+
this.#replaceContainer(this.#data.containers.materials, materialsContainer.value);
|
|
624
|
+
this.#storeChangedFlagsForContainer(this.#data.containers.materials);
|
|
433
625
|
}
|
|
434
626
|
|
|
627
|
+
this.#setOptionsMaterials();
|
|
628
|
+
this.#setOptionsCamera();
|
|
435
629
|
this.#setVisibilityOfWallAndFloorInModel();
|
|
436
|
-
|
|
630
|
+
|
|
631
|
+
this.#resetChangedFlags();
|
|
632
|
+
|
|
437
633
|
this.dispatchEvent(
|
|
438
634
|
new CustomEvent("model-loaded", {
|
|
439
635
|
detail: { success: "" },
|
|
@@ -460,11 +656,21 @@ class PrefViewer extends HTMLElement {
|
|
|
460
656
|
if (!config) {
|
|
461
657
|
return false;
|
|
462
658
|
}
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
this.#
|
|
466
|
-
this.#
|
|
467
|
-
this.#
|
|
659
|
+
|
|
660
|
+
// AssetContainers
|
|
661
|
+
this.#data.containers.model.storage = config.model?.storage || null;
|
|
662
|
+
this.#data.containers.model.show = config.model?.visible !== undefined ? config.model.visible : this.#data.containers.model.show;
|
|
663
|
+
this.#data.containers.environment.storage = config.scene?.storage || null;
|
|
664
|
+
this.#data.containers.environment.show = config.scene?.visible !== undefined ? config.scene.visible : this.#data.containers.environment.show;
|
|
665
|
+
this.#data.containers.materials.storage = config.materials?.storage || null;
|
|
666
|
+
|
|
667
|
+
// Options
|
|
668
|
+
if (config.options) {
|
|
669
|
+
this.#checkCameraChanged(config.options);
|
|
670
|
+
this.#checkMaterialsChanged(config.options);
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
this.#initialized && this.#loadContainers(true, true, true);
|
|
468
674
|
}
|
|
469
675
|
|
|
470
676
|
loadModel(model) {
|
|
@@ -472,9 +678,9 @@ class PrefViewer extends HTMLElement {
|
|
|
472
678
|
if (!model) {
|
|
473
679
|
return false;
|
|
474
680
|
}
|
|
475
|
-
this.#model.storage = model.storage || null;
|
|
476
|
-
this.#model.show = model.visible !== undefined ? model.visible : this.#model.show;
|
|
477
|
-
this.#initialized && this.#loadContainers(true, false);
|
|
681
|
+
this.#data.containers.model.storage = model.storage || null;
|
|
682
|
+
this.#data.containers.model.show = model.visible !== undefined ? model.visible : this.#data.containers.model.show;
|
|
683
|
+
this.#initialized && this.#loadContainers(true, false, false);
|
|
478
684
|
}
|
|
479
685
|
|
|
480
686
|
loadScene(scene) {
|
|
@@ -482,43 +688,43 @@ class PrefViewer extends HTMLElement {
|
|
|
482
688
|
if (!scene) {
|
|
483
689
|
return false;
|
|
484
690
|
}
|
|
485
|
-
this.#environment.storage = scene.storage || null;
|
|
486
|
-
this.#environment.show = scene.visible !== undefined ? scene.visible : this.#environment.show;
|
|
487
|
-
this.#initialized && this.#loadContainers(false, true);
|
|
691
|
+
this.#data.containers.environment.storage = scene.storage || null;
|
|
692
|
+
this.#data.containers.environment.show = scene.visible !== undefined ? scene.visible : this.#data.containers.environment.show;
|
|
693
|
+
this.#initialized && this.#loadContainers(false, true, false);
|
|
488
694
|
}
|
|
489
695
|
|
|
490
696
|
showModel() {
|
|
491
|
-
this.#model.show = true;
|
|
492
|
-
this.#addContainer(this.#model);
|
|
697
|
+
this.#data.containers.model.show = true;
|
|
698
|
+
this.#addContainer(this.#data.containers.model);
|
|
493
699
|
}
|
|
494
700
|
|
|
495
701
|
hideModel() {
|
|
496
|
-
this.#model.show = false;
|
|
497
|
-
this.#removeContainer(this.#model);
|
|
702
|
+
this.#data.containers.model.show = false;
|
|
703
|
+
this.#removeContainer(this.#data.containers.model);
|
|
498
704
|
}
|
|
499
705
|
|
|
500
706
|
showScene() {
|
|
501
|
-
this.#environment.show = true;
|
|
502
|
-
this.#addContainer(this.#environment);
|
|
707
|
+
this.#data.containers.environment.show = true;
|
|
708
|
+
this.#addContainer(this.#data.containers.environment);
|
|
503
709
|
this.#setVisibilityOfWallAndFloorInModel();
|
|
504
710
|
}
|
|
505
711
|
|
|
506
712
|
hideScene() {
|
|
507
|
-
this.#environment.show = false;
|
|
508
|
-
this.#removeContainer(this.#environment);
|
|
713
|
+
this.#data.containers.environment.show = false;
|
|
714
|
+
this.#removeContainer(this.#data.containers.environment);
|
|
509
715
|
this.#setVisibilityOfWallAndFloorInModel();
|
|
510
716
|
}
|
|
511
717
|
|
|
512
718
|
downloadModelGLB() {
|
|
513
719
|
const fileName = "model";
|
|
514
|
-
GLTF2Export.GLBAsync(this.#model.
|
|
720
|
+
GLTF2Export.GLBAsync(this.#data.containers.model.assetContainer, fileName, { exportWithoutWaitingForScene: true }).then((glb) => {
|
|
515
721
|
glb.downloadFiles();
|
|
516
722
|
});
|
|
517
723
|
}
|
|
518
724
|
|
|
519
725
|
downloadModelUSDZ() {
|
|
520
726
|
const fileName = "model";
|
|
521
|
-
USDZExportAsync(this.#model.
|
|
727
|
+
USDZExportAsync(this.#data.containers.model.assetContainer).then((response) => {
|
|
522
728
|
if (response) {
|
|
523
729
|
Tools.Download(new Blob([response], { type: "model/vnd.usdz+zip" }), `${fileName}.usdz`);
|
|
524
730
|
}
|