Forráskód Böngészése

Merge branch 'master' of https://github.com/BabylonJS/Babylon.js into msDestiny14/nme

Pamela Wolf 4 éve
szülő
commit
62553675b7
78 módosított fájl, 3789 hozzáadás és 3894 törlés
  1. 4 4
      Playground/src/tools/monacoManager.ts
  2. 3 3
      Viewer/src/managers/sceneManager.ts
  3. 1 1
      Viewer/src/viewer/viewer.ts
  4. 3 3
      Viewer/tests/unit/src/viewer/viewer.ts
  5. 125 143
      dist/preview release/babylon.d.ts
  6. 1 1
      dist/preview release/babylon.js
  7. 407 294
      dist/preview release/babylon.max.js
  8. 1 1
      dist/preview release/babylon.max.js.map
  9. 250 298
      dist/preview release/babylon.module.d.ts
  10. 125 143
      dist/preview release/documentation.d.ts
  11. 48 48
      dist/preview release/gui/babylon.gui.js
  12. 1 1
      dist/preview release/gui/babylon.gui.js.map
  13. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.js
  14. 12 13
      dist/preview release/inspector/babylon.inspector.bundle.max.js
  15. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.max.js.map
  16. 2 2
      dist/preview release/loaders/babylon.glTF1FileLoader.js
  17. 1 1
      dist/preview release/loaders/babylon.glTF1FileLoader.js.map
  18. 2 2
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  19. 2 2
      dist/preview release/loaders/babylon.glTFFileLoader.js
  20. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.js.map
  21. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  22. 2 2
      dist/preview release/loaders/babylonjs.loaders.js
  23. 1 1
      dist/preview release/loaders/babylonjs.loaders.js.map
  24. 1 1
      dist/preview release/loaders/babylonjs.loaders.min.js
  25. 1 1
      dist/preview release/nodeEditor/babylon.nodeEditor.js
  26. 6 3
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js
  27. 1 1
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map
  28. 1 1
      dist/preview release/packagesSizeBaseLine.json
  29. 250 298
      dist/preview release/viewer/babylon.module.d.ts
  30. 38 38
      dist/preview release/viewer/babylon.viewer.js
  31. 4 4
      dist/preview release/viewer/babylon.viewer.max.js
  32. 3 0
      dist/preview release/what's new.md
  33. 21 23
      inspector/src/components/sceneExplorer/entities/cameraTreeItemComponent.tsx
  34. 2 2
      loaders/src/glTF/1.0/glTFLoader.ts
  35. 1 1
      materialsLibrary/index.html
  36. 69 60
      nodeEditor/src/components/preview/previewManager.ts
  37. 119 122
      postProcessLibrary/index.html
  38. 1 1
      proceduralTexturesLibrary/index.html
  39. 58 57
      sandbox/src/components/renderingZone.tsx
  40. 16 0
      src/Audio/sound.ts
  41. 4 5
      src/Behaviors/Meshes/pointerDragBehavior.ts
  42. 4 5
      src/Behaviors/Meshes/sixDofDragBehavior.ts
  43. 19 30
      src/Cameras/Inputs/BaseCameraMouseWheelInput.ts
  44. 9 7
      src/Cameras/Inputs/BaseCameraPointersInput.ts
  45. 2 4
      src/Cameras/Inputs/arcRotateCameraGamepadInput.ts
  46. 13 24
      src/Cameras/Inputs/arcRotateCameraKeyboardMoveInput.ts
  47. 6 5
      src/Cameras/Inputs/arcRotateCameraMouseWheelInput.ts
  48. 5 6
      src/Cameras/Inputs/arcRotateCameraVRDeviceOrientationInput.ts
  49. 4 4
      src/Cameras/Inputs/flyCameraKeyboardInput.ts
  50. 5 6
      src/Cameras/Inputs/flyCameraMouseInput.ts
  51. 4 4
      src/Cameras/Inputs/followCameraKeyboardMoveInput.ts
  52. 5 5
      src/Cameras/Inputs/followCameraMouseWheelInput.ts
  53. 2 5
      src/Cameras/Inputs/freeCameraDeviceOrientationInput.ts
  54. 2 5
      src/Cameras/Inputs/freeCameraGamepadInput.ts
  55. 4 4
      src/Cameras/Inputs/freeCameraKeyboardMoveInput.ts
  56. 32 25
      src/Cameras/Inputs/freeCameraMouseInput.ts
  57. 19 19
      src/Cameras/Inputs/freeCameraTouchInput.ts
  58. 2 6
      src/Cameras/Inputs/freeCameraVirtualJoystickInput.ts
  59. 3 3
      src/Cameras/VR/vrExperienceHelper.ts
  60. 8 11
      src/Cameras/VR/webVRCamera.ts
  61. 29 29
      src/Cameras/arcRotateCamera.ts
  62. 2 4
      src/Cameras/camera.ts
  63. 36 31
      src/Cameras/cameraInputsManager.ts
  64. 6 6
      src/Cameras/flyCamera.ts
  65. 5 6
      src/Cameras/followCamera.ts
  66. 6 6
      src/Cameras/freeCamera.ts
  67. 29 23
      src/DeviceInput/InputDevices/deviceSourceManager.ts
  68. 84 18
      src/DeviceInput/deviceInputSystem.ts
  69. 2 2
      src/Helpers/sceneHelpers.ts
  70. 150 107
      src/Misc/tools.ts
  71. 23 4
      src/XR/features/WebXRPlaneDetector.ts
  72. 1 0
      src/XR/features/index.ts
  73. 1 1
      src/XR/webXRDefaultExperience.ts
  74. 8 0
      src/XR/webXREnterExitUI.ts
  75. 3 3
      src/scene.ts
  76. 1 1
      tests/es6Modules/minGridMaterial.ts
  77. 2 2
      tests/es6Modules/minStandardMaterial.ts
  78. 1662 1888
      tests/unit/babylon/src/Cameras/babylon.pointerInput.tests.ts

+ 4 - 4
Playground/src/tools/monacoManager.ts

