Bläddra i källkod

Refactor the HUD and separate internal components from user space

customisations
alemart 5 månader sedan
förälder
incheckning
010228ea5f
5 ändrade filer med 82 tillägg och 59 borttagningar
  1. 44
    6
      src/core/hud.ts
  2. 6
    12
      src/core/session.ts
  3. 14
    15
      src/core/viewport.ts
  4. 6
    2
      src/ui/fullscreen-button.ts
  5. 12
    24
      src/ui/stats-panel.ts

+ 44
- 6
src/core/hud.ts Visa fil

@@ -20,7 +20,10 @@
20 20
  * Heads Up Display
21 21
  */
22 22
 
23
-import { Nullable, Utils } from "../utils/utils";
23
+import { Viewport } from './viewport';
24
+import { StatsPanel } from '../ui/stats-panel';
25
+import { FullscreenButton } from '../ui/fullscreen-button';
26
+import { Nullable, Utils } from '../utils/utils';
24 27
 
25 28
 /** HUD container */
26 29
 export type HUDContainer = HTMLDivElement;
@@ -36,14 +39,24 @@ export class HUD
36 39
     /** Whether or not we have created our own container */
37 40
     private _isOwnContainer: boolean;
38 41
 
42
+    /** Container for the internal components */
43
+    private _internalContainer: ShadowRoot;
44
+
45
+    /** Stats panel */
46
+    #statsPanel: StatsPanel;
47
+
48
+    /** Fullscreen button */
49
+    #fullscreenButton: FullscreenButton;
50
+
39 51
 
40 52
 
41 53
     /**
42 54
      * Constructor
55
+     * @param viewport viewport
43 56
      * @param parent parent of the hud container
44 57
      * @param hudContainer an existing hud container (optional)
45 58
      */
46
-    constructor(parent: HTMLElement, hudContainer: Nullable<HUDContainer>)
59
+    constructor(viewport: Viewport, parent: HTMLElement, hudContainer: Nullable<HUDContainer> = null)
47 60
     {
48 61
         this._container = hudContainer || this._createContainer(parent);
49 62
         this._isOwnContainer = (hudContainer == null);
@@ -59,6 +72,14 @@ export class HUD
59 72
             Utils.warning(`The container of the HUD should have the hidden attribute`);
60 73
             this._container.hidden = true;
61 74
         }
75
+
76
+        // create a shadow tree for the internal components
77
+        this._internalContainer = parent.attachShadow({ mode: 'closed' });
78
+        this._internalContainer.appendChild(document.createElement('slot'));
79
+
80
+        // create internal components
81
+        this.#statsPanel = new StatsPanel();
82
+        this.#fullscreenButton = new FullscreenButton(viewport);
62 83
     }
63 84
 
64 85
     /**
@@ -86,14 +107,28 @@ export class HUD
86 107
     }
87 108
 
88 109
     /**
110
+     * Stats panel
111
+     * @internal
112
+     */
113
+    get _statsPanel(): StatsPanel
114
+    {
115
+        return this.#statsPanel; // same name
116
+    }
117
+
118
+    /**
89 119
      * Initialize the HUD
90 120
      * @param zIndex the z-index of the container
121
+     * @param wantStatsPanel
122
+     * @param wantFullscreenButton
91 123
      * @internal
92 124
      */
