123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914 |
- /*
- * MARTINS.js
- * GPU-accelerated Augmented Reality for the web
- * Copyright (C) 2022-2024 Alexandre Martins <alemartf(at)gmail.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * viewport.ts
- * Viewport
- */
-
- import Speedy from 'speedy-vision';
- import { SpeedySize } from 'speedy-vision/types/core/speedy-size';
- import { SpeedyPromise } from 'speedy-vision/types/core/speedy-promise';
- import { Nullable } from '../utils/utils';
- import { Resolution } from '../utils/resolution';
- import { Utils } from '../utils/utils';
- import { IllegalArgumentError, IllegalOperationError, NotSupportedError, AccessDeniedError } from '../utils/errors';
- import { HUD, HUDContainer } from './hud';
- import { AREvent, AREventTarget, AREventListener } from '../utils/ar-events';
-
-
-
-
- /** Viewport container */
- export type ViewportContainer = HTMLDivElement;
-
- /** We admit that the size of the drawing buffer of the background canvas of the viewport may change over time */
- type ViewportSizeGetter = () => SpeedySize;
-
- /** All possible event types emitted by a Viewport */
- type ViewportEventType = 'resize';
-
- /** An event emitted by a Viewport */
- class ViewportEvent extends AREvent<ViewportEventType> { }
-
- /** Viewport event target */
- class ViewportEventTarget extends AREventTarget<ViewportEventType> { }
-
- /** Viewport style (immersive mode) */
- type ViewportStyle = 'best-fit' | 'stretch' | 'inline';
-
-
-
-
- /**
- * Viewport constructor settings
- */
- export interface ViewportSettings
- {
- /** Viewport container */
- container: Nullable<ViewportContainer>;
-
- /** HUD container */
- hudContainer?: Nullable<HUDContainer>;
-
- /** Resolution of the canvas on which the virtual scene will be drawn */
- resolution?: Resolution;
-
- /** Viewport style */
- style?: ViewportStyle;
-
- /** An existing <canvas> on which the virtual scene will be drawn */
- canvas?: Nullable<HTMLCanvasElement>;
- }
-
- /** Default viewport constructor settings */
- const DEFAULT_VIEWPORT_SETTINGS: Readonly<Required<ViewportSettings>> = {
- container: null,
- hudContainer: null,
- resolution: 'lg',
- style: 'best-fit',
- canvas: null,
- };
-
-
-
-
- /** Base z-index of the children of the viewport container */
- const BASE_ZINDEX = 0;
-
- /** Z-index of the background canvas */
- const BACKGROUND_ZINDEX = BASE_ZINDEX + 0;
-
- /** Z-index of the foreground canvas */
- const FOREGROUND_ZINDEX = BASE_ZINDEX + 1;
-
- /** Z-index of the HUD */
- const HUD_ZINDEX = BASE_ZINDEX + 2;
-
-
-
-
- /**
- * Helper class to work with the containers of the viewport
- */
- class ViewportContainers
- {
- /** The viewport container */
- private readonly _container: ViewportContainer;
-
- /** A direct child of the viewport container */
- private readonly _subContainer: HTMLDivElement;
-
-
-
-
- /**
- * Constructor
- * @param container viewport container
- */
- constructor(container: Nullable<ViewportContainer>)
- {
- // validate
- if(container == null)
- throw new IllegalArgumentError('Unspecified viewport container');
- else if(!(container instanceof HTMLElement))
- throw new IllegalArgumentError('Invalid viewport container');
-
- // store the viewport container
- this._container = container;
-
- // create the sub-container
- this._subContainer = document.createElement('div') as HTMLDivElement;
- container.appendChild(this._subContainer);
- }
-
- /**
- * The viewport container
- */
- get container(): ViewportContainer
- {
- return this._container;
- }
-
- /**
- * The sub-container
- */
- get subContainer(): HTMLDivElement
- {
- return this._subContainer;
- }
-
- /**
- * Initialize
- */
- init(): void
- {
- this._container.style.touchAction = 'none';
- this._container.style.backgroundColor = 'black';
- }
-
- /**
- * Release
- */
- release(): void
- {
- this._container.style.backgroundColor = 'initial';
- this._container.style.touchAction = 'auto';
- }
- }
-
-
-
-
- /**
- * Helper class to work with the canvases of the viewport
- */
- class ViewportCanvases
- {
- /** A canvas used to render the physical scene */
- private readonly _backgroundCanvas: HTMLCanvasElement;
-
- /** A canvas used to render the virtual scene */
- private readonly _foregroundCanvas: HTMLCanvasElement;
-
- /** Original CSS of the foreground canvas */
- private readonly _originalCSSTextOfForegroundCanvas: string;
-
-
-
- /**
- * Constructor
- * @param parent container for the canvases
- * @param initialSize initial size of the canvases
- * @param fgCanvas optional existing foreground canvas
- */
- constructor(parent: HTMLElement, initialSize: SpeedySize, fgCanvas: Nullable<HTMLCanvasElement> = null)
- {
- if(fgCanvas !== null && !(fgCanvas instanceof HTMLCanvasElement))
- throw new IllegalArgumentError('Not a canvas: ' + fgCanvas);
-
- this._originalCSSTextOfForegroundCanvas = fgCanvas ? fgCanvas.style.cssText : '';
-
- this._foregroundCanvas = this._styleCanvas(
- fgCanvas || this._createCanvas(initialSize),
- FOREGROUND_ZINDEX
- );
-
- this._backgroundCanvas = this._styleCanvas(
- this._createCanvas(initialSize),
- BACKGROUND_ZINDEX
- );
-
- parent.appendChild(this._backgroundCanvas);
- parent.appendChild(this._foregroundCanvas);
- }
-
- /**
- * The background canvas
- */
- get backgroundCanvas(): HTMLCanvasElement
- {
- return this._backgroundCanvas;
- }
-
- /**
- * The foreground canvas
- */
- get foregroundCanvas(): HTMLCanvasElement
- {
- return this._foregroundCanvas;
- }
-
- /**
- * Initialize
- */
- init(): void
- {
- }
-
- /**
- * Release
- */
- release(): void
- {
- this._backgroundCanvas.style.cssText = '';
- this._foregroundCanvas.style.cssText = this._originalCSSTextOfForegroundCanvas;
- }
-
- /**
- * Create a canvas
- * @param size size of the drawing buffer
- * @returns a new canvas
- */
- private _createCanvas(size: SpeedySize): HTMLCanvasElement
- {
- const canvas = document.createElement('canvas') as HTMLCanvasElement;
-
- canvas.width = size.width;
- canvas.height = size.height;
-
- return canvas;
- }
-
- /**
- * Add suitable CSS rules to a canvas
- * @param canvas
- * @param zIndex
- * @returns canvas
- */
- private _styleCanvas(canvas: HTMLCanvasElement, zIndex: number): HTMLCanvasElement
- {
- canvas.style.position = 'absolute';
- canvas.style.left = '0px';
- canvas.style.top = '0px';
- canvas.style.width = '100%';
- canvas.style.height = '100%';
- canvas.style.zIndex = String(zIndex);
-
- return canvas;
- }
- }
-
-
-
-
- /**
- * Fullscreen utilities
- */
- class ViewportFullscreenHelper
- {
- /**
- * Constructor
- * @param _container the container which will be put in fullscreen
- */
- constructor(private readonly _container: HTMLElement)
- {
- }
-
- /**
- * Make a request to the user agent so that the viewport container is
- * displayed in fullscreen mode. The container must be a compatible element[1]
- * and the user must interact with the page in order to comply with browser
- * policies[2]. In case of error, the returned promise is rejected.
- * [1] https://developer.mozilla.org/en-US/docs/Web/API/Element/requestFullscreen#compatible_elements
- * [2] https://developer.mozilla.org/en-US/docs/Web/API/Element/requestFullscreen#security
- * @returns promise
- */
- request(): SpeedyPromise<void>
- {
- const container = this._container;
-
- // fallback for older WebKit versions
- if(container.requestFullscreen === undefined) {
- if((container as any).webkitRequestFullscreen === undefined)
- return Speedy.Promise.reject(new NotSupportedError());
- else if(!(document as any).webkitFullscreenEnabled)
- return Speedy.Promise.reject(new AccessDeniedError());
-
- // webkitRequestFullscreen() does not return a value
- (container as any).webkitRequestFullscreen();
-
- return new Speedy.Promise<void>((resolve, reject) => {
- setTimeout(() => {
- if(container === (document as any).webkitFullscreenElement) {
- Utils.log('Entering fullscreen mode...');
- resolve();
- }
- else
- reject(new TypeError());
- }, 100);
- });
- }
-
- // check if the fullscreen mode is available
- if(!document.fullscreenEnabled)
- return Speedy.Promise.reject(new AccessDeniedError());
-
- // request fullscreen
- return new Speedy.Promise<void>((resolve, reject) => {
- container.requestFullscreen({
- navigationUI: 'hide'
- }).then(() => {
- Utils.log('Entering fullscreen mode...');
- resolve();
- }, reject);
- });
- }
-
- /**
- * Exit fullscreen mode
- * @returns promise
- */
- exit(): SpeedyPromise<void>
- {
- // fallback for older WebKit versions
- if(document.exitFullscreen === undefined) {
- const doc = document as any;
-
- if(doc.webkitExitFullscreen === undefined)
- return Speedy.Promise.reject(new NotSupportedError());
- else if(doc.webkitFullscreenElement === null)
- return Speedy.Promise.reject(new IllegalOperationError('Not in fullscreen mode'));
-
- // webkitExitFullscreen() does not return a value
- doc.webkitExitFullscreen();
-
- return new Speedy.Promise<void>((resolve, reject) => {
- setTimeout(() => {
- if(doc.webkitFullscreenElement === null) {
- Utils.log('Exiting fullscreen mode...');
- resolve();
- }
- else
- reject(new TypeError());
- }, 100);
- });
- }
-
- // error if not in fullscreen mode
- if(document.fullscreenElement === null)
- return Speedy.Promise.reject(new IllegalOperationError('Not in fullscreen mode'));
-
- // exit fullscreen
- return new Speedy.Promise<void>((resolve, reject) => {
- document.exitFullscreen().then(() => {
- Utils.log('Exiting fullscreen mode...');
- resolve();
- }, reject);
- });
- }
-
- /**
- * Is the fullscreen mode available in this platform?
- * @returns true if the fullscreen mode is available in this platform
- */
- isAvailable(): boolean
- {
- return document.fullscreenEnabled ||
- !!((document as any).webkitFullscreenEnabled);
- }
-
- /**
- * Is the container currently being displayed in fullscreen mode?
- * @returns true if the container is currently being displayed in fullscreen mode
- */
- isActivated(): boolean
- {
- if(document.fullscreenElement !== undefined)
- return document.fullscreenElement === this._container;
- else if((document as any).webkitFullscreenElement !== undefined)
- return (document as any).webkitFullscreenElement === this._container;
- else
- return false;
- }
- }
-
-
-
-
- /**
- * Helper class to resize the viewport
- */
- class ViewportResizer
- {
- /** the viewport to be resized */
- private readonly _viewport: Viewport;
-
- /** is this viewport subject to being resized? */
- private _active: boolean;
-
- /** bound resize method */
- private readonly _resize: () => void;
-
- /** resize strategy */
- private _resizeStrategy: ViewportResizeStrategy;
-
-
-
-
- /**
- * Constructor
- * @param viewport the viewport to be resized
- */
- constructor(viewport: Viewport)
- {
- this._viewport = viewport;
- this._active = false;
- this._resize = this._onResize.bind(this);
- this._resizeStrategy = new InlineResizeStrategy();
-
- // initial setup
- // (the size is yet unknown)
- this._resize();
- }
-
- /**
- * Initialize
- */
- init(): void
- {
- // Configure the resize listener. We want the viewport
- // to adjust itself if the phone/screen is resized or
- // changes orientation
- let timeout: Nullable<ReturnType<typeof setTimeout>> = null;
- const onWindowResize = () => {
- if(!this._active) {
- window.removeEventListener('resize', onWindowResize);
- return;
- }
-
- if(timeout !== null)
- clearTimeout(timeout);
-
- timeout = setTimeout(() => {
- timeout = null;
- this._resize();
- }, 50);
- };
- window.addEventListener('resize', onWindowResize);
-
- // handle changes of orientation
- // (is this needed? we already listen to resize events)
- if(screen.orientation !== undefined)
- screen.orientation.addEventListener('change', this._resize);
- else
- window.addEventListener('orientationchange', this._resize); // deprecated
-
- // setup event listener & finish!
- this._viewport.addEventListener('resize', this._resize);
- this._active = true;
-
- // trigger a resize to setup the sizes / the CSS
- this.resize();
- }
-
- /**
- * Release
- */
- release(): void
- {
- this._resizeStrategy.clear(this._viewport);
- this._active = false;
- this._viewport.removeEventListener('resize', this._resize);
-
- if(screen.orientation !== undefined)
- screen.orientation.removeEventListener('change', this._resize);
- else
- window.removeEventListener('orientationchange', this._resize); // deprecated
- }
-
- /**
- * Trigger a resize event
- */
- resize(): void
- {
- const event = new ViewportEvent('resize');
- this._viewport.dispatchEvent(event);
- }
-
- /**
- * Change the resize strategy
- * @param strategy new strategy
- */
- setStrategy(strategy: ViewportResizeStrategy): void
- {
- this._resizeStrategy.clear(this._viewport);
- this._resizeStrategy = strategy;
- this.resize();
- }
-
- /**
- * Resize callback
- */
- private _onResize(): void
- {
- const viewport = this._viewport;
-
- // Resize the drawing buffer of the foreground canvas, so that it
- // matches the desired resolution, as well as the aspect ratio of the
- // background canvas
- const foregroundCanvas = viewport.canvas;
- const virtualSize = viewport.virtualSize;
- foregroundCanvas.width = virtualSize.width;
- foregroundCanvas.height = virtualSize.height;
-
- // Resize the drawing buffer of the background canvas
- const backgroundCanvas = viewport._backgroundCanvas;
- const realSize = viewport._realSize;
- backgroundCanvas.width = realSize.width;
- backgroundCanvas.height = realSize.height;
-
- // Call strategy
- this._resizeStrategy.resize(viewport);
- }
- }
-
-
-
-
- /**
- * Resize strategies
- */
- abstract class ViewportResizeStrategy
- {
- /**
- * Resize the viewport
- * @param viewport
- */
- abstract resize(viewport: Viewport): void;
-
- /**
- * Clear CSS rules
- * @param viewport
- */
- clear(viewport: Viewport): void
- {
- viewport.container.style.cssText = '';
- viewport._subContainer.style.cssText = '';
- }
- }
-
- /**
- * Inline viewport: it follows the typical flow of a web page
- */
- class InlineResizeStrategy extends ViewportResizeStrategy
- {
- resize(viewport: Viewport): void
- {
- const container = viewport.container;
- const subContainer = viewport._subContainer;
- const virtualSize = viewport.virtualSize;
-
- container.style.position = 'relative';
- container.style.left = '0px';
- container.style.top = '0px';
- container.style.width = virtualSize.width + 'px';
- container.style.height = virtualSize.height + 'px';
-
- subContainer.style.position = 'absolute';
- subContainer.style.left = '0px';
- subContainer.style.top = '0px';
- subContainer.style.width = '100%';
- subContainer.style.height = '100%';
- }
- }
-
- /**
- * Immersive viewport: it occupies the entire page
- */
- abstract class ImmersiveResizeStrategy extends ViewportResizeStrategy
- {
- resize(viewport: Viewport): void
- {
- const CONTAINER_ZINDEX = 1000000000;
- const container = viewport.container;
-
- container.style.position = 'fixed';
- container.style.left = '0px';
- container.style.top = '0px';
- container.style.width = '100vw';
- container.style.height = '100vh';
- container.style.zIndex = String(CONTAINER_ZINDEX);
- }
- }
-
- /**
- * Immersive viewport with best-fit style: it occupies the entire page and
- * preserves the aspect ratio of the media
- */
- class BestFitResizeStrategy extends ImmersiveResizeStrategy
- {
- resize(viewport: Viewport): void
- {
- const subContainer = viewport._subContainer;
- const windowAspectRatio = window.innerWidth / window.innerHeight;
- const viewportAspectRatio = viewport._realSize.width / viewport._realSize.height;
- let width = 1, height = 1;
-
- if(viewportAspectRatio <= windowAspectRatio) {
- height = window.innerHeight;
- width = (height * viewportAspectRatio) | 0;
- }
- else {
- width = window.innerWidth;
- height = (width / viewportAspectRatio) | 0;
- }
-
- subContainer.style.position = 'absolute';
- subContainer.style.left = `calc(50% - ${(width+1) >>> 1}px)`;
- subContainer.style.top = `calc(50% - ${(height+1) >>> 1}px)`;
- subContainer.style.width = width + 'px';
- subContainer.style.height = height + 'px';
-
- super.resize(viewport);
- }
- }
-
- /**
- * Immersive viewport with stretch style: it occupies the entire page and
- * fully stretches the media
- */
- class StretchResizeStrategy extends ImmersiveResizeStrategy
- {
- resize(viewport: Viewport): void
- {
- const subContainer = viewport._subContainer;
-
- subContainer.style.position = 'absolute';
- subContainer.style.left = '0px';
- subContainer.style.top = '0px';
- subContainer.style.width = window.innerWidth + 'px';
- subContainer.style.height = window.innerHeight + 'px';
-
- super.resize(viewport);
- }
- }
-
-
-
-
- /**
- * Viewport
- */
- export class Viewport extends ViewportEventTarget
- {
- /** Viewport resolution (controls the size of the drawing buffer of the foreground canvas) */
- private readonly _resolution: Resolution;
-
- /** The containers */
- private readonly _containers: ViewportContainers;
-
- /** An overlay displayed in front of the augmented scene */
- protected readonly _hud: HUD;
-
- /** Viewport style */
- protected _style: Nullable<ViewportStyle>;
-
- /** The canvases of the viewport */
- private readonly _canvases: ViewportCanvases;
-
- /** Fullscreen utilities */
- private readonly _fullscreen: ViewportFullscreenHelper;
-
- /** Resize helper */
- private readonly _resizer: ViewportResizer;
-
- /** The current size of the underlying SpeedyMedia */
- private _mediaSize: ViewportSizeGetter;
-
-
-
-
- /**
- * Constructor
- * @param viewportSettings
- */
- constructor(viewportSettings: ViewportSettings)
- {
- const settings = Object.assign({}, DEFAULT_VIEWPORT_SETTINGS, viewportSettings);
-
- super();
-
- const guessedAspectRatio = window.innerWidth / window.innerHeight;
- const initialSize = Utils.resolution(settings.resolution, guessedAspectRatio);
- this._mediaSize = () => initialSize;
-
- this._resolution = settings.resolution;
- this._style = null;
- this._containers = new ViewportContainers(settings.container);
- this._hud = new HUD(this._subContainer, settings.hudContainer);
- this._canvases = new ViewportCanvases(this._subContainer, initialSize, settings.canvas);
-
- this._fullscreen = new ViewportFullscreenHelper(this.container);
- this._resizer = new ViewportResizer(this);
- this.style = settings.style;
- }
-
- /**
- * Viewport container
- */
- get container(): ViewportContainer
- {
- return this._containers.container;
- }
-
- /**
- * Viewport style
- */
- get style(): ViewportStyle
- {
- if(this._style === null)
- throw new IllegalOperationError();
-
- return this._style;
- }
-
- /**
- * Set viewport style
- */
- set style(value: ViewportStyle)
- {
- // nothing to do
- if(value === this._style)
- return;
-
- // change style
- switch(value) {
- case 'best-fit':
- this._resizer.setStrategy(new BestFitResizeStrategy());
- break;
-
- case 'stretch':
- this._resizer.setStrategy(new StretchResizeStrategy());
- break;
-
- case 'inline':
- this._resizer.setStrategy(new InlineResizeStrategy());
- break;
-
- default:
- throw new IllegalArgumentError('Invalid viewport style: ' + value);
- }
-
- this._style = value;
-
- // note: the viewport style is independent of the session mode!
- }
-
- /**
- * HUD
- */
- get hud(): HUD
- {
- return this._hud;
- }
-
- /**
- * Resolution of the virtual scene
- */
- get resolution(): Resolution
- {
- return this._resolution;
- }
-
- /**
- * Size in pixels of the drawing buffer of the canvas
- * on which the virtual scene will be drawn
- */
- get virtualSize(): SpeedySize
- {
- const size = this._realSize;
- const aspectRatio = size.width / size.height;
-
- return Utils.resolution(this._resolution, aspectRatio);
- }
-
- /**
- * Is the viewport currently being displayed in fullscreen mode?
- */
- get fullscreen(): boolean
- {
- return this._fullscreen.isActivated();
- }
-
- /**
- * Is the fullscreen mode available in this platform?
- */
- get fullscreenAvailable(): boolean
- {
- return this._fullscreen.isAvailable();
- }
-
- /**
- * The canvas on which the virtual scene will be drawn
- */
- get canvas(): HTMLCanvasElement
- {
- return this._canvases.foregroundCanvas;
- }
-
- /**
- * The canvas on which the physical scene will be drawn
- * @internal
- */
- get _backgroundCanvas(): HTMLCanvasElement
- {
- return this._canvases.backgroundCanvas;
- }
-
- /**
- * Size of the drawing buffer of the background canvas, in pixels
- * @internal
- */
- get _realSize(): SpeedySize
- {
- return this._mediaSize();
- }
-
- /**
- * Sub-container of the viewport container
- * @internal
- */
- get _subContainer(): HTMLDivElement
- {
- return this._containers.subContainer;
- }
-
- /**
- * Request fullscreen mode
- * @returns promise
- */
- requestFullscreen(): SpeedyPromise<void>
- {
- return this._fullscreen.request();
- }
-
- /**
- * Exit fullscreen mode
- * @returns promise
- */
- exitFullscreen(): SpeedyPromise<void>
- {
- return this._fullscreen.exit();
- }
-
- /**
- * Initialize the viewport (when the session starts)
- * @internal
- */
- _init(getMediaSize: ViewportSizeGetter): void
- {
- this._mediaSize = getMediaSize;
-
- this._containers.init();
- this._hud._init(HUD_ZINDEX);
- this._canvases.init();
- this._resizer.init();
- }
-
- /**
- * Release the viewport (when the session ends)
- * @internal
- */
- _release(): void
- {
- this._resizer.release();
- this._canvases.release();
- this._hud._release();
- this._containers.release();
- }
- }
|