@@ -136,7 +136,7 @@ var createScene = function() {
     camera.setTarget(BABYLON.Vector3.Zero());
 
     // This attaches the camera to the canvas
-    camera.attachControl(canvas, true);
+    camera.attachControl(true);
 
     return scene;
 };`);
@@ -155,7 +155,7 @@ class Playground {
         camera.setTarget(BABYLON.Vector3.Zero());
 
         // This attaches the camera to the canvas
-        camera.attachControl(canvas, true);
+        camera.attachControl(true);
 
         return scene;
     }
@@ -287,7 +287,7 @@ class Playground {
     camera.setTarget(BABYLON.Vector3.Zero());
 
     // This attaches the camera to the canvas
-    camera.attachControl(canvas, true);
+    camera.attachControl(true);
 
     // This creates a light, aiming 0,1,0 - to the sky (non-mesh)
     var light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
@@ -320,7 +320,7 @@ class Playground {
         camera.setTarget(BABYLON.Vector3.Zero());
 
         // This attaches the camera to the canvas
-        camera.attachControl(canvas, true);
+        camera.attachControl(true);
 
         // This creates a light, aiming 0,1,0 - to the sky (non-mesh)
         var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene);

+ 3 - 3
Viewer/src/managers/sceneManager.ts

@@ -670,9 +670,9 @@ export class SceneManager {
 
         if (canvas) {
             if (this.camera && sceneConfig.disableCameraControl) {
-                this.camera.detachControl(canvas);
+                this.camera.detachControl();
             } else if (this.camera && sceneConfig.disableCameraControl === false) {
-                this.camera.attachControl(canvas);
+                this.camera.attachControl();
             }
         }
 
@@ -925,7 +925,7 @@ export class SceneManager {
             }
             let canvas = this.scene.getEngine().getInputElement();
             if (canvas) {
-                this.scene.activeCamera.attachControl(canvas);
+                this.scene.activeCamera.attachControl();
             }
 
             this.camera = <ArcRotateCamera>this.scene.activeCamera!;

+ 1 - 1
Viewer/src/viewer/viewer.ts

@@ -561,7 +561,7 @@ export abstract class AbstractViewer {
 
         if (this.sceneManager) {
             if (this.sceneManager.scene && this.sceneManager.scene.activeCamera) {
-                this.sceneManager.scene.activeCamera.detachControl(this.canvas);
+                this.sceneManager.scene.activeCamera.detachControl();
             }
             this.sceneManager.dispose();
         }

+ 3 - 3
Viewer/tests/unit/src/viewer/viewer.ts

@@ -192,19 +192,19 @@ describe('Viewer', function() {
     it('should attach and detach camera control correctly', (done) => {
         let viewer = Helper.getNewViewerInstance();
         viewer.onInitDoneObservable.add(() => {
-            assert.isDefined(viewer.sceneManager.camera.inputs.attachedElement, "Camera is not attached per default");
+            assert.isTrue(viewer.sceneManager.camera.inputs.attachedToElement, "Camera is not attached per default");
             viewer.updateConfiguration({
                 scene: {
                     disableCameraControl: true
                 }
             });
-            assert.isNull(viewer.sceneManager.camera.inputs.attachedElement, "Camera is still attached");
+            assert.isFalse(viewer.sceneManager.camera.inputs.attachedToElement, "Camera is still attached");
             viewer.updateConfiguration({
                 scene: {
                     disableCameraControl: false
                 }
             });
-            assert.isDefined(viewer.sceneManager.camera.inputs.attachedElement, "Camera not attached");
+            assert.isTrue(viewer.sceneManager.camera.inputs.attachedToElement, "Camera not attached");
             viewer.dispose();
             done();
         });

+ 125 - 143
dist/preview release/babylon.d.ts

@@ -6407,15 +6407,13 @@ declare module BABYLON {
         getSimpleName(): string;
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Update the current camera state depending on the inputs that have been used this frame.
          * This is a dynamically created lambda to avoid the performance penalty of looping for inputs in the render loop.
@@ -6449,7 +6447,7 @@ declare module BABYLON {
          * Defines the dom element the camera is collecting inputs from.
          * This is null if the controls have not been attached.
          */
-        attachedElement: Nullable<HTMLElement>;
+        attachedToElement: boolean;
         /**
          * Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
@@ -6497,13 +6495,13 @@ declare module BABYLON {
          * @param element Defines the dom element to collect the events from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachElement(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachElement(noPreventDefault?: boolean): void;
         /**
          * Detach the current manager inputs controls from a specific dom element.
          * @param element Defines the dom element to collect the events from
          * @param disconnect Defines whether the input should be removed from the current list of attached inputs
          */
-        detachElement(element: HTMLElement, disconnect?: boolean): void;
+        detachElement(disconnect?: boolean): void;
         /**
          * Rebuild the dynamic inputCheck function from the current list of
          * defined inputs in the manager.
@@ -18802,15 +18800,13 @@ declare module BABYLON {
         private _scene;
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Update the current camera state depending on the inputs that have been used this frame.
          * This is a dynamically created lambda to avoid the performance penalty of looping for inputs in the render loop.
@@ -19010,10 +19006,9 @@ declare module BABYLON {
         touchEnabled?: boolean);
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Called on JS contextmenu event.
          * Override this method to provide functionality.
@@ -19021,9 +19016,8 @@ declare module BABYLON {
         protected onContextMenu(evt: PointerEvent): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Gets the class name of the current intput.
          * @returns the class name
@@ -19074,17 +19068,15 @@ declare module BABYLON {
         private _observer;
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls
          *   should call preventdefault().
          *   (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Called for each rendered frame.
          */
@@ -19303,7 +19295,7 @@ declare module BABYLON {
         private _offsetX;
         private _offsetY;
         private _pointerPressed;
-        private _pointerInput;
+        private _pointerInput?;
         private _observer;
         private _onLostFocus;
         /**
@@ -19318,15 +19310,14 @@ declare module BABYLON {
         allowMouse?: boolean);
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach the current controls from the specified dom element.
          * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Update the current camera state depending on the inputs that have been used this frame.
          * This is a dynamically created lambda to avoid the performance penalty of looping for inputs in the render loop.
@@ -19498,16 +19489,14 @@ declare module BABYLON {
         constructor(name: string, position: Vector3, scene: Scene, setActiveOnSceneIfNoneActive?: boolean);
         /**
          * Attached controls to the current camera.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach the current controls from the camera.
          * The camera will stop reacting to inputs.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: HTMLElement): void;
+        detachControl(): void;
         private _collisionMask;
         /**
          * Define a collision mask to limit the list of object the camera can collide with
@@ -20535,7 +20524,6 @@ declare module BABYLON {
          * @param poseData Pose coming from the device
          */
         updateFromDevice(poseData: DevicePose): void;
-        private _htmlElementAttached;
         private _detachIfAttached;
         /**
          * WebVR's attach control will start broadcasting frames to the device.
@@ -20543,16 +20531,13 @@ declare module BABYLON {
          * within a user-interaction callback. Example:
          * <pre> scene.onPointerDown = function() { camera.attachControl(canvas); }</pre>
          *
-         * @param element html element to attach the vrDevice to
          * @param noPreventDefault prevent the default html element operation when attaching the vrDevice
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detaches the camera from the html element and disables VR
-         *
-         * @param element html element to detach from
          */
-        detachControl(element: HTMLElement): void;
+        detachControl(): void;
         /**
          * @returns the name of this class
          */
@@ -34211,15 +34196,13 @@ declare module BABYLON {
         _isSynchronizedProjectionMatrix(): boolean;
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: HTMLElement): void;
+        detachControl(): void;
         /**
          * Update the camera state according to the different inputs gathered during the frame.
          */
@@ -41711,14 +41694,14 @@ declare module BABYLON {
         static get PreprocessUrl(): (url: string) => string;
         static set PreprocessUrl(processor: (url: string) => string);
         /**
-        * Loads an image as an HTMLImageElement.
-        * @param input url string, ArrayBuffer, or Blob to load
-        * @param onLoad callback called when the image successfully loads
-        * @param onError callback called when the image fails to load
-        * @param offlineProvider offline provider for caching
-        * @param mimeType optional mime type
-        * @returns the HTMLImageElement of the loaded image
-        */
+         * Loads an image as an HTMLImageElement.
+         * @param input url string, ArrayBuffer, or Blob to load
+         * @param onLoad callback called when the image successfully loads
+         * @param onError callback called when the image fails to load
+         * @param offlineProvider offline provider for caching
+         * @param mimeType optional mime type
+         * @returns the HTMLImageElement of the loaded image
+         */
         static LoadImage(input: string | ArrayBuffer | Blob, onLoad: (img: HTMLImageElement | ImageBitmap) => void, onError: (message?: string, exception?: any) => void, offlineProvider: Nullable<IOfflineProvider>, mimeType?: string): Nullable<HTMLImageElement>;
         /**
          * Loads a file from a url
@@ -41854,6 +41837,14 @@ declare module BABYLON {
          */
         static Download(blob: Blob, fileName: string): void;
         /**
+         * Will return the right value of the noPreventDefault variable
+         * Needed to keep backwards compatibility to the old API.
+         *
+         * @param args arguments passed to the attachControl function
+         * @returns the correct value for noPreventDefault
+         */
+        static BackCompatCameraNoPreventDefault(args: IArguments): boolean;
+        /**
          * Captures a screenshot of the current rendering
          * @see https://doc.babylonjs.com/how_to/render_scene_on_a_png
          * @param engine defines the rendering engine
@@ -41933,16 +41924,16 @@ declare module BABYLON {
          */
         static RandomId(): string;
         /**
-        * Test if the given uri is a base64 string
-        * @param uri The uri to test
-        * @return True if the uri is a base64 string or false otherwise
-        */
+         * Test if the given uri is a base64 string
+         * @param uri The uri to test
+         * @return True if the uri is a base64 string or false otherwise
+         */
         static IsBase64(uri: string): boolean;
         /**
-        * Decode the given base64 uri.
-        * @param uri The uri to decode
-        * @return The decoded base64 data.
-        */
+         * Decode the given base64 uri.
+         * @param uri The uri to decode
+         * @return The decoded base64 data.
+         */
         static DecodeBase64(uri: string): ArrayBuffer;
         /**
          * Gets the absolute url.
@@ -44946,6 +44937,10 @@ declare module BABYLON {
          * Observable event when the current playing sound finishes.
          */
         onEndedObservable: Observable<Sound>;
+        /**
+         * Gets the current time for the sound.
+         */
+        get currentTime(): number;
         private _panningModel;
         private _playbackRate;
         private _streaming;
@@ -45868,12 +45863,11 @@ declare module BABYLON {
          * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Gets the class name of the current input.
          * @returns the class name
@@ -46082,15 +46076,13 @@ declare module BABYLON {
         private _scene;
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Update the current camera state depending on the inputs that have been used this frame.
          * This is a dynamically created lambda to avoid the performance penalty of looping for inputs in the render loop.
@@ -46132,15 +46124,13 @@ declare module BABYLON {
         private computeDeltaFromMouseWheelLegacyEvent;
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Gets the class name of the current intput.
          * @returns the class name
@@ -46506,18 +46496,16 @@ declare module BABYLON {
         _isSynchronizedViewMatrix(): boolean;
         /**
          * Attached controls to the current camera.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          * @param useCtrlForPanning  Defines whether ctrl is used for paning within the controls
          * @param panningMouseButton Defines whether panning is allowed through mouse click button
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean, useCtrlForPanning?: boolean, panningMouseButton?: number): void;
+        attachControl(noPreventDefault?: boolean, useCtrlForPanning?: boolean, panningMouseButton?: number): void;
         /**
          * Detach the current controls from the camera.
          * The camera will stop reacting to inputs.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: HTMLElement): void;
+        detachControl(): void;
         /** @hidden */
         _checkInputs(): void;
         protected _checkLimits(): void;
@@ -47329,15 +47317,13 @@ declare module BABYLON {
         private _onGamepadDisconnectedObserver;
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
-         * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(): void;
         /**
          * Detach the current controls from the specified dom element.
          * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Update the current camera state depending on the inputs that have been used this frame.
          * This is a dynamically created lambda to avoid the performance penalty of looping for inputs in the render loop.
@@ -47390,10 +47376,9 @@ declare module BABYLON {
         constructor();
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /** @hidden */
         _onOrientationEvent(evt: DeviceOrientationEvent): void;
         /**
@@ -47403,9 +47388,8 @@ declare module BABYLON {
         checkInputs(): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Gets the class name of the current intput.
          * @returns the class name
@@ -47474,15 +47458,13 @@ declare module BABYLON {
         constructor(touchEnabled?: boolean);
         /**
          * Attach the mouse control to the HTML DOM element.
-         * @param element Defines the element that listens to the input events.
          * @param noPreventDefault Defines whether events caught by the controls should call preventdefault().
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Gets the class name of the current input.
          * @returns the class name.
@@ -47667,16 +47649,14 @@ declare module BABYLON {
         constructor(name: string, position: Vector3, scene: Scene, setActiveOnSceneIfNoneActive?: boolean);
         /**
          * Attach a control to the HTML DOM element.
-         * @param element Defines the element that listens to the input events.
          * @param noPreventDefault Defines whether events caught by the controls should call preventdefault(). https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach a control from the HTML DOM element.
          * The camera will stop reacting to that input.
-         * @param element Defines the element that listens to the input events.
          */
-        detachControl(element: HTMLElement): void;
+        detachControl(): void;
         private _collisionMask;
         /**
          * Get the mask that the camera ignores in collision events.
@@ -47754,15 +47734,13 @@ declare module BABYLON {
         private _scene;
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Gets the class name of the current intput.
          * @returns the class name
@@ -47818,15 +47796,13 @@ declare module BABYLON {
         private _observer;
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Gets the class name of the current intput.
          * @returns the class name
@@ -48038,16 +48014,14 @@ declare module BABYLON {
         private _follow;
         /**
          * Attached controls to the current camera.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach the current controls from the camera.
          * The camera will stop reacting to inputs.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: HTMLElement): void;
+        detachControl(): void;
         /** @hidden */
         _checkInputs(): void;
         private _checkLimits;
@@ -48193,15 +48167,13 @@ declare module BABYLON {
         private _scene;
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Update the current camera state depending on the inputs that have been used this frame.
          * This is a dynamically created lambda to avoid the performance penalty of looping for inputs in the render loop.
@@ -48281,17 +48253,14 @@ declare module BABYLON {
         set camera(camera: FreeCamera);
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
-         * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(): void;
         private _orientationChanged;
         private _deviceOrientation;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Update the current camera state depending on the inputs that have been used this frame.
          * This is a dynamically created lambda to avoid the performance penalty of looping for inputs in the render loop.
@@ -48347,15 +48316,12 @@ declare module BABYLON {
         private _vector2;
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
-         * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Update the current camera state depending on the inputs that have been used this frame.
          * This is a dynamically created lambda to avoid the performance penalty of looping for inputs in the render loop.
@@ -48612,15 +48578,12 @@ declare module BABYLON {
         checkInputs(): void;
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
-         * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Gets the class name of the current intput.
          * @returns the class name
@@ -52462,6 +52425,10 @@ declare module BABYLON {
          * A list of optional features to init the session with
          */
         requiredFeatures?: string[];
+        /**
+         * If defined, this function will be executed if the UI encounters an error when entering XR
+         */
+        onError?: (error: any) => void;
     }
     /**
      * UI to allow the user to enter/exit XR mode
@@ -54971,9 +54938,15 @@ declare module BABYLON {
      */
     export class DeviceInputSystem implements IDisposable {
         /**
-         * Callback to be triggered when a device is connected
+         * Returns onDeviceConnected callback property
+         * @returns Callback with function to execute when a device is connected
          */
-        onDeviceConnected: (deviceType: DeviceType, deviceSlot: number) => void;
+        get onDeviceConnected(): (deviceType: DeviceType, deviceSlot: number) => void;
+        /**
+         * Sets callback function when a device is connected and executes against all connected devices
+         * @param callback Function to execute when a device is connected
+         */
+        set onDeviceConnected(callback: (deviceType: DeviceType, deviceSlot: number) => void);
         /**
          * Callback to be triggered when a device is disconnected
          */
@@ -54994,6 +54967,7 @@ declare module BABYLON {
         private _pointerUpEvent;
         private _gamepadConnectedEvent;
         private _gamepadDisconnectedEvent;
+        private _onDeviceConnected;
         private static _MAX_KEYCODES;
         private static _MAX_POINTER_INPUTS;
         private constructor();
@@ -55022,6 +54996,24 @@ declare module BABYLON {
          */
         dispose(): void;
         /**
+         * Checks for existing connections to devices and register them, if necessary
+         * Currently handles gamepads and mouse
+         */
+        private _checkForConnectedDevices;
+        /**
+         * Add a gamepad to the DeviceInputSystem
+         * @param gamepad A single DOM Gamepad object
+         */
+        private _addGamePad;
+        /**
+         * Add pointer device to DeviceInputSystem
+         * @param deviceType Type of Pointer to add
+         * @param deviceSlot Pointer ID (0 for mouse, pointerId for Touch)
+         * @param currentX Current X at point of adding
+         * @param currentY Current Y at point of adding
+         */
+        private _addPointerDevice;
+        /**
          * Add device and inputs to device array
          * @param deviceType Enum specifiying device type
          * @param deviceSlot "Slot" or index that device is referenced in
@@ -55108,33 +55100,13 @@ declare module BABYLON {
      */
     export class DeviceSourceManager implements IDisposable {
         /**
-         * Observable to be triggered when before a device is connected
+         * Observable to be triggered when after a device is connected, any new observers added will be triggered against already connected devices
          */
-        readonly onBeforeDeviceConnectedObservable: Observable<{
-            deviceType: DeviceType;
-            deviceSlot: number;
-        }>;
-        /**
-         * Observable to be triggered when before a device is disconnected
-         */
-        readonly onBeforeDeviceDisconnectedObservable: Observable<{
-            deviceType: DeviceType;
-            deviceSlot: number;
-        }>;
-        /**
-         * Observable to be triggered when after a device is connected
-         */
-        readonly onAfterDeviceConnectedObservable: Observable<{
-            deviceType: DeviceType;
-            deviceSlot: number;
-        }>;
+        readonly onDeviceConnectedObservable: Observable<DeviceSource<DeviceType>>;
         /**
          * Observable to be triggered when after a device is disconnected
          */
-        readonly onAfterDeviceDisconnectedObservable: Observable<{
-            deviceType: DeviceType;
-            deviceSlot: number;
-        }>;
+        readonly onDeviceDisconnectedObservable: Observable<DeviceSource<DeviceType>>;
         private readonly _devices;
         private readonly _firstDevice;
         private readonly _deviceInputSystem;
@@ -55157,6 +55129,11 @@ declare module BABYLON {
          */
         getDeviceSources<T extends DeviceType>(deviceType: T): ReadonlyArray<DeviceSource<T>>;
         /**
+         * Returns a read-only list of all available devices
+         * @returns Read-only array with active devices
+         */
+        getDevices(): ReadonlyArray<DeviceSource<DeviceType>>;
+        /**
          * Dispose of DeviceInputSystem and other parts
          */
         dispose(): void;
@@ -72862,9 +72839,9 @@ declare module BABYLON {
          */
         onAfterBoxRenderingObservable: Observable<BoundingBox>;
         /**
-         * Observable raised after ressources are created
+         * Observable raised after resources are created
          */
-        onRessourcesReadyObservable: Observable<BoundingBoxRenderer>;
+        onResourcesReadyObservable: Observable<BoundingBoxRenderer>;
         /**
          * When false, no bounding boxes will be rendered
          */
@@ -72889,7 +72866,7 @@ declare module BABYLON {
         register(): void;
         private _evaluateSubMesh;
         private _preActiveMesh;
-        private _prepareRessources;
+        private _prepareResources;
         private _createIndexBuffer;
         /**
          * Rebuilds the elements related to this component in case of
@@ -76045,6 +76022,11 @@ declare module BABYLON {
          * Dispose this feature and all of the resources attached
          */
         dispose(): void;
+        /**
+         * Check if the needed objects are defined.
+         * This does not mean that the feature is enabled, but that the objects needed are well defined.
+         */
+        isCompatible(): boolean;
         protected _onXRFrame(frame: XRFrame): void;
         private _init;
         private _updatePlaneWithXRPlane;

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
dist/preview release/babylon.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 407 - 294
dist/preview release/babylon.max.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
dist/preview release/babylon.max.js.map


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 250 - 298
dist/preview release/babylon.module.d.ts


+ 125 - 143
dist/preview release/documentation.d.ts

@@ -6407,15 +6407,13 @@ declare module BABYLON {
         getSimpleName(): string;
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Update the current camera state depending on the inputs that have been used this frame.
          * This is a dynamically created lambda to avoid the performance penalty of looping for inputs in the render loop.
@@ -6449,7 +6447,7 @@ declare module BABYLON {
          * Defines the dom element the camera is collecting inputs from.
          * This is null if the controls have not been attached.
          */
-        attachedElement: Nullable<HTMLElement>;
+        attachedToElement: boolean;
         /**
          * Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
@@ -6497,13 +6495,13 @@ declare module BABYLON {
          * @param element Defines the dom element to collect the events from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachElement(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachElement(noPreventDefault?: boolean): void;
         /**
          * Detach the current manager inputs controls from a specific dom element.
          * @param element Defines the dom element to collect the events from
          * @param disconnect Defines whether the input should be removed from the current list of attached inputs
          */
-        detachElement(element: HTMLElement, disconnect?: boolean): void;
+        detachElement(disconnect?: boolean): void;
         /**
          * Rebuild the dynamic inputCheck function from the current list of
          * defined inputs in the manager.
@@ -18802,15 +18800,13 @@ declare module BABYLON {
         private _scene;
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Update the current camera state depending on the inputs that have been used this frame.
          * This is a dynamically created lambda to avoid the performance penalty of looping for inputs in the render loop.
@@ -19010,10 +19006,9 @@ declare module BABYLON {
         touchEnabled?: boolean);
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Called on JS contextmenu event.
          * Override this method to provide functionality.
@@ -19021,9 +19016,8 @@ declare module BABYLON {
         protected onContextMenu(evt: PointerEvent): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Gets the class name of the current intput.
          * @returns the class name
@@ -19074,17 +19068,15 @@ declare module BABYLON {
         private _observer;
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls
          *   should call preventdefault().
          *   (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Called for each rendered frame.
          */
@@ -19303,7 +19295,7 @@ declare module BABYLON {
         private _offsetX;
         private _offsetY;
         private _pointerPressed;
-        private _pointerInput;
+        private _pointerInput?;
         private _observer;
         private _onLostFocus;
         /**
@@ -19318,15 +19310,14 @@ declare module BABYLON {
         allowMouse?: boolean);
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach the current controls from the specified dom element.
          * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Update the current camera state depending on the inputs that have been used this frame.
          * This is a dynamically created lambda to avoid the performance penalty of looping for inputs in the render loop.
@@ -19498,16 +19489,14 @@ declare module BABYLON {
         constructor(name: string, position: Vector3, scene: Scene, setActiveOnSceneIfNoneActive?: boolean);
         /**
          * Attached controls to the current camera.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach the current controls from the camera.
          * The camera will stop reacting to inputs.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: HTMLElement): void;
+        detachControl(): void;
         private _collisionMask;
         /**
          * Define a collision mask to limit the list of object the camera can collide with
@@ -20535,7 +20524,6 @@ declare module BABYLON {
          * @param poseData Pose coming from the device
          */
         updateFromDevice(poseData: DevicePose): void;
-        private _htmlElementAttached;
         private _detachIfAttached;
         /**
          * WebVR's attach control will start broadcasting frames to the device.
@@ -20543,16 +20531,13 @@ declare module BABYLON {
          * within a user-interaction callback. Example:
          * <pre> scene.onPointerDown = function() { camera.attachControl(canvas); }</pre>
          *
-         * @param element html element to attach the vrDevice to
          * @param noPreventDefault prevent the default html element operation when attaching the vrDevice
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detaches the camera from the html element and disables VR
-         *
-         * @param element html element to detach from
          */
-        detachControl(element: HTMLElement): void;
+        detachControl(): void;
         /**
          * @returns the name of this class
          */
@@ -34211,15 +34196,13 @@ declare module BABYLON {
         _isSynchronizedProjectionMatrix(): boolean;
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: HTMLElement): void;
+        detachControl(): void;
         /**
          * Update the camera state according to the different inputs gathered during the frame.
          */
@@ -41711,14 +41694,14 @@ declare module BABYLON {
         static get PreprocessUrl(): (url: string) => string;
         static set PreprocessUrl(processor: (url: string) => string);
         /**
-        * Loads an image as an HTMLImageElement.
-        * @param input url string, ArrayBuffer, or Blob to load
-        * @param onLoad callback called when the image successfully loads
-        * @param onError callback called when the image fails to load
-        * @param offlineProvider offline provider for caching
-        * @param mimeType optional mime type
-        * @returns the HTMLImageElement of the loaded image
-        */
+         * Loads an image as an HTMLImageElement.
+         * @param input url string, ArrayBuffer, or Blob to load
+         * @param onLoad callback called when the image successfully loads
+         * @param onError callback called when the image fails to load
+         * @param offlineProvider offline provider for caching
+         * @param mimeType optional mime type
+         * @returns the HTMLImageElement of the loaded image
+         */
         static LoadImage(input: string | ArrayBuffer | Blob, onLoad: (img: HTMLImageElement | ImageBitmap) => void, onError: (message?: string, exception?: any) => void, offlineProvider: Nullable<IOfflineProvider>, mimeType?: string): Nullable<HTMLImageElement>;
         /**
          * Loads a file from a url
@@ -41854,6 +41837,14 @@ declare module BABYLON {
          */
         static Download(blob: Blob, fileName: string): void;
         /**
+         * Will return the right value of the noPreventDefault variable
+         * Needed to keep backwards compatibility to the old API.
+         *
+         * @param args arguments passed to the attachControl function
+         * @returns the correct value for noPreventDefault
+         */
+        static BackCompatCameraNoPreventDefault(args: IArguments): boolean;
+        /**
          * Captures a screenshot of the current rendering
          * @see https://doc.babylonjs.com/how_to/render_scene_on_a_png
          * @param engine defines the rendering engine
@@ -41933,16 +41924,16 @@ declare module BABYLON {
          */
         static RandomId(): string;
         /**
-        * Test if the given uri is a base64 string
-        * @param uri The uri to test
-        * @return True if the uri is a base64 string or false otherwise
-        */
+         * Test if the given uri is a base64 string
+         * @param uri The uri to test
+         * @return True if the uri is a base64 string or false otherwise
+         */
         static IsBase64(uri: string): boolean;
         /**
-        * Decode the given base64 uri.
-        * @param uri The uri to decode
-        * @return The decoded base64 data.
-        */
+         * Decode the given base64 uri.
+         * @param uri The uri to decode
+         * @return The decoded base64 data.
+         */
         static DecodeBase64(uri: string): ArrayBuffer;
         /**
          * Gets the absolute url.
@@ -44946,6 +44937,10 @@ declare module BABYLON {
          * Observable event when the current playing sound finishes.
          */
         onEndedObservable: Observable<Sound>;
+        /**
+         * Gets the current time for the sound.
+         */
+        get currentTime(): number;
         private _panningModel;
         private _playbackRate;
         private _streaming;
@@ -45868,12 +45863,11 @@ declare module BABYLON {
          * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Gets the class name of the current input.
          * @returns the class name
@@ -46082,15 +46076,13 @@ declare module BABYLON {
         private _scene;
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Update the current camera state depending on the inputs that have been used this frame.
          * This is a dynamically created lambda to avoid the performance penalty of looping for inputs in the render loop.
@@ -46132,15 +46124,13 @@ declare module BABYLON {
         private computeDeltaFromMouseWheelLegacyEvent;
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Gets the class name of the current intput.
          * @returns the class name
@@ -46506,18 +46496,16 @@ declare module BABYLON {
         _isSynchronizedViewMatrix(): boolean;
         /**
          * Attached controls to the current camera.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          * @param useCtrlForPanning  Defines whether ctrl is used for paning within the controls
          * @param panningMouseButton Defines whether panning is allowed through mouse click button
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean, useCtrlForPanning?: boolean, panningMouseButton?: number): void;
+        attachControl(noPreventDefault?: boolean, useCtrlForPanning?: boolean, panningMouseButton?: number): void;
         /**
          * Detach the current controls from the camera.
          * The camera will stop reacting to inputs.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: HTMLElement): void;
+        detachControl(): void;
         /** @hidden */
         _checkInputs(): void;
         protected _checkLimits(): void;
@@ -47329,15 +47317,13 @@ declare module BABYLON {
         private _onGamepadDisconnectedObserver;
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
-         * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(): void;
         /**
          * Detach the current controls from the specified dom element.
          * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Update the current camera state depending on the inputs that have been used this frame.
          * This is a dynamically created lambda to avoid the performance penalty of looping for inputs in the render loop.
@@ -47390,10 +47376,9 @@ declare module BABYLON {
         constructor();
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /** @hidden */
         _onOrientationEvent(evt: DeviceOrientationEvent): void;
         /**
@@ -47403,9 +47388,8 @@ declare module BABYLON {
         checkInputs(): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Gets the class name of the current intput.
          * @returns the class name
@@ -47474,15 +47458,13 @@ declare module BABYLON {
         constructor(touchEnabled?: boolean);
         /**
          * Attach the mouse control to the HTML DOM element.
-         * @param element Defines the element that listens to the input events.
          * @param noPreventDefault Defines whether events caught by the controls should call preventdefault().
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Gets the class name of the current input.
          * @returns the class name.
@@ -47667,16 +47649,14 @@ declare module BABYLON {
         constructor(name: string, position: Vector3, scene: Scene, setActiveOnSceneIfNoneActive?: boolean);
         /**
          * Attach a control to the HTML DOM element.
-         * @param element Defines the element that listens to the input events.
          * @param noPreventDefault Defines whether events caught by the controls should call preventdefault(). https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach a control from the HTML DOM element.
          * The camera will stop reacting to that input.
-         * @param element Defines the element that listens to the input events.
          */
-        detachControl(element: HTMLElement): void;
+        detachControl(): void;
         private _collisionMask;
         /**
          * Get the mask that the camera ignores in collision events.
@@ -47754,15 +47734,13 @@ declare module BABYLON {
         private _scene;
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Gets the class name of the current intput.
          * @returns the class name
@@ -47818,15 +47796,13 @@ declare module BABYLON {
         private _observer;
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Gets the class name of the current intput.
          * @returns the class name
@@ -48038,16 +48014,14 @@ declare module BABYLON {
         private _follow;
         /**
          * Attached controls to the current camera.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach the current controls from the camera.
          * The camera will stop reacting to inputs.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: HTMLElement): void;
+        detachControl(): void;
         /** @hidden */
         _checkInputs(): void;
         private _checkLimits;
@@ -48193,15 +48167,13 @@ declare module BABYLON {
         private _scene;
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
          * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(noPreventDefault?: boolean): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Update the current camera state depending on the inputs that have been used this frame.
          * This is a dynamically created lambda to avoid the performance penalty of looping for inputs in the render loop.
@@ -48281,17 +48253,14 @@ declare module BABYLON {
         set camera(camera: FreeCamera);
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
-         * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(): void;
         private _orientationChanged;
         private _deviceOrientation;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Update the current camera state depending on the inputs that have been used this frame.
          * This is a dynamically created lambda to avoid the performance penalty of looping for inputs in the render loop.
@@ -48347,15 +48316,12 @@ declare module BABYLON {
         private _vector2;
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
-         * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Update the current camera state depending on the inputs that have been used this frame.
          * This is a dynamically created lambda to avoid the performance penalty of looping for inputs in the render loop.
@@ -48612,15 +48578,12 @@ declare module BABYLON {
         checkInputs(): void;
         /**
          * Attach the input controls to a specific dom element to get the input from.
-         * @param element Defines the element the controls should be listened from
-         * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
          */
-        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        attachControl(): void;
         /**
          * Detach the current controls from the specified dom element.
-         * @param element Defines the element to stop listening the inputs from
          */
-        detachControl(element: Nullable<HTMLElement>): void;
+        detachControl(): void;
         /**
          * Gets the class name of the current intput.
          * @returns the class name
@@ -52462,6 +52425,10 @@ declare module BABYLON {
          * A list of optional features to init the session with
          */
         requiredFeatures?: string[];
+        /**
+         * If defined, this function will be executed if the UI encounters an error when entering XR
+         */
+        onError?: (error: any) => void;
     }
     /**
      * UI to allow the user to enter/exit XR mode
@@ -54971,9 +54938,15 @@ declare module BABYLON {
      */
     export class DeviceInputSystem implements IDisposable {
         /**
-         * Callback to be triggered when a device is connected
+         * Returns onDeviceConnected callback property
+         * @returns Callback with function to execute when a device is connected
          */
-        onDeviceConnected: (deviceType: DeviceType, deviceSlot: number) => void;
+        get onDeviceConnected(): (deviceType: DeviceType, deviceSlot: number) => void;
+        /**
+         * Sets callback function when a device is connected and executes against all connected devices
+         * @param callback Function to execute when a device is connected
+         */
+        set onDeviceConnected(callback: (deviceType: DeviceType, deviceSlot: number) => void);
         /**
          * Callback to be triggered when a device is disconnected
          */
@@ -54994,6 +54967,7 @@ declare module BABYLON {
         private _pointerUpEvent;
         private _gamepadConnectedEvent;
         private _gamepadDisconnectedEvent;
+        private _onDeviceConnected;
         private static _MAX_KEYCODES;
         private static _MAX_POINTER_INPUTS;
         private constructor();
@@ -55022,6 +54996,24 @@ declare module BABYLON {
          */
         dispose(): void;
         /**
+         * Checks for existing connections to devices and register them, if necessary
+         * Currently handles gamepads and mouse
+         */
+        private _checkForConnectedDevices;
+        /**
+         * Add a gamepad to the DeviceInputSystem
+         * @param gamepad A single DOM Gamepad object
+         */
+        private _addGamePad;
+        /**
+         * Add pointer device to DeviceInputSystem
+         * @param deviceType Type of Pointer to add
+         * @param deviceSlot Pointer ID (0 for mouse, pointerId for Touch)
+         * @param currentX Current X at point of adding
+         * @param currentY Current Y at point of adding
+         */
+        private _addPointerDevice;
+        /**
          * Add device and inputs to device array
          * @param deviceType Enum specifiying device type
          * @param deviceSlot "Slot" or index that device is referenced in
@@ -55108,33 +55100,13 @@ declare module BABYLON {
      */
     export class DeviceSourceManager implements IDisposable {
         /**
-         * Observable to be triggered when before a device is connected
+         * Observable to be triggered when after a device is connected, any new observers added will be triggered against already connected devices
          */
-        readonly onBeforeDeviceConnectedObservable: Observable<{
-            deviceType: DeviceType;
-            deviceSlot: number;
-        }>;
-        /**
-         * Observable to be triggered when before a device is disconnected
-         */
-        readonly onBeforeDeviceDisconnectedObservable: Observable<{
-            deviceType: DeviceType;
-            deviceSlot: number;
-        }>;
-        /**
-         * Observable to be triggered when after a device is connected
-         */
-        readonly onAfterDeviceConnectedObservable: Observable<{
-            deviceType: DeviceType;
-            deviceSlot: number;
-        }>;
+        readonly onDeviceConnectedObservable: Observable<DeviceSource<DeviceType>>;
         /**
          * Observable to be triggered when after a device is disconnected
          */
-        readonly onAfterDeviceDisconnectedObservable: Observable<{
-            deviceType: DeviceType;
-            deviceSlot: number;
-        }>;
+        readonly onDeviceDisconnectedObservable: Observable<DeviceSource<DeviceType>>;
         private readonly _devices;
         private readonly _firstDevice;
         private readonly _deviceInputSystem;
@@ -55157,6 +55129,11 @@ declare module BABYLON {
          */
         getDeviceSources<T extends DeviceType>(deviceType: T): ReadonlyArray<DeviceSource<T>>;
         /**
+         * Returns a read-only list of all available devices
+         * @returns Read-only array with active devices
+         */
+        getDevices(): ReadonlyArray<DeviceSource<DeviceType>>;
+        /**
          * Dispose of DeviceInputSystem and other parts
          */
         dispose(): void;
@@ -72862,9 +72839,9 @@ declare module BABYLON {
          */
         onAfterBoxRenderingObservable: Observable<BoundingBox>;
         /**
-         * Observable raised after ressources are created
+         * Observable raised after resources are created
          */
-        onRessourcesReadyObservable: Observable<BoundingBoxRenderer>;
+        onResourcesReadyObservable: Observable<BoundingBoxRenderer>;
         /**
          * When false, no bounding boxes will be rendered
          */
@@ -72889,7 +72866,7 @@ declare module BABYLON {
         register(): void;
         private _evaluateSubMesh;
         private _preActiveMesh;
-        private _prepareRessources;
+        private _prepareResources;
         private _createIndexBuffer;
         /**
          * Rebuilds the elements related to this component in case of
@@ -76045,6 +76022,11 @@ declare module BABYLON {
          * Dispose this feature and all of the resources attached
          */
         dispose(): void;
+        /**
+         * Check if the needed objects are defined.
+         * This does not mean that the feature is enabled, but that the objects needed are well defined.
+         */
+        isCompatible(): boolean;
         protected _onXRFrame(frame: XRFrame): void;
         private _init;
         private _updatePlaneWithXRPlane;

+ 48 - 48
dist/preview release/gui/babylon.gui.js

@@ -7,7 +7,7 @@
 		exports["babylonjs-gui"] = factory(require("babylonjs"));
 	else
 		root["BABYLON"] = root["BABYLON"] || {}, root["BABYLON"]["GUI"] = factory(root["BABYLON"]);
-})((typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : this), function(__WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_observable__) {
+})((typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : this), function(__WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_perfCounter__) {
 return /******/ (function(modules) { // webpackBootstrap
 /******/ 	// The module cache
 /******/ 	var installedModules = {};
@@ -400,7 +400,7 @@ module.exports = g;
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AdvancedDynamicTextureInstrumentation", function() { return AdvancedDynamicTextureInstrumentation; });
-/* harmony import */ var babylonjs_Misc_perfCounter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/perfCounter */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_perfCounter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/perfCounter */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_perfCounter__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_perfCounter__WEBPACK_IMPORTED_MODULE_0__);
 
 /**
@@ -543,7 +543,7 @@ var AdvancedDynamicTextureInstrumentation = /** @class */ (function () {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AdvancedDynamicTexture", function() { return AdvancedDynamicTexture; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _controls_container__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./controls/container */ "./2D/controls/container.ts");
 /* harmony import */ var _style__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./style */ "./2D/style.ts");
@@ -1532,7 +1532,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _textBlock__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./textBlock */ "./2D/controls/textBlock.ts");
 /* harmony import */ var _image__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./image */ "./2D/controls/image.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_5__);
 
 
@@ -1764,7 +1764,7 @@ babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_5__["_TypeStore"].RegisteredTy
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Checkbox", function() { return Checkbox; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _stackPanel__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./stackPanel */ "./2D/controls/stackPanel.ts");
@@ -1947,7 +1947,7 @@ babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].RegisteredT
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ColorPicker", function() { return ColorPicker; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _inputText__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./inputText */ "./2D/controls/inputText.ts");
@@ -3340,7 +3340,7 @@ babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].RegisteredT
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Container", function() { return Container; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/logger */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/logger */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _measure__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../measure */ "./2D/measure.ts");
@@ -3757,7 +3757,7 @@ babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].RegisteredTypes
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Control", function() { return Control; });
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _measure__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../measure */ "./2D/measure.ts");
@@ -5706,7 +5706,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DisplayGrid", function() { return DisplayGrid; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 
 
@@ -5939,7 +5939,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _container__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./container */ "./2D/controls/container.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__);
 
 
@@ -6036,7 +6036,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _container__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./container */ "./2D/controls/container.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_4__);
 
 
@@ -6494,7 +6494,7 @@ babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_4__["_TypeStore"].RegisteredTypes[
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Image", function() { return Image; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 
@@ -7431,7 +7431,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InputPassword", function() { return InputPassword; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _inputText__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./inputText */ "./2D/controls/inputText.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 
 
@@ -7470,7 +7470,7 @@ babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__["_TypeStore"].RegisteredTy
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InputText", function() { return InputText; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
@@ -8483,7 +8483,7 @@ babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].RegisteredT
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Line", function() { return Line; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
@@ -8754,7 +8754,7 @@ babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].Registere
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MultiLine", function() { return MultiLine; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/abstractMesh */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/abstractMesh */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _multiLinePoint__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../multiLinePoint */ "./2D/multiLinePoint.ts");
@@ -9024,7 +9024,7 @@ babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].Registe
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RadioButton", function() { return RadioButton; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _stackPanel__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./stackPanel */ "./2D/controls/stackPanel.ts");
@@ -9231,7 +9231,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Rectangle", function() { return Rectangle; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _container__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./container */ "./2D/controls/container.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 
 
@@ -9381,7 +9381,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _scrollViewerWindow__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./scrollViewerWindow */ "./2D/controls/scrollViewers/scrollViewerWindow.ts");
 /* harmony import */ var _sliders_scrollBar__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../sliders/scrollBar */ "./2D/controls/sliders/scrollBar.ts");
 /* harmony import */ var _sliders_imageScrollBar__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../sliders/imageScrollBar */ "./2D/controls/sliders/imageScrollBar.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_7__);
 
 
@@ -11012,7 +11012,7 @@ var SelectionPanel = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BaseSlider", function() { return BaseSlider; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../control */ "./2D/controls/control.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../valueAndUnit */ "./2D/valueAndUnit.ts");
@@ -11346,7 +11346,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _baseSlider__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./baseSlider */ "./2D/controls/sliders/baseSlider.ts");
 /* harmony import */ var _measure__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../measure */ "./2D/measure.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__);
 
 
@@ -11939,7 +11939,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Slider", function() { return Slider; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _baseSlider__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./baseSlider */ "./2D/controls/sliders/baseSlider.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 
 
@@ -12211,7 +12211,7 @@ babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__["_TypeStore"].RegisteredTy
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StackPanel", function() { return StackPanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _container__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container */ "./2D/controls/container.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
@@ -12481,7 +12481,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextWrapping", function() { return TextWrapping; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextBlock", function() { return TextBlock; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
@@ -13017,7 +13017,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "KeyPropertySet", function() { return KeyPropertySet; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VirtualKeyboard", function() { return VirtualKeyboard; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _stackPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./stackPanel */ "./2D/controls/stackPanel.ts");
 /* harmony import */ var _button__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./button */ "./2D/controls/button.ts");
@@ -13406,7 +13406,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector2WithInfo", function() { return Vector2WithInfo; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Matrix2D", function() { return Matrix2D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 
 
@@ -13631,7 +13631,7 @@ var Matrix2D = /** @class */ (function () {
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Measure", function() { return Measure; });
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__);
 
 var tmpRect = [
@@ -13796,7 +13796,7 @@ var Measure = /** @class */ (function () {
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MultiLinePoint", function() { return MultiLinePoint; });
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./valueAndUnit */ "./2D/valueAndUnit.ts");
 
@@ -13939,7 +13939,7 @@ var MultiLinePoint = /** @class */ (function () {
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Style", function() { return Style; });
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./valueAndUnit */ "./2D/valueAndUnit.ts");
 
@@ -14245,7 +14245,7 @@ var ValueAndUnit = /** @class */ (function () {
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "XmlLoader", function() { return XmlLoader; });
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_0__);
 
 /**
@@ -14564,7 +14564,7 @@ var XmlLoader = /** @class */ (function () {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AbstractButton3D", function() { return AbstractButton3D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/transformNode */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/transformNode */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control3D */ "./3D/controls/control3D.ts");
 
@@ -14607,7 +14607,7 @@ var AbstractButton3D = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Button3D", function() { return Button3D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _abstractButton3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./abstractButton3D */ "./3D/controls/abstractButton3D.ts");
 /* harmony import */ var _2D_advancedDynamicTexture__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../2D/advancedDynamicTexture */ "./2D/advancedDynamicTexture.ts");
@@ -14788,7 +14788,7 @@ var Button3D = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Container3D", function() { return Container3D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/transformNode */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/transformNode */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control3D */ "./3D/controls/control3D.ts");
 
@@ -14945,7 +14945,7 @@ var Container3D = /** @class */ (function (_super) {
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Control3D", function() { return Control3D; });
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _vector3WithInfo__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../vector3WithInfo */ "./3D/vector3WithInfo.ts");
 
@@ -15351,7 +15351,7 @@ var Control3D = /** @class */ (function () {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CylinderPanel", function() { return CylinderPanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
@@ -15437,7 +15437,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "HolographicButton", function() { return HolographicButton; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _button3D__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./button3D */ "./3D/controls/button3D.ts");
-/* harmony import */ var babylonjs_Materials_standardMaterial__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Materials/standardMaterial */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Materials_standardMaterial__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Materials/standardMaterial */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Materials_standardMaterial__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_standardMaterial__WEBPACK_IMPORTED_MODULE_2__);
 /* harmony import */ var _materials_fluentMaterial__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../materials/fluentMaterial */ "./3D/materials/fluentMaterial.ts");
 /* harmony import */ var _2D_controls_stackPanel__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../2D/controls/stackPanel */ "./2D/controls/stackPanel.ts");
@@ -15931,7 +15931,7 @@ var MeshButton3D = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PlanePanel", function() { return PlanePanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
@@ -15986,7 +15986,7 @@ var PlanePanel = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ScatterPanel", function() { return ScatterPanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
@@ -16113,7 +16113,7 @@ var ScatterPanel = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SpherePanel", function() { return SpherePanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
@@ -16199,7 +16199,7 @@ var SpherePanel = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StackPanel3D", function() { return StackPanel3D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 
@@ -16324,7 +16324,7 @@ var StackPanel3D = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VolumeBasedPanel", function() { return VolumeBasedPanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 
@@ -16515,7 +16515,7 @@ var VolumeBasedPanel = /** @class */ (function (_super) {
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GUI3DManager", function() { return GUI3DManager; });
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _controls_container3D__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./controls/container3D */ "./3D/controls/container3D.ts");
 
@@ -16782,7 +16782,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FluentMaterialDefines", function() { return FluentMaterialDefines; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FluentMaterial", function() { return FluentMaterial; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/decorators */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/decorators */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _shaders_fluent_vertex__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./shaders/fluent.vertex */ "./3D/materials/shaders/fluent.vertex.ts");
 /* harmony import */ var _shaders_fluent_fragment__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./shaders/fluent.fragment */ "./3D/materials/shaders/fluent.fragment.ts");
@@ -17098,7 +17098,7 @@ __webpack_require__.r(__webpack_exports__);
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fluentPixelShader", function() { return fluentPixelShader; });
-/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__);
 
 var name = 'fluentPixelShader';
@@ -17120,7 +17120,7 @@ var fluentPixelShader = { name: name, shader: shader };
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fluentVertexShader", function() { return fluentVertexShader; });
-/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__);
 
 var name = 'fluentVertexShader';
@@ -17143,7 +17143,7 @@ var fluentVertexShader = { name: name, shader: shader };
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector3WithInfo", function() { return Vector3WithInfo; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/perfCounter");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 
 
@@ -17445,14 +17445,14 @@ if (typeof globalObject !== "undefined") {
 
 /***/ }),
 
-/***/ "babylonjs/Misc/observable":
+/***/ "babylonjs/Misc/perfCounter":
 /*!****************************************************************************************************!*\
   !*** external {"root":"BABYLON","commonjs":"babylonjs","commonjs2":"babylonjs","amd":"babylonjs"} ***!
   \****************************************************************************************************/
 /*! no static exports found */
 /***/ (function(module, exports) {
 
-module.exports = __WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_observable__;
+module.exports = __WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_perfCounter__;
 
 /***/ })
 

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
dist/preview release/gui/babylon.gui.js.map


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 12 - 13
dist/preview release/inspector/babylon.inspector.bundle.max.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.max.js.map


+ 2 - 2
dist/preview release/loaders/babylon.glTF1FileLoader.js

@@ -1253,14 +1253,14 @@ var importNode = function (gltfRuntime, node, id, parent) {
                 var orthoCamera = new babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__["FreeCamera"](node.camera, babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__["Vector3"].Zero(), gltfRuntime.scene, false);
                 orthoCamera.name = node.name || "";
                 orthoCamera.mode = babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__["Camera"].ORTHOGRAPHIC_CAMERA;
-                orthoCamera.attachControl(gltfRuntime.scene.getEngine().getInputElement());
+                orthoCamera.attachControl();
                 lastNode = orthoCamera;
             }
             else if (camera.type === "perspective") {
                 var perspectiveCamera = camera[camera.type];
                 var persCamera = new babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__["FreeCamera"](node.camera, babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__["Vector3"].Zero(), gltfRuntime.scene, false);
                 persCamera.name = node.name || "";
-                persCamera.attachControl(gltfRuntime.scene.getEngine().getInputElement());
+                persCamera.attachControl();
                 if (!perspectiveCamera.aspectRatio) {
                     perspectiveCamera.aspectRatio = gltfRuntime.scene.getEngine().getRenderWidth() / gltfRuntime.scene.getEngine().getRenderHeight();
                 }

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
dist/preview release/loaders/babylon.glTF1FileLoader.js.map


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 2 - 2
dist/preview release/loaders/babylon.glTF1FileLoader.min.js


+ 2 - 2
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -1253,14 +1253,14 @@ var importNode = function (gltfRuntime, node, id, parent) {
                 var orthoCamera = new babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__["FreeCamera"](node.camera, babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__["Vector3"].Zero(), gltfRuntime.scene, false);
                 orthoCamera.name = node.name || "";
                 orthoCamera.mode = babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__["Camera"].ORTHOGRAPHIC_CAMERA;
-                orthoCamera.attachControl(gltfRuntime.scene.getEngine().getInputElement());
+                orthoCamera.attachControl();
                 lastNode = orthoCamera;
             }
             else if (camera.type === "perspective") {
                 var perspectiveCamera = camera[camera.type];
                 var persCamera = new babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__["FreeCamera"](node.camera, babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__["Vector3"].Zero(), gltfRuntime.scene, false);
                 persCamera.name = node.name || "";
-                persCamera.attachControl(gltfRuntime.scene.getEngine().getInputElement());
+                persCamera.attachControl();
                 if (!perspectiveCamera.aspectRatio) {
                     perspectiveCamera.aspectRatio = gltfRuntime.scene.getEngine().getRenderWidth() / gltfRuntime.scene.getEngine().getRenderHeight();
                 }

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.js.map


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.min.js


+ 2 - 2
dist/preview release/loaders/babylonjs.loaders.js

@@ -2633,14 +2633,14 @@ var importNode = function (gltfRuntime, node, id, parent) {
                 var orthoCamera = new babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__["FreeCamera"](node.camera, babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__["Vector3"].Zero(), gltfRuntime.scene, false);
                 orthoCamera.name = node.name || "";
                 orthoCamera.mode = babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__["Camera"].ORTHOGRAPHIC_CAMERA;
-                orthoCamera.attachControl(gltfRuntime.scene.getEngine().getInputElement());
+                orthoCamera.attachControl();
                 lastNode = orthoCamera;
             }
             else if (camera.type === "perspective") {
                 var perspectiveCamera = camera[camera.type];
                 var persCamera = new babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__["FreeCamera"](node.camera, babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__["Vector3"].Zero(), gltfRuntime.scene, false);
                 persCamera.name = node.name || "";
-                persCamera.attachControl(gltfRuntime.scene.getEngine().getInputElement());
+                persCamera.attachControl();
                 if (!perspectiveCamera.aspectRatio) {
                     perspectiveCamera.aspectRatio = gltfRuntime.scene.getEngine().getRenderWidth() / gltfRuntime.scene.getEngine().getRenderHeight();
                 }

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.js.map


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.min.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
dist/preview release/nodeEditor/babylon.nodeEditor.js


+ 6 - 3
dist/preview release/nodeEditor/babylon.nodeEditor.max.js

@@ -64245,7 +64245,7 @@ var PreviewManager = /** @class */ (function () {
         this._camera.upperRadiusLimit = 10;
         this._camera.wheelPrecision = 20;
         this._camera.minZ = 0.1;
-        this._camera.attachControl(targetCanvas, false);
+        this._camera.attachControl(false);
         this._lightParent = new babylonjs_Materials_Node_nodeMaterial__WEBPACK_IMPORTED_MODULE_0__["TransformNode"]("LightParent", this._scene);
         this._refreshPreviewMesh();
         this._engine.runRenderLoop(function () {
@@ -64334,6 +64334,7 @@ var PreviewManager = /** @class */ (function () {
                 this._prepareLights();
                 var framingBehavior = this._camera.getBehaviorByName("Framing");
                 setTimeout(function () {
+                    // Let the behavior activate first
                     framingBehavior.framingTime = 0;
                     framingBehavior.elevationReturnTime = -1;
                     if (_this._scene.meshes.length) {
@@ -64597,7 +64598,8 @@ var PreviewManager = /** @class */ (function () {
                 default: {
                     if (this._meshes.length) {
                         var tasks = this._meshes.map(function (m) { return _this._forceCompilationAsync(tempMaterial_1, m); });
-                        Promise.all(tasks).then(function () {
+                        Promise.all(tasks)
+                            .then(function () {
                             for (var _i = 0, _a = _this._meshes; _i < _a.length; _i++) {
                                 var mesh = _a[_i];
                                 mesh.material = tempMaterial_1;
@@ -64607,7 +64609,8 @@ var PreviewManager = /** @class */ (function () {
                             }
                             _this._material = tempMaterial_1;
                             _this._globalState.onIsLoadingChanged.notifyObservers(false);
-                        }).catch(function (reason) {
+                        })
+                            .catch(function (reason) {
                             _this._globalState.onLogRequiredObservable.notifyObservers(new _log_logComponent__WEBPACK_IMPORTED_MODULE_2__["LogEntry"]("Shader compilation error:\r\n" + reason, true));
                             _this._globalState.onIsLoadingChanged.notifyObservers(false);
                         });

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map


+ 1 - 1
dist/preview release/packagesSizeBaseLine.json

@@ -1 +1 @@
-{"thinEngineOnly":118763,"engineOnly":155203,"sceneOnly":522470,"minGridMaterial":671368,"minStandardMaterial":827575}
+{"thinEngineOnly":118763,"engineOnly":155203,"sceneOnly":522649,"minGridMaterial":671882,"minStandardMaterial":828088}

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 250 - 298
dist/preview release/viewer/babylon.module.d.ts


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 38 - 38
dist/preview release/viewer/babylon.viewer.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 4 - 4
dist/preview release/viewer/babylon.viewer.max.js


+ 3 - 0
dist/preview release/what's new.md

@@ -54,6 +54,7 @@
 - Allow cross-eye mode in photo and video dome ([#8897](https://github.com/BabylonJS/Babylon.js/issues/8897)) ([RaananW](https://github.com/RaananW))
 - Added noMipMap option to the photo dome construction process ([#8972](https://github.com/BabylonJS/Babylon.js/issues/8972)) ([RaananW](https://github.com/RaananW))
 - Add a `disableBoundingBoxesFromEffectLayer` property to the `EffectLayer` class to render the bounding boxes unaffected by the effect ([Popov72](https://github.com/Popov72))
+- Removed all references to HTML element from cameras' attach and detach control functions ([RaananW](https://github.com/RaananW))
 - Added `boundingBoxRenderer.onResourcesReadyObservable` ([aWeirdo](https://github.com/aWeirdo))
 
 ### Engine
@@ -219,6 +220,7 @@
 - XR tracking state was added to the camera ([#9076](https://github.com/BabylonJS/Babylon.js/issues/9076)) ([RaananW](https://github.com/RaananW))
 - Individual post processing can be applied to the XR rig cameras ([#9038](https://github.com/BabylonJS/Babylon.js/issues/9038)) ([RaananW](https://github.com/RaananW))
 - Pointer selection improvements - single/dual hand selection, max ray distance and more ([#7974](https://github.com/BabylonJS/Babylon.js/issues/7974)) ([RaananW](https://github.com/RaananW))
+- Updated Plane Detection API ([RaananW](https://github.com/RaananW))
 
 ### Collisions
 
@@ -246,6 +248,7 @@
 ### Audio
 
 - Added support of `metadata` in `Sound` class. ([julien-moreau](https://github.com/julien-moreau))
+- Added `currentTime` property to the `Sound` class. ([jocravio](https://github.com/jocravio))
 
 ### Build
 

+ 21 - 23
inspector/src/components/sceneExplorer/entities/cameraTreeItemComponent.tsx

@@ -4,21 +4,21 @@ import { IExplorerExtensibilityGroup } from "babylonjs/Debug/debugLayer";
 import { Camera } from "babylonjs/Cameras/camera";
 import { Scene } from "babylonjs/scene";
 
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { faVideo, faCamera, faEye } from '@fortawesome/free-solid-svg-icons';
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faVideo, faCamera, faEye } from "@fortawesome/free-solid-svg-icons";
 import { TreeItemLabelComponent } from "../treeItemLabelComponent";
 import { ExtensionsComponent } from "../extensionsComponent";
 import * as React from "react";
 import { GlobalState } from "../../globalState";
 
 interface ICameraTreeItemComponentProps {
-    camera: Camera,
-    extensibilityGroups?: IExplorerExtensibilityGroup[],
-    onClick: () => void,
-    globalState: GlobalState
+    camera: Camera;
+    extensibilityGroups?: IExplorerExtensibilityGroup[];
+    onClick: () => void;
+    globalState: GlobalState;
 }
 
-export class CameraTreeItemComponent extends React.Component<ICameraTreeItemComponentProps, { isActive: boolean, isGizmoEnabled:boolean }> {
+export class CameraTreeItemComponent extends React.Component<ICameraTreeItemComponentProps, { isActive: boolean; isGizmoEnabled: boolean }> {
     private _onBeforeRenderObserver: Nullable<Observer<Scene>>;
 
     constructor(props: ICameraTreeItemComponentProps) {
@@ -27,7 +27,7 @@ export class CameraTreeItemComponent extends React.Component<ICameraTreeItemComp
         const camera = this.props.camera;
         const scene = camera.getScene();
 
-        this.state = { isActive: scene.activeCamera === camera, isGizmoEnabled: (camera.reservedDataStore && camera.reservedDataStore.cameraGizmo) };
+        this.state = { isActive: scene.activeCamera === camera, isGizmoEnabled: camera.reservedDataStore && camera.reservedDataStore.cameraGizmo };
     }
 
     setActive(): void {
@@ -35,27 +35,26 @@ export class CameraTreeItemComponent extends React.Component<ICameraTreeItemComp
         const scene = camera.getScene();
 
         scene.activeCamera = camera;
-        camera.attachControl(scene.getEngine().getRenderingCanvas()!, true);
+        camera.attachControl(true);
 
         this.setState({ isActive: true });
     }
 
-    componentDidMount() {        
+    componentDidMount() {
         const scene = this.props.camera.getScene();
 
         this._onBeforeRenderObserver = scene.onBeforeRenderObservable.add(() => {
             const camera = this.props.camera;
             // This will deactivate the previous camera when the camera is changed. Multiple camera's cycle frequently so only do this for single cameras
             if (this.state.isActive && scene.activeCameras.length <= 1 && scene.activeCamera !== camera) {
-                camera.detachControl(scene.getEngine().getRenderingCanvas()!);
+                camera.detachControl();
             }
-            let newState =  scene.activeCamera === camera;
+            let newState = scene.activeCamera === camera;
 
             if (newState !== this.state.isActive) {
-                this.setState({ isActive: newState});
+                this.setState({ isActive: newState });
             }
-            
-        })
+        });
     }
 
     componentWillUnmount() {
@@ -69,13 +68,13 @@ export class CameraTreeItemComponent extends React.Component<ICameraTreeItemComp
 
     toggleGizmo(): void {
         const camera = this.props.camera;
-        if(camera.reservedDataStore && camera.reservedDataStore.cameraGizmo){
+        if (camera.reservedDataStore && camera.reservedDataStore.cameraGizmo) {
             if (camera.getScene().reservedDataStore && camera.getScene().reservedDataStore.gizmoManager) {
                 camera.getScene().reservedDataStore.gizmoManager.attachToMesh(null);
             }
             this.props.globalState.enableCameraGizmo(camera, false);
             this.setState({ isGizmoEnabled: false });
-        }else{
+        } else {
             this.props.globalState.enableCameraGizmo(camera, true);
             this.setState({ isGizmoEnabled: true });
         }
@@ -84,21 +83,20 @@ export class CameraTreeItemComponent extends React.Component<ICameraTreeItemComp
     render() {
         const isActiveElement = this.state.isActive ? <FontAwesomeIcon icon={faVideo} /> : <FontAwesomeIcon icon={faVideo} className="isNotActive" />;
         const scene = this.props.camera.getScene()!;
-        const isGizmoEnabled = (this.state.isGizmoEnabled || (this.props.camera && this.props.camera.reservedDataStore && this.props.camera.reservedDataStore.cameraGizmo)) ? <FontAwesomeIcon icon={faEye} /> : <FontAwesomeIcon icon={faEye} className="isNotActive" />;
+        const isGizmoEnabled = this.state.isGizmoEnabled || (this.props.camera && this.props.camera.reservedDataStore && this.props.camera.reservedDataStore.cameraGizmo) ? <FontAwesomeIcon icon={faEye} /> : <FontAwesomeIcon icon={faEye} className="isNotActive" />;
         return (
             <div className="cameraTools">
                 <TreeItemLabelComponent label={this.props.camera.name} onClick={() => this.props.onClick()} icon={faCamera} color="green" />
-                {
-                    (!scene.activeCameras || scene.activeCameras.length === 0) &&
+                {(!scene.activeCameras || scene.activeCameras.length === 0) && (
                     <div className="activeCamera icon" onClick={() => this.setActive()} title="Set as main camera and attach to controls">
                         {isActiveElement}
                     </div>
-                }
+                )}
                 <div className="enableGizmo icon" onClick={() => this.toggleGizmo()} title="Turn on/off the camera's gizmo">
                     {isGizmoEnabled}
                 </div>
                 <ExtensionsComponent target={this.props.camera} extensibilityGroups={this.props.extensibilityGroups} />
             </div>
-        )
+        );
     }
-}
+}

+ 2 - 2
loaders/src/glTF/1.0/glTFLoader.ts

@@ -929,7 +929,7 @@ var importNode = (gltfRuntime: IGLTFRuntime, node: IGLTFNode, id: string, parent
 
                 orthoCamera.name = node.name || "";
                 orthoCamera.mode = Camera.ORTHOGRAPHIC_CAMERA;
-                orthoCamera.attachControl(<HTMLElement>gltfRuntime.scene.getEngine().getInputElement());
+                orthoCamera.attachControl();
 
                 lastNode = orthoCamera;
             }
@@ -938,7 +938,7 @@ var importNode = (gltfRuntime: IGLTFRuntime, node: IGLTFNode, id: string, parent
                 var persCamera = new FreeCamera(node.camera, Vector3.Zero(), gltfRuntime.scene, false);
 
                 persCamera.name = node.name || "";
-                persCamera.attachControl(<HTMLElement>gltfRuntime.scene.getEngine().getInputElement());
+                persCamera.attachControl();
 
                 if (!perspectiveCamera.aspectRatio) {
                     perspectiveCamera.aspectRatio = gltfRuntime.scene.getEngine().getRenderWidth() / gltfRuntime.scene.getEngine().getRenderHeight();

+ 1 - 1
materialsLibrary/index.html

@@ -68,7 +68,7 @@
 			scene = new BABYLON.Scene(engine);
 
 			var camera = new BABYLON.ArcRotateCamera("Camera", Math.PI / 2, Math.PI / 6, 50, BABYLON.Vector3.Zero(), scene);
-			camera.attachControl(canvas, true);
+			camera.attachControl(true);
 			camera.minZ = 0.1;
 
 			// Lights

+ 69 - 60
nodeEditor/src/components/preview/previewManager.ts

@@ -1,36 +1,36 @@
-import { GlobalState } from '../../globalState';
-import { NodeMaterial } from 'babylonjs/Materials/Node/nodeMaterial';
-import { Nullable } from 'babylonjs/types';
-import { Observer } from 'babylonjs/Misc/observable';
-import { Engine } from 'babylonjs/Engines/engine';
-import { Scene } from 'babylonjs/scene';
-import { Mesh } from 'babylonjs/Meshes/mesh';
-import { Vector3 } from 'babylonjs/Maths/math.vector';
-import { HemisphericLight } from 'babylonjs/Lights/hemisphericLight';
-import { ArcRotateCamera } from 'babylonjs/Cameras/arcRotateCamera';
-import { PreviewType } from './previewType';
-import { Animation } from 'babylonjs/Animations/animation';
-import { SceneLoader } from 'babylonjs/Loading/sceneLoader';
-import { TransformNode } from 'babylonjs/Meshes/transformNode';
-import { AbstractMesh } from 'babylonjs/Meshes/abstractMesh';
-import { FramingBehavior } from 'babylonjs/Behaviors/Cameras/framingBehavior';
-import { DirectionalLight } from 'babylonjs/Lights/directionalLight';
-import { LogEntry } from '../log/logComponent';
-import { PointerEventTypes } from 'babylonjs/Events/pointerEvents';
-import { Color3, Color4 } from 'babylonjs/Maths/math.color';
-import { PostProcess } from 'babylonjs/PostProcesses/postProcess';
-import { Constants } from 'babylonjs/Engines/constants';
-import { CurrentScreenBlock } from 'babylonjs/Materials/Node/Blocks/Dual/currentScreenBlock';
-import { NodeMaterialModes } from 'babylonjs/Materials/Node/Enums/nodeMaterialModes';
-import { ParticleSystem } from 'babylonjs/Particles/particleSystem';
-import { IParticleSystem } from 'babylonjs/Particles/IParticleSystem';
-import { ParticleHelper } from 'babylonjs/Particles/particleHelper';
-import { Texture } from 'babylonjs/Materials/Textures/texture';
-import { ParticleTextureBlock } from 'babylonjs/Materials/Node/Blocks/Particle/particleTextureBlock';
-import { FileTools } from 'babylonjs/Misc/fileTools';
-import { ProceduralTexture } from 'babylonjs/Materials/Textures/Procedurals/proceduralTexture';
-import { StandardMaterial } from 'babylonjs/Materials/standardMaterial';
-import { Layer } from 'babylonjs/Layers/layer';
+import { GlobalState } from "../../globalState";
+import { NodeMaterial } from "babylonjs/Materials/Node/nodeMaterial";
+import { Nullable } from "babylonjs/types";
+import { Observer } from "babylonjs/Misc/observable";
+import { Engine } from "babylonjs/Engines/engine";
+import { Scene } from "babylonjs/scene";
+import { Mesh } from "babylonjs/Meshes/mesh";
+import { Vector3 } from "babylonjs/Maths/math.vector";
+import { HemisphericLight } from "babylonjs/Lights/hemisphericLight";
+import { ArcRotateCamera } from "babylonjs/Cameras/arcRotateCamera";
+import { PreviewType } from "./previewType";
+import { Animation } from "babylonjs/Animations/animation";
+import { SceneLoader } from "babylonjs/Loading/sceneLoader";
+import { TransformNode } from "babylonjs/Meshes/transformNode";
+import { AbstractMesh } from "babylonjs/Meshes/abstractMesh";
+import { FramingBehavior } from "babylonjs/Behaviors/Cameras/framingBehavior";
+import { DirectionalLight } from "babylonjs/Lights/directionalLight";
+import { LogEntry } from "../log/logComponent";
+import { PointerEventTypes } from "babylonjs/Events/pointerEvents";
+import { Color3, Color4 } from "babylonjs/Maths/math.color";
+import { PostProcess } from "babylonjs/PostProcesses/postProcess";
+import { Constants } from "babylonjs/Engines/constants";
+import { CurrentScreenBlock } from "babylonjs/Materials/Node/Blocks/Dual/currentScreenBlock";
+import { NodeMaterialModes } from "babylonjs/Materials/Node/Enums/nodeMaterialModes";
+import { ParticleSystem } from "babylonjs/Particles/particleSystem";
+import { IParticleSystem } from "babylonjs/Particles/IParticleSystem";
+import { ParticleHelper } from "babylonjs/Particles/particleHelper";
+import { Texture } from "babylonjs/Materials/Textures/texture";
+import { ParticleTextureBlock } from "babylonjs/Materials/Node/Blocks/Particle/particleTextureBlock";
+import { FileTools } from "babylonjs/Misc/fileTools";
+import { ProceduralTexture } from "babylonjs/Materials/Textures/Procedurals/proceduralTexture";
+import { StandardMaterial } from "babylonjs/Materials/standardMaterial";
+import { Layer } from "babylonjs/Layers/layer";
 
 export class PreviewManager {
     private _nodeMaterial: NodeMaterial;
@@ -105,7 +105,7 @@ export class PreviewManager {
         this._camera.upperRadiusLimit = 10;
         this._camera.wheelPrecision = 20;
         this._camera.minZ = 0.1;
-        this._camera.attachControl(targetCanvas, false);
+        this._camera.attachControl(false);
 
         this._lightParent = new TransformNode("LightParent", this._scene);
 
@@ -212,7 +212,8 @@ export class PreviewManager {
 
                 var framingBehavior = this._camera.getBehaviorByName("Framing") as FramingBehavior;
 
-                setTimeout(() => { // Let the behavior activate first
+                setTimeout(() => {
+                    // Let the behavior activate first
                     framingBehavior.framingTime = 0;
                     framingBehavior.elevationReturnTime = -1;
 
@@ -234,7 +235,7 @@ export class PreviewManager {
                 this._handleAnimations();
                 break;
             }
-            case NodeMaterialModes.PostProcess: 
+            case NodeMaterialModes.PostProcess:
             case NodeMaterialModes.ProceduralTexture: {
                 this._camera.radius = 4;
                 this._camera.upperRadiusLimit = 10;
@@ -359,13 +360,19 @@ export class PreviewManager {
                         this._loadParticleSystem(this._globalState.previewType);
                         return;
                     case PreviewType.Custom:
-                        FileTools.ReadFile(this._globalState.previewFile, (json) =>  {
-                            this._particleSystem = ParticleSystem.Parse(JSON.parse(json), this._scene, "");
-                            this._particleSystem.start();
-                            this._prepareScene();
-                        }, undefined, false, (error) => {
-                            console.log(error);
-                        });
+                        FileTools.ReadFile(
+                            this._globalState.previewFile,
+                            (json) => {
+                                this._particleSystem = ParticleSystem.Parse(JSON.parse(json), this._scene, "");
+                                this._particleSystem.start();
+                                this._prepareScene();
+                            },
+                            undefined,
+                            false,
+                            (error) => {
+                                console.log(error);
+                            }
+                        );
                         return;
                 }
             }
@@ -461,7 +468,7 @@ export class PreviewManager {
                     this._globalState.onIsLoadingChanged.notifyObservers(false);
 
                     this._proceduralTexture = tempMaterial.createProceduralTexture(512, this._scene);
-                   
+
                     if (this._material) {
                         this._material.dispose();
                     }
@@ -497,21 +504,23 @@ export class PreviewManager {
                     if (this._meshes.length) {
                         let tasks = this._meshes.map((m) => this._forceCompilationAsync(tempMaterial, m));
 
-                        Promise.all(tasks).then(() => {
-                            for (var mesh of this._meshes) {
-                                mesh.material = tempMaterial;
-                            }
-
-                            if (this._material) {
-                                this._material.dispose();
-                            }
-
-                            this._material = tempMaterial;
-                            this._globalState.onIsLoadingChanged.notifyObservers(false);
-                        }).catch((reason) => {
-                            this._globalState.onLogRequiredObservable.notifyObservers(new LogEntry("Shader compilation error:\r\n" + reason, true));
-                            this._globalState.onIsLoadingChanged.notifyObservers(false);
-                        });
+                        Promise.all(tasks)
+                            .then(() => {
+                                for (var mesh of this._meshes) {
+                                    mesh.material = tempMaterial;
+                                }
+
+                                if (this._material) {
+                                    this._material.dispose();
+                                }
+
+                                this._material = tempMaterial;
+                                this._globalState.onIsLoadingChanged.notifyObservers(false);
+                            })
+                            .catch((reason) => {
+                                this._globalState.onLogRequiredObservable.notifyObservers(new LogEntry("Shader compilation error:\r\n" + reason, true));
+                                this._globalState.onIsLoadingChanged.notifyObservers(false);
+                            });
                     } else {
                         this._material = tempMaterial;
                     }
@@ -546,4 +555,4 @@ export class PreviewManager {
         this._scene.dispose();
         this._engine.dispose();
     }
-}
+}

+ 119 - 122
postProcessLibrary/index.html

@@ -1,124 +1,121 @@
 <!DOCTYPE html>
 <html xmlns="http://www.w3.org/1999/xhtml">
-
-<head>
-	<title>Shaders Library</title>
-	<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
-	<script src="../Tools/DevLoader/BabylonLoader.js"></script>
-
-	<style>
-		html,
-		body {
-			width: 100%;
-			height: 100%;
-			padding: 0;
-			margin: 0;
-			overflow: hidden;
-		}
-		
-		#renderCanvas {
-			width: 100%;
-			height: 100%;
-		}
-		
-		#fps {
-			position: absolute;
-			background-color: black;
-			border: 2px solid red;
-			text-align: center;
-			font-size: 16px;
-			color: white;
-			top: 15px;
-			left: 10px;
-			width: 60px;
-			height: 20px;
-		}
-	</style>
-</head>
-
-<body>
-	<div id="fps">0</div>
-	<canvas id="renderCanvas"></canvas>
-
-	<script>
-	BABYLONDEVTOOLS.Loader.load(function() {
-		if (BABYLON.Engine.isSupported()) {
-			var canvas = document.getElementById("renderCanvas");
-			var engine = new BABYLON.Engine(canvas, true);					
-			BABYLONDEVTOOLS.Loader.debugShortcut(engine);	
-			var divFps = document.getElementById("fps");
-
-			var scene = new BABYLON.Scene(engine);
-
-			var camera = new BABYLON.ArcRotateCamera("Camera", Math.PI / 2, Math.PI / 6, 50, BABYLON.Vector3.Zero(), scene);
-			camera.attachControl(canvas, true);
-			camera.minZ = 0.1;
-
-			// Lights
-			var hemisphericLight = new BABYLON.HemisphericLight("hemi", new BABYLON.Vector3(0, 1, 0), scene);
-			
-			// Create meshes
-			var sphere = BABYLON.Mesh.CreateSphere("sphere", 48, 30.0, scene);
-
-			var skybox = BABYLON.Mesh.CreateBox("skyBox", 1000.0, scene);
-			var skyboxMaterial = new BABYLON.StandardMaterial("skyBox", scene);
-			skyboxMaterial.backFaceCulling = false;
-			skyboxMaterial.reflectionTexture = new BABYLON.CubeTexture("/Playground/textures/TropicalSunnyDay", scene);
-			skyboxMaterial.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE;
-			skyboxMaterial.diffuseColor = new BABYLON.Color3(0, 0, 0);
-			skyboxMaterial.specularColor = new BABYLON.Color3(0, 0, 0);
-			skyboxMaterial.disableLighting = true;
-			skybox.material = skyboxMaterial;
-			skybox.setEnabled(false);
-			
-			// Materials
-			sphere.material = new BABYLON.StandardMaterial("std", scene);
-			sphere.material.diffuseTexture = new BABYLON.Texture("/Playground/textures/amiga.jpg", scene);
-			sphere.material.diffuseTexture.uScale = 5;
-			sphere.material.diffuseTexture.vScale = 5;
-
-			// Register a render loop to repeatedly render the scene
-			engine.runRenderLoop(function () {
-				scene.render();
-				divFps.innerHTML = engine.getFps().toFixed() + " fps";
-			});
-
-			// Resize
-			window.addEventListener("resize", function () {
-				engine.resize();
-			});
-
-			// Post-processes
-			var aaPostProcess = new BABYLON.AsciiArtPostProcess("AsciiArt", camera);
-			var drPostProcess = new BABYLON.DigitalRainPostProcess("AsciiArt", camera);
-			
-			//camera.detachPostProcess(aaPostProcess);
-			camera.detachPostProcess(drPostProcess);
-
-			var gui = new dat.GUI();
-			var options = {
-				postProcess: "asciiArt"
-			}
-
-			gui.add(options, 'postProcess', ['asciiArt', 'digitalRain']).onFinishChange(function () {
-				camera.detachPostProcess(aaPostProcess);
-				camera.detachPostProcess(drPostProcess);
-
-				skybox.setEnabled(false);
-
-				switch (options.postProcess) {
-					case "asciiArt":
-						camera.attachPostProcess(aaPostProcess);
-						break;
-					case "digitalRain":
-						camera.attachPostProcess(drPostProcess);
-						break;
-				}
-			});
-		}
-	});
-
-	</script>
-</body>
-
-</html>
+    <head>
+        <title>Shaders Library</title>
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
+        <script src="../Tools/DevLoader/BabylonLoader.js"></script>
+
+        <style>
+            html,
+            body {
+                width: 100%;
+                height: 100%;
+                padding: 0;
+                margin: 0;
+                overflow: hidden;
+            }
+
+            #renderCanvas {
+                width: 100%;
+                height: 100%;
+            }
+
+            #fps {
+                position: absolute;
+                background-color: black;
+                border: 2px solid red;
+                text-align: center;
+                font-size: 16px;
+                color: white;
+                top: 15px;
+                left: 10px;
+                width: 60px;
+                height: 20px;
+            }
+        </style>
+    </head>
+
+    <body>
+        <div id="fps">0</div>
+        <canvas id="renderCanvas"></canvas>
+
+        <script>
+            BABYLONDEVTOOLS.Loader.load(function () {
+                if (BABYLON.Engine.isSupported()) {
+                    var canvas = document.getElementById("renderCanvas");
+                    var engine = new BABYLON.Engine(canvas, true);
+                    BABYLONDEVTOOLS.Loader.debugShortcut(engine);
+                    var divFps = document.getElementById("fps");
+
+                    var scene = new BABYLON.Scene(engine);
+
+                    var camera = new BABYLON.ArcRotateCamera("Camera", Math.PI / 2, Math.PI / 6, 50, BABYLON.Vector3.Zero(), scene);
+                    camera.attachControl(true);
+                    camera.minZ = 0.1;
+
+                    // Lights
+                    var hemisphericLight = new BABYLON.HemisphericLight("hemi", new BABYLON.Vector3(0, 1, 0), scene);
+
+                    // Create meshes
+                    var sphere = BABYLON.Mesh.CreateSphere("sphere", 48, 30.0, scene);
+
+                    var skybox = BABYLON.Mesh.CreateBox("skyBox", 1000.0, scene);
+                    var skyboxMaterial = new BABYLON.StandardMaterial("skyBox", scene);
+                    skyboxMaterial.backFaceCulling = false;
+                    skyboxMaterial.reflectionTexture = new BABYLON.CubeTexture("/Playground/textures/TropicalSunnyDay", scene);
+                    skyboxMaterial.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE;
+                    skyboxMaterial.diffuseColor = new BABYLON.Color3(0, 0, 0);
+                    skyboxMaterial.specularColor = new BABYLON.Color3(0, 0, 0);
+                    skyboxMaterial.disableLighting = true;
+                    skybox.material = skyboxMaterial;
+                    skybox.setEnabled(false);
+
+                    // Materials
+                    sphere.material = new BABYLON.StandardMaterial("std", scene);
+                    sphere.material.diffuseTexture = new BABYLON.Texture("/Playground/textures/amiga.jpg", scene);
+                    sphere.material.diffuseTexture.uScale = 5;
+                    sphere.material.diffuseTexture.vScale = 5;
+
+                    // Register a render loop to repeatedly render the scene
+                    engine.runRenderLoop(function () {
+                        scene.render();
+                        divFps.innerHTML = engine.getFps().toFixed() + " fps";
+                    });
+
+                    // Resize
+                    window.addEventListener("resize", function () {
+                        engine.resize();
+                    });
+
+                    // Post-processes
+                    var aaPostProcess = new BABYLON.AsciiArtPostProcess("AsciiArt", camera);
+                    var drPostProcess = new BABYLON.DigitalRainPostProcess("AsciiArt", camera);
+
+                    //camera.detachPostProcess(aaPostProcess);
+                    camera.detachPostProcess(drPostProcess);
+
+                    var gui = new dat.GUI();
+                    var options = {
+                        postProcess: "asciiArt",
+                    };
+
+                    gui.add(options, "postProcess", ["asciiArt", "digitalRain"]).onFinishChange(function () {
+                        camera.detachPostProcess(aaPostProcess);
+                        camera.detachPostProcess(drPostProcess);
+
+                        skybox.setEnabled(false);
+
+                        switch (options.postProcess) {
+                            case "asciiArt":
+                                camera.attachPostProcess(aaPostProcess);
+                                break;
+                            case "digitalRain":
+                                camera.attachPostProcess(drPostProcess);
+                                break;
+                        }
+                    });
+                }
+            });
+        </script>
+    </body>
+</html>

+ 1 - 1
proceduralTexturesLibrary/index.html

@@ -62,7 +62,7 @@
 			scene = new BABYLON.Scene(engine);
 
 			var camera = new BABYLON.ArcRotateCamera("Camera", Math.PI / 2, Math.PI / 6, 50, BABYLON.Vector3.Zero(), scene);
-			camera.attachControl(canvas, true);
+			camera.attachControl(true);
 
 			// Lights
 			var hemisphericLight = new BABYLON.HemisphericLight("hemi", new BABYLON.Vector3(0, 1, 0), scene);

+ 58 - 57
sandbox/src/components/renderingZone.tsx

@@ -1,17 +1,17 @@
 import * as React from "react";
-import { GlobalState } from '../globalState';
+import { GlobalState } from "../globalState";
 
-import { Engine } from 'babylonjs/Engines/engine';
-import { SceneLoader } from 'babylonjs/Loading/sceneLoader';
+import { Engine } from "babylonjs/Engines/engine";
+import { SceneLoader } from "babylonjs/Loading/sceneLoader";
 import { GLTFFileLoader } from "babylonjs-loaders/glTF/glTFFileLoader";
-import { Scene } from 'babylonjs/scene';
-import { Vector3 } from 'babylonjs/Maths/math.vector';
-import { ArcRotateCamera } from 'babylonjs/Cameras/arcRotateCamera';
-import { FramingBehavior } from 'babylonjs/Behaviors/Cameras/framingBehavior';
-import { EnvironmentTools } from '../tools/environmentTools';
-import { Tools } from 'babylonjs/Misc/tools';
-import { FilesInput } from 'babylonjs/Misc/filesInput';
-import {Animation} from 'babylonjs/Animations/animation';
+import { Scene } from "babylonjs/scene";
+import { Vector3 } from "babylonjs/Maths/math.vector";
+import { ArcRotateCamera } from "babylonjs/Cameras/arcRotateCamera";
+import { FramingBehavior } from "babylonjs/Behaviors/Cameras/framingBehavior";
+import { EnvironmentTools } from "../tools/environmentTools";
+import { Tools } from "babylonjs/Misc/tools";
+import { FilesInput } from "babylonjs/Misc/filesInput";
+import { Animation } from "babylonjs/Animations/animation";
 
 require("../scss/renderingZone.scss");
 
@@ -35,7 +35,7 @@ export class RenderingZone extends React.Component<IRenderingZoneProps> {
     initEngine() {
         this._canvas = document.getElementById("renderCanvas") as HTMLCanvasElement;
         this._engine = new Engine(this._canvas, true, { premultipliedAlpha: false, preserveDrawingBuffer: true });
-   
+
         this._engine.loadingUIBackgroundColor = "#2A2342";
 
         // Resize
@@ -46,12 +46,16 @@ export class RenderingZone extends React.Component<IRenderingZoneProps> {
         this.loadAsset();
 
         // File inputs
-        let filesInput = new FilesInput(this._engine, null, 
+        let filesInput = new FilesInput(
+            this._engine,
+            null,
             (sceneFile: File, scene: Scene) => {
                 this._scene = scene;
                 this.onSceneLoaded(sceneFile.name);
             },
-            null, null, null, 
+            null,
+            null,
+            null,
             () => {
                 Tools.ClearLogCache();
                 if (this._scene) {
@@ -61,15 +65,16 @@ export class RenderingZone extends React.Component<IRenderingZoneProps> {
                         this._scene.debugLayer.hide();
                     }
                 }
-            }, null, (file, scene, message) => {
-                this.props.globalState.onError.notifyObservers({ message : message});
-            });
+            },
+            null,
+            (file, scene, message) => {
+                this.props.globalState.onError.notifyObservers({ message: message });
+            }
+        );
 
         filesInput.onProcessFileCallback = (file, name, extension) => {
             if (filesInput.filesToLoad && filesInput.filesToLoad.length === 1 && extension) {
-                if (extension.toLowerCase() === "dds" ||
-                    extension.toLowerCase() === "env" ||
-                    extension.toLowerCase() === "hdr") {
+                if (extension.toLowerCase() === "dds" || extension.toLowerCase() === "env" || extension.toLowerCase() === "hdr") {
                     FilesInput.FilesToLoad[name] = file;
                     EnvironmentTools.SkyboxPath = "file:" + (file as any).correctName;
                     return false;
@@ -86,8 +91,7 @@ export class RenderingZone extends React.Component<IRenderingZoneProps> {
             if (event.keyCode === 82 && event.target && (event.target as HTMLElement).nodeName !== "INPUT" && this._scene) {
                 if (this.props.assetUrl) {
                     this.loadAssetFromUrl();
-                }
-                else {
+                } else {
                     filesInput.reload();
                 }
             }
@@ -105,8 +109,7 @@ export class RenderingZone extends React.Component<IRenderingZoneProps> {
 
             if (this.props.cameraPosition) {
                 camera.setPosition(this.props.cameraPosition);
-            }
-            else {
+            } else {
                 if (this._currentPluginName === "gltf") {
                     // glTF assets use a +Z forward convention while the default camera faces +Z. Rotate the camera to look at the front of the asset.
                     camera.alpha += Math.PI;
@@ -120,7 +123,7 @@ export class RenderingZone extends React.Component<IRenderingZoneProps> {
                 framingBehavior.elevationReturnTime = -1;
 
                 if (this._scene.meshes.length) {
-                   camera.lowerRadiusLimit = null;
+                    camera.lowerRadiusLimit = null;
 
                     var worldExtends = this._scene.getWorldExtends(function (mesh) {
                         return mesh.isVisible && mesh.isEnabled();
@@ -136,20 +139,19 @@ export class RenderingZone extends React.Component<IRenderingZoneProps> {
             camera.pinchDeltaPercentage = 0.01;
         }
 
-        this._scene.activeCamera!.attachControl(this._canvas);     
+        this._scene.activeCamera!.attachControl();
     }
 
     handleErrors() {
         // In case of error during loading, meshes will be empty and clearColor is set to red
         if (this._scene.meshes.length === 0 && this._scene.clearColor.r === 1 && this._scene.clearColor.g === 0 && this._scene.clearColor.b === 0) {
             this._canvas.style.opacity = "0";
-            this.props.globalState.onError.notifyObservers({scene: this._scene, message: "No mesh found in your scene"});
-        }
-        else {
+            this.props.globalState.onError.notifyObservers({ scene: this._scene, message: "No mesh found in your scene" });
+        } else {
             if (Tools.errorsCount > 0) {
-                this.props.globalState.onError.notifyObservers({scene: this._scene, message: "Scene loaded but several errors were found"});
+                this.props.globalState.onError.notifyObservers({ scene: this._scene, message: "Scene loaded but several errors were found" });
             }
-        //    this._canvas.style.opacity = "1";
+            //    this._canvas.style.opacity = "1";
             let camera = this._scene.activeCamera! as ArcRotateCamera;
             if (camera.keysUp) {
                 camera.keysUp.push(90); // Z
@@ -160,7 +162,7 @@ export class RenderingZone extends React.Component<IRenderingZoneProps> {
                 camera.keysRight.push(69); // E
                 camera.keysRight.push(68); // D
             }
-        }      
+        }
     }
 
     prepareLighting() {
@@ -172,8 +174,7 @@ export class RenderingZone extends React.Component<IRenderingZoneProps> {
             if (this._scene.environmentTexture) {
                 this._scene.createDefaultSkybox(this._scene.environmentTexture, true, (this._scene.activeCamera!.maxZ - this._scene.activeCamera!.minZ) / 2, 0.3, false);
             }
-        }
-        else {
+        } else {
             var pbrPresent = false;
             for (var i = 0; i < this._scene.materials.length; i++) {
                 if (this._scene.materials[i].transparencyMode !== undefined) {
@@ -186,8 +187,7 @@ export class RenderingZone extends React.Component<IRenderingZoneProps> {
                 if (!this._scene.environmentTexture) {
                     this._scene.environmentTexture = EnvironmentTools.LoadSkyboxPathTexture(this._scene);
                 }
-            }
-            else {
+            } else {
                 this._scene.createDefaultLight();
             }
         }
@@ -198,7 +198,7 @@ export class RenderingZone extends React.Component<IRenderingZoneProps> {
 
         this._scene.skipFrustumClipping = true;
 
-        this.props.globalState.onSceneLoaded.notifyObservers({scene: this._scene, filename: filename});
+        this.props.globalState.onSceneLoaded.notifyObservers({ scene: this._scene, filename: filename });
 
         this.prepareCamera();
         this.prepareLighting();
@@ -213,24 +213,26 @@ export class RenderingZone extends React.Component<IRenderingZoneProps> {
         let assetUrl = this.props.assetUrl!;
         let rootUrl = Tools.GetFolderPath(assetUrl);
         let fileName = Tools.GetFilename(assetUrl);
-        SceneLoader.LoadAsync(rootUrl, fileName, this._engine).then((scene) => {
-            if (this._scene) {
-                this._scene.dispose();
-            }
+        SceneLoader.LoadAsync(rootUrl, fileName, this._engine)
+            .then((scene) => {
+                if (this._scene) {
+                    this._scene.dispose();
+                }
 
-            this._scene = scene;
+                this._scene = scene;
 
-            this.onSceneLoaded(fileName);
+                this.onSceneLoaded(fileName);
 
-            scene.whenReadyAsync().then(() => {
-                this._engine.runRenderLoop(() => {
-                    scene.render();
+                scene.whenReadyAsync().then(() => {
+                    this._engine.runRenderLoop(() => {
+                        scene.render();
+                    });
                 });
+            })
+            .catch((reason) => {
+                this.props.globalState.onError.notifyObservers({ message: reason.message });
+                //TODO sceneError({ name: fileName }, null, reason.message || reason);
             });
-        }).catch((reason) => {
-            this.props.globalState.onError.notifyObservers({ message : reason.message});
-            //TODO sceneError({ name: fileName }, null, reason.message || reason);
-        });
     }
 
     loadAsset() {
@@ -249,13 +251,13 @@ export class RenderingZone extends React.Component<IRenderingZoneProps> {
 
         // This is really important to tell Babylon.js to use decomposeLerp and matrix interpolation
         Animation.AllowMatricesInterpolation = true;
-    
+
         // Setting up some GLTF values
         GLTFFileLoader.IncrementalLoading = false;
-        SceneLoader.OnPluginActivatedObservable.add((plugin) =>{
+        SceneLoader.OnPluginActivatedObservable.add((plugin) => {
             this._currentPluginName = plugin.name;
             if (this._currentPluginName === "gltf") {
-                (plugin as GLTFFileLoader).onValidatedObservable.add((results) =>{
+                (plugin as GLTFFileLoader).onValidatedObservable.add((results) => {
                     if (results.issues.numErrors > 0) {
                         this.props.globalState.showDebugLayer();
                     }
@@ -277,9 +279,8 @@ export class RenderingZone extends React.Component<IRenderingZoneProps> {
     public render() {
         return (
             <div id="canvasZone" className={this.props.expanded ? "expanded" : ""}>
-                <canvas id="renderCanvas" touch-action="none" 
-                    onContextMenu={evt => evt.preventDefault()}></canvas>
+                <canvas id="renderCanvas" touch-action="none" onContextMenu={(evt) => evt.preventDefault()}></canvas>
             </div>
-        )
+        );
     }
-}
+}

+ 16 - 0
src/Audio/sound.ts

@@ -150,6 +150,21 @@ export class Sound {
      */
     public onEndedObservable = new Observable<Sound>();
 
+    /**
+     * Gets the current time for the sound.
+     */
+    public get currentTime(): number {
+        if (this._htmlAudioElement) {
+            return this._htmlAudioElement.currentTime;
+        }
+
+        let currentTime: number = this._startOffset;
+        if (this.isPlaying && Engine.audioEngine.audioContext) {
+            currentTime += Engine.audioEngine.audioContext.currentTime - this._startTime;
+        }
+        return currentTime;
+    }
+
     private _panningModel: string = "equalpower";
     private _playbackRate: number = 1;
     private _streaming: boolean = false;
@@ -835,6 +850,7 @@ export class Sound {
 
     private _onended() {
         this.isPlaying = false;
+        this._startOffset = 0;
         if (this.onended) {
             this.onended();
         }

+ 4 - 5
src/Behaviors/Meshes/pointerDragBehavior.ts

@@ -261,9 +261,9 @@ export class PointerDragBehavior implements Behavior<AbstractMesh> {
         if (this.detachCameraControls && this._attachedElement && this._scene.activeCamera && !this._scene.activeCamera.leftCamera) {
             if (this._scene.activeCamera.getClassName() === "ArcRotateCamera") {
                 const arcRotateCamera = this._scene.activeCamera as ArcRotateCamera;
-                arcRotateCamera.attachControl(this._attachedElement, arcRotateCamera.inputs ? arcRotateCamera.inputs.noPreventDefault : true, arcRotateCamera._useCtrlForPanning, arcRotateCamera._panningMouseButton);
+                arcRotateCamera.attachControl(arcRotateCamera.inputs ? arcRotateCamera.inputs.noPreventDefault : true, arcRotateCamera._useCtrlForPanning, arcRotateCamera._panningMouseButton);
             } else {
-                this._scene.activeCamera.attachControl(this._attachedElement, this._scene.activeCamera.inputs ? this._scene.activeCamera.inputs.noPreventDefault : true);
+                this._scene.activeCamera.attachControl(this._scene.activeCamera.inputs ? this._scene.activeCamera.inputs.noPreventDefault : true);
             }
         }
     }
@@ -318,9 +318,8 @@ export class PointerDragBehavior implements Behavior<AbstractMesh> {
 
             // Detatch camera controls
             if (this.detachCameraControls && this._scene.activeCamera && this._scene.activeCamera.inputs && !this._scene.activeCamera.leftCamera) {
-                if (this._scene.activeCamera.inputs.attachedElement) {
-                    this._attachedElement = this._scene.activeCamera.inputs.attachedElement;
-                    this._scene.activeCamera.detachControl(this._scene.activeCamera.inputs.attachedElement);
+                if (this._scene.activeCamera.inputs.attachedToElement) {
+                    this._scene.activeCamera.detachControl();
                 } else {
                     this._attachedElement = null;
                 }

+ 4 - 5
src/Behaviors/Meshes/sixDofDragBehavior.ts

@@ -146,9 +146,8 @@ export class SixDofDragBehavior implements Behavior<Mesh> {
 
                     // Detatch camera controls
                     if (this.detachCameraControls && this._pointerCamera && !this._pointerCamera.leftCamera) {
-                        if (this._pointerCamera.inputs.attachedElement) {
-                            this._attachedElement = this._pointerCamera.inputs.attachedElement;
-                            this._pointerCamera.detachControl(this._pointerCamera.inputs.attachedElement);
+                        if (this._pointerCamera.inputs.attachedToElement) {
+                            this._pointerCamera.detachControl();
                         } else {
                             this._attachedElement = null;
                         }
@@ -166,7 +165,7 @@ export class SixDofDragBehavior implements Behavior<Mesh> {
 
                     // Reattach camera controls
                     if (this.detachCameraControls && this._attachedElement && this._pointerCamera && !this._pointerCamera.leftCamera) {
-                        this._pointerCamera.attachControl(this._attachedElement, true);
+                        this._pointerCamera.attachControl(true);
                     }
                     this.onDragEndObservable.notifyObservers({});
                 }
@@ -247,7 +246,7 @@ export class SixDofDragBehavior implements Behavior<Mesh> {
     public detach(): void {
         if (this._scene) {
             if (this.detachCameraControls && this._attachedElement && this._pointerCamera && !this._pointerCamera.leftCamera) {
-                this._pointerCamera.attachControl(this._attachedElement, true);
+                this._pointerCamera.attachControl(true);
             }
             this._scene.onPointerObservable.remove(this._pointerObserver);
         }

+ 19 - 30
src/Cameras/Inputs/BaseCameraMouseWheelInput.ts

@@ -4,6 +4,7 @@ import { Observable, Observer } from "../../Misc/observable";
 import { Camera } from "../../Cameras/camera";
 import { ICameraInput } from "../../Cameras/cameraInputsManager";
 import { PointerInfo, PointerEventTypes } from "../../Events/pointerEvents";
+import { Tools } from "../../Misc/tools";
 
 /**
  * Base class for mouse wheel input..
@@ -40,28 +41,29 @@ export abstract class BaseCameraMouseWheelInput implements ICameraInput<Camera>
     /**
      * Observable for when a mouse wheel move event occurs.
      */
-    public onChangedObservable = new Observable<
-        {wheelDeltaX: number, wheelDeltaY: number, wheelDeltaZ: number}>();
+    public onChangedObservable = new Observable<{ wheelDeltaX: number; wheelDeltaY: number; wheelDeltaZ: number }>();
 
     private _wheel: Nullable<(pointer: PointerInfo) => void>;
     private _observer: Nullable<Observer<PointerInfo>>;
 
     /**
      * Attach the input controls to a specific dom element to get the input from.
-     * @param element Defines the element the controls should be listened from
      * @param noPreventDefault Defines whether event caught by the controls
      *   should call preventdefault().
      *   (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
      */
-    public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
+    public attachControl(noPreventDefault?: boolean): void {
+        noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments);
+
         this._wheel = (pointer) => {
             // sanity check - this should be a PointerWheel event.
-            if (pointer.type !== PointerEventTypes.POINTERWHEEL) { return; }
+            if (pointer.type !== PointerEventTypes.POINTERWHEEL) {
+                return;
+            }
 
             const event = <MouseWheelEvent>pointer.event;
 
-            const platformScale =
-                event.deltaMode === WheelEvent.DOM_DELTA_LINE ? this._ffMultiplier : 1;
+            const platformScale = event.deltaMode === WheelEvent.DOM_DELTA_LINE ? this._ffMultiplier : 1;
 
             if (event.deltaY !== undefined) {
                 // Most recent browsers versions have delta properties.
@@ -69,29 +71,19 @@ export abstract class BaseCameraMouseWheelInput implements ICameraInput<Camera>
                 // Chrome >=  v31  (Has WebGL >= v8)
                 // Edge >=    v12  (Has WebGl >= v12)
                 // https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent
-                this._wheelDeltaX +=
-                    this.wheelPrecisionX * platformScale * event.deltaX / this._normalize;
-                this._wheelDeltaY -=
-                    this.wheelPrecisionY * platformScale * event.deltaY / this._normalize;
-                this._wheelDeltaZ +=
-                    this.wheelPrecisionZ * platformScale * event.deltaZ / this._normalize;
+                this._wheelDeltaX += (this.wheelPrecisionX * platformScale * event.deltaX) / this._normalize;
+                this._wheelDeltaY -= (this.wheelPrecisionY * platformScale * event.deltaY) / this._normalize;
+                this._wheelDeltaZ += (this.wheelPrecisionZ * platformScale * event.deltaZ) / this._normalize;
             } else if ((<any>event).wheelDeltaY !== undefined) {
                 // Unsure whether these catch anything more. Documentation
                 // online is contradictory.
-                this._wheelDeltaX +=
-                    this.wheelPrecisionX * platformScale *
-                    (<any>event).wheelDeltaX / this._normalize;
-                this._wheelDeltaY -=
-                    this.wheelPrecisionY * platformScale *
-                    (<any>event).wheelDeltaY / this._normalize;
-                this._wheelDeltaZ +=
-                    this.wheelPrecisionZ * platformScale *
-                    (<any>event).wheelDeltaZ / this._normalize;
+                this._wheelDeltaX += (this.wheelPrecisionX * platformScale * (<any>event).wheelDeltaX) / this._normalize;
+                this._wheelDeltaY -= (this.wheelPrecisionY * platformScale * (<any>event).wheelDeltaY) / this._normalize;
+                this._wheelDeltaZ += (this.wheelPrecisionZ * platformScale * (<any>event).wheelDeltaZ) / this._normalize;
             } else if ((<any>event).wheelDelta) {
                 // IE >= v9   (Has WebGL >= v11)
                 // Maybe others?
-                this._wheelDeltaY -=
-                    this.wheelPrecisionY * (<any>event).wheelDelta / this._normalize;
+                this._wheelDeltaY -= (this.wheelPrecisionY * (<any>event).wheelDelta) / this._normalize;
             }
 
             if (event.preventDefault) {
@@ -101,16 +93,13 @@ export abstract class BaseCameraMouseWheelInput implements ICameraInput<Camera>
             }
         };
 
-        this._observer = this.camera.getScene().onPointerObservable.add(
-            this._wheel,
-            PointerEventTypes.POINTERWHEEL);
+        this._observer = this.camera.getScene().onPointerObservable.add(this._wheel, PointerEventTypes.POINTERWHEEL);
     }
 
     /**
      * Detach the current controls from the specified dom element.
-     * @param element Defines the element to stop listening the inputs from
      */
-    public detachControl(element: Nullable<HTMLElement>): void {
+    public detachControl(): void {
         if (this._observer) {
             this.camera.getScene().onPointerObservable.remove(this._observer);
             this._observer = null;
@@ -128,7 +117,7 @@ export abstract class BaseCameraMouseWheelInput implements ICameraInput<Camera>
         this.onChangedObservable.notifyObservers({
             wheelDeltaX: this._wheelDeltaX,
             wheelDeltaY: this._wheelDeltaY,
-            wheelDeltaZ: this._wheelDeltaZ
+            wheelDeltaZ: this._wheelDeltaZ,
         });
 
         // Clear deltas.

+ 9 - 7
src/Cameras/Inputs/BaseCameraPointersInput.ts

@@ -42,8 +42,10 @@ export abstract class BaseCameraPointersInput implements ICameraInput<Camera> {
      * @param element Defines the element the controls should be listened from
      * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
      */
-    public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
+    public attachControl(noPreventDefault?: boolean): void {
+        noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments);
         var engine = this.camera.getEngine();
+        const element = engine.getInputElement();
         var previousPinchSquaredDistance = 0;
         var previousMultiTouchPanPosition: Nullable<PointerTouch> = null;
 
@@ -115,7 +117,7 @@ export abstract class BaseCameraPointersInput implements ICameraInput<Camera> {
 
                 if (!noPreventDefault) {
                     evt.preventDefault();
-                    element.focus();
+                    element && element.focus();
                 }
             } else if (p.type === PointerEventTypes.POINTERDOUBLETAP) {
                 this.onDoubleTap(evt.pointerType);
@@ -225,7 +227,7 @@ export abstract class BaseCameraPointersInput implements ICameraInput<Camera> {
             this.onLostFocus();
         };
 
-        element.addEventListener("contextmenu",
+        element && element.addEventListener("contextmenu",
             <EventListener>this.onContextMenu.bind(this), false);
 
         let hostWindow = this.camera.getScene().getEngine().getHostWindow();
@@ -239,9 +241,8 @@ export abstract class BaseCameraPointersInput implements ICameraInput<Camera> {
 
     /**
      * Detach the current controls from the specified dom element.
-     * @param element Defines the element to stop listening the inputs from
      */
-    public detachControl(element: Nullable<HTMLElement>): void {
+    public detachControl(): void {
         if (this._onLostFocus) {
             let hostWindow = this.camera.getScene().getEngine().getHostWindow();
             if (hostWindow) {
@@ -251,12 +252,13 @@ export abstract class BaseCameraPointersInput implements ICameraInput<Camera> {
             }
         }
 
-        if (element && this._observer) {
+        if (this._observer) {
             this.camera.getScene().onPointerObservable.remove(this._observer);
             this._observer = null;
 
             if (this.onContextMenu) {
-                element.removeEventListener("contextmenu", <EventListener>this.onContextMenu);
+                const inputElement = this.camera.getScene().getEngine().getInputElement();
+                inputElement && inputElement.removeEventListener("contextmenu", <EventListener>this.onContextMenu);
             }
 
             this._onLostFocus = null;

+ 2 - 4
src/Cameras/Inputs/arcRotateCameraGamepadInput.ts

@@ -51,10 +51,8 @@ export class ArcRotateCameraGamepadInput implements ICameraInput<ArcRotateCamera
 
     /**
      * Attach the input controls to a specific dom element to get the input from.
-     * @param element Defines the element the controls should be listened from
-     * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
      */
-    public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
+    public attachControl(): void {
         let manager = this.camera.getScene().gamepadManager;
         this._onGamepadConnectedObserver = manager.onGamepadConnectedObservable.add((gamepad) => {
             if (gamepad.type !== Gamepad.POSE_ENABLED) {
@@ -78,7 +76,7 @@ export class ArcRotateCameraGamepadInput implements ICameraInput<ArcRotateCamera
      * Detach the current controls from the specified dom element.
      * @param element Defines the element to stop listening the inputs from
      */
-    public detachControl(element: Nullable<HTMLElement>): void {
+    public detachControl(): void {
         this.camera.getScene().gamepadManager.onGamepadConnectedObservable.remove(this._onGamepadConnectedObserver);
         this.camera.getScene().gamepadManager.onGamepadDisconnectedObservable.remove(this._onGamepadDisconnectedObserver);
         this.gamepad = null;

+ 13 - 24
src/Cameras/Inputs/arcRotateCameraKeyboardMoveInput.ts

@@ -6,6 +6,7 @@ import { ArcRotateCamera } from "../../Cameras/arcRotateCamera";
 import { ICameraInput, CameraInputTypes } from "../../Cameras/cameraInputsManager";
 import { Engine } from "../../Engines/engine";
 import { KeyboardInfo, KeyboardEventTypes } from "../../Events/keyboardEvents";
+import { Tools } from '../../Misc/tools';
 
 /**
  * Manage the keyboard inputs to control the movement of an arc rotate camera.
@@ -85,10 +86,12 @@ export class ArcRotateCameraKeyboardMoveInput implements ICameraInput<ArcRotateC
 
     /**
      * Attach the input controls to a specific dom element to get the input from.
-     * @param element Defines the element the controls should be listened from
      * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
      */
-    public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
+    public attachControl(noPreventDefault?: boolean): void {
+        // was there a second variable defined?
+        noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments);
+
         if (this._onCanvasBlurObserver) {
             return;
         }
@@ -107,11 +110,7 @@ export class ArcRotateCameraKeyboardMoveInput implements ICameraInput<ArcRotateC
                     this._ctrlPressed = evt.ctrlKey;
                     this._altPressed = evt.altKey;
 
-                    if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
-                        this.keysDown.indexOf(evt.keyCode) !== -1 ||
-                        this.keysLeft.indexOf(evt.keyCode) !== -1 ||
-                        this.keysRight.indexOf(evt.keyCode) !== -1 ||
-                        this.keysReset.indexOf(evt.keyCode) !== -1) {
+                    if (this.keysUp.indexOf(evt.keyCode) !== -1 || this.keysDown.indexOf(evt.keyCode) !== -1 || this.keysLeft.indexOf(evt.keyCode) !== -1 || this.keysRight.indexOf(evt.keyCode) !== -1 || this.keysReset.indexOf(evt.keyCode) !== -1) {
                         var index = this._keys.indexOf(evt.keyCode);
 
                         if (index === -1) {
@@ -124,13 +123,8 @@ export class ArcRotateCameraKeyboardMoveInput implements ICameraInput<ArcRotateC
                             }
                         }
                     }
-                }
-                else {
-                    if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
-                        this.keysDown.indexOf(evt.keyCode) !== -1 ||
-                        this.keysLeft.indexOf(evt.keyCode) !== -1 ||
-                        this.keysRight.indexOf(evt.keyCode) !== -1 ||
-                        this.keysReset.indexOf(evt.keyCode) !== -1) {
+                } else {
+                    if (this.keysUp.indexOf(evt.keyCode) !== -1 || this.keysDown.indexOf(evt.keyCode) !== -1 || this.keysLeft.indexOf(evt.keyCode) !== -1 || this.keysRight.indexOf(evt.keyCode) !== -1 || this.keysReset.indexOf(evt.keyCode) !== -1) {
                         var index = this._keys.indexOf(evt.keyCode);
 
                         if (index >= 0) {
@@ -150,9 +144,8 @@ export class ArcRotateCameraKeyboardMoveInput implements ICameraInput<ArcRotateC
 
     /**
      * Detach the current controls from the specified dom element.
-     * @param element Defines the element to stop listening the inputs from
      */
-    public detachControl(element: Nullable<HTMLElement>) {
+    public detachControl() {
         if (this._scene) {
             if (this._onKeyboardObserver) {
                 this._scene.onKeyboardObservable.remove(this._onKeyboardObserver);
@@ -186,11 +179,9 @@ export class ArcRotateCameraKeyboardMoveInput implements ICameraInput<ArcRotateC
                 } else if (this.keysUp.indexOf(keyCode) !== -1) {
                     if (this._ctrlPressed && this.camera._useCtrlForPanning) {
                         camera.inertialPanningY += 1 / this.panningSensibility;
-                    }
-                    else if (this._altPressed && this.useAltToZoom) {
+                    } else if (this._altPressed && this.useAltToZoom) {
                         camera.inertialRadiusOffset += 1 / this.zoomingSensibility;
-                    }
-                    else {
+                    } else {
                         camera.inertialBetaOffset -= this.angularSpeed;
                     }
                 } else if (this.keysRight.indexOf(keyCode) !== -1) {
@@ -202,11 +193,9 @@ export class ArcRotateCameraKeyboardMoveInput implements ICameraInput<ArcRotateC
                 } else if (this.keysDown.indexOf(keyCode) !== -1) {
                     if (this._ctrlPressed && this.camera._useCtrlForPanning) {
                         camera.inertialPanningY -= 1 / this.panningSensibility;
-                    }
-                    else if (this._altPressed && this.useAltToZoom) {
+                    } else if (this._altPressed && this.useAltToZoom) {
                         camera.inertialRadiusOffset -= 1 / this.zoomingSensibility;
-                    }
-                    else {
+                    } else {
                         camera.inertialBetaOffset += this.angularSpeed;
                     }
                 } else if (this.keysReset.indexOf(keyCode) !== -1) {

+ 6 - 5
src/Cameras/Inputs/arcRotateCameraMouseWheelInput.ts

@@ -5,6 +5,7 @@ import { ArcRotateCamera } from "../../Cameras/arcRotateCamera";
 import { ICameraInput, CameraInputTypes } from "../../Cameras/cameraInputsManager";
 import { PointerInfo, PointerEventTypes } from "../../Events/pointerEvents";
 import { Scalar } from '../../Maths/math.scalar';
+import { Tools } from '../../Misc/tools';
 
 /**
  * Manage the mouse wheel inputs to control an arc rotate camera.
@@ -44,10 +45,11 @@ export class ArcRotateCameraMouseWheelInput implements ICameraInput<ArcRotateCam
     }
     /**
      * Attach the input controls to a specific dom element to get the input from.
-     * @param element Defines the element the controls should be listened from
      * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
      */
-    public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
+    public attachControl(noPreventDefault?: boolean): void {
+        // was there a second variable defined?
+        noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments);
         this._wheel = (p, s) => {
             //sanity check - this should be a PointerWheel event.
             if (p.type !== PointerEventTypes.POINTERWHEEL) { return; }
@@ -98,10 +100,9 @@ export class ArcRotateCameraMouseWheelInput implements ICameraInput<ArcRotateCam
 
     /**
      * Detach the current controls from the specified dom element.
-     * @param element Defines the element to stop listening the inputs from
      */
-    public detachControl(element: Nullable<HTMLElement>): void {
-        if (this._observer && element) {
+    public detachControl(): void {
+        if (this._observer) {
             this.camera.getScene().onPointerObservable.remove(this._observer);
             this._observer = null;
             this._wheel = null;

+ 5 - 6
src/Cameras/Inputs/arcRotateCameraVRDeviceOrientationInput.ts

@@ -1,4 +1,3 @@
-import { Nullable } from "../../types";
 import { ArcRotateCamera } from "../../Cameras/arcRotateCamera";
 import { ICameraInput, CameraInputTypes } from "../../Cameras/cameraInputsManager";
 import { ArcRotateCameraInputsManager } from "../../Cameras/arcRotateCameraInputsManager";
@@ -59,11 +58,12 @@ export class ArcRotateCameraVRDeviceOrientationInput implements ICameraInput<Arc
 
     /**
      * Attach the input controls to a specific dom element to get the input from.
-     * @param element Defines the element the controls should be listened from
      * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
      */
-    public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
-        this.camera.attachControl(element, noPreventDefault);
+    public attachControl(noPreventDefault?: boolean): void {
+        noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments);
+
+        this.camera.attachControl(noPreventDefault);
 
         let hostWindow = this.camera.getScene().getEngine().getHostWindow();
 
@@ -118,9 +118,8 @@ export class ArcRotateCameraVRDeviceOrientationInput implements ICameraInput<Arc
 
     /**
      * Detach the current controls from the specified dom element.
-     * @param element Defines the element to stop listening the inputs from
      */
-    public detachControl(element: Nullable<HTMLElement>): void {
+    public detachControl(): void {
         window.removeEventListener("deviceorientation", this._deviceOrientationHandler);
     }
 

+ 4 - 4
src/Cameras/Inputs/flyCameraKeyboardInput.ts

@@ -7,6 +7,7 @@ import { Engine } from "../../Engines/engine";
 import { KeyboardInfo, KeyboardEventTypes } from "../../Events/keyboardEvents";
 import { Scene } from "../../scene";
 import { Vector3 } from "../../Maths/math.vector";
+import { Tools } from '../../Misc/tools';
 
 /**
  * Listen to keyboard events to control the camera.
@@ -62,10 +63,10 @@ export class FlyCameraKeyboardInput implements ICameraInput<FlyCamera> {
 
     /**
      * Attach the input controls to a specific dom element to get the input from.
-     * @param element Defines the element the controls should be listened from
      * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
      */
-    public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
+    public attachControl(noPreventDefault?: boolean): void {
+        noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments);
         if (this._onCanvasBlurObserver) {
             return;
         }
@@ -118,9 +119,8 @@ export class FlyCameraKeyboardInput implements ICameraInput<FlyCamera> {
 
     /**
      * Detach the current controls from the specified dom element.
-     * @param element Defines the element to stop listening the inputs from
      */
-    public detachControl(element: Nullable<HTMLElement>): void {
+    public detachControl(): void {
         if (this._scene) {
             if (this._onKeyboardObserver) {
                 this._scene.onKeyboardObservable.remove(this._onKeyboardObserver);

+ 5 - 6
src/Cameras/Inputs/flyCameraMouseInput.ts

@@ -7,6 +7,7 @@ import { PointerInfo, PointerEventTypes } from "../../Events/pointerEvents";
 import { Scene } from "../../scene";
 import { Quaternion } from "../../Maths/math.vector";
 import { Axis } from '../../Maths/math.axis';
+import { Tools } from '../../Misc/tools';
 /**
  * Listen to mouse events to control the camera.
  * @see https://doc.babylonjs.com/how_to/customizing_camera_inputs
@@ -75,11 +76,10 @@ export class FlyCameraMouseInput implements ICameraInput<FlyCamera> {
 
     /**
      * Attach the mouse control to the HTML DOM element.
-     * @param element Defines the element that listens to the input events.
      * @param noPreventDefault Defines whether events caught by the controls should call preventdefault().
      */
-    public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
-        this.element = element;
+    public attachControl(noPreventDefault?: boolean): void {
+        noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments);
         this.noPreventDefault = noPreventDefault;
 
         this._observer = this.camera.getScene().onPointerObservable.add(
@@ -101,10 +101,9 @@ export class FlyCameraMouseInput implements ICameraInput<FlyCamera> {
 
     /**
      * Detach the current controls from the specified dom element.
-     * @param element Defines the element to stop listening the inputs from
      */
-    public detachControl(element: Nullable<HTMLElement>): void {
-        if (this._observer && element) {
+    public detachControl(): void {
+        if (this._observer) {
             this.camera.getScene().onPointerObservable.remove(this._observer);
 
             this.camera.getScene().onBeforeRenderObservable.remove(this._rollObserver);

+ 4 - 4
src/Cameras/Inputs/followCameraKeyboardMoveInput.ts

@@ -6,6 +6,7 @@ import { Observer } from "../../Misc/observable";
 import { Engine } from "../../Engines/engine";
 import { KeyboardInfo, KeyboardEventTypes } from "../../Events/keyboardEvents";
 import { Scene } from "../../scene";
+import { Tools } from '../../Misc/tools';
 
 /**
  * Manage the keyboard inputs to control the movement of a follow camera.
@@ -136,10 +137,10 @@ export class FollowCameraKeyboardMoveInput implements ICameraInput<FollowCamera>
 
     /**
      * Attach the input controls to a specific dom element to get the input from.
-     * @param element Defines the element the controls should be listened from
      * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
      */
-    public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
+    public attachControl(noPreventDefault?: boolean): void {
+        noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments);
         if (this._onCanvasBlurObserver) {
             return;
         }
@@ -203,9 +204,8 @@ export class FollowCameraKeyboardMoveInput implements ICameraInput<FollowCamera>
 
     /**
      * Detach the current controls from the specified dom element.
-     * @param element Defines the element to stop listening the inputs from
      */
-    public detachControl(element: Nullable<HTMLElement>) {
+    public detachControl() {
         if (this._scene) {
             if (this._onKeyboardObserver) {
                 this._scene.onKeyboardObservable.remove(this._onKeyboardObserver);

+ 5 - 5
src/Cameras/Inputs/followCameraMouseWheelInput.ts

@@ -4,6 +4,7 @@ import { EventState, Observer } from "../../Misc/observable";
 import { FollowCamera } from "../../Cameras/followCamera";
 import { ICameraInput, CameraInputTypes } from "../../Cameras/cameraInputsManager";
 import { PointerInfo, PointerEventTypes } from "../../Events/pointerEvents";
+import { Tools } from '../../Misc/tools';
 
 /**
  * Manage the mouse wheel inputs to control a follow camera.
@@ -52,10 +53,10 @@ export class FollowCameraMouseWheelInput implements ICameraInput<FollowCamera> {
 
     /**
      * Attach the input controls to a specific dom element to get the input from.
-     * @param element Defines the element the controls should be listened from
      * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
      */
-    public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
+    public attachControl(noPreventDefault?: boolean): void {
+        noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments);
         this._wheel = (p, s) => {
             // sanity check - this should be a PointerWheel event.
             if (p.type !== PointerEventTypes.POINTERWHEEL) { return; }
@@ -117,10 +118,9 @@ export class FollowCameraMouseWheelInput implements ICameraInput<FollowCamera> {
 
     /**
      * Detach the current controls from the specified dom element.
-     * @param element Defines the element to stop listening the inputs from
      */
-    public detachControl(element: Nullable<HTMLElement>): void {
-        if (this._observer && element) {
+    public detachControl(): void {
+        if (this._observer) {
             this.camera.getScene().onPointerObservable.remove(this._observer);
             this._observer = null;
             this._wheel = null;

+ 2 - 5
src/Cameras/Inputs/freeCameraDeviceOrientationInput.ts

@@ -127,10 +127,8 @@ export class FreeCameraDeviceOrientationInput implements ICameraInput<FreeCamera
 
     /**
      * Attach the input controls to a specific dom element to get the input from.
-     * @param element Defines the element the controls should be listened from
-     * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
      */
-    public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
+    public attachControl(): void {
 
         let hostWindow = this.camera.getScene().getEngine().getHostWindow();
 
@@ -178,9 +176,8 @@ export class FreeCameraDeviceOrientationInput implements ICameraInput<FreeCamera
 
     /**
      * Detach the current controls from the specified dom element.
-     * @param element Defines the element to stop listening the inputs from
      */
-    public detachControl(element: Nullable<HTMLElement>): void {
+    public detachControl(): void {
         window.removeEventListener("orientationchange", this._orientationChanged);
         window.removeEventListener("deviceorientation", this._deviceOrientation);
         this._alpha = 0;

+ 2 - 5
src/Cameras/Inputs/freeCameraGamepadInput.ts

@@ -58,10 +58,8 @@ export class FreeCameraGamepadInput implements ICameraInput<FreeCamera> {
 
     /**
      * Attach the input controls to a specific dom element to get the input from.
-     * @param element Defines the element the controls should be listened from
-     * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
      */
-    public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
+    public attachControl(): void {
         let manager = this.camera.getScene().gamepadManager;
         this._onGamepadConnectedObserver = manager.onGamepadConnectedObservable.add((gamepad) => {
             if (gamepad.type !== Gamepad.POSE_ENABLED) {
@@ -88,9 +86,8 @@ export class FreeCameraGamepadInput implements ICameraInput<FreeCamera> {
 
     /**
      * Detach the current controls from the specified dom element.
-     * @param element Defines the element to stop listening the inputs from
      */
-    public detachControl(element: Nullable<HTMLElement>): void {
+    public detachControl(): void {
         this.camera.getScene().gamepadManager.onGamepadConnectedObservable.remove(this._onGamepadConnectedObserver);
         this.camera.getScene().gamepadManager.onGamepadDisconnectedObservable.remove(this._onGamepadDisconnectedObserver);
         this.gamepad = null;

+ 4 - 4
src/Cameras/Inputs/freeCameraKeyboardMoveInput.ts

@@ -7,6 +7,7 @@ import { KeyboardInfo, KeyboardEventTypes } from "../../Events/keyboardEvents";
 import { Scene } from "../../scene";
 import { Vector3 } from "../../Maths/math.vector";
 import { Engine } from "../../Engines/engine";
+import { Tools } from '../../Misc/tools';
 /**
  * Manage the keyboard inputs to control the movement of a free camera.
  * @see https://doc.babylonjs.com/how_to/customizing_camera_inputs
@@ -61,10 +62,10 @@ export class FreeCameraKeyboardMoveInput implements ICameraInput<FreeCamera> {
 
     /**
      * Attach the input controls to a specific dom element to get the input from.
-     * @param element Defines the element the controls should be listened from
      * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
      */
-    public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
+    public attachControl(noPreventDefault?: boolean): void {
+        noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments);
         if (this._onCanvasBlurObserver) {
             return;
         }
@@ -118,9 +119,8 @@ export class FreeCameraKeyboardMoveInput implements ICameraInput<FreeCamera> {
 
     /**
      * Detach the current controls from the specified dom element.
-     * @param element Defines the element to stop listening the inputs from
      */
-    public detachControl(element: Nullable<HTMLElement>): void {
+    public detachControl(): void {
         if (this._scene) {
             if (this._onKeyboardObserver) {
                 this._scene.onKeyboardObservable.remove(this._onKeyboardObserver);

+ 32 - 25
src/Cameras/Inputs/freeCameraMouseInput.ts

@@ -4,6 +4,7 @@ import { Nullable } from "../../types";
 import { ICameraInput, CameraInputTypes } from "../../Cameras/cameraInputsManager";
 import { FreeCamera } from "../../Cameras/freeCamera";
 import { PointerInfo, PointerEventTypes } from "../../Events/pointerEvents";
+import { Tools } from "../../Misc/tools";
 /**
  * Manage the mouse inputs to control the movement of a free camera.
  * @see https://doc.babylonjs.com/how_to/customizing_camera_inputs
@@ -29,12 +30,12 @@ export class FreeCameraMouseInput implements ICameraInput<FreeCamera> {
     private _pointerInput: (p: PointerInfo, s: EventState) => void;
     private _onMouseMove: Nullable<(e: MouseEvent) => any>;
     private _observer: Nullable<Observer<PointerInfo>>;
-    private previousPosition: Nullable<{ x: number, y: number }> = null;
+    private previousPosition: Nullable<{ x: number; y: number }> = null;
 
     /**
      * Observable for when a pointer move event occurs containing the move offset
      */
-    public onPointerMovedObservable = new Observable<{ offsetX: number, offsetY: number }>();
+    public onPointerMovedObservable = new Observable<{ offsetX: number; offsetY: number }>();
     /**
      * @hidden
      * If the camera should be rotated automatically based on pointer movement
@@ -49,16 +50,17 @@ export class FreeCameraMouseInput implements ICameraInput<FreeCamera> {
         /**
          * Define if touch is enabled in the mouse input
          */
-        public touchEnabled = true) {
-    }
+        public touchEnabled = true
+    ) {}
 
     /**
      * Attach the input controls to a specific dom element to get the input from.
-     * @param element Defines the element the controls should be listened from
      * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
      */
-    public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
+    public attachControl(noPreventDefault?: boolean): void {
+        noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments);
         var engine = this.camera.getEngine();
+        const element = engine.getInputElement();
 
         if (!this._pointerInput) {
             this._pointerInput = (p) => {
@@ -87,20 +89,19 @@ export class FreeCameraMouseInput implements ICameraInput<FreeCamera> {
 
                     this.previousPosition = {
                         x: evt.clientX,
-                        y: evt.clientY
+                        y: evt.clientY,
                     };
 
                     if (!noPreventDefault) {
                         evt.preventDefault();
-                        element.focus();
+                        element && element.focus();
                     }
 
                     // This is required to move while pointer button is down
                     if (engine.isPointerLock && this._onMouseMove) {
                         this._onMouseMove(p.event);
                     }
-                }
-                else if (p.type === PointerEventTypes.POINTERUP && srcElement) {
+                } else if (p.type === PointerEventTypes.POINTERUP && srcElement) {
                     try {
                         srcElement.releasePointerCapture(evt.pointerId);
                     } catch (e) {
@@ -111,9 +112,7 @@ export class FreeCameraMouseInput implements ICameraInput<FreeCamera> {
                     if (!noPreventDefault) {
                         evt.preventDefault();
                     }
-                }
-
-                else if (p.type === PointerEventTypes.POINTERMOVE) {
+                } else if (p.type === PointerEventTypes.POINTERMOVE) {
                     if (!this.previousPosition) {
                         if (engine.isPointerLock && this._onMouseMove) {
                             this._onMouseMove(p.event);
@@ -124,18 +123,22 @@ export class FreeCameraMouseInput implements ICameraInput<FreeCamera> {
 
                     var offsetX = evt.clientX - this.previousPosition.x;
                     var offsetY = evt.clientY - this.previousPosition.y;
-                    if (this.camera.getScene().useRightHandedSystem) { offsetX *= -1; }
-                    if (this.camera.parent && this.camera.parent._getWorldMatrixDeterminant() < 0) { offsetX *= -1; }
+                    if (this.camera.getScene().useRightHandedSystem) {
+                        offsetX *= -1;
+                    }
+                    if (this.camera.parent && this.camera.parent._getWorldMatrixDeterminant() < 0) {
+                        offsetX *= -1;
+                    }
 
                     if (this._allowCameraRotation) {
                         this.camera.cameraRotation.y += offsetX / this.angularSensibility;
                         this.camera.cameraRotation.x += offsetY / this.angularSensibility;
                     }
-                    this.onPointerMovedObservable.notifyObservers({offsetX: offsetX, offsetY: offsetY});
+                    this.onPointerMovedObservable.notifyObservers({ offsetX: offsetX, offsetY: offsetY });
 
                     this.previousPosition = {
                         x: evt.clientX,
-                        y: evt.clientY
+                        y: evt.clientY,
                     };
 
                     if (!noPreventDefault) {
@@ -155,8 +158,12 @@ export class FreeCameraMouseInput implements ICameraInput<FreeCamera> {
             }
 
             var offsetX = evt.movementX || evt.mozMovementX || evt.webkitMovementX || evt.msMovementX || 0;
-            if (this.camera.getScene().useRightHandedSystem) { offsetX *= -1; }
-            if (this.camera.parent && this.camera.parent._getWorldMatrixDeterminant() < 0) { offsetX *= -1; }
+            if (this.camera.getScene().useRightHandedSystem) {
+                offsetX *= -1;
+            }
+            if (this.camera.parent && this.camera.parent._getWorldMatrixDeterminant() < 0) {
+                offsetX *= -1;
+            }
             this.camera.cameraRotation.y += offsetX / this.angularSensibility;
 
             var offsetY = evt.movementY || evt.mozMovementY || evt.webkitMovementY || evt.msMovementY || 0;
@@ -171,8 +178,7 @@ export class FreeCameraMouseInput implements ICameraInput<FreeCamera> {
 
         this._observer = this.camera.getScene().onPointerObservable.add(this._pointerInput, PointerEventTypes.POINTERDOWN | PointerEventTypes.POINTERUP | PointerEventTypes.POINTERMOVE);
 
-        element.addEventListener("contextmenu",
-            <EventListener>this.onContextMenu.bind(this), false);
+        element && element.addEventListener("contextmenu", <EventListener>this.onContextMenu.bind(this), false);
     }
 
     /**
@@ -185,14 +191,15 @@ export class FreeCameraMouseInput implements ICameraInput<FreeCamera> {
 
     /**
      * Detach the current controls from the specified dom element.
-     * @param element Defines the element to stop listening the inputs from
      */
-    public detachControl(element: Nullable<HTMLElement>): void {
-        if (this._observer && element) {
+    public detachControl(): void {
+        if (this._observer) {
             this.camera.getScene().onPointerObservable.remove(this._observer);
 
             if (this.onContextMenu) {
-                element.removeEventListener("contextmenu", <EventListener>this.onContextMenu);
+                const engine = this.camera.getEngine();
+                const element = engine.getInputElement();
+                element && element.removeEventListener("contextmenu", <EventListener>this.onContextMenu);
             }
 
             if (this.onPointerMovedObservable) {

+ 19 - 19
src/Cameras/Inputs/freeCameraTouchInput.ts

@@ -5,6 +5,7 @@ import { ICameraInput, CameraInputTypes } from "../../Cameras/cameraInputsManage
 import { FreeCamera } from "../../Cameras/freeCamera";
 import { PointerInfo, PointerEventTypes } from "../../Events/pointerEvents";
 import { Matrix, Vector3 } from "../../Maths/math.vector";
+import { Tools } from "../../Misc/tools";
 /**
  * Manage the touch inputs to control the movement of a free camera.
  * @see https://doc.babylonjs.com/how_to/customizing_camera_inputs
@@ -33,7 +34,7 @@ export class FreeCameraTouchInput implements ICameraInput<FreeCamera> {
     private _offsetY: Nullable<number> = null;
 
     private _pointerPressed = new Array<number>();
-    private _pointerInput: (p: PointerInfo, s: EventState) => void;
+    private _pointerInput?: (p: PointerInfo, s: EventState) => void;
     private _observer: Nullable<Observer<PointerInfo>>;
     private _onLostFocus: Nullable<(e: FocusEvent) => any>;
 
@@ -46,16 +47,16 @@ export class FreeCameraTouchInput implements ICameraInput<FreeCamera> {
         /**
          * Define if mouse events can be treated as touch events
          */
-        public allowMouse = false) {
-    }
+        public allowMouse = false
+    ) {}
 
     /**
      * Attach the input controls to a specific dom element to get the input from.
-     * @param element Defines the element the controls should be listened from
      * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
      */
-    public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
-        var previousPosition: Nullable<{ x: number, y: number }> = null;
+    public attachControl(noPreventDefault?: boolean): void {
+        noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments);
+        var previousPosition: Nullable<{ x: number; y: number }> = null;
 
         if (this._pointerInput === undefined) {
             this._onLostFocus = () => {
@@ -72,7 +73,6 @@ export class FreeCameraTouchInput implements ICameraInput<FreeCamera> {
                 }
 
                 if (p.type === PointerEventTypes.POINTERDOWN) {
-
                     if (!noPreventDefault) {
                         evt.preventDefault();
                     }
@@ -85,11 +85,9 @@ export class FreeCameraTouchInput implements ICameraInput<FreeCamera> {
 
                     previousPosition = {
                         x: evt.clientX,
-                        y: evt.clientY
+                        y: evt.clientY,
                     };
-                }
-
-                else if (p.type === PointerEventTypes.POINTERUP) {
+                } else if (p.type === PointerEventTypes.POINTERUP) {
                     if (!noPreventDefault) {
                         evt.preventDefault();
                     }
@@ -107,9 +105,7 @@ export class FreeCameraTouchInput implements ICameraInput<FreeCamera> {
                     previousPosition = null;
                     this._offsetX = null;
                     this._offsetY = null;
-                }
-
-                else if (p.type === PointerEventTypes.POINTERMOVE) {
+                } else if (p.type === PointerEventTypes.POINTERMOVE) {
                     if (!noPreventDefault) {
                         evt.preventDefault();
                     }
@@ -133,7 +129,9 @@ export class FreeCameraTouchInput implements ICameraInput<FreeCamera> {
         this._observer = this.camera.getScene().onPointerObservable.add(this._pointerInput, PointerEventTypes.POINTERDOWN | PointerEventTypes.POINTERUP | PointerEventTypes.POINTERMOVE);
 
         if (this._onLostFocus) {
-            element.addEventListener("blur", this._onLostFocus);
+            const engine = this.camera.getEngine();
+            const element = engine.getInputElement();
+            element && element.addEventListener("blur", this._onLostFocus);
         }
     }
 
@@ -141,15 +139,17 @@ export class FreeCameraTouchInput implements ICameraInput<FreeCamera> {
      * Detach the current controls from the specified dom element.
      * @param element Defines the element to stop listening the inputs from
      */
-    public detachControl(element: Nullable<HTMLElement>): void {
-        if (this._pointerInput && element) {
+    public detachControl(): void {
+        if (this._pointerInput) {
             if (this._observer) {
                 this.camera.getScene().onPointerObservable.remove(this._observer);
                 this._observer = null;
             }
 
             if (this._onLostFocus) {
-                element.removeEventListener("blur", this._onLostFocus);
+                const engine = this.camera.getEngine();
+                const element = engine.getInputElement();
+                element && element.removeEventListener("blur", this._onLostFocus);
                 this._onLostFocus = null;
             }
             this._pointerPressed = [];
@@ -177,7 +177,7 @@ export class FreeCameraTouchInput implements ICameraInput<FreeCamera> {
             camera.cameraRotation.x = -this._offsetY / this.touchAngularSensibility;
         } else {
             var speed = camera._computeLocalCameraSpeed();
-            var direction = new Vector3(0, 0, speed * this._offsetY / this.touchMoveSensibility);
+            var direction = new Vector3(0, 0, (speed * this._offsetY) / this.touchMoveSensibility);
 
             Matrix.RotationYawPitchRollToRef(camera.rotation.y, camera.rotation.x, 0, camera._cameraRotationMatrix);
             camera.cameraDirection.addInPlace(Vector3.TransformCoordinates(direction, camera._cameraRotationMatrix));

+ 2 - 6
src/Cameras/Inputs/freeCameraVirtualJoystickInput.ts

@@ -1,5 +1,4 @@
 import { VirtualJoystick, JoystickAxis } from "../../Misc/virtualJoystick";
-import { Nullable } from "../../types";
 import { ICameraInput, CameraInputTypes } from "../../Cameras/cameraInputsManager";
 import { FreeCamera } from "../../Cameras/freeCamera";
 import { Matrix, Vector3 } from "../../Maths/math.vector";
@@ -78,10 +77,8 @@ export class FreeCameraVirtualJoystickInput implements ICameraInput<FreeCamera>
 
     /**
      * Attach the input controls to a specific dom element to get the input from.
-     * @param element Defines the element the controls should be listened from
-     * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
      */
-    public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
+    public attachControl(): void {
         this._leftjoystick = new VirtualJoystick(true);
         this._leftjoystick.setAxisForUpDown(JoystickAxis.Z);
         this._leftjoystick.setAxisForLeftRight(JoystickAxis.X);
@@ -96,9 +93,8 @@ export class FreeCameraVirtualJoystickInput implements ICameraInput<FreeCamera>
 
     /**
      * Detach the current controls from the specified dom element.
-     * @param element Defines the element to stop listening the inputs from
      */
-    public detachControl(element: Nullable<HTMLElement>): void {
+    public detachControl(): void {
         this._leftjoystick.releaseCanvas();
         this._rightjoystick.releaseCanvas();
     }

+ 3 - 3
src/Cameras/VR/vrExperienceHelper.ts

@@ -787,7 +787,7 @@ export class VRExperienceHelper {
 
             this._scene.activeCamera = this._deviceOrientationCamera;
             if (this._inputElement) {
-                this._scene.activeCamera.attachControl(this._inputElement);
+                this._scene.activeCamera.attachControl();
             }
         } else {
             this._existingCamera = this._scene.activeCamera;
@@ -1180,7 +1180,7 @@ export class VRExperienceHelper {
         }
 
         if (this._scene.activeCamera && this._inputElement) {
-            this._scene.activeCamera.attachControl(this._inputElement);
+            this._scene.activeCamera.attachControl();
         }
 
         if (this._interactionsEnabled) {
@@ -1248,7 +1248,7 @@ export class VRExperienceHelper {
                 this._existingCamera.position = this._position;
                 this._scene.activeCamera = this._existingCamera;
                 if (this._inputElement) {
-                    this._scene.activeCamera.attachControl(this._inputElement);
+                    this._scene.activeCamera.attachControl();
                 }
 
                 // Restore angular sensibility

+ 8 - 11
src/Cameras/VR/webVRCamera.ts

@@ -21,6 +21,7 @@ import "../RigModes/webVRRigMode";
 
 // Side effect import to add webvr support to engine
 import "../../Engines/Extensions/engine.webVR";
+import { Tools } from '../../Misc/tools';
 
 Node.AddNodeConstructor("WebVRFreeCamera", (name, scene) => {
     return () => new WebVRFreeCamera(name, Vector3.Zero(), scene);
@@ -481,11 +482,10 @@ export class WebVRFreeCamera extends FreeCamera implements PoseControlled {
         }
     }
 
-    private _htmlElementAttached: Nullable<HTMLElement> = null;
     private _detachIfAttached = () => {
         var vrDisplay = this.getEngine().getVRDevice();
-        if (vrDisplay && !vrDisplay.isPresenting && this._htmlElementAttached) {
-            this.detachControl(this._htmlElementAttached);
+        if (vrDisplay && !vrDisplay.isPresenting) {
+            this.detachControl();
         }
     }
 
@@ -495,13 +495,12 @@ export class WebVRFreeCamera extends FreeCamera implements PoseControlled {
      * within a user-interaction callback. Example:
      * <pre> scene.onPointerDown = function() { camera.attachControl(canvas); }</pre>
      *
-     * @param element html element to attach the vrDevice to
      * @param noPreventDefault prevent the default html element operation when attaching the vrDevice
      */
-    public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
-        super.attachControl(element, noPreventDefault);
+    public attachControl(noPreventDefault?: boolean): void {
+        noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments);
+        super.attachControl(noPreventDefault);
         this._attached = true;
-        this._htmlElementAttached = element;
 
         noPreventDefault = Camera.ForceAttachControlToAlwaysPreventDefault ? false : noPreventDefault;
 
@@ -518,14 +517,12 @@ export class WebVRFreeCamera extends FreeCamera implements PoseControlled {
 
     /**
      * Detaches the camera from the html element and disables VR
-     *
-     * @param element html element to detach from
      */
-    public detachControl(element: HTMLElement): void {
+    public detachControl(): void {
         this.getScene().gamepadManager.onGamepadConnectedObservable.remove(this._onGamepadConnectedObserver);
         this.getScene().gamepadManager.onGamepadDisconnectedObservable.remove(this._onGamepadDisconnectedObserver);
 
-        super.detachControl(element);
+        super.detachControl();
         this._attached = false;
         this.getEngine().disableVR();
         window.removeEventListener('vrdisplaypresentchange', this._detachIfAttached);

+ 29 - 29
src/Cameras/arcRotateCamera.ts

@@ -15,7 +15,8 @@ import { ArcRotateCameraPointersInput } from "../Cameras/Inputs/arcRotateCameraP
 import { ArcRotateCameraKeyboardMoveInput } from "../Cameras/Inputs/arcRotateCameraKeyboardMoveInput";
 import { ArcRotateCameraMouseWheelInput } from "../Cameras/Inputs/arcRotateCameraMouseWheelInput";
 import { ArcRotateCameraInputsManager } from "../Cameras/arcRotateCameraInputsManager";
-import { Epsilon } from '../Maths/math.constants';
+import { Epsilon } from "../Maths/math.constants";
+import { Tools } from "../Misc/tools";
 
 declare type Collider = import("../Collisions/collider").Collider;
 
@@ -757,25 +758,21 @@ export class ArcRotateCamera extends TargetCamera {
             return false;
         }
 
-        return this._cache._target.equals(this._getTargetPosition())
-            && this._cache.alpha === this.alpha
-            && this._cache.beta === this.beta
-            && this._cache.radius === this.radius
-            && this._cache.targetScreenOffset.equals(this.targetScreenOffset);
+        return this._cache._target.equals(this._getTargetPosition()) && this._cache.alpha === this.alpha && this._cache.beta === this.beta && this._cache.radius === this.radius && this._cache.targetScreenOffset.equals(this.targetScreenOffset);
     }
 
     /**
      * Attached controls to the current camera.
-     * @param element Defines the element the controls should be listened from
      * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
      * @param useCtrlForPanning  Defines whether ctrl is used for paning within the controls
      * @param panningMouseButton Defines whether panning is allowed through mouse click button
      */
-    public attachControl(element: HTMLElement, noPreventDefault?: boolean, useCtrlForPanning: boolean = true, panningMouseButton: number = 2): void {
+    public attachControl(noPreventDefault?: boolean, useCtrlForPanning: boolean = true, panningMouseButton: number = 2): void {
+        noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments);
         this._useCtrlForPanning = useCtrlForPanning;
         this._panningMouseButton = panningMouseButton;
 
-        this.inputs.attachElement(element, noPreventDefault);
+        this.inputs.attachElement(noPreventDefault);
 
         this._reset = () => {
             this.inertialAlphaOffset = 0;
@@ -789,10 +786,9 @@ export class ArcRotateCamera extends TargetCamera {
     /**
      * Detach the current controls from the camera.
      * The camera will stop reacting to inputs.
-     * @param element Defines the element to stop listening the inputs from
      */
-    public detachControl(element: HTMLElement): void {
-        this.inputs.detachElement(element);
+    public detachControl(): void {
+        this.inputs.detachElement();
 
         if (this._reset) {
             this._reset();
@@ -810,9 +806,15 @@ export class ArcRotateCamera extends TargetCamera {
         // Inertia
         if (this.inertialAlphaOffset !== 0 || this.inertialBetaOffset !== 0 || this.inertialRadiusOffset !== 0) {
             let inertialAlphaOffset = this.inertialAlphaOffset;
-            if (this.beta <= 0) { inertialAlphaOffset *= -1; }
-            if (this.getScene().useRightHandedSystem) { inertialAlphaOffset *= -1; }
-            if (this.parent && this.parent._getWorldMatrixDeterminant() < 0) { inertialAlphaOffset *= -1; }
+            if (this.beta <= 0) {
+                inertialAlphaOffset *= -1;
+            }
+            if (this.getScene().useRightHandedSystem) {
+                inertialAlphaOffset *= -1;
+            }
+            if (this.parent && this.parent._getWorldMatrixDeterminant() < 0) {
+                inertialAlphaOffset *= -1;
+            }
             this.alpha += inertialAlphaOffset;
 
             this.beta += this.inertialBetaOffset;
@@ -852,11 +854,10 @@ export class ArcRotateCamera extends TargetCamera {
                 if (this.panningDistanceLimit) {
                     this._transformedDirection.addInPlace(this._target);
                     var distanceSquared = Vector3.DistanceSquared(this._transformedDirection, this.panningOriginTarget);
-                    if (distanceSquared <= (this.panningDistanceLimit * this.panningDistanceLimit)) {
+                    if (distanceSquared <= this.panningDistanceLimit * this.panningDistanceLimit) {
                         this._target.copyFrom(this._transformedDirection);
                     }
-                }
-                else {
+                } else {
                     this._target.addInPlace(this._transformedDirection);
                 }
             }
@@ -881,7 +882,7 @@ export class ArcRotateCamera extends TargetCamera {
     protected _checkLimits() {
         if (this.lowerBetaLimit === null || this.lowerBetaLimit === undefined) {
             if (this.allowUpsideDown && this.beta > Math.PI) {
-                this.beta = this.beta - (2 * Math.PI);
+                this.beta = this.beta - 2 * Math.PI;
             }
         } else {
             if (this.beta < this.lowerBetaLimit) {
@@ -891,7 +892,7 @@ export class ArcRotateCamera extends TargetCamera {
 
         if (this.upperBetaLimit === null || this.upperBetaLimit === undefined) {
             if (this.allowUpsideDown && this.beta < -Math.PI) {
-                this.beta = this.beta + (2 * Math.PI);
+                this.beta = this.beta + 2 * Math.PI;
             }
         } else {
             if (this.beta > this.upperBetaLimit) {
@@ -971,7 +972,6 @@ export class ArcRotateCamera extends TargetCamera {
      * @param allowSamePosition If false, prevents reapplying the new computed position if it is identical to the current one (optim)
      */
     public setTarget(target: AbstractMesh | Vector3, toBoundingCenter = false, allowSamePosition = false): void {
-
         if ((<any>target).getBoundingInfo) {
             if (toBoundingCenter) {
                 this._targetBoundingCenter = (<any>target).getBoundingInfo().boundingBox.centerWorld.clone();
@@ -1050,7 +1050,6 @@ export class ArcRotateCamera extends TargetCamera {
     }
 
     protected _onCollisionPositionChange = (collisionId: number, newPosition: Vector3, collidedMesh: Nullable<AbstractMesh> = null) => {
-
         if (!collidedMesh) {
             this._previousPosition.copyFrom(this._position);
         } else {
@@ -1087,7 +1086,7 @@ export class ArcRotateCamera extends TargetCamera {
         this._viewMatrix.addAtIndex(13, this.targetScreenOffset.y);
 
         this._collisionTriggered = false;
-    }
+    };
 
     /**
      * Zooms on a mesh to be at the min distance where we could see it fully in the current viewport.
@@ -1111,16 +1110,17 @@ export class ArcRotateCamera extends TargetCamera {
      * @param meshesOrMinMaxVectorAndDistance Defines the mesh or bounding info to focus on
      * @param doNotUpdateMaxZ Defines whether or not maxZ should be updated whilst zooming on the mesh (this can happen if the mesh is big and the maxradius pretty small for instance)
      */
-    public focusOn(meshesOrMinMaxVectorAndDistance: AbstractMesh[] | { min: Vector3, max: Vector3, distance: number }, doNotUpdateMaxZ = false): void {
-        var meshesOrMinMaxVector: { min: Vector3, max: Vector3 };
+    public focusOn(meshesOrMinMaxVectorAndDistance: AbstractMesh[] | { min: Vector3; max: Vector3; distance: number }, doNotUpdateMaxZ = false): void {
+        var meshesOrMinMaxVector: { min: Vector3; max: Vector3 };
         var distance: number;
 
-        if ((<any>meshesOrMinMaxVectorAndDistance).min === undefined) { // meshes
-            var meshes = (<AbstractMesh[]>meshesOrMinMaxVectorAndDistance) || this.getScene().meshes;
+        if ((<any>meshesOrMinMaxVectorAndDistance).min === undefined) {
+            // meshes
+            var meshes = <AbstractMesh[]>meshesOrMinMaxVectorAndDistance || this.getScene().meshes;
             meshesOrMinMaxVector = Mesh.MinMax(meshes);
             distance = Vector3.Distance(meshesOrMinMaxVector.min, meshesOrMinMaxVector.max);
-        }
-        else { //minMaxVector and distance
+        } else {
+            //minMaxVector and distance
             var minMaxVectorAndDistance = <any>meshesOrMinMaxVectorAndDistance;
             meshesOrMinMaxVector = minMaxVectorAndDistance;
             distance = minMaxVectorAndDistance.distance;

+ 2 - 4
src/Cameras/camera.ts

@@ -523,17 +523,15 @@ export class Camera extends Node {
 
     /**
      * Attach the input controls to a specific dom element to get the input from.
-     * @param element Defines the element the controls should be listened from
      * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
      */
-    public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
+    public attachControl(noPreventDefault?: boolean): void {
     }
 
     /**
      * Detach the current controls from the specified dom element.
-     * @param element Defines the element to stop listening the inputs from
      */
-    public detachControl(element: HTMLElement): void {
+    public detachControl(): void {
     }
 
     /**

+ 36 - 31
src/Cameras/cameraInputsManager.ts

@@ -30,15 +30,13 @@ export interface ICameraInput<TCamera extends Camera> {
     getSimpleName(): string;
     /**
      * Attach the input controls to a specific dom element to get the input from.
-     * @param element Defines the element the controls should be listened from
      * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
      */
-    attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+    attachControl(noPreventDefault?: boolean): void;
     /**
      * Detach the current controls from the specified dom element.
-     * @param element Defines the element to stop listening the inputs from
      */
-    detachControl(element: Nullable<HTMLElement>): void;
+    detachControl(): void;
     /**
      * Update the current camera state depending on the inputs that have been used this frame.
      * This is a dynamically created lambda to avoid the performance penalty of looping for inputs in the render loop.
@@ -75,7 +73,7 @@ export class CameraInputsManager<TCamera extends Camera> {
      * Defines the dom element the camera is collecting inputs from.
      * This is null if the controls have not been attached.
      */
-    public attachedElement: Nullable<HTMLElement>;
+    public attachedToElement: boolean = false;
 
     /**
      * Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
@@ -100,7 +98,7 @@ export class CameraInputsManager<TCamera extends Camera> {
     constructor(camera: TCamera) {
         this.attached = {};
         this.camera = camera;
-        this.checkInputs = () => { };
+        this.checkInputs = () => {};
     }
 
     /**
@@ -125,8 +123,8 @@ export class CameraInputsManager<TCamera extends Camera> {
             this.checkInputs = this._addCheckInputs(input.checkInputs.bind(input));
         }
 
-        if (this.attachedElement) {
-            input.attachControl(this.attachedElement);
+        if (this.attachedToElement) {
+            input.attachControl();
         }
     }
 
@@ -139,7 +137,7 @@ export class CameraInputsManager<TCamera extends Camera> {
         for (var cam in this.attached) {
             var input = this.attached[cam];
             if (input === inputToRemove) {
-                input.detachControl(this.attachedElement);
+                input.detachControl();
                 input.camera = null;
                 delete this.attached[cam];
                 this.rebuildInputCheck();
@@ -156,7 +154,7 @@ export class CameraInputsManager<TCamera extends Camera> {
         for (var cam in this.attached) {
             var input = this.attached[cam];
             if (input.getClassName() === inputType) {
-                input.detachControl(this.attachedElement);
+                input.detachControl();
                 input.camera = null;
                 delete this.attached[cam];
                 this.rebuildInputCheck();
@@ -177,8 +175,8 @@ export class CameraInputsManager<TCamera extends Camera> {
      * @param input Defines the input to attach
      */
     public attachInput(input: ICameraInput<TCamera>): void {
-        if (this.attachedElement) {
-            input.attachControl(this.attachedElement, this.noPreventDefault);
+        if (this.attachedToElement) {
+            input.attachControl(this.noPreventDefault);
         }
     }
 
@@ -187,17 +185,17 @@ export class CameraInputsManager<TCamera extends Camera> {
      * @param element Defines the dom element to collect the events from
      * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
      */
-    public attachElement(element: HTMLElement, noPreventDefault: boolean = false): void {
-        if (this.attachedElement) {
+    public attachElement(noPreventDefault: boolean = false): void {
+        if (this.attachedToElement) {
             return;
         }
 
         noPreventDefault = Camera.ForceAttachControlToAlwaysPreventDefault ? false : noPreventDefault;
-        this.attachedElement = element;
+        this.attachedToElement = true;
         this.noPreventDefault = noPreventDefault;
 
         for (var cam in this.attached) {
-            this.attached[cam].attachControl(element, noPreventDefault);
+            this.attached[cam].attachControl(noPreventDefault);
         }
     }
 
@@ -206,20 +204,15 @@ export class CameraInputsManager<TCamera extends Camera> {
      * @param element Defines the dom element to collect the events from
      * @param disconnect Defines whether the input should be removed from the current list of attached inputs
      */
-    public detachElement(element: HTMLElement, disconnect = false): void {
-        if (this.attachedElement !== element) {
-            return;
-        }
-
+    public detachElement(disconnect = false): void {
         for (var cam in this.attached) {
-            this.attached[cam].detachControl(element);
+            this.attached[cam].detachControl();
 
             if (disconnect) {
                 this.attached[cam].camera = null;
             }
         }
-
-        this.attachedElement = null;
+        this.attachedToElement = false;
     }
 
     /**
@@ -227,7 +220,7 @@ export class CameraInputsManager<TCamera extends Camera> {
      * defined inputs in the manager.
      */
     public rebuildInputCheck(): void {
-        this.checkInputs = () => { };
+        this.checkInputs = () => {};
 
         for (var cam in this.attached) {
             var input = this.attached[cam];
@@ -241,12 +234,12 @@ export class CameraInputsManager<TCamera extends Camera> {
      * Remove all attached input methods from a camera
      */
     public clear(): void {
-        if (this.attachedElement) {
-            this.detachElement(this.attachedElement, true);
+        if (this.attachedToElement) {
+            this.detachElement(true);
         }
         this.attached = {};
-        this.attachedElement = null;
-        this.checkInputs = () => { };
+        this.attachedToElement = false;
+        this.checkInputs = () => {};
     }
 
     /**
@@ -280,7 +273,13 @@ export class CameraInputsManager<TCamera extends Camera> {
                 var construct = (<any>CameraInputTypes)[n];
                 if (construct) {
                     var parsedinput = parsedInputs[n];
-                    var input = SerializationHelper.Parse(() => { return new construct(); }, parsedinput, null);
+                    var input = SerializationHelper.Parse(
+                        () => {
+                            return new construct();
+                        },
+                        parsedinput,
+                        null
+                    );
                     this.add(input as any);
                 }
             }
@@ -289,7 +288,13 @@ export class CameraInputsManager<TCamera extends Camera> {
             for (var n in this.attached) {
                 var construct = (<any>CameraInputTypes)[this.attached[n].getClassName()];
                 if (construct) {
-                    var input = SerializationHelper.Parse(() => { return new construct(); }, parsedCamera, null);
+                    var input = SerializationHelper.Parse(
+                        () => {
+                            return new construct();
+                        },
+                        parsedCamera,
+                        null
+                    );
                     this.remove(this.attached[n]);
                     this.add(input as any);
                 }

+ 6 - 6
src/Cameras/flyCamera.ts

@@ -8,6 +8,7 @@ import { TargetCamera } from "./targetCamera";
 import { FlyCameraInputsManager } from "./flyCameraInputsManager";
 import { FlyCameraMouseInput } from "../Cameras/Inputs/flyCameraMouseInput";
 import { FlyCameraKeyboardInput } from "../Cameras/Inputs/flyCameraKeyboardInput";
+import { Tools } from '../Misc/tools';
 
 declare type Collider = import("../Collisions/collider").Collider;
 
@@ -273,20 +274,19 @@ export class FlyCamera extends TargetCamera {
 
     /**
      * Attach a control to the HTML DOM element.
-     * @param element Defines the element that listens to the input events.
      * @param noPreventDefault Defines whether events caught by the controls should call preventdefault(). https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault
      */
-    public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
-        this.inputs.attachElement(element, noPreventDefault);
+    public attachControl(noPreventDefault?: boolean): void {
+        noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments);
+        this.inputs.attachElement(noPreventDefault);
     }
 
     /**
      * Detach a control from the HTML DOM element.
      * The camera will stop reacting to that input.
-     * @param element Defines the element that listens to the input events.
      */
-    public detachControl(element: HTMLElement): void {
-        this.inputs.detachElement(element);
+    public detachControl(): void {
+        this.inputs.detachElement();
 
         this.cameraDirection = new Vector3(0, 0, 0);
     }

+ 5 - 6
src/Cameras/followCamera.ts

@@ -168,11 +168,11 @@ export class FollowCamera extends TargetCamera {
 
     /**
      * Attached controls to the current camera.
-     * @param element Defines the element the controls should be listened from
      * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
      */
-    public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
-        this.inputs.attachElement(element, noPreventDefault);
+    public attachControl(noPreventDefault?: boolean): void {
+        noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments);
+        this.inputs.attachElement(noPreventDefault);
 
         this._reset = () => {
         };
@@ -181,10 +181,9 @@ export class FollowCamera extends TargetCamera {
     /**
      * Detach the current controls from the camera.
      * The camera will stop reacting to inputs.
-     * @param element Defines the element to stop listening the inputs from
      */
-    public detachControl(element: HTMLElement): void {
-        this.inputs.detachElement(element);
+    public detachControl(): void {
+        this.inputs.detachElement();
 
         if (this._reset) {
             this._reset();

+ 6 - 6
src/Cameras/freeCamera.ts

@@ -8,6 +8,7 @@ import { TargetCamera } from "./targetCamera";
 import { FreeCameraInputsManager } from "./freeCameraInputsManager";
 import { FreeCameraMouseInput } from "../Cameras/Inputs/freeCameraMouseInput";
 import { FreeCameraKeyboardMoveInput } from "../Cameras/Inputs/freeCameraKeyboardMoveInput";
+import { Tools } from '../Misc/tools';
 
 declare type Collider = import("../Collisions/collider").Collider;
 
@@ -222,20 +223,19 @@ export class FreeCamera extends TargetCamera {
 
     /**
      * Attached controls to the current camera.
-     * @param element Defines the element the controls should be listened from
      * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
      */
-    public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
-        this.inputs.attachElement(element, noPreventDefault);
+    public attachControl(noPreventDefault?: boolean): void {
+        noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments);
+        this.inputs.attachElement(noPreventDefault);
     }
 
     /**
      * Detach the current controls from the camera.
      * The camera will stop reacting to inputs.
-     * @param element Defines the element to stop listening the inputs from
      */
-    public detachControl(element: HTMLElement): void {
-        this.inputs.detachElement(element);
+    public detachControl(): void {
+        this.inputs.detachElement();
 
         this.cameraDirection = new Vector3(0, 0, 0);
         this.cameraRotation = new Vector2(0, 0);

+ 29 - 23
src/DeviceInput/InputDevices/deviceSourceManager.ts

@@ -49,24 +49,18 @@ export class DeviceSource<T extends DeviceType> {
 export class DeviceSourceManager implements IDisposable {
     // Public Members
     /**
-     * Observable to be triggered when before a device is connected
+     * Observable to be triggered when after a device is connected, any new observers added will be triggered against already connected devices
      */
-    public readonly onBeforeDeviceConnectedObservable = new Observable<{ deviceType: DeviceType, deviceSlot: number }>();
-
-    /**
-     * Observable to be triggered when before a device is disconnected
-     */
-    public readonly onBeforeDeviceDisconnectedObservable = new Observable<{ deviceType: DeviceType, deviceSlot: number }>();
-
-    /**
-     * Observable to be triggered when after a device is connected
-     */
-    public readonly onAfterDeviceConnectedObservable = new Observable<{ deviceType: DeviceType, deviceSlot: number }>();
+    public readonly onDeviceConnectedObservable = new Observable<DeviceSource<DeviceType>>((observer) => {
+        this.getDevices().forEach((device) => {
+            this.onDeviceConnectedObservable.notifyObserver(observer, device);
+        });
+    });
 
     /**
      * Observable to be triggered when after a device is disconnected
      */
-    public readonly onAfterDeviceDisconnectedObservable = new Observable<{ deviceType: DeviceType, deviceSlot: number }>();
+    public readonly onDeviceDisconnectedObservable = new Observable<DeviceSource<DeviceType>>();
 
     // Private Members
     private readonly _devices: Array<Array<DeviceSource<DeviceType>>>;
@@ -84,14 +78,13 @@ export class DeviceSourceManager implements IDisposable {
         this._deviceInputSystem = DeviceInputSystem.Create(engine);
 
         this._deviceInputSystem.onDeviceConnected = (deviceType, deviceSlot) => {
-            this.onBeforeDeviceConnectedObservable.notifyObservers({ deviceType, deviceSlot });
             this._addDevice(deviceType, deviceSlot);
-            this.onAfterDeviceConnectedObservable.notifyObservers({ deviceType, deviceSlot });
+            this.onDeviceConnectedObservable.notifyObservers(this.getDeviceSource(deviceType, deviceSlot)!);
         };
         this._deviceInputSystem.onDeviceDisconnected = (deviceType, deviceSlot) => {
-            this.onBeforeDeviceDisconnectedObservable.notifyObservers({ deviceType, deviceSlot });
+            const device = this.getDeviceSource(deviceType, deviceSlot)!; // Grab local reference to use before removing from devices
             this._removeDevice(deviceType, deviceSlot);
-            this.onAfterDeviceDisconnectedObservable.notifyObservers({ deviceType, deviceSlot });
+            this.onDeviceDisconnectedObservable.notifyObservers(device);
         };
 
         if (!this._deviceInputSystem.onInputChanged) {
@@ -134,13 +127,24 @@ export class DeviceSourceManager implements IDisposable {
     }
 
     /**
+     * Returns a read-only list of all available devices
+     * @returns Read-only array with active devices
+     */
+    public getDevices(): ReadonlyArray<DeviceSource<DeviceType>> {
+        const deviceArray = new Array<DeviceSource<DeviceType>>();
+        this._devices.forEach((deviceSet) => {
+            deviceArray.push.apply(deviceArray, deviceSet);
+        });
+
+        return deviceArray;
+    }
+
+    /**
      * Dispose of DeviceInputSystem and other parts
      */
     public dispose() {
-        this.onBeforeDeviceConnectedObservable.clear();
-        this.onBeforeDeviceDisconnectedObservable.clear();
-        this.onAfterDeviceConnectedObservable.clear();
-        this.onAfterDeviceDisconnectedObservable.clear();
+        this.onDeviceConnectedObservable.clear();
+        this.onDeviceDisconnectedObservable.clear();
         this._deviceInputSystem.dispose();
     }
 
@@ -155,8 +159,10 @@ export class DeviceSourceManager implements IDisposable {
             this._devices[deviceType] = new Array<DeviceSource<DeviceType>>();
         }
 
-        this._devices[deviceType][deviceSlot] = new DeviceSource(this._deviceInputSystem, deviceType, deviceSlot);
-        this._updateFirstDevices(deviceType);
+        if (!this._devices[deviceType][deviceSlot]) {
+            this._devices[deviceType][deviceSlot] = new DeviceSource(this._deviceInputSystem, deviceType, deviceSlot);
+            this._updateFirstDevices(deviceType);
+        }
     }
 
     /**

+ 84 - 18
src/DeviceInput/deviceInputSystem.ts

@@ -13,10 +13,31 @@ declare const _native: any;
  * pointer device and one keyboard.
  */
 export class DeviceInputSystem implements IDisposable {
+
     /**
-     * Callback to be triggered when a device is connected
+     * Returns onDeviceConnected callback property
+     * @returns Callback with function to execute when a device is connected
      */
-    public onDeviceConnected: (deviceType: DeviceType, deviceSlot: number) => void = () => { };
+    public get onDeviceConnected() { return this._onDeviceConnected; }
+
+    /**
+     * Sets callback function when a device is connected and executes against all connected devices
+     * @param callback Function to execute when a device is connected
+     */
+    public set onDeviceConnected(callback) {
+        this._onDeviceConnected = callback;
+
+        // Iterate through each active device and rerun new callback
+        for (let deviceType = 0; deviceType < this._inputs.length; deviceType++) {
+            if (this._inputs[deviceType]) {
+                for (let deviceSlot = 0; deviceSlot < this._inputs[deviceType].length; deviceSlot++) {
+                    if (this._inputs[deviceType][deviceSlot]) {
+                        this._onDeviceConnected(deviceType, deviceSlot);
+                    }
+                }
+            }
+        }
+    }
 
     /**
      * Callback to be triggered when a device is disconnected
@@ -45,16 +66,22 @@ export class DeviceInputSystem implements IDisposable {
     private _gamepadConnectedEvent = (evt: any) => { };
     private _gamepadDisconnectedEvent = (evt: any) => { };
 
+    private _onDeviceConnected: (deviceType: DeviceType, deviceSlot: number) => void = () => { };
+
     private static _MAX_KEYCODES: number = 255;
     private static _MAX_POINTER_INPUTS: number = 7;
 
     private constructor(engine: Engine) {
         const inputElement = engine.getInputElement();
+
         if (inputElement) {
             this._elementToAttachTo = inputElement;
             this._handleKeyActions();
             this._handlePointerActions();
             this._handleGamepadActions();
+
+            // Check for devices that are already connected but aren't registered. Currently, only checks for gamepads and mouse
+            this._checkForConnectedDevices();
         }
     }
 
@@ -125,8 +152,57 @@ export class DeviceInputSystem implements IDisposable {
         window.removeEventListener("gamepaddisconnected", this._gamepadDisconnectedEvent);
     }
 
+    /**
+     * Checks for existing connections to devices and register them, if necessary
+     * Currently handles gamepads and mouse
+     */
+    private _checkForConnectedDevices() {
+        const gamepads = navigator.getGamepads();
+
+        for (const gamepad of gamepads) {
+            if (gamepad) {
+                this._addGamePad(gamepad);
+            }
+        }
+
+        // If the device in use has mouse capabilities, pre-register mouse
+        if (matchMedia('(pointer:fine)').matches) {
+            // This will provide a dummy value for the cursor position and is expected to be overriden when the first mouse event happens.
+            // There isn't any good way to get the current position outside of a pointer event so that's why this was done.
+            this._addPointerDevice(DeviceType.Mouse, 0, 0, 0);
+        }
+    }
+
     // Private functions
     /**
+     * Add a gamepad to the DeviceInputSystem
+     * @param gamepad A single DOM Gamepad object
+     */
+    private _addGamePad(gamepad: any) {
+        const deviceType = this._getGamepadDeviceType(gamepad.id);
+        const deviceSlot = gamepad.index;
+
+        this._registerDevice(deviceType, deviceSlot, gamepad.buttons.length + gamepad.axes.length);
+        this._gamepads = this._gamepads || new Array<DeviceType>(gamepad.index + 1);
+        this._gamepads[deviceSlot] = deviceType;
+    }
+
+    /**
+     * Add pointer device to DeviceInputSystem
+     * @param deviceType Type of Pointer to add
+     * @param deviceSlot Pointer ID (0 for mouse, pointerId for Touch)
+     * @param currentX Current X at point of adding
+     * @param currentY Current Y at point of adding
+     */
+    private _addPointerDevice(deviceType: DeviceType, deviceSlot: number, currentX: number, currentY: number) {
+        this._pointerActive = true;
+        this._registerDevice(deviceType, deviceSlot, DeviceInputSystem._MAX_POINTER_INPUTS);
+        const pointer = this._inputs[deviceType][deviceSlot]; /* initalize our pointer position immediately after registration */
+        pointer[0] = currentX;
+        pointer[1] = currentY;
+    }
+
+    /**
      * Add device and inputs to device array
      * @param deviceType Enum specifiying device type
      * @param deviceSlot "Slot" or index that device is referenced in
@@ -207,11 +283,7 @@ export class DeviceInputSystem implements IDisposable {
             }
 
             if (!this._inputs[deviceType][deviceSlot]) {
-                this._pointerActive = true;
-                this._registerDevice(deviceType, deviceSlot, DeviceInputSystem._MAX_POINTER_INPUTS);
-                const pointer = this._inputs[deviceType][deviceSlot]; /* initalize our pointer position immediately after registration */
-                pointer[0] = evt.clientX;
-                pointer[1] = evt.clientY;
+                this._addPointerDevice(deviceType, deviceSlot, evt.clientX, evt.clientY);
             }
 
             const pointer = this._inputs[deviceType][deviceSlot];
@@ -234,11 +306,7 @@ export class DeviceInputSystem implements IDisposable {
             }
 
             if (!this._inputs[deviceType][deviceSlot]) {
-                this._pointerActive = true;
-                this._registerDevice(deviceType, deviceSlot, DeviceInputSystem._MAX_POINTER_INPUTS);
-                const pointer = this._inputs[deviceType][deviceSlot]; /* initalize our pointer position immediately after registration */
-                pointer[0] = evt.clientX;
-                pointer[1] = evt.clientY;
+                this._addPointerDevice(deviceType, deviceSlot, evt.clientX, evt.clientY);
             }
 
             const pointer = this._inputs[deviceType][deviceSlot];
@@ -263,6 +331,9 @@ export class DeviceInputSystem implements IDisposable {
                 if (this.onInputChanged) {
                     this.onInputChanged(deviceType, deviceSlot, evt.button + 2, pointer[evt.button + 2], 0);
                 }
+
+                pointer[0] = evt.clientX;
+                pointer[1] = evt.clientY;
                 pointer[evt.button + 2] = 0;
             }
             // We don't want to unregister the mouse because we may miss input data when a mouse is moving after a click
@@ -282,12 +353,7 @@ export class DeviceInputSystem implements IDisposable {
      */
     private _handleGamepadActions() {
         this._gamepadConnectedEvent = ((evt: any) => {
-            const deviceType = this._getGamepadDeviceType(evt.gamepad.id);
-            const deviceSlot = evt.gamepad.index;
-
-            this._registerDevice(deviceType, deviceSlot, evt.gamepad.buttons.length + evt.gamepad.axes.length);
-            this._gamepads = this._gamepads || new Array<string>(evt.gamepad.index + 1);
-            this._gamepads[deviceSlot] = deviceType;
+            this._addGamePad(evt.gamepad);
         });
 
         this._gamepadDisconnectedEvent = ((evt: any) => {

+ 2 - 2
src/Helpers/sceneHelpers.ts

@@ -142,9 +142,9 @@ Scene.prototype.createDefaultCamera = function(createArcRotateCamera = false, re
         camera.speed = radius * 0.2;
         this.activeCamera = camera;
 
-        let canvas = this.getEngine().getInputElement();
+        const canvas = this.getEngine().getInputElement();
         if (attachCameraControls && canvas) {
-            camera.attachControl(canvas);
+            camera.attachControl();
         }
     }
 };

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 150 - 107
src/Misc/tools.ts


+ 23 - 4
src/XR/features/WebXRPlaneDetector.ts

@@ -5,6 +5,8 @@ import { Observable } from "../../Misc/observable";
 import { Vector3, Matrix } from "../../Maths/math.vector";
 import { WebXRAbstractFeature } from "./WebXRAbstractFeature";
 
+declare const XRPlane: XRPlane;
+
 /**
  * Options used in the plane detector module
  */
@@ -90,6 +92,7 @@ export class WebXRPlaneDetector extends WebXRAbstractFeature {
      */
     constructor(_xrSessionManager: WebXRSessionManager, private _options: IWebXRPlaneDetectorOptions = {}) {
         super(_xrSessionManager);
+        this.xrNativeFeatureName = "plane-detection";
         if (this._xrSessionManager.session) {
             this._init();
         } else {
@@ -132,6 +135,14 @@ export class WebXRPlaneDetector extends WebXRAbstractFeature {
         this.onPlaneUpdatedObservable.clear();
     }
 
+    /**
+     * Check if the needed objects are defined.
+     * This does not mean that the feature is enabled, but that the objects needed are well defined.
+     */
+    public isCompatible(): boolean {
+        return typeof XRPlane !== "undefined";
+    }
+
     protected _onXRFrame(frame: XRFrame) {
         if (!this.attached || !this._enabled || !frame) {
             return;
@@ -177,15 +188,23 @@ export class WebXRPlaneDetector extends WebXRAbstractFeature {
     }
 
     private _init() {
+        const internalInit = () => {
+            this._enabled = true;
+            if (this._detectedPlanes.length) {
+                this._detectedPlanes.length = 0;
+            }
+        };
         if (!this._xrSessionManager.session.updateWorldTrackingState) {
+            // check if this was enabled by a flag
+            const alreadyEnabled = (this._xrSessionManager.session as any).worldTrackingState?.planeDetectionState?.enabled;
+            if (alreadyEnabled) {
+                internalInit();
+            }
             // fail silently
             return;
         }
         this._xrSessionManager.session.updateWorldTrackingState({ planeDetectionState: { enabled: true } });
-        this._enabled = true;
-        if (this._detectedPlanes.length) {
-            this._detectedPlanes = [];
-        }
+        internalInit();
     }
 
     private _updatePlaneWithXRPlane(xrPlane: XRPlane, plane: Partial<IWebXRPlane>, xrFrame: XRFrame): IWebXRPlane {

+ 1 - 0
src/XR/features/index.ts

@@ -1,3 +1,4 @@
+export * from "./WebXRAbstractFeature";
 export * from "./WebXRHitTestLegacy";
 export * from "./WebXRAnchorSystem";
 export * from "./WebXRPlaneDetector";

+ 1 - 1
src/XR/webXRDefaultExperience.ts

@@ -141,7 +141,7 @@ export class WebXRDefaultExperience {
                     };
                     if (options.optionalFeatures) {
                         if (typeof options.optionalFeatures === "boolean") {
-                            uiOptions.optionalFeatures = ["hit-test", "anchors", "planes", "hand-tracking"];
+                            uiOptions.optionalFeatures = ["hit-test", "anchors", "plane-detection", "hand-tracking"];
                         } else {
                             uiOptions.optionalFeatures = options.optionalFeatures;
                         }

+ 8 - 0
src/XR/webXREnterExitUI.ts

@@ -62,6 +62,11 @@ export class WebXREnterExitUIOptions {
      * A list of optional features to init the session with
      */
     requiredFeatures?: string[];
+
+    /**
+     * If defined, this function will be executed if the UI encounters an error when entering XR
+     */
+    onError?: (error: any) => void;
 }
 /**
  * UI to allow the user to enter/exit XR mode
@@ -180,6 +185,9 @@ export class WebXREnterExitUI implements IDisposable {
                                     const prevTitle = element.title;
                                     element.title = "Error entering XR session : " + prevTitle;
                                     element.classList.add("xr-error");
+                                    if (options.onError) {
+                                        options.onError(e);
+                                    }
                                 }
                             }
                         }

+ 3 - 3
src/scene.ts

@@ -2522,11 +2522,11 @@ export class Scene extends AbstractScene implements IAnimatable, IClipPlanesHold
         }
 
         if (this.activeCamera) {
-            this.activeCamera.detachControl(canvas);
+            this.activeCamera.detachControl();
         }
         this.activeCamera = newCamera;
         if (attachControl) {
-            newCamera.attachControl(canvas);
+            newCamera.attachControl();
         }
     }
 
@@ -4261,7 +4261,7 @@ export class Scene extends AbstractScene implements IAnimatable, IClipPlanesHold
         if (canvas) {
             var index;
             for (index = 0; index < this.cameras.length; index++) {
-                this.cameras[index].detachControl(canvas);
+                this.cameras[index].detachControl();
             }
         }
 

+ 1 - 1
tests/es6Modules/minGridMaterial.ts

@@ -21,7 +21,7 @@ var camera = new FreeCamera("camera1", new Vector3(0, 5, -10), scene);
 camera.setTarget(Vector3.Zero());
 
 // This attaches the camera to the canvas
-camera.attachControl(canvas, true);
+camera.attachControl(true);
 
 // This creates a light, aiming 0,1,0 - to the sky (non-mesh)
 var light = new HemisphericLight("light1", new Vector3(0, 1, 0), scene);

+ 2 - 2
tests/es6Modules/minStandardMaterial.ts

@@ -20,7 +20,7 @@ var camera = new FreeCamera("camera1", new Vector3(0, 5, -10), scene);
 camera.setTarget(Vector3.Zero());
 
 // This attaches the camera to the canvas
-camera.attachControl(canvas, true);
+camera.attachControl(true);
 
 // This creates a light, aiming 0,1,0 - to the sky (non-mesh)
 var light = new HemisphericLight("light1", new Vector3(0, 1, 0), scene);
@@ -39,4 +39,4 @@ var ground = Mesh.CreateGround("ground1", 6, 6, 2, scene);
 
 engine.runRenderLoop(() => {
     scene.render();
-});
+});

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1662 - 1888
tests/unit/babylon/src/Cameras/babylon.pointerInput.tests.ts