93
-    _init(zIndex: number): void
125
+    _init(zIndex: number, wantStatsPanel: boolean, wantFullscreenButton: boolean): void
94 126
     {
95
-        const container = this._container;
127
+        const parent = this._internalContainer;
128
+        this.#statsPanel.init(parent, wantStatsPanel);
129
+        this.#fullscreenButton.init(parent, wantFullscreenButton);
96 130
 
131
+        const container = this._container;
97 132
         container.style.position = 'absolute';
98 133
         container.style.left = container.style.top = '0px';
99 134
         container.style.right = container.style.bottom = '0px';
@@ -112,6 +147,9 @@ export class HUD
112 147
     {
113 148
         this.visible = false;
114 149
 
150
+        this.#fullscreenButton.release();
151
+        this.#statsPanel.release();
152
+
115 153
         if(this._isOwnContainer) {
116 154
             this._isOwnContainer = false;
117 155
             this._container.remove();
@@ -125,11 +163,11 @@ export class HUD
125 163
      */
126 164
     private _createContainer(parent: HTMLElement): HUDContainer
127 165
     {
128
-        const node = document.createElement('div') as HTMLDivElement;
166
+        const node = document.createElement('div');
129 167
 
130 168
         node.hidden = true;
131 169
         parent.insertAdjacentElement('afterbegin', node);
132 170
 
133 171
         return node;
134 172
     }
135
-}
173
+}

+ 6
- 12
src/core/session.ts Visa fil

@@ -31,7 +31,6 @@ import { IllegalArgumentError, IllegalOperationError, NotSupportedError, AccessD
31 31
 import { Viewport } from './viewport';
32 32
 import { Settings } from './settings';
33 33
 import { Stats } from './stats';
34
-import { StatsPanel } from '../ui/stats-panel';
35 34
 import { Gizmos } from '../ui/gizmos';
36 35
 import { Frame } from './frame';
37 36
 import { Tracker } from '../trackers/tracker';
@@ -132,9 +131,6 @@ export class Session extends AREventTarget<SessionEventType>
132 131
     /** Render stats (FPS) */
133 132
     private _renderStats: Stats;
134 133
 
135
-    /** Stats panel */
136
-    private _statsPanel: StatsPanel;
137
-
138 134
     /** Gizmos */
139 135
     private _gizmos: Gizmos;
140 136
 
@@ -174,13 +170,9 @@ export class Session extends AREventTarget<SessionEventType>
174 170
         // setup the viewport
175 171
         this._viewport = viewport;
176 172
         if(this._primarySource !== null)
177
-            this._viewport._init(() => this._primarySource!._internalMedia.size, mode);
173
+            this._viewport._init(() => this._primarySource!._internalMedia.size, mode, stats);
178 174
         else
179
-            this._viewport._init(() => Utils.resolution('sm', window.innerWidth / window.innerHeight), mode);
180
-
181
-        // setup the stats panel
182
-        this._statsPanel = new StatsPanel(this._viewport);
183
-        this._statsPanel.visible = stats;
175
+            this._viewport._init(() => Utils.resolution('sm', window.innerWidth / window.innerHeight), mode, stats);
184 176
 
185 177
         // done!
186 178
         Session._count++;
@@ -397,7 +389,6 @@ export class Session extends AREventTarget<SessionEventType>
397 389
             // release internal components
398 390
             this._updateStats.reset();
399 391
             this._renderStats.reset();
400
-            this._statsPanel.release();
401 392
             this._viewport._release();
402 393
 
403 394
             // end the session
@@ -735,9 +726,12 @@ export class Session extends AREventTarget<SessionEventType>
735 726
 
736 727
                 // update internals
737 728
                 this._renderStats.update();
738
-                this._statsPanel.update(time, this._sources, this._trackers, this._viewport, this._updateStats.cyclesPerSecond, this._renderStats.cyclesPerSecond);
739 729
                 this._frameReady = false;
740 730
 
731
+                // update stats panel
732
+                const statsPanel = this._viewport.hud._statsPanel;
733
+                statsPanel.update(time, this._sources, this._trackers, this._viewport, this._updateStats.cyclesPerSecond, this._renderStats.cyclesPerSecond);
734
+
741 735
             }
742 736
             else {
743 737
 

+ 14
- 15
src/core/viewport.ts Visa fil

@@ -26,7 +26,6 @@ import { SpeedySize } from 'speedy-vision/types/core/speedy-size';
26 26
 import { SpeedyPromise } from 'speedy-vision/types/core/speedy-promise';
27 27
 import { SessionMode } from './session';
28 28
 import { HUD, HUDContainer } from './hud';
29
-import { FullscreenButton } from '../ui/fullscreen-button';
30 29
 import { Vector2 } from '../geometry/vector2';
31 30
 import { Resolution } from '../utils/resolution';
32 31
 import { Nullable } from '../utils/utils';
@@ -794,6 +793,9 @@ export class Viewport extends ViewportEventTarget
794 793
     /** Viewport resolution (controls the size of the drawing buffer of the foreground canvas) */
795 794
     private readonly _resolution: Resolution;
796 795
 
796
+    /** Viewport settings */
797
+    private readonly _settings: Readonly<Required<ViewportSettings>>
798
+
797 799
     /** The containers */
798 800
     private readonly _containers: ViewportContainers;
799 801
 
@@ -815,8 +817,6 @@ export class Viewport extends ViewportEventTarget
815 817
     /** Fullscreen utilities */
816 818
     private readonly _fullscreen: ViewportFullscreenHelper;
817 819
 
818
-    /** Built-in fullscreen button */
819
-    private readonly _fullscreenButton: Nullable<FullscreenButton>;
820 820
 
821 821
 
822 822
 
@@ -827,10 +827,11 @@ export class Viewport extends ViewportEventTarget
827 827
      */
828 828
     constructor(viewportSettings: ViewportSettings)
829 829
     {
830
-        const settings = Object.assign({}, DEFAULT_VIEWPORT_SETTINGS, viewportSettings);
831
-
832 830
         super();
833 831
 
832
+        const settings = Object.assign({}, DEFAULT_VIEWPORT_SETTINGS, viewportSettings);
833
+        this._settings = Object.freeze(settings);
834
+
834 835
         const guessedAspectRatio = window.innerWidth / window.innerHeight;
835 836
         const initialSize = Utils.resolution(settings.resolution, guessedAspectRatio);
836 837
         this._mediaSize = () => initialSize;
@@ -839,17 +840,13 @@ export class Viewport extends ViewportEventTarget
839 840
         this._style = settings.style;
840 841
 
841 842
         this._containers = new ViewportContainers(settings.container);
842
-        this._hud = new HUD(this._subContainer, settings.hudContainer);
843
+        this._hud = new HUD(this, this._subContainer, settings.hudContainer);
843 844
         this._canvases = new ViewportCanvases(this._subContainer, initialSize, settings.canvas);
844 845
 
845 846
         this._resizer = new ViewportResizer(this);
846 847
         this._resizer.setStrategyByName(this._style);
847 848
 
848 849
         this._fullscreen = new ViewportFullscreenHelper(this);
849
-        this._fullscreenButton = null;
850
-
851
-        if(settings.fullscreenUI && this.fullscreenAvailable)
852
-            this._fullscreenButton = new FullscreenButton(this);
853 850
     }
854 851
 
855 852
     /**
@@ -1054,9 +1051,10 @@ export class Viewport extends ViewportEventTarget
1054 1051
      * Initialize the viewport (when the session starts)
1055 1052
      * @param getMediaSize
1056 1053
      * @param sessionMode
1054
+     * @param wantStatsPanel
1057 1055
      * @internal
1058 1056
      */
1059
-    _init(getMediaSize: ViewportSizeGetter, sessionMode: SessionMode): void
1057
+    _init(getMediaSize: ViewportSizeGetter, sessionMode: SessionMode, wantStatsPanel: boolean): void
1060 1058
     {
1061 1059
         // validate if the viewport style matches the session mode
1062 1060
         if(sessionMode == 'immersive') {
@@ -1079,11 +1077,13 @@ export class Viewport extends ViewportEventTarget
1079 1077
 
1080 1078
         // initialize the components
1081 1079
         this._containers.init();
1082
-        this._hud._init(HUD_ZINDEX);
1083 1080
         this._canvases.init();
1084 1081
         this._resizer.init();
1085 1082
         this._fullscreen.init();
1086
-        this._fullscreenButton?.init();
1083
+
1084
+        // initialize the HUD
1085
+        const wantFullscreenButton = this.fullscreenAvailable && this._settings.fullscreenUI;
1086
+        this._hud._init(HUD_ZINDEX, wantStatsPanel, wantFullscreenButton);
1087 1087
     }
1088 1088
 
1089 1089
     /**
@@ -1092,11 +1092,10 @@ export class Viewport extends ViewportEventTarget
1092 1092
      */
1093 1093
     _release(): void
1094 1094
     {
1095
-        this._fullscreenButton?.release();
1095
+        this._hud._release();
1096 1096
         this._fullscreen.release();
1097 1097
         this._resizer.release();
1098 1098
         this._canvases.release();
1099
-        this._hud._release();
1100 1099
         this._containers.release();
1101 1100
     }
1102 1101
 }

+ 6
- 2
src/ui/fullscreen-button.ts Visa fil

@@ -65,10 +65,13 @@ export class FullscreenButton
65 65
 
66 66
     /**
67 67
      * Initialize
68
+     * @param parent parent node
69
+     * @param isVisible
68 70
      */
69
-    init(): void
71
+    init(parent: Node, isVisible: boolean): void
70 72
     {
71
-        this._viewport.hud.container.appendChild(this._button);
73
+        parent.appendChild(this._button);
74
+        this._button.hidden = !isVisible;
72 75
         this._viewport.addEventListener('fullscreenchange', this._boundEventHandler);
73 76
     }
74 77
 
@@ -95,6 +98,7 @@ export class FullscreenButton
95 98
         button.style.height = BUTTON_SIZE + 'px';
96 99
 
97 100
         button.style.opacity = '0.5';
101
+        button.style.zIndex = '1000000';
98 102
         button.style.cursor = 'pointer';
99 103
         button.style.outline = 'none';
100 104
         (button.style as any)['-webkit-tap-highlight-color'] = 'transparent';

+ 12
- 24
src/ui/stats-panel.ts Visa fil

@@ -49,9 +49,6 @@ const BUTTON_ICONS = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAQCAYA
49 49
  */
50 50
 export class StatsPanel
51 51
 {
52
-    /** The viewport associated to this panel */
53
-    private readonly _viewport: Viewport;
54
-
55 52
     /** A container for the panel */
56 53
     private readonly _container: HTMLDivElement;
57 54
 
@@ -63,15 +60,22 @@ export class StatsPanel
63 60
 
64 61
     /**
65 62
      * Constructor
66
-     * @param viewport Viewport
67 63
      */
68
-    constructor(viewport: Viewport)
64
+    constructor()
69 65
     {
70
-        this._viewport = viewport;
66
+        this._container = this._createContainer();
71 67
         this._lastUpdate = 0;
68
+    }
72 69
 
73
-        this._container = this._createContainer();
74
-        viewport.hud.container.appendChild(this._container);
70
+    /**
71
+     * Initialize the panel
72
+     * @param parent parent node
73
+     * @param isVisible
74
+     */
75
+    init(parent: Node, isVisible: boolean): void
76
+    {
77
+        parent.appendChild(this._container);
78
+        this._container.hidden = !isVisible;
75 79
     }
76 80
 
77 81
     /**
@@ -100,22 +104,6 @@ export class StatsPanel
100 104
     }
101 105
 
102 106
     /**
103
-     * Visibility of the panel
104
-     */
105
-    get visible(): boolean
106
-    {
107
-        return !this._container.hidden;
108
-    }
109
-
110
-    /**
111
-     * Visibility of the panel
112
-     */
113
-    set visible(visible: boolean)
114
-    {
115
-        this._container.hidden = !visible;
116
-    }
117
-
118
-    /**
119 107
      * Update the contents of the panel
120 108
      * @param sources the sources of media linked to the session
121 109
      * @param trackers the trackers attached to the session

Laddar…
Avbryt
Spara