import { Nullable } from "babylonjs/types" ; import { Observable , Observer } from "babylonjs/Misc/observable" ; import { Vector2 , Vector3 , Matrix } from "babylonjs/Maths/math.vector" ; import { Tools } from "babylonjs/Misc/tools" ; import { PointerInfoPre , PointerInfo , PointerEventTypes , PointerInfoBase } from "babylonjs/Events/pointerEvents" ; import { ClipboardEventTypes , ClipboardInfo } from "babylonjs/Events/clipboardEvents" ; import { KeyboardInfoPre , KeyboardEventTypes } from "babylonjs/Events/keyboardEvents" ; import { Camera } from "babylonjs/Cameras/camera" ; import { StandardMaterial } from "babylonjs/Materials/standardMaterial" ; import { Texture } from "babylonjs/Materials/Textures/texture" ; import { DynamicTexture } from "babylonjs/Materials/Textures/dynamicTexture" ; import { AbstractMesh } from "babylonjs/Meshes/abstractMesh" ; import { Layer } from "babylonjs/Layers/layer" ; import { Engine } from "babylonjs/Engines/engine" ; import { Scene } from "babylonjs/scene" ; import { Container } from "./controls/container" ; import { Control } from "./controls/control" ; import { IFocusableControl } from "./controls/focusableControl" ; import { Style } from "./style" ; import { Measure } from "./measure" ; import { Constants } from "babylonjs/Engines/constants" ; import { Viewport } from "babylonjs/Maths/math.viewport" ; import { Color3 } from "babylonjs/Maths/math.color" ; import { WebRequest } from "babylonjs/Misc/webRequest" ; import { IPointerEvent , IWheelEvent } from "babylonjs/Events/deviceInputEvents" ; import { RandomGUID } from "babylonjs/Misc/guid" ; see https export class AdvancedDynamicTexture extends DynamicTexture { /** Define the Uurl to load snippets */ public static SnippetUrl = "https://snippet.babylonjs.com" ; /** Indicates if some optimizations can be performed in GUI GPU management (the downside is additional memory/GPU texture memory used) */ public static AllowGPUOptimizations = true ; /** Snippet ID if the content was created from the snippet server */ public snippetId : string ; private _isDirty = false ; private _renderObserver : Nullable < Observer < Camera > > ; private _resizeObserver : Nullable < Observer < Engine > > ; private _preKeyboardObserver : Nullable < Observer < KeyboardInfoPre > > ; private _pointerMoveObserver : Nullable < Observer < PointerInfoPre > > ; private _pointerObserver : Nullable < Observer < PointerInfo > > ; private _canvasPointerOutObserver : Nullable < Observer < IPointerEvent > > ; private _canvasBlurObserver : Nullable < Observer < Engine > > ; private _background : string ; hidden public _rootContainer = new Container ( "root" ) ; hidden public _lastPickedControl : Control ; hidden public _lastControlOver : { [ pointerId ] : Control ; } = { } ; hidden public _lastControlDown : { [ pointerId ] : Control ; } = { } ; hidden public _capturingControl : { [ pointerId ] : Control ; } = { } ; hidden public _shouldBlockPointer : boolean ; hidden public _layerToDispose : Nullable < Layer > ; hidden public _linkedControls = new Array < Control > ( ) ; private _isFullscreen = false ; private _fullscreenViewport = new Viewport ( 0 , 0 , 1 , 1 ) ; private _idealWidth = 0 ; private _idealHeight = 0 ; private _useSmallestIdeal : boolean = false ; private _renderAtIdealSize = false ; private _focusedControl : Nullable < IFocusableControl > ; private _blockNextFocusCheck = false ; private _renderScale = 1 ; private _rootElement : Nullable < HTMLElement > ; private _cursorChanged = false ; private _defaultMousePointerId = 0 ; hidden public _numLayoutCalls = 0 ; /** Gets the number of layout calls made the last time the ADT has been rendered */ public get numLayoutCalls ( ) : number { return this . _numLayoutCalls ; } hidden public _numRenderCalls = 0 ; /** Gets the number of render calls made the last time the ADT has been rendered */ public get numRenderCalls ( ) : number { return this . _numRenderCalls ; } /**
     * Define type to string to ensure compatibility across browsers
     * Safari doesn't support DataTransfer constructor
     */ private _clipboardData : string = "" ; /**
     * Observable event triggered each time an clipboard event is received from the rendering canvas
     */ public onClipboardObservable = new Observable < ClipboardInfo > ( ) ; /**
     * Observable event triggered each time a pointer down is intercepted by a control
     */ public onControlPickedObservable = new Observable < Control > ( ) ; /**
     * Observable event triggered before layout is evaluated
     */ public onBeginLayoutObservable = new Observable < AdvancedDynamicTexture > ( ) ; /**
     * Observable event triggered after the layout was evaluated
     */ public onEndLayoutObservable = new Observable < AdvancedDynamicTexture > ( ) ; /**
     * Observable event triggered before the texture is rendered
     */ public onBeginRenderObservable = new Observable < AdvancedDynamicTexture > ( ) ; /**
     * Observable event triggered after the texture was rendered
     */ public onEndRenderObservable = new Observable < AdvancedDynamicTexture > ( ) ; /**
     * Gets or sets a boolean defining if alpha is stored as premultiplied
     */ public premulAlpha = false ; /**
     * Gets or sets a boolean indicating that the canvas must be reverted on Y when updating the texture
     */ public applyYInversionOnUpdate = true ; /**
     * Gets or sets a number used to scale rendering size (2 means that the texture will be twice bigger).
     * Useful when you want more antialiasing
     */ public get renderScale ( ) : number { return this . _renderScale ; } public set renderScale ( value ) { if ( value === this . _renderScale ) { return ; } this . _renderScale = value ; this . _onResize ( ) ; } /** Gets or sets the background color */ public get background ( ) : string { return this . _background ; } public set background ( value ) { if ( this . _background === value ) { return ; } this . _background = value ; this . markAsDirty ( ) ; } see https public get idealWidth ( ) : number { return this . _idealWidth ; } public set idealWidth ( value ) { if ( this . _idealWidth === value ) { return ; } this . _idealWidth = value ; this . markAsDirty ( ) ; this . _rootContainer . _markAllAsDirty ( ) ; } see https public get idealHeight ( ) : number { return this . _idealHeight ; } public set idealHeight ( value ) { if ( this . _idealHeight === value ) { return ; } this . _idealHeight = value ; this . markAsDirty ( ) ; this . _rootContainer . _markAllAsDirty ( ) ; } see https public get useSmallestIdeal ( ) : boolean { return this . _useSmallestIdeal ; } public set useSmallestIdeal ( value ) { if ( this . _useSmallestIdeal === value ) { return ; } this . _useSmallestIdeal = value ; this . markAsDirty ( ) ; this . _rootContainer . _markAllAsDirty ( ) ; } see https public get renderAtIdealSize ( ) : boolean { return this . _renderAtIdealSize ; } public set renderAtIdealSize ( value ) { if ( this . _renderAtIdealSize === value ) { return ; } this . _renderAtIdealSize = value ; this . _onResize ( ) ; } see https public get idealRatio ( ) : number { var rwidth = 0 ; var rheight = 0 ; if ( this . _idealWidth ) { rwidth = this . getSize ( ) . width / this . _idealWidth ; } if ( this . _idealHeight ) { rheight = this . getSize ( ) . height / this . _idealHeight ; } if ( this . _useSmallestIdeal && this . _idealWidth && this . _idealHeight ) { return window . innerWidth < window . innerHeight ? rwidth : rheight ; } if ( this . _idealWidth ) { return rwidth ; } if ( this . _idealHeight ) { return rheight ; } return 1 ; } /**
     * Gets the underlying layer used to render the texture when in fullscreen mode
     */ public get layer ( ) : Nullable < Layer > { return this . _layerToDispose ; } /**
     * Gets the root container control
     */ public get rootContainer ( ) : Container { return this . _rootContainer ; } returns public getChildren ( ) { return [ this . _rootContainer ] ; } param directDescendantsOnly param predicate return public getDescendants ( directDescendantsOnly ? , predicate ? ) { return this . _rootContainer . getDescendants ( directDescendantsOnly , predicate ) ; } param typeName returns public getControlsByType ( typeName ) { return this . _rootContainer . getDescendants ( false , ( control ) => control . typeName === typeName ) ; } param name return public getControlByName ( name ) { return this . _getControlByKey ( "name" , name ) ; } private _getControlByKey ( key , value ) { return this . _rootContainer . getDescendants ( ) . find ( ( control ) => control [ key as keyof Control ] === value ) || null ; } /**
     * Gets or sets the current focused control
     */ public get focusedControl ( ) : Nullable < IFocusableControl > { return this . _focusedControl ; } public set focusedControl ( control ) { if ( this . _focusedControl == control ) { return ; } if ( this . _focusedControl ) { this . _focusedControl . onBlur ( ) ; } if ( control ) { control . onFocus ( ) ; } this . _focusedControl = control ; } /**
     * Gets or sets a boolean indicating if the texture must be rendered in background or foreground when in fullscreen mode
     */ public get isForeground ( ) : boolean { if ( ! this . layer ) { return true ; } return ! this . layer . isBackground ; } public set isForeground ( value ) { if ( ! this . layer ) { return ; } if ( this . layer . isBackground === ! value ) { return ; } this . layer . isBackground = ! value ; } /**
     * Gets or set information about clipboardData
     */ public get clipboardData ( ) : string { return this . _clipboardData ; } public set clipboardData ( value ) { this . _clipboardData = value ; } param name param width param height param scene param generateMipMaps param samplingMode param invertY constructor ( name , width = 0 , height = 0 , scene , generateMipMaps = false , samplingMode = Texture . NEAREST_SAMPLINGMODE , invertY = true ) { super ( name , { width : width , height : height } , scene , generateMipMaps , samplingMode , Constants . TEXTUREFORMAT_RGBA , invertY ) ; scene = this . getScene ( ) ; if ( ! scene || ! this . _texture ) { return ; } this . applyYInversionOnUpdate = invertY ; this . _rootElement = scene . getEngine ( ) . getInputElement ( ) ; this . _renderObserver = scene . onBeforeCameraRenderObservable . add ( ( camera ) => this . _checkUpdate ( camera ) ) ; this . _preKeyboardObserver = scene . onPreKeyboardObservable . add ( ( info ) => { if ( ! this . _focusedControl ) { return ; } if ( info . type === KeyboardEventTypes . KEYDOWN ) { this . _focusedControl . processKeyboard ( info . event ) ; } info . skipOnPointerObservable = true ; } ) ; this . _rootContainer . _link ( this ) ; this . hasAlpha = true ; if ( ! width || ! height ) { this . _resizeObserver = scene . getEngine ( ) . onResizeObservable . add ( ( ) => this . _onResize ( ) ) ; this . _onResize ( ) ; } this . _texture . isReady = true ; } returns public getClassName ( ) { return "AdvancedDynamicTexture" ; } param func param container public executeOnAllControls ( func , container ? ) { if ( ! container ) { container = this . _rootContainer ; } func ( container ) ; for ( var child of container . children ) { if ( ( < any > child ) . children ) { this . executeOnAllControls ( func , < Container > child ) ; continue ; } func ( child ) ; } } private _useInvalidateRectOptimization = true ; /**
     * Gets or sets a boolean indicating if the InvalidateRect optimization should be turned on
     */ public get useInvalidateRectOptimization ( ) : boolean { return this . _useInvalidateRectOptimization ; } public set useInvalidateRectOptimization ( value ) { this . _useInvalidateRectOptimization = value ; } private _invalidatedRectangle : Nullable < Measure > = null ; param invalidMinX param invalidMinY param invalidMaxX param invalidMaxY public invalidateRect ( invalidMinX , invalidMinY , invalidMaxX , invalidMaxY ) { if ( ! this . _useInvalidateRectOptimization ) { return ; } if ( ! this . _invalidatedRectangle ) { this . _invalidatedRectangle = new Measure ( invalidMinX , invalidMinY , invalidMaxX - invalidMinX + 1 , invalidMaxY - invalidMinY + 1 ) ; } else { var maxX = Math . ceil ( Math . max ( this . _invalidatedRectangle . left + this . _invalidatedRectangle . width - 1 , invalidMaxX ) ) ; var maxY = Math . ceil ( Math . max ( this . _invalidatedRectangle . top + this . _invalidatedRectangle . height - 1 , invalidMaxY ) ) ; this . _invalidatedRectangle . left = Math . floor ( Math . min ( this . _invalidatedRectangle . left , invalidMinX ) ) ; this . _invalidatedRectangle . top = Math . floor ( Math . min ( this . _invalidatedRectangle . top , invalidMinY ) ) ; this . _invalidatedRectangle . width = maxX - this . _invalidatedRectangle . left + 1 ; this . _invalidatedRectangle . height = maxY - this . _invalidatedRectangle . top + 1 ; } } /**
     * Marks the texture as dirty forcing a complete update
     */ public markAsDirty ( ) { this . _isDirty = true ; } returns see https public createStyle ( ) { return new Style ( this ) ; } param control returns public addControl ( control ) { this . _rootContainer . addControl ( control ) ; return this ; } param control returns public removeControl ( control ) { this . _rootContainer . removeControl ( control ) ; return this ; } param overlapGroup param deltaStep param repelFactor public moveToNonOverlappedPosition ( overlapGroup ? , deltaStep = 1 , repelFactor = 1 ) { let controlsForGroup ; if ( Array . isArray ( overlapGroup ) ) { controlsForGroup = overlapGroup ; } else { const descendants = this . getDescendants ( true ) ; controlsForGroup = overlapGroup === undefined ? descendants . filter ( ( c ) => c . overlapGroup !== undefined ) : descendants . filter ( ( c ) => c . overlapGroup === overlapGroup ) ; } controlsForGroup . forEach ( ( control1 ) => { let velocity = Vector2 . Zero ( ) ; const center = new Vector2 ( control1 . centerX , control1 . centerY ) ; controlsForGroup . forEach ( ( control2 ) => { if ( control1 !== control2 && AdvancedDynamicTexture . _Overlaps ( control1 , control2 ) ) { const diff = center . subtract ( new Vector2 ( control2 . centerX , control2 . centerY ) ) ; const diffLength = diff . length ( ) ; if ( diffLength > 0 ) { velocity = velocity . add ( diff . normalize ( ) . scale ( repelFactor / diffLength ) ) ; } } } ) ; if ( velocity . length ( ) > 0 ) { velocity = velocity . normalize ( ) . scale ( deltaStep * ( control1 . overlapDeltaMultiplier ?? 1 ) ) ; control1 . linkOffsetXInPixels += velocity . x ; control1 . linkOffsetYInPixels += velocity . y ; } } ) ; } /**
     * Release all resources
     */ public dispose ( ) { let scene = this . getScene ( ) ; if ( ! scene ) { return ; } this . _rootElement = null ; scene . onBeforeCameraRenderObservable . remove ( this . _renderObserver ) ; if ( this . _resizeObserver ) { scene . getEngine ( ) . onResizeObservable . remove ( this . _resizeObserver ) ; } if ( this . _pointerMoveObserver ) { scene . onPrePointerObservable . remove ( this . _pointerMoveObserver ) ; } if ( this . _pointerObserver ) { scene . onPointerObservable . remove ( this . _pointerObserver ) ; } if ( this . _preKeyboardObserver ) { scene . onPreKeyboardObservable . remove ( this . _preKeyboardObserver ) ; } if ( this . _canvasPointerOutObserver ) { scene . getEngine ( ) . onCanvasPointerOutObservable . remove ( this . _canvasPointerOutObserver ) ; } if ( this . _canvasBlurObserver ) { scene . getEngine ( ) . onCanvasBlurObservable . remove ( this . _canvasBlurObserver ) ; } if ( this . _layerToDispose ) { this . _layerToDispose . texture = null ; this . _layerToDispose . dispose ( ) ; this . _layerToDispose = null ; } this . _rootContainer . dispose ( ) ; this . onClipboardObservable . clear ( ) ; this . onControlPickedObservable . clear ( ) ; this . onBeginRenderObservable . clear ( ) ; this . onEndRenderObservable . clear ( ) ; this . onBeginLayoutObservable . clear ( ) ; this . onEndLayoutObservable . clear ( ) ; super . dispose ( ) ; } private _onResize ( ) { let scene = this . getScene ( ) ; if ( ! scene ) { return ; } var engine = scene . getEngine ( ) ; var textureSize = this . getSize ( ) ; var renderWidth = engine . getRenderWidth ( ) * this . _renderScale ; var renderHeight = engine . getRenderHeight ( ) * this . _renderScale ; if ( this . _renderAtIdealSize ) { if ( this . _idealWidth ) { renderHeight = ( renderHeight * this . _idealWidth ) / renderWidth ; renderWidth = this . _idealWidth ; } else if ( this . _idealHeight ) { renderWidth = ( renderWidth * this . _idealHeight ) / renderHeight ; renderHeight = this . _idealHeight ; } } if ( textureSize . width !== renderWidth || textureSize . height !== renderHeight ) { this . scaleTo ( renderWidth , renderHeight ) ; this . markAsDirty ( ) ; if ( this . _idealWidth || this . _idealHeight ) { this . _rootContainer . _markAllAsDirty ( ) ; } } this . invalidateRect ( 0 , 0 , textureSize . width - 1 , textureSize . height - 1 ) ; } hidden public _getGlobalViewport ( ) { var size = this . getSize ( ) ; const globalViewPort = this . _fullscreenViewport . toGlobal ( size . width , size . height ) ; const targetX = Math . round ( globalViewPort . width * ( 1 / this . rootContainer . scaleX ) ) ; const targetY = Math . round ( globalViewPort . height * ( 1 / this . rootContainer . scaleY ) ) ; globalViewPort . x += ( globalViewPort . width - targetX ) / 2 ; globalViewPort . y += ( globalViewPort . height - targetY ) / 2 ; globalViewPort . width = targetX ; globalViewPort . height = targetY ; return globalViewPort ; } param position param worldMatrix returns public getProjectedPosition ( position , worldMatrix ) { const result = this . getProjectedPositionWithZ ( position , worldMatrix ) ; return new Vector2 ( result . x , result . y ) ; } param position param worldMatrix returns public getProjectedPositionWithZ ( position , worldMatrix ) { var scene = this . getScene ( ) ; if ( ! scene ) { return Vector3 . Zero ( ) ; } var globalViewport = this . _getGlobalViewport ( ) ; var projectedPosition = Vector3 . Project ( position , worldMatrix , scene . getTransformMatrix ( ) , globalViewport ) ; return new Vector3 ( projectedPosition . x , projectedPosition . y , projectedPosition . z ) ; } private _checkUpdate ( camera ) { if ( this . _layerToDispose ) { if ( ( camera . layerMask & this . _layerToDispose . layerMask ) === 0 ) { return ; } } if ( this . _isFullscreen && this . _linkedControls . length ) { var scene = this . getScene ( ) ; if ( ! scene ) { return ; } var globalViewport = this . _getGlobalViewport ( ) ; for ( let control of this . _linkedControls ) { if ( ! control . isVisible ) { continue ; } let mesh = control . _linkedMesh as AbstractMesh ; if ( ! mesh || mesh . isDisposed ( ) ) { Tools . SetImmediate ( ( ) => { control . linkWithMesh ( null ) ; } ) ; continue ; } let position = mesh . getBoundingInfo ? mesh . getBoundingInfo ( ) . boundingSphere . center : ( Vector3 . ZeroReadOnly as Vector3 ) ; let projectedPosition = Vector3 . Project ( position , mesh . getWorldMatrix ( ) , scene . getTransformMatrix ( ) , globalViewport ) ; if ( projectedPosition . z < 0 || projectedPosition . z > 1 ) { control . notRenderable = true ; continue ; } control . notRenderable = false ; control . _moveToProjectedPosition ( projectedPosition ) ; } } if ( ! this . _isDirty && ! this . _rootContainer . isDirty ) { return ; } this . _isDirty = false ; this . _render ( ) ; this . update ( this . applyYInversionOnUpdate , this . premulAlpha , AdvancedDynamicTexture . AllowGPUOptimizations ) ; } private _clearMeasure = new Measure ( 0 , 0 , 0 , 0 ) ; private _render ( ) { var textureSize = this . getSize ( ) ; var renderWidth = textureSize . width ; var renderHeight = textureSize . height ; var context = this . getContext ( ) ; context . font = "18px Arial" ; context . strokeStyle = "white" ; this . onBeginLayoutObservable . notifyObservers ( this ) ; var measure = new Measure ( 0 , 0 , renderWidth , renderHeight ) ; this . _numLayoutCalls = 0 ; this . _rootContainer . _layout ( measure , context ) ; this . onEndLayoutObservable . notifyObservers ( this ) ; this . _isDirty = false ; if ( this . _invalidatedRectangle ) { this . _clearMeasure . copyFrom ( this . _invalidatedRectangle ) ; } else { this . _clearMeasure . copyFromFloats ( 0 , 0 , renderWidth , renderHeight ) ; } context . clearRect ( this . _clearMeasure . left , this . _clearMeasure . top , this . _clearMeasure . width , this . _clearMeasure . height ) ; if ( this . _background ) { context . save ( ) ; context . fillStyle = this . _background ; context . fillRect ( this . _clearMeasure . left , this . _clearMeasure . top , this . _clearMeasure . width , this . _clearMeasure . height ) ; context . restore ( ) ; } this . onBeginRenderObservable . notifyObservers ( this ) ; this . _numRenderCalls = 0 ; this . _rootContainer . _render ( context , this . _invalidatedRectangle ) ; this . onEndRenderObservable . notifyObservers ( this ) ; this . _invalidatedRectangle = null ; } hidden public _changeCursor ( cursor ) { if ( this . _rootElement ) { this . _rootElement . style . cursor = cursor ; this . _cursorChanged = true ; } } hidden public _registerLastControlDown ( control , pointerId ) { this . _lastControlDown [ pointerId ] = control ; this . onControlPickedObservable . notifyObservers ( control ) ; } private _doPicking ( x , y , pi , type , pointerId , buttonIndex , deltaX ? , deltaY ? ) { var scene = this . getScene ( ) ; if ( ! scene ) { return ; } var engine = scene . getEngine ( ) ; var textureSize = this . getSize ( ) ; if ( this . _isFullscreen ) { let camera = scene . cameraToUseForPointers || scene . activeCamera ; if ( ! camera ) { return ; } let viewport = camera . viewport ; x = x * ( textureSize . width / ( engine . getRenderWidth ( ) * viewport . width ) ) ; y = y * ( textureSize . height / ( engine . getRenderHeight ( ) * viewport . height ) ) ; } if ( this . _capturingControl [ pointerId ] ) { this . _capturingControl [ pointerId ] . _processObservables ( type , x , y , pi , pointerId , buttonIndex ) ; return ; } this . _cursorChanged = false ; if ( ! this . _rootContainer . _processPicking ( x , y , pi , type , pointerId , buttonIndex , deltaX , deltaY ) ) { if ( ! scene . doNotHandleCursors ) { this . _changeCursor ( "" ) ; } if ( type === PointerEventTypes . POINTERMOVE ) { if ( this . _lastControlOver [ pointerId ] ) { this . _lastControlOver [ pointerId ] . _onPointerOut ( this . _lastControlOver [ pointerId ] , pi ) ; delete this . _lastControlOver [ pointerId ] ; } } } if ( ! this . _cursorChanged && ! scene . doNotHandleCursors ) { this . _changeCursor ( "" ) ; } this . _manageFocus ( ) ; } hidden public _cleanControlAfterRemovalFromList ( list , control ) { for ( var pointerId in list ) { if ( ! list . hasOwnProperty ( pointerId ) ) { continue ; } var lastControlOver = list [ pointerId ] ; if ( lastControlOver === control ) { delete list [ pointerId ] ; } } } hidden public _cleanControlAfterRemoval ( control ) { this . _cleanControlAfterRemovalFromList ( this . _lastControlDown , control ) ; this . _cleanControlAfterRemovalFromList ( this . _lastControlOver , control ) ; } /** Attach to all scene events required to support pointer events */ public attach ( ) { const scene = this . getScene ( ) ; if ( ! scene ) { return ; } let tempViewport = new Viewport ( 0 , 0 , 0 , 0 ) ; this . _pointerMoveObserver = scene . onPrePointerObservable . add ( ( pi , state ) => { if ( scene . isPointerCaptured ( ( < IPointerEvent > pi . event ) . pointerId ) ) { return ; } if ( pi . type !== PointerEventTypes . POINTERMOVE && pi . type !== PointerEventTypes . POINTERUP && pi . type !== PointerEventTypes . POINTERDOWN && pi . type !== PointerEventTypes . POINTERWHEEL ) { return ; } if ( pi . type === PointerEventTypes . POINTERMOVE && ( pi . event as IPointerEvent ) . pointerId ) { this . _defaultMousePointerId = ( pi . event as IPointerEvent ) . pointerId ; } const camera = scene . cameraToUseForPointers || scene . activeCamera ; const engine = scene . getEngine ( ) ; const originalCameraToUseForPointers = scene . cameraToUseForPointers ; if ( ! camera ) { tempViewport . x = 0 ; tempViewport . y = 0 ; tempViewport . width = engine . getRenderWidth ( ) ; tempViewport . height = engine . getRenderHeight ( ) ; } else { if ( camera . rigCameras . length ) { let rigViewport = new Viewport ( 0 , 0 , 1 , 1 ) ; camera . rigCameras . forEach ( ( rigCamera ) => { rigCamera . viewport . toGlobalToRef ( engine . getRenderWidth ( ) , engine . getRenderHeight ( ) , rigViewport ) ; let x = scene . pointerX / engine . getHardwareScalingLevel ( ) - rigViewport . x ; let y = scene . pointerY / engine . getHardwareScalingLevel ( ) - ( engine . getRenderHeight ( ) - rigViewport . y - rigViewport . height ) ; if ( x < 0 || y < 0 || x > rigViewport . width || y > rigViewport . height ) { return ; } scene . cameraToUseForPointers = rigCamera ; tempViewport . x = rigViewport . x ; tempViewport . y = rigViewport . y ; tempViewport . width = rigViewport . width ; tempViewport . height = rigViewport . height ; } ) ; } else { camera . viewport . toGlobalToRef ( engine . getRenderWidth ( ) , engine . getRenderHeight ( ) , tempViewport ) ; } } let x = scene . pointerX / engine . getHardwareScalingLevel ( ) - tempViewport . x ; let y = scene . pointerY / engine . getHardwareScalingLevel ( ) - ( engine . getRenderHeight ( ) - tempViewport . y - tempViewport . height ) ; this . _shouldBlockPointer = false ; let pointerId = ( pi . event as IPointerEvent ) . pointerId || this . _defaultMousePointerId ; this . _doPicking ( x , y , pi , pi . type , pointerId , pi . event . button , ( < IWheelEvent > pi . event ) . deltaX , ( < IWheelEvent > pi . event ) . deltaY ) ; if ( this . _shouldBlockPointer ) { pi . skipOnPointerObservable = this . _shouldBlockPointer ; } scene . cameraToUseForPointers = originalCameraToUseForPointers ; } ) ; this . _attachToOnPointerOut ( scene ) ; this . _attachToOnBlur ( scene ) ; } hidden private onClipboardCopy = ( rawEvt ) => { const evt = rawEvt as ClipboardEvent ; let ev = new ClipboardInfo ( ClipboardEventTypes . COPY , evt ) ; this . onClipboardObservable . notifyObservers ( ev ) ; evt . preventDefault ( ) ; } ; hidden private onClipboardCut = ( rawEvt ) => { const evt = rawEvt as ClipboardEvent ; let ev = new ClipboardInfo ( ClipboardEventTypes . CUT , evt ) ; this . onClipboardObservable . notifyObservers ( ev ) ; evt . preventDefault ( ) ; } ; hidden private onClipboardPaste = ( rawEvt ) => { const evt = rawEvt as ClipboardEvent ; let ev = new ClipboardInfo ( ClipboardEventTypes . PASTE , evt ) ; this . onClipboardObservable . notifyObservers ( ev ) ; evt . preventDefault ( ) ; } ; /**
     * Register the clipboard Events onto the canvas
     */ public registerClipboardEvents ( ) { self . addEventListener ( "copy" , this . onClipboardCopy , false ) ; self . addEventListener ( "cut" , this . onClipboardCut , false ) ; self . addEventListener ( "paste" , this . onClipboardPaste , false ) ; } /**
     * Unregister the clipboard Events from the canvas
     */ public unRegisterClipboardEvents ( ) { self . removeEventListener ( "copy" , this . onClipboardCopy ) ; self . removeEventListener ( "cut" , this . onClipboardCut ) ; self . removeEventListener ( "paste" , this . onClipboardPaste ) ; } param mesh param supportPointerMove public attachToMesh ( mesh , supportPointerMove = true ) { var scene = this . getScene ( ) ; if ( ! scene ) { return ; } this . _pointerObserver = scene . onPointerObservable . add ( ( pi , state ) => { if ( pi . type !== PointerEventTypes . POINTERMOVE && pi . type !== PointerEventTypes . POINTERUP && pi . type !== PointerEventTypes . POINTERDOWN && pi . type !== PointerEventTypes . POINTERWHEEL ) { return ; } if ( pi . type === PointerEventTypes . POINTERMOVE && ( pi . event as IPointerEvent ) . pointerId ) { this . _defaultMousePointerId = ( pi . event as IPointerEvent ) . pointerId ; } var pointerId = ( pi . event as IPointerEvent ) . pointerId || this . _defaultMousePointerId ; if ( pi . pickInfo && pi . pickInfo . hit && pi . pickInfo . pickedMesh === mesh ) { var uv = pi . pickInfo . getTextureCoordinates ( ) ; if ( uv ) { let size = this . getSize ( ) ; this . _doPicking ( uv . x * size . width , ( this . applyYInversionOnUpdate ? 1.0 - uv . y : uv . y ) * size . height , pi , pi . type , pointerId , pi . event . button , ( < IWheelEvent > pi . event ) . deltaX , ( < IWheelEvent > pi . event ) . deltaY ) ; } } else if ( pi . type === PointerEventTypes . POINTERUP ) { if ( this . _lastControlDown [ pointerId ] ) { this . _lastControlDown [ pointerId ] . _forcePointerUp ( pointerId ) ; } delete this . _lastControlDown [ pointerId ] ; if ( this . focusedControl ) { const friendlyControls = this . focusedControl . keepsFocusWith ( ) ; let canMoveFocus = true ; if ( friendlyControls ) { for ( var control of friendlyControls ) { if ( this === control . _host ) { continue ; } const otherHost = control . _host ; if ( otherHost . _lastControlOver [ pointerId ] && otherHost . _lastControlOver [ pointerId ] . isAscendant ( control ) ) { canMoveFocus = false ; break ; } } } if ( canMoveFocus ) { this . focusedControl = null ; } } } else if ( pi . type === PointerEventTypes . POINTERMOVE ) { if ( this . _lastControlOver [ pointerId ] ) { this . _lastControlOver [ pointerId ] . _onPointerOut ( this . _lastControlOver [ pointerId ] , pi , true ) ; } delete this . _lastControlOver [ pointerId ] ; } } ) ; mesh . enablePointerMoveEvents = supportPointerMove ; this . _attachToOnPointerOut ( scene ) ; this . _attachToOnBlur ( scene ) ; } param control public moveFocusToControl ( control ) { this . focusedControl = control ; this . _lastPickedControl = < any > control ; this . _blockNextFocusCheck = true ; } private _manageFocus ( ) { if ( this . _blockNextFocusCheck ) { this . _blockNextFocusCheck = false ; this . _lastPickedControl = < any > this . _focusedControl ; return ; } if ( this . _focusedControl ) { if ( this . _focusedControl !== < any > this . _lastPickedControl ) { if ( this . _lastPickedControl . isFocusInvisible ) { return ; } this . focusedControl = null ; } } } private _attachToOnPointerOut ( scene ) { this . _canvasPointerOutObserver = scene . getEngine ( ) . onCanvasPointerOutObservable . add ( ( pointerEvent ) => { if ( this . _lastControlOver [ pointerEvent . pointerId ] ) { this . _lastControlOver [ pointerEvent . pointerId ] . _onPointerOut ( this . _lastControlOver [ pointerEvent . pointerId ] , null ) ; } delete this . _lastControlOver [ pointerEvent . pointerId ] ; if ( this . _lastControlDown [ pointerEvent . pointerId ] && this . _lastControlDown [ pointerEvent . pointerId ] !== this . _capturingControl [ pointerEvent . pointerId ] ) { this . _lastControlDown [ pointerEvent . pointerId ] . _forcePointerUp ( ) ; delete this . _lastControlDown [ pointerEvent . pointerId ] ; } } ) ; } private _attachToOnBlur ( scene ) { this . _canvasBlurObserver = scene . getEngine ( ) . onCanvasBlurObservable . add ( ( pointerEvent ) => { Object . entries ( this . _lastControlDown ) . forEach ( ( [ key , value ] ) => { value . _onCanvasBlur ( ) ; } ) ; this . focusedControl = null ; this . _lastControlDown = { } ; } ) ; } returns public serializeContent ( ) { const size = this . getSize ( ) ; let serializationObject = { root : { } , width : size . width , height : size . height , } ; this . _rootContainer . serialize ( serializationObject . root ) ; return serializationObject ; } param serializedObject param scaleToSize public parseContent ( serializedObject , scaleToSize ? ) { this . _rootContainer = Control . Parse ( serializedObject . root , this ) as Container ; if ( scaleToSize ) { const width = serializedObject . width ; const height = serializedObject . height ; if ( typeof width === "number" && typeof height === "number" && width >= 0 && height >= 0 ) { this . scaleTo ( width , height ) ; } } } param snippetId param scaleToSize returns public parseFromSnippetAsync ( snippetId , scaleToSize ? ) { if ( snippetId === "_BLANK" ) { return Promise . resolve ( ) ; } return new Promise ( ( resolve , reject ) => { var request = new WebRequest ( ) ; request . addEventListener ( "readystatechange" , ( ) => { if ( request . readyState == 4 ) { if ( request . status == 200 ) { var snippet = JSON . parse ( JSON . parse ( request . responseText ) . jsonPayload ) ; let serializationObject = JSON . parse ( snippet . gui ) ; this . parseContent ( serializationObject , scaleToSize ) ; this . snippetId = snippetId ; resolve ( ) ; } else { reject ( "Unable to load the snippet " + snippetId ) ; } } } ) ; request . open ( "GET" , AdvancedDynamicTexture . SnippetUrl + "/" + snippetId . replace ( /#/g , "/" ) ) ; request . send ( ) ; } ) ; } param url param scaleToSize returns public parseFromURLAsync ( url , scaleToSize ? ) { if ( url === "" ) { return Promise . resolve ( ) ; } return new Promise ( ( resolve , reject ) => { var request = new WebRequest ( ) ; request . addEventListener ( "readystatechange" , ( ) => { if ( request . readyState == 4 ) { if ( request . status == 200 ) { var gui = request . responseText ; let serializationObject = JSON . parse ( gui ) ; this . parseContent ( serializationObject , scaleToSize ) ; resolve ( ) ; } else { reject ( "Unable to load" ) ; } } } ) ; request . open ( "GET" , url ) ; request . send ( ) ; } ) ; } param control1 param control2 returns private static _Overlaps ( control1 , control2 ) { return ! ( control1 . centerX > control2 . centerX + control2 . widthInPixels || control1 . centerX + control1 . widthInPixels < control2 . centerX || control1 . centerY + control1 . heightInPixels < control2 . centerY || control1 . centerY > control2 . centerY + control2 . heightInPixels ) ; } param mesh param width param height param supportPointerMove param onlyAlphaTesting param invertY returns public static CreateForMesh ( mesh , width = 1024 , height = 1024 , supportPointerMove = true , onlyAlphaTesting = false , invertY ? ) { const uniqueId = RandomGUID ( ) ; var result = new AdvancedDynamicTexture ( `AdvancedDynamicTexture for ${ mesh . name } [${ uniqueId }]` , width , height , mesh . getScene ( ) , true , Texture . TRILINEAR_SAMPLINGMODE , invertY ) ; var material = new StandardMaterial ( `AdvancedDynamicTextureMaterial for ${ mesh . name } [${ uniqueId }]` , mesh . getScene ( ) ) ; material . backFaceCulling = false ; material . diffuseColor = Color3 . Black ( ) ; material . specularColor = Color3 . Black ( ) ; if ( onlyAlphaTesting ) { material . diffuseTexture = result ; material . emissiveTexture = result ; result . hasAlpha = true ; } else { material . emissiveTexture = result ; material . opacityTexture = result ; } mesh . material = material ; result . attachToMesh ( mesh , supportPointerMove ) ; return result ; } param mesh param width param height param supportPointerMove param invertY returns public static CreateForMeshTexture ( mesh , width = 1024 , height = 1024 , supportPointerMove = true , invertY ? ) { var result = new AdvancedDynamicTexture ( mesh . name + " AdvancedDynamicTexture" , width , height , mesh . getScene ( ) , true , Texture . TRILINEAR_SAMPLINGMODE , invertY ) ; result . attachToMesh ( mesh , supportPointerMove ) ; return result ; } param name param foreground param scene param sampling param adaptiveScaling returns public static CreateFullscreenUI ( name , foreground = true , scene = null , sampling = Texture . BILINEAR_SAMPLINGMODE , adaptiveScaling = false ) { var result = new AdvancedDynamicTexture ( name , 0 , 0 , scene , false , sampling ) ; const resultScene = result . getScene ( ) ; var layer = new Layer ( name + "_layer" , null , resultScene , ! foreground ) ; layer . texture = result ; result . _layerToDispose = layer ; result . _isFullscreen = true ; if ( adaptiveScaling && resultScene ) { const newScale = 1 / resultScene . getEngine ( ) . getHardwareScalingLevel ( ) ; result . _rootContainer . scaleX = newScale ; result . _rootContainer . scaleY = newScale ; } result . attach ( ) ; return result ; } }