@preference-sl/pref-viewer 2.11.0-beta.12 → 2.11.0-beta.14

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.
@@ -1,4 +1,3 @@
1
- import { AdvancedDynamicTexture } from "@babylonjs/gui";
2
1
  import OpeningAnimationMenu from "./babylonjs-animation-opening-menu.js";
3
2
 
4
3
  /**
@@ -19,7 +18,7 @@ import OpeningAnimationMenu from "./babylonjs-animation-opening-menu.js";
19
18
  * - pause(): Pauses the current animation.
20
19
  * - goToOpened(): Moves animation to the fully opened state.
21
20
  * - goToClosed(): Moves animation to the fully closed state.
22
- * - showControls(advancedDynamicTexture): Displays the animation control menu.
21
+ * - showControls(canvas): Displays the animation control menu.
23
22
  * - hideControls(): Hides the animation control menu.
24
23
  * - isControlsVisible(): Returns true if the control menu is visible for this animation.
25
24
  *
@@ -39,14 +38,6 @@ import OpeningAnimationMenu from "./babylonjs-animation-opening-menu.js";
39
38
  * - #checkProgress(progress): Applies threshold logic to progress.
40
39
  * - #updateControlsSlider(): Updates the slider in the control menu.
41
40
  * - #updateControls(): Updates all controls in the menu.
42
- *
43
- * Usage Example:
44
- * const anim = new OpeningAnimation("door", openGroup, closeGroup);
45
- * anim.playOpen();
46
- * anim.pause();
47
- * anim.goToClosed();
48
- * anim.showControls(adt);
49
- * anim.hideControls();
50
41
  */
51
42
  export default class OpeningAnimation {
52
43
  static states = {
@@ -68,7 +59,6 @@ export default class OpeningAnimation {
68
59
  #speedRatio = 1.0;
69
60
  #loop = false;
70
61
 
71
- #advancedDynamicTexture = null;
72
62
  #menu = null;
73
63
  #progressThreshold = 0.025;
74
64
 
@@ -138,13 +128,18 @@ export default class OpeningAnimation {
138
128
  #goToOpened(useLoop = false) {
139
129
  this.#lastPausedFrame = this.#endFrame;
140
130
 
141
- if (this.#openAnimation._isStarted && !this.#openAnimation._isPaused) {
131
+ if (this.#openAnimation._isStarted && !this.#openAnimation._isPaused){
142
132
  this.#openAnimation.pause();
143
133
  }
144
- this.#openAnimation.goToFrame(this.#endFrame);
134
+ this.#openAnimation.goToFrame(this.#endFrame);
145
135
 
146
- this.#closeAnimation.pause();
147
- this.#closeAnimation.goToFrame(this.#startFrame);
136
+ if (this.#closeAnimation._isStarted && this.#closeAnimation._isPaused) {
137
+ this.#closeAnimation.goToFrame(this.#startFrame);
138
+ } else {
139
+ this.#closeAnimation.start();
140
+ this.#closeAnimation.pause();
141
+ this.#closeAnimation.goToFrame(this.#startFrame);
142
+ }
148
143
 
149
144
  this.#state = OpeningAnimation.states.opened;
150
145
  this.#updateControls();
@@ -167,8 +162,13 @@ export default class OpeningAnimation {
167
162
  }
168
163
  this.#closeAnimation.goToFrame(this.#endFrame - this.#startFrame);
169
164
 
170
- this.#openAnimation.pause();
171
- this.#openAnimation.goToFrame(this.#startFrame);
165
+ if (this.#openAnimation._isStarted && this.#openAnimation._isPaused) {
166
+ this.#openAnimation.goToFrame(this.#startFrame);
167
+ } else {
168
+ this.#openAnimation.start();
169
+ this.#openAnimation.pause();
170
+ this.#openAnimation.goToFrame(this.#startFrame);
171
+ }
172
172
 
173
173
  this.#state = OpeningAnimation.states.closed;
174
174
  this.#updateControls();
@@ -320,6 +320,7 @@ export default class OpeningAnimation {
320
320
  if (this.#state === OpeningAnimation.states.opening || this.#state === OpeningAnimation.states.opened) {
321
321
  return;
322
322
  }
323
+
323
324
  if (this.#state === OpeningAnimation.states.closing) {
324
325
  this.#lastPausedFrame = this.#endFrame - this.#closeAnimation.getCurrentFrame();
325
326
  this.#closeAnimation.pause();
@@ -344,6 +345,7 @@ export default class OpeningAnimation {
344
345
  if (this.#state === OpeningAnimation.states.closing || this.#state === OpeningAnimation.states.closed) {
345
346
  return;
346
347
  }
348
+
347
349
  if (this.#state === OpeningAnimation.states.opening) {
348
350
  this.#lastPausedFrame = this.#openAnimation.getCurrentFrame();
349
351
  this.#openAnimation.pause();
@@ -397,11 +399,9 @@ export default class OpeningAnimation {
397
399
  * Displays the animation control menu and sets up callbacks.
398
400
  * Synchronizes slider and button states with animation.
399
401
  * @public
400
- * @param {AdvancedDynamicTexture} advancedDynamicTexture - Babylon.js GUI texture.
402
+ * @param {HTMLCanvasElement} canvas - The canvas element for rendering.
401
403
  */
402
- showControls(advancedDynamicTexture) {
403
- this.#advancedDynamicTexture = advancedDynamicTexture;
404
- this.#advancedDynamicTexture.metadata = { animationName: this.name };
404
+ showControls(canvas) {
405
405
  const controlCallbacks = {
406
406
  onGoToOpened: () => {
407
407
  if (this.#state === OpeningAnimation.states.opened) {
@@ -449,7 +449,7 @@ export default class OpeningAnimation {
449
449
  this.#menu.animationLoop = this.#loop;
450
450
  },
451
451
  };
452
- this.#menu = new OpeningAnimationMenu(this.#advancedDynamicTexture, this.#state, this.#getProgress(), this.#loop, controlCallbacks);
452
+ this.#menu = new OpeningAnimationMenu(this.name, canvas, this.#state, this.#getProgress(), this.#loop, controlCallbacks);
453
453
 
454
454
  // Attach to Babylon.js scene render loop for real-time updates
455
455
  this.#openAnimation._scene.onBeforeRenderObservable.add(this.#updateControlsSlider.bind(this));
@@ -463,10 +463,9 @@ export default class OpeningAnimation {
463
463
  if (!this.isControlsVisible()) {
464
464
  return;
465
465
  }
466
- // Remove the observer when controls are hidden
467
466
  this.#openAnimation._scene.onBeforeRenderObservable.removeCallback(this.#updateControlsSlider.bind(this));
468
- this.#advancedDynamicTexture.dispose();
469
- this.#advancedDynamicTexture = null;
467
+ this.#menu.dispose();
468
+ this.#menu = null;
470
469
  }
471
470
 
472
471
  /**
@@ -475,7 +474,7 @@ export default class OpeningAnimation {
475
474
  * @returns {boolean} True if controls are visible for this animation; otherwise, false.
476
475
  */
477
476
  isControlsVisible() {
478
- return !!(this.#advancedDynamicTexture && this.#advancedDynamicTexture.metadata?.animationName === this.name && this.#menu);
477
+ return !!(this.#menu?.isVisible);
479
478
  }
480
479
 
481
480
  /**
@@ -489,7 +488,6 @@ export default class OpeningAnimation {
489
488
  * @public
490
489
  * @returns {number}
491
490
  */
492
-
493
491
  get state() {
494
492
  return this.#state;
495
493
  }
@@ -1,7 +1,7 @@
1
- import { ArcRotateCamera, AssetContainer, Camera, Color4, DirectionalLight, Engine, HDRCubeTexture, HemisphericLight, IblShadowsRenderPipeline, LoadAssetContainerAsync, MeshBuilder, PointLight, Scene, ShadowGenerator, Tools, Vector3, WebXRDefaultExperience, WebXRFeatureName, WebXRSessionManager } from "@babylonjs/core";
2
- import { DracoCompression } from "@babylonjs/core/Meshes/Compression/dracoCompression";
1
+ import { ArcRotateCamera, AssetContainer, Camera, Color4, DirectionalLight, Engine, HDRCubeTexture, HemisphericLight, IblShadowsRenderPipeline, LoadAssetContainerAsync, MeshBuilder, PointerEventTypes, PointLight, Scene, ShadowGenerator, Tools, Vector3, WebXRDefaultExperience, WebXRFeatureName, WebXRSessionManager } from "@babylonjs/core";
2
+ import { DracoCompression } from "@babylonjs/core/Meshes/Compression/dracoCompression.js";
3
3
  import "@babylonjs/loaders";
4
- import "@babylonjs/loaders/glTF/2.0/Extensions/KHR_draco_mesh_compression";
4
+ import "@babylonjs/loaders/glTF/2.0/Extensions/KHR_draco_mesh_compression.js";
5
5
  import { USDZExportAsync, GLTF2Export } from "@babylonjs/serializers";
6
6
 
7
7
  import GLTFResolver from "./gltf-resolver.js";
@@ -45,19 +45,37 @@ import BabylonJSAnimationController from "./babylonjs-animation-controller.js";
45
45
  * - #renderLoop(): Babylon.js render loop callback.
46
46
  * - #addStylesToARButton(): Styles AR button.
47
47
  * - #createXRExperience(): Initializes WebXR AR experience.
48
- * - #createCamera(), #createLights(), #initializeEnvironmentTexture(), #initializeIBLShadows(), #initializeShadows(): Scene setup.
49
- * - #setMaxSimultaneousLights(): Updates max simultaneous lights for materials.
50
- * - #enableInteraction(), #disableInteraction(): Canvas interaction handlers.
51
- * - #disposeEngine(): Disposes engine and resources.
52
- * - #onMouseWheel(event), #onKeyUp(event): Canvas event handlers.
53
- * - #setOptionsMaterial(), #setOptions_Materials(), #setOptions_Camera(): Applies material/camera options.
54
- * - #findContainerByName(), #addContainer(), #removeContainer(), #replaceContainer(): Container management.
55
- * - #getPrefViewer3DComponent(), #getPrefViewerComponent(): Custom element references.
56
- * - #updateVisibilityAttributeInComponents(): Updates parent visibility attributes.
57
- * - #setVisibilityOfWallAndFloorInModel(): Controls wall/floor mesh visibility.
58
- * - #stopRender(), #startRender(): Render loop control.
59
- * - #loadAssetContainer(), #loadContainers(): Asset loading.
60
- * - #downloadZip(): Generates and downloads a ZIP file.
48
+ * - #createCamera(): Creates and configures the main camera.
49
+ * - #createLights(): Creates and configures scene lights and shadows.
50
+ * - #initializeEnvironmentTexture(): Loads and sets the HDR environment texture.
51
+ * - #initializeIBLShadows(): Sets up IBL shadow pipeline and assigns meshes/materials.
52
+ * - #initializeShadows(): Sets up standard or IBL shadows for meshes.
53
+ * - #setMaxSimultaneousLights(): Updates max simultaneous lights for all materials.
54
+ * - #onPointerObservable(info): Handles pointer events and dispatches to pointer/mouse handlers.
55
+ * - #onPointerUp(event, pickInfo): Handles pointer up events (e.g., right-click for animation menu).
56
+ * - #onPointerMove(event, pickInfo): Handles pointer move events (e.g., mesh highlighting).
57
+ * - #onMouseWheel(event, pickInfo): Handles mouse wheel events for camera zoom.
58
+ * - #onKeyUp(event): Handles keyup events for download dialog and shortcuts.
59
+ * - #enableInteraction(): Adds canvas and scene interaction event listeners.
60
+ * - #disableInteraction(): Removes canvas and scene interaction event listeners.
61
+ * - #disposeEngine(): Disposes engine and releases all resources.
62
+ * - #setOptionsMaterial(optionMaterial): Applies a material option to relevant meshes.
63
+ * - #setOptions_Materials(): Applies all material options from configuration.
64
+ * - #setOptions_Camera(): Applies camera options from configuration.
65
+ * - #findContainerByName(name): Finds a container by its name.
66
+ * - #addContainer(container, updateVisibility): Adds a container to the scene and updates visibility.
67
+ * - #removeContainer(container, updateVisibility): Removes a container from the scene and updates visibility.
68
+ * - #replaceContainer(container, newAssetContainer): Replaces a container in the scene.
69
+ * - #getPrefViewer3DComponent(): Caches and retrieves the parent PREF-VIEWER-3D element.
70
+ * - #getPrefViewerComponent(): Caches and retrieves the parent PREF-VIEWER element.
71
+ * - #updateVisibilityAttributeInComponents(name, isVisible): Updates parent visibility attributes.
72
+ * - #setVisibilityOfWallAndFloorInModel(show): Controls wall/floor mesh visibility.
73
+ * - #stopRender(): Stops the Babylon.js render loop.
74
+ * - #startRender(): Starts the Babylon.js render loop.
75
+ * - #loadAssetContainer(container): Loads an asset container asynchronously.
76
+ * - #loadContainers(): Loads all asset containers and adds them to the scene.
77
+ * - #addDateToName(name): Appends the current date/time to a name string.
78
+ * - #downloadZip(files, name, comment, addDateInName): Generates and downloads a ZIP file.
61
79
  * - #openDownloadDialog(): Opens the modal download dialog.
62
80
  *
63
81
  * Notes:
@@ -401,13 +419,34 @@ export default class BabylonJSController {
401
419
  }
402
420
 
403
421
  /**
404
- * Sets up interaction handlers for the Babylon.js canvas.
422
+ * Handles pointer events observed on the Babylon.js scene.
423
+ * @private
424
+ * @param {PointerInfo} info - The pointer event information from Babylon.js.
425
+ * @returns {void}
426
+ */
427
+ #onPointerObservable(info) {
428
+ const pickInfo = this.#scene.pick(this.#scene.pointerX, this.#scene.pointerY);
429
+ if (info.type === PointerEventTypes.POINTERUP) {
430
+ this.#onPointerUp(info.event, pickInfo);
431
+ } else if (info.type === PointerEventTypes.POINTERMOVE) {
432
+ this.#onPointerMove(info.event, pickInfo);
433
+ } else if (info.type === PointerEventTypes.POINTERWHEEL) {
434
+ this.#onMouseWheel(info.event, pickInfo);
435
+ }
436
+ }
437
+
438
+ /**
439
+ * Sets up interaction handlers for the Babylon.js canvas and scene.
405
440
  * @private
406
441
  * @returns {void}
407
442
  */
408
443
  #enableInteraction() {
409
- this.#canvas.addEventListener("wheel", this.#onMouseWheel.bind(this));
410
- this.#canvas.addEventListener("keyup", this.#onKeyUp.bind(this));
444
+ if (this.#canvas) {
445
+ this.#canvas.addEventListener("keyup", this.#onKeyUp.bind(this));
446
+ }
447
+ if (this.#scene) {
448
+ this.#scene.onPointerObservable.add(this.#onPointerObservable.bind(this));
449
+ }
411
450
  }
412
451
 
413
452
  /**
@@ -416,8 +455,12 @@ export default class BabylonJSController {
416
455
  * @returns {void}
417
456
  */
418
457
  #disableInteraction() {
419
- this.#canvas.removeEventListener("wheel", this.#onMouseWheel.bind(this));
420
- this.#canvas.removeEventListener("keyup", this.#onKeyUp.bind(this));
458
+ if (this.#canvas) {
459
+ this.#canvas.removeEventListener("keyup", this.#onKeyUp.bind(this));
460
+ }
461
+ if (this.#scene !== null) {
462
+ this.#scene.onPointerObservable.removeCallback(this.#onPointerObservable.bind(this));
463
+ }
421
464
  }
422
465
 
423
466
  /**
@@ -436,18 +479,37 @@ export default class BabylonJSController {
436
479
  this.#XRExperience = null;
437
480
  }
438
481
 
482
+ /**
483
+ * Handles keyup events on the Babylon.js canvas for triggering model and scene downloads.
484
+ * @private
485
+ * @param {KeyboardEvent} event - The keyup event.
486
+ * @returns {void}
487
+ */
488
+ #onKeyUp(event) {
489
+ // CTRL + ALT + letter
490
+ if (event.ctrlKey && event.altKey && event.key !== undefined) {
491
+ switch (event.key.toLowerCase()) {
492
+ case "d":
493
+ this.#openDownloadDialog();
494
+ break;
495
+ default:
496
+ break;
497
+ }
498
+ }
499
+ }
500
+
439
501
  /**
440
502
  * Handles mouse wheel events on the Babylon.js canvas for zooming the camera.
441
503
  * @private
442
504
  * @param {WheelEvent} event - The mouse wheel event.
443
- * @returns {void|false}
505
+ * @param {Object} pickInfo - The result of the scene pick operation (not used in this method).
506
+ * @returns {void|false} Returns false if there is no active camera; otherwise, void.
444
507
  */
445
- #onMouseWheel(event) {
446
- if (!this.#scene || !this.#camera) {
508
+ #onMouseWheel(event, pickInfo) {
509
+ if (!this.#scene?.activeCamera) {
447
510
  return false;
448
511
  }
449
- //const pick = this.#scene.pick(this.#scene.pointerX, this.#scene.pointerY);
450
- //this.#camera.target = pick.hit ? pick.pickedPoint.clone() : this.#camera.target;
512
+ //this.#scene.activeCamera.target = pickInfo.hit ? pickInfo.pickedPoint.clone() : this.#scene.activeCamera.target;
451
513
  if (!this.#scene.activeCamera.metadata?.locked) {
452
514
  this.#scene.activeCamera.inertialRadiusOffset -= event.deltaY * this.#scene.activeCamera.wheelPrecision * 0.001;
453
515
  }
@@ -455,24 +517,35 @@ export default class BabylonJSController {
455
517
  }
456
518
 
457
519
  /**
458
- * Handles keyup events on the Babylon.js canvas for triggering model and scene downloads.
520
+ * Handles pointer up events on the Babylon.js scene.
459
521
  * @private
460
- * @param {KeyboardEvent} event - The keyup event.
522
+ * @param {PointerEvent} event - The pointer up event.
523
+ * @param {PickInfo} pickInfo - The result of the scene pick operation.
461
524
  * @returns {void}
462
525
  */
463
- #onKeyUp(event) {
464
- // CTRL + ALT + letter
465
- if (event.ctrlKey && event.altKey && event.key !== undefined) {
466
- switch (event.key.toLowerCase()) {
467
- case "d":
468
- this.#openDownloadDialog();
469
- break;
470
- default:
471
- break;
526
+ #onPointerUp(event, pickInfo) {
527
+ if (this.#babylonJSAnimationController) {
528
+ this.#babylonJSAnimationController.hideMenu();
529
+ // Right click for showing animation menu
530
+ if (event.button === 2) {
531
+ this.#babylonJSAnimationController.showMenu(pickInfo);
472
532
  }
473
533
  }
474
534
  }
475
535
 
536
+ /**
537
+ * Handles pointer move events on the Babylon.js scene.
538
+ * @private
539
+ * @param {PointerEvent} event - The pointer move event.
540
+ * @param {PickInfo} pickInfo - The result of the scene pick operation.
541
+ * @returns {void}
542
+ */
543
+ #onPointerMove(event, pickInfo) {
544
+ if (this.#babylonJSAnimationController) {
545
+ this.#babylonJSAnimationController.hightlightMeshes(pickInfo);
546
+ }
547
+ }
548
+
476
549
  /**
477
550
  * Applies material options from the configuration to the relevant meshes.
478
551
  * @private