Parcourir la source

Merge pull request #6181 from BabylonJS/master

Nightly
David Catuhe il y a 6 ans
Parent
commit
03ff9e7f24
59 fichiers modifiés avec 5349 ajouts et 3100 suppressions
  1. 227 121
      Playground/babylon.d.txt
  2. 247 122
      dist/preview release/babylon.d.ts
  3. 2 2
      dist/preview release/babylon.js
  4. 1241 982
      dist/preview release/babylon.max.js
  5. 1 1
      dist/preview release/babylon.max.js.map
  6. 507 244
      dist/preview release/babylon.module.d.ts
  7. 1 1
      dist/preview release/gui/babylon.gui.js
  8. 7 7
      dist/preview release/inspector/babylon.inspector.bundle.js
  9. 1224 338
      dist/preview release/inspector/babylon.inspector.bundle.max.js
  10. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.max.js.map
  11. 1 1
      dist/preview release/loaders/babylon.glTF1FileLoader.js
  12. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.js
  13. 1 1
      dist/preview release/loaders/babylonjs.loaders.js
  14. 1 1
      dist/preview release/materialsLibrary/babylon.cellMaterial.js
  15. 1 1
      dist/preview release/materialsLibrary/babylon.customMaterial.js
  16. 1 1
      dist/preview release/materialsLibrary/babylon.fireMaterial.js
  17. 1 1
      dist/preview release/materialsLibrary/babylon.furMaterial.js
  18. 1 1
      dist/preview release/materialsLibrary/babylon.gradientMaterial.js
  19. 1 1
      dist/preview release/materialsLibrary/babylon.gridMaterial.js
  20. 1 1
      dist/preview release/materialsLibrary/babylon.lavaMaterial.js
  21. 1 1
      dist/preview release/materialsLibrary/babylon.mixMaterial.js
  22. 1 1
      dist/preview release/materialsLibrary/babylon.normalMaterial.js
  23. 1 1
      dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.js
  24. 1 1
      dist/preview release/materialsLibrary/babylon.simpleMaterial.js
  25. 1 1
      dist/preview release/materialsLibrary/babylon.skyMaterial.js
  26. 1 1
      dist/preview release/materialsLibrary/babylon.terrainMaterial.js
  27. 1 1
      dist/preview release/materialsLibrary/babylon.triPlanarMaterial.js
  28. 1 1
      dist/preview release/materialsLibrary/babylon.waterMaterial.js
  29. 1 1
      dist/preview release/materialsLibrary/babylonjs.materials.js
  30. 1 1
      dist/preview release/packagesSizeBaseLine.json
  31. 1 1
      dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.js
  32. 1 1
      dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.js
  33. 1 1
      dist/preview release/postProcessesLibrary/babylon.oceanPostProcess.js
  34. 1 1
      dist/preview release/postProcessesLibrary/babylonjs.postProcess.js
  35. 1 1
      dist/preview release/proceduralTexturesLibrary/babylon.brickProceduralTexture.js
  36. 1 1
      dist/preview release/proceduralTexturesLibrary/babylon.cloudProceduralTexture.js
  37. 1 1
      dist/preview release/proceduralTexturesLibrary/babylon.fireProceduralTexture.js
  38. 1 1
      dist/preview release/proceduralTexturesLibrary/babylon.grassProceduralTexture.js
  39. 1 1
      dist/preview release/proceduralTexturesLibrary/babylon.marbleProceduralTexture.js
  40. 1 1
      dist/preview release/proceduralTexturesLibrary/babylon.normalMapProceduralTexture.js
  41. 1 1
      dist/preview release/proceduralTexturesLibrary/babylon.perlinNoiseProceduralTexture.js
  42. 1 1
      dist/preview release/proceduralTexturesLibrary/babylon.roadProceduralTexture.js
  43. 1 1
      dist/preview release/proceduralTexturesLibrary/babylon.starfieldProceduralTexture.js
  44. 1 1
      dist/preview release/proceduralTexturesLibrary/babylon.woodProceduralTexture.js
  45. 1 1
      dist/preview release/proceduralTexturesLibrary/babylonjs.proceduralTextures.js
  46. 507 244
      dist/preview release/viewer/babylon.module.d.ts
  47. 15 1
      dist/preview release/viewer/babylon.viewer.d.ts
  48. 27 19
      dist/preview release/viewer/babylon.viewer.js
  49. 5 5
      dist/preview release/viewer/babylon.viewer.max.js
  50. 18 1
      dist/preview release/viewer/babylon.viewer.module.d.ts
  51. 4 1
      src/Cameras/VR/webVRCamera.ts
  52. 1 1
      src/Culling/Octrees/octreeSceneComponent.ts
  53. 280 0
      src/Engines/Extensions/engine.webVR.ts
  54. 2 1
      src/Engines/Extensions/index.ts
  55. 56 231
      src/Engines/engine.ts
  56. 871 0
      src/Inputs/scene.inputManager.ts
  57. 5 1
      src/Meshes/Compression/dracoCompression.ts
  58. 1 1
      src/Sprites/spriteSceneComponent.ts
  59. 64 740
      src/scene.ts

+ 227 - 121
Playground/babylon.d.txt

@@ -12972,6 +12972,71 @@ declare module BABYLON {
     }
 }
 declare module BABYLON {
+        /**
+         * Defines the interface used by display changed events
+         */
+        interface IDisplayChangedEventArgs {
+            /** Gets the vrDisplay object (if any) */
+            vrDisplay: Nullable<any>;
+            /** Gets a boolean indicating if webVR is supported */
+            vrSupported: boolean;
+        }
+        interface Engine {
+            /** @hidden */
vrDisplay: any;
+            /** @hidden */
vrSupported: boolean;
+            /** @hidden */
oldSize: Size;
+            /** @hidden */
oldHardwareScaleFactor: number;
+            /** @hidden */
vrExclusivePointerMode: boolean;
+            /** @hidden */
webVRInitPromise: Promise<IDisplayChangedEventArgs>;
+            /** @hidden */
onVRDisplayPointerRestricted: () => void;
+            /** @hidden */
onVRDisplayPointerUnrestricted: () => void;
+            /** @hidden */
onVrDisplayConnect: Nullable<(display: any) => void>;
+            /** @hidden */
onVrDisplayDisconnect: Nullable<() => void>;
+            /** @hidden */
onVrDisplayPresentChange: Nullable<() => void>;
+            /**
+             * Observable signaled when VR display mode changes
+             */
+            onVRDisplayChangedObservable: Observable<IDisplayChangedEventArgs>;
+            /**
+             * Observable signaled when VR request present is complete
+             */
+            onVRRequestPresentComplete: Observable<boolean>;
+            /**
+             * Observable signaled when VR request present starts
+             */
+            onVRRequestPresentStart: Observable<Engine>;
+            /**
+             * Gets a boolean indicating that the engine is currently in VR exclusive mode for the pointers
+             * @see https://docs.microsoft.com/en-us/microsoft-edge/webvr/essentials#mouse-input
+             */
+            isInVRExclusivePointerMode: boolean;
+            /**
+             * Gets a boolean indicating if a webVR device was detected
+             * @returns true if a webVR device was detected
+             */
+            isVRDevicePresent(): boolean;
+            /**
+             * Gets the current webVR device
+             * @returns the current webVR device (or null)
+             */
+            getVRDevice(): any;
+            /**
+             * Initializes a webVR display and starts listening to display change events
+             * The onVRDisplayChangedObservable will be notified upon these changes
+             * @returns A promise containing a VRDisplay and if vr is supported
+             */
+            initWebVRAsync(): Promise<IDisplayChangedEventArgs>;
+            /** @hidden */
getVRDisplaysAsync(): Promise<IDisplayChangedEventArgs>;
+            /**
+             * Call this function to switch to webVR mode
+             * Will do nothing if webVR is not supported or if there is no webVR device
+             * @see http://doc.babylonjs.com/how_to/webvr_camera
+             */
+            enableVR(): void;
+            /** @hidden */
onVRFullScreenTriggered(): void;
+        }
+}
+declare module BABYLON {
     /**
      * This is a copy of VRPose. See https://developer.mozilla.org/en-US/docs/Web/API/VRPose
      * IMPORTANT!! The data is right-hand data.
@@ -26605,15 +26670,6 @@ declare module BABYLON {
         useHighPrecisionFloats?: boolean;
     }
     /**
-     * Defines the interface used by display changed events
-     */
-    export interface IDisplayChangedEventArgs {
-        /** Gets the vrDisplay object (if any) */
-        vrDisplay: Nullable<any>;
-        /** Gets a boolean indicating if webVR is supported */
-        vrSupported: boolean;
-    }
-    /**
      * The engine class is responsible for interfacing with all lower-level APIs such as WebGL and Audio
      */
     export class Engine {
@@ -26932,17 +26988,6 @@ declare module BABYLON {
          * Observable event triggered before each texture is initialized
          */
         onBeforeTextureInitObservable: Observable<Texture>;
-        private _vrDisplay;
-        private _vrSupported;
-        private _oldSize;
-        private _oldHardwareScaleFactor;
-        private _vrExclusivePointerMode;
-        private _webVRInitPromise;
-        /**
-         * Gets a boolean indicating that the engine is currently in VR exclusive mode for the pointers
-         * @see https://docs.microsoft.com/en-us/microsoft-edge/webvr/essentials#mouse-input
-         */
-        readonly isInVRExclusivePointerMode: boolean;
         /**
          * Gets or sets a boolean indicating that uniform buffers must be disabled even if they are supported
          */
@@ -27009,23 +27054,6 @@ declare module BABYLON {
         private _onCanvasFocus;
         private _onFullscreenChange;
         private _onPointerLockChange;
-        private _onVRDisplayPointerRestricted;
-        private _onVRDisplayPointerUnrestricted;
-        private _onVrDisplayConnect;
-        private _onVrDisplayDisconnect;
-        private _onVrDisplayPresentChange;
-        /**
-         * Observable signaled when VR display mode changes
-         */
-        onVRDisplayChangedObservable: Observable<IDisplayChangedEventArgs>;
-        /**
-         * Observable signaled when VR request present is complete
-         */
-        onVRRequestPresentComplete: Observable<boolean>;
-        /**
-         * Observable signaled when VR request present starts
-         */
-        onVRRequestPresentStart: Observable<Engine>;
         private _hardwareScalingLevel;
         /** @hidden */
caps: EngineCapabilities;
         private _pointerLockRequested;
@@ -27119,7 +27147,7 @@ declare module BABYLON {
         private _rescalePostProcess;
         private _dummyFramebuffer;
         private _externalData;
-        private _bindedRenderFunction;
+        /** @hidden */
bindedRenderFunction: any;
         private _vaoRecordInProgress;
         private _mustWipeVertexAttributes;
         private _emptyTexture;
@@ -27167,6 +27195,27 @@ declare module BABYLON {
          * @param adaptToDeviceRatio defines whether to adapt to the device's viewport characteristics (default: false)
          */
         constructor(canvasOrContext: Nullable<HTMLCanvasElement | WebGLRenderingContext>, antialias?: boolean, options?: EngineOptions, adaptToDeviceRatio?: boolean);
+        /**
+         * Initializes a webVR display and starts listening to display change events
+         * The onVRDisplayChangedObservable will be notified upon these changes
+         * @returns The onVRDisplayChangedObservable
+         */
+        initWebVR(): Observable<IDisplayChangedEventArgs>;
+        /** @hidden */
prepareVRComponent(): void;
+        /** @hidden */
connectVREvents(canvas: HTMLCanvasElement, document: any): void;
+        /** @hidden */
submitVRFrame(): void;
+        /**
+         * Call this function to leave webVR mode
+         * Will do nothing if webVR is not supported or if there is no webVR device
+         * @see http://doc.babylonjs.com/how_to/webvr_camera
+         */
+        disableVR(): void;
+        /**
+         * Gets a boolean indicating that the system is in VR mode and is presenting
+         * @returns true if VR mode is engaged
+         */
+        isVRPresenting(): boolean;
+        /** @hidden */
requestVRFrame(): void;
         private _disableTouchAction;
         private _rebuildInternalTextures;
         private _rebuildEffects;
@@ -27491,42 +27540,6 @@ declare module BABYLON {
          */
         setSize(width: number, height: number): void;
         /**
-         * Gets a boolean indicating if a webVR device was detected
-         * @returns true if a webVR device was detected
-         */
-        isVRDevicePresent(): boolean;
-        /**
-         * Gets the current webVR device
-         * @returns the current webVR device (or null)
-         */
-        getVRDevice(): any;
-        /**
-         * Initializes a webVR display and starts listening to display change events
-         * The onVRDisplayChangedObservable will be notified upon these changes
-         * @returns The onVRDisplayChangedObservable
-         */
-        initWebVR(): Observable<IDisplayChangedEventArgs>;
-        /**
-         * Initializes a webVR display and starts listening to display change events
-         * The onVRDisplayChangedObservable will be notified upon these changes
-         * @returns A promise containing a VRDisplay and if vr is supported
-         */
-        initWebVRAsync(): Promise<IDisplayChangedEventArgs>;
-        /**
-         * Call this function to switch to webVR mode
-         * Will do nothing if webVR is not supported or if there is no webVR device
-         * @see http://doc.babylonjs.com/how_to/webvr_camera
-         */
-        enableVR(): void;
-        /**
-         * Call this function to leave webVR mode
-         * Will do nothing if webVR is not supported or if there is no webVR device
-         * @see http://doc.babylonjs.com/how_to/webvr_camera
-         */
-        disableVR(): void;
-        private _onVRFullScreenTriggered;
-        private _getVRDisplaysAsync;
-        /**
          * Binds the frame buffer to the specified texture.
          * @param texture The texture to render to or null for the default canvas
          * @param faceIndex The face of the texture to render to in case of cube texture
@@ -30922,6 +30935,130 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
+     * Class used to manage all inputs for the scene.
+     */
+    export class InputManager {
+        /** The distance in pixel that you have to move to prevent some events */
+        static DragMovementThreshold: number;
+        /** Time in milliseconds to wait to raise long press events if button is still pressed */
+        static LongPressDelay: number;
+        /** Time in milliseconds with two consecutive clicks will be considered as a double click */
+        static DoubleClickDelay: number;
+        /** If you need to check double click without raising a single click at first click, enable this flag */
+        static ExclusiveDoubleClickMode: boolean;
+        private _wheelEventName;
+        private _onPointerMove;
+        private _onPointerDown;
+        private _onPointerUp;
+        private _initClickEvent;
+        private _initActionManager;
+        private _delayedSimpleClick;
+        private _delayedSimpleClickTimeout;
+        private _previousDelayedSimpleClickTimeout;
+        private _meshPickProceed;
+        private _previousButtonPressed;
+        private _currentPickResult;
+        private _previousPickResult;
+        private _totalPointersPressed;
+        private _doubleClickOccured;
+        private _pointerOverMesh;
+        private _pickedDownMesh;
+        private _pickedUpMesh;
+        private _pointerX;
+        private _pointerY;
+        private _unTranslatedPointerX;
+        private _unTranslatedPointerY;
+        private _startingPointerPosition;
+        private _previousStartingPointerPosition;
+        private _startingPointerTime;
+        private _previousStartingPointerTime;
+        private _pointerCaptures;
+        private _onKeyDown;
+        private _onKeyUp;
+        private _onCanvasFocusObserver;
+        private _onCanvasBlurObserver;
+        private _scene;
+        /**
+         * Creates a new InputManager
+         * @param scene defines the hosting scene
+         */
+        constructor(scene: Scene);
+        /**
+        * Gets the mesh that is currently under the pointer
+        */
+        readonly meshUnderPointer: Nullable<AbstractMesh>;
+        /**
+         * Gets the pointer coordinates in 2D without any translation (ie. straight out of the pointer event)
+         */
+        readonly unTranslatedPointer: Vector2;
+        /**
+         * Gets or sets the current on-screen X position of the pointer
+         */
+        pointerX: number;
+        /**
+         * Gets or sets the current on-screen Y position of the pointer
+         */
+        pointerY: number;
+        private _updatePointerPosition;
+        private _processPointerMove;
+        private _setRayOnPointerInfo;
+        private _checkPrePointerObservable;
+        /**
+         * Use this method to simulate a pointer move on a mesh
+         * The pickResult parameter can be obtained from a scene.pick or scene.pickWithRay
+         * @param pickResult pickingInfo of the object wished to simulate pointer event on
+         * @param pointerEventInit pointer event state to be used when simulating the pointer event (eg. pointer id for multitouch)
+         */
+        simulatePointerMove(pickResult: PickingInfo, pointerEventInit?: PointerEventInit): void;
+        /**
+         * Use this method to simulate a pointer down on a mesh
+         * The pickResult parameter can be obtained from a scene.pick or scene.pickWithRay
+         * @param pickResult pickingInfo of the object wished to simulate pointer event on
+         * @param pointerEventInit pointer event state to be used when simulating the pointer event (eg. pointer id for multitouch)
+         */
+        simulatePointerDown(pickResult: PickingInfo, pointerEventInit?: PointerEventInit): void;
+        private _processPointerDown;
+        /** @hidden */
isPointerSwiping(): boolean;
+        /**
+         * Use this method to simulate a pointer up on a mesh
+         * The pickResult parameter can be obtained from a scene.pick or scene.pickWithRay
+         * @param pickResult pickingInfo of the object wished to simulate pointer event on
+         * @param pointerEventInit pointer event state to be used when simulating the pointer event (eg. pointer id for multitouch)
+         * @param doubleTap indicates that the pointer up event should be considered as part of a double click (false by default)
+         */
+        simulatePointerUp(pickResult: PickingInfo, pointerEventInit?: PointerEventInit, doubleTap?: boolean): void;
+        private _processPointerUp;
+        /**
+         * Gets a boolean indicating if the current pointer event is captured (meaning that the scene has already handled the pointer down)
+         * @param pointerId defines the pointer id to use in a multi-touch scenario (0 by default)
+         * @returns true if the pointer was captured
+         */
+        isPointerCaptured(pointerId?: number): boolean;
+        /**
+        * Attach events to the canvas (To handle actionManagers triggers and raise onPointerMove, onPointerDown and onPointerUp
+        * @param attachUp defines if you want to attach events to pointerup
+        * @param attachDown defines if you want to attach events to pointerdown
+        * @param attachMove defines if you want to attach events to pointermove
+        */
+        attachControl(attachUp?: boolean, attachDown?: boolean, attachMove?: boolean): void;
+        /**
+         * Detaches all event handlers
+         */
+        detachControl(): void;
+        /**
+         * Force the value of meshUnderPointer
+         * @param mesh defines the mesh to use
+         */
+        setPointerOverMesh(mesh: Nullable<AbstractMesh>): void;
+        /**
+         * Gets the mesh under the pointer
+         * @returns a Mesh or null if no mesh is under the pointer
+         */
+        getPointerOverMesh(): Nullable<AbstractMesh>;
+    }
+}
+declare module BABYLON {
+    /**
      * This class defines the direct association between an animation and a target
      */
     export class TargetedAnimation {
@@ -31180,6 +31317,9 @@ declare module BABYLON {
          * @returns The collision coordinator
          */
         static CollisionCoordinatorFactory(): ICollisionCoordinator;
+        /** @hidden */
inputManager: InputManager;
+        /** Define this parameter if you are using multiple cameras and you want to specify which one should be used for pointer position */
+        cameraToUseForPointers: Nullable<Camera>;
         /** @hidden */
protected readonly _isScene: boolean;
         /**
          * Gets or sets a boolean that indicates if the scene must clear the render buffer before rendering a frame
@@ -31506,9 +31646,6 @@ declare module BABYLON {
          * Gets or sets a predicate used to select candidate meshes for a pointer move event
          */
         pointerMovePredicate: (Mesh: AbstractMesh) => boolean;
-        private _onPointerMove;
-        private _onPointerDown;
-        private _onPointerUp;
         /** Callback called when a pointer move is detected */
         onPointerMove: (evt: PointerEvent, pickInfo: PickingInfo, type: PointerEventTypes) => void;
         /** Callback called when a pointer down is detected  */
@@ -31530,39 +31667,20 @@ declare module BABYLON {
          * Gets the pointer coordinates without any translation (ie. straight out of the pointer event)
          */
         readonly unTranslatedPointer: Vector2;
-        /** The distance in pixel that you have to move to prevent some events */
+        /**
+         * Gets or sets the distance in pixel that you have to move to prevent some events. Default is 10 pixels
+         */
         static DragMovementThreshold: number;
-        /** Time in milliseconds to wait to raise long press events if button is still pressed */
+        /**
+         * Time in milliseconds to wait to raise long press events if button is still pressed. Default is 500 ms
+         */
         static LongPressDelay: number;
-        /** Time in milliseconds with two consecutive clicks will be considered as a double click */
+        /**
+         * Time in milliseconds to wait to raise long press events if button is still pressed. Default is 300 ms
+         */
         static DoubleClickDelay: number;
         /** If you need to check double click without raising a single click at first click, enable this flag */
         static ExclusiveDoubleClickMode: boolean;
-        private _initClickEvent;
-        private _initActionManager;
-        private _delayedSimpleClick;
-        private _delayedSimpleClickTimeout;
-        private _previousDelayedSimpleClickTimeout;
-        private _meshPickProceed;
-        private _previousButtonPressed;
-        private _currentPickResult;
-        private _previousPickResult;
-        private _totalPointersPressed;
-        private _doubleClickOccured;
-        /** Define this parameter if you are using multiple cameras and you want to specify which one should be used for pointer position */
-        cameraToUseForPointers: Nullable<Camera>;
-        private _pointerX;
-        private _pointerY;
-        private _unTranslatedPointerX;
-        private _unTranslatedPointerY;
-        private _startingPointerPosition;
-        private _previousStartingPointerPosition;
-        private _startingPointerTime;
-        private _previousStartingPointerTime;
-        private _pointerCaptures;
-        private _timeAccumulator;
-        private _currentStepId;
-        private _currentInternalStep;
         /** @hidden */
mirroredCameraPosition: Nullable<Vector3>;
         /**
          * This observable event is triggered when any keyboard event si raised and registered during Scene.attachControl()
@@ -31573,15 +31691,14 @@ declare module BABYLON {
          * Observable event triggered each time an keyboard event is received from the hosting window
          */
         onKeyboardObservable: Observable<KeyboardInfo>;
-        private _onKeyDown;
-        private _onKeyUp;
-        private _onCanvasFocusObserver;
-        private _onCanvasBlurObserver;
         private _useRightHandedSystem;
         /**
         * Gets or sets a boolean indicating if the scene must use right-handed coordinates system
         */
         useRightHandedSystem: boolean;
+        private _timeAccumulator;
+        private _currentStepId;
+        private _currentInternalStep;
         /**
          * Sets the step Id used by deterministic lock step
          * @see http://doc.babylonjs.com/babylon101/animations#deterministic-lockstep
@@ -31793,7 +31910,6 @@ declare module BABYLON {
         private _sceneUbo;
         /** @hidden */
viewMatrix: Matrix;
         private _projectionMatrix;
-        private _wheelEventName;
         /** @hidden */
forcedViewPosition: Nullable<Vector3>;
         /** @hidden */
frustumPlanes: Plane[];
         /**
@@ -31809,9 +31925,6 @@ declare module BABYLON {
         readonly useMaterialMeshMap: boolean;
         /** @hidden */
         readonly useClonedMeshhMap: boolean;
-        private _pointerOverMesh;
-        private _pickedDownMesh;
-        private _pickedUpMesh;
         private _externalData;
         private _uid;
         /**
@@ -32058,9 +32171,7 @@ declare module BABYLON {
         getFrameId(): number;
         /** Call this function if you want to manually increment the render Id*/
         incrementRenderId(): void;
-        private _updatePointerPosition;
         private _createUbo;
-        private _setRayOnPointerInfo;
         /**
          * Use this method to simulate a pointer move on a mesh
          * The pickResult parameter can be obtained from a scene.pick or scene.pickWithRay
@@ -32069,8 +32180,6 @@ declare module BABYLON {
          * @returns the current scene
          */
         simulatePointerMove(pickResult: PickingInfo, pointerEventInit?: PointerEventInit): Scene;
-        private _processPointerMove;
-        private _checkPrePointerObservable;
         /**
          * Use this method to simulate a pointer down on a mesh
          * The pickResult parameter can be obtained from a scene.pick or scene.pickWithRay
@@ -32079,7 +32188,6 @@ declare module BABYLON {
          * @returns the current scene
          */
         simulatePointerDown(pickResult: PickingInfo, pointerEventInit?: PointerEventInit): Scene;
-        private _processPointerDown;
         /**
          * Use this method to simulate a pointer up on a mesh
          * The pickResult parameter can be obtained from a scene.pick or scene.pickWithRay
@@ -32089,14 +32197,12 @@ declare module BABYLON {
          * @returns the current scene
          */
         simulatePointerUp(pickResult: PickingInfo, pointerEventInit?: PointerEventInit, doubleTap?: boolean): Scene;
-        private _processPointerUp;
         /**
          * Gets a boolean indicating if the current pointer event is captured (meaning that the scene has already handled the pointer down)
          * @param pointerId defines the pointer id to use in a multi-touch scenario (0 by default)
          * @returns true if the pointer was captured
          */
         isPointerCaptured(pointerId?: number): boolean;
-        /** @hidden */
isPointerSwiping(): boolean;
         /**
         * Attach events to the canvas (To handle actionManagers triggers and raise onPointerMove, onPointerDown and onPointerUp
         * @param attachUp defines if you want to attach events to pointerup
@@ -39704,7 +39810,7 @@ declare module BABYLON {
      */
     export class OctreeSceneComponent {
         /**
-         * The component name helpfull to identify the component in the list of scene components.
+         * The component name help to identify the component in the list of scene components.
          */
         readonly name: string;
         /**

+ 247 - 122
dist/preview release/babylon.d.ts

@@ -13165,6 +13165,84 @@ declare module BABYLON {
     }
 }
 declare module BABYLON {
+        /**
+         * Defines the interface used by display changed events
+         */
+        interface IDisplayChangedEventArgs {
+            /** Gets the vrDisplay object (if any) */
+            vrDisplay: Nullable<any>;
+            /** Gets a boolean indicating if webVR is supported */
+            vrSupported: boolean;
+        }
+        interface Engine {
+            /** @hidden */
+            _vrDisplay: any;
+            /** @hidden */
+            _vrSupported: boolean;
+            /** @hidden */
+            _oldSize: Size;
+            /** @hidden */
+            _oldHardwareScaleFactor: number;
+            /** @hidden */
+            _vrExclusivePointerMode: boolean;
+            /** @hidden */
+            _webVRInitPromise: Promise<IDisplayChangedEventArgs>;
+            /** @hidden */
+            _onVRDisplayPointerRestricted: () => void;
+            /** @hidden */
+            _onVRDisplayPointerUnrestricted: () => void;
+            /** @hidden */
+            _onVrDisplayConnect: Nullable<(display: any) => void>;
+            /** @hidden */
+            _onVrDisplayDisconnect: Nullable<() => void>;
+            /** @hidden */
+            _onVrDisplayPresentChange: Nullable<() => void>;
+            /**
+             * Observable signaled when VR display mode changes
+             */
+            onVRDisplayChangedObservable: Observable<IDisplayChangedEventArgs>;
+            /**
+             * Observable signaled when VR request present is complete
+             */
+            onVRRequestPresentComplete: Observable<boolean>;
+            /**
+             * Observable signaled when VR request present starts
+             */
+            onVRRequestPresentStart: Observable<Engine>;
+            /**
+             * Gets a boolean indicating that the engine is currently in VR exclusive mode for the pointers
+             * @see https://docs.microsoft.com/en-us/microsoft-edge/webvr/essentials#mouse-input
+             */
+            isInVRExclusivePointerMode: boolean;
+            /**
+             * Gets a boolean indicating if a webVR device was detected
+             * @returns true if a webVR device was detected
+             */
+            isVRDevicePresent(): boolean;
+            /**
+             * Gets the current webVR device
+             * @returns the current webVR device (or null)
+             */
+            getVRDevice(): any;
+            /**
+             * Initializes a webVR display and starts listening to display change events
+             * The onVRDisplayChangedObservable will be notified upon these changes
+             * @returns A promise containing a VRDisplay and if vr is supported
+             */
+            initWebVRAsync(): Promise<IDisplayChangedEventArgs>;
+            /** @hidden */
+            _getVRDisplaysAsync(): Promise<IDisplayChangedEventArgs>;
+            /**
+             * Call this function to switch to webVR mode
+             * Will do nothing if webVR is not supported or if there is no webVR device
+             * @see http://doc.babylonjs.com/how_to/webvr_camera
+             */
+            enableVR(): void;
+            /** @hidden */
+            _onVRFullScreenTriggered(): void;
+        }
+}
+declare module BABYLON {
     /**
      * This is a copy of VRPose. See https://developer.mozilla.org/en-US/docs/Web/API/VRPose
      * IMPORTANT!! The data is right-hand data.
@@ -27063,15 +27141,6 @@ declare module BABYLON {
         useHighPrecisionFloats?: boolean;
     }
     /**
-     * Defines the interface used by display changed events
-     */
-    export interface IDisplayChangedEventArgs {
-        /** Gets the vrDisplay object (if any) */
-        vrDisplay: Nullable<any>;
-        /** Gets a boolean indicating if webVR is supported */
-        vrSupported: boolean;
-    }
-    /**
      * The engine class is responsible for interfacing with all lower-level APIs such as WebGL and Audio
      */
     export class Engine {
@@ -27392,17 +27461,6 @@ declare module BABYLON {
          * Observable event triggered before each texture is initialized
          */
         onBeforeTextureInitObservable: Observable<Texture>;
-        private _vrDisplay;
-        private _vrSupported;
-        private _oldSize;
-        private _oldHardwareScaleFactor;
-        private _vrExclusivePointerMode;
-        private _webVRInitPromise;
-        /**
-         * Gets a boolean indicating that the engine is currently in VR exclusive mode for the pointers
-         * @see https://docs.microsoft.com/en-us/microsoft-edge/webvr/essentials#mouse-input
-         */
-        readonly isInVRExclusivePointerMode: boolean;
         /**
          * Gets or sets a boolean indicating that uniform buffers must be disabled even if they are supported
          */
@@ -27474,23 +27532,6 @@ declare module BABYLON {
         private _onCanvasFocus;
         private _onFullscreenChange;
         private _onPointerLockChange;
-        private _onVRDisplayPointerRestricted;
-        private _onVRDisplayPointerUnrestricted;
-        private _onVrDisplayConnect;
-        private _onVrDisplayDisconnect;
-        private _onVrDisplayPresentChange;
-        /**
-         * Observable signaled when VR display mode changes
-         */
-        onVRDisplayChangedObservable: Observable<IDisplayChangedEventArgs>;
-        /**
-         * Observable signaled when VR request present is complete
-         */
-        onVRRequestPresentComplete: Observable<boolean>;
-        /**
-         * Observable signaled when VR request present starts
-         */
-        onVRRequestPresentStart: Observable<Engine>;
         private _hardwareScalingLevel;
         /** @hidden */
         _caps: EngineCapabilities;
@@ -27591,7 +27632,8 @@ declare module BABYLON {
         private _rescalePostProcess;
         private _dummyFramebuffer;
         private _externalData;
-        private _bindedRenderFunction;
+        /** @hidden */
+        _bindedRenderFunction: any;
         private _vaoRecordInProgress;
         private _mustWipeVertexAttributes;
         private _emptyTexture;
@@ -27641,6 +27683,31 @@ declare module BABYLON {
          * @param adaptToDeviceRatio defines whether to adapt to the device's viewport characteristics (default: false)
          */
         constructor(canvasOrContext: Nullable<HTMLCanvasElement | WebGLRenderingContext>, antialias?: boolean, options?: EngineOptions, adaptToDeviceRatio?: boolean);
+        /**
+         * Initializes a webVR display and starts listening to display change events
+         * The onVRDisplayChangedObservable will be notified upon these changes
+         * @returns The onVRDisplayChangedObservable
+         */
+        initWebVR(): Observable<IDisplayChangedEventArgs>;
+        /** @hidden */
+        _prepareVRComponent(): void;
+        /** @hidden */
+        _connectVREvents(canvas: HTMLCanvasElement, document: any): void;
+        /** @hidden */
+        _submitVRFrame(): void;
+        /**
+         * Call this function to leave webVR mode
+         * Will do nothing if webVR is not supported or if there is no webVR device
+         * @see http://doc.babylonjs.com/how_to/webvr_camera
+         */
+        disableVR(): void;
+        /**
+         * Gets a boolean indicating that the system is in VR mode and is presenting
+         * @returns true if VR mode is engaged
+         */
+        isVRPresenting(): boolean;
+        /** @hidden */
+        _requestVRFrame(): void;
         private _disableTouchAction;
         private _rebuildInternalTextures;
         private _rebuildEffects;
@@ -27968,42 +28035,6 @@ declare module BABYLON {
          */
         setSize(width: number, height: number): void;
         /**
-         * Gets a boolean indicating if a webVR device was detected
-         * @returns true if a webVR device was detected
-         */
-        isVRDevicePresent(): boolean;
-        /**
-         * Gets the current webVR device
-         * @returns the current webVR device (or null)
-         */
-        getVRDevice(): any;
-        /**
-         * Initializes a webVR display and starts listening to display change events
-         * The onVRDisplayChangedObservable will be notified upon these changes
-         * @returns The onVRDisplayChangedObservable
-         */
-        initWebVR(): Observable<IDisplayChangedEventArgs>;
-        /**
-         * Initializes a webVR display and starts listening to display change events
-         * The onVRDisplayChangedObservable will be notified upon these changes
-         * @returns A promise containing a VRDisplay and if vr is supported
-         */
-        initWebVRAsync(): Promise<IDisplayChangedEventArgs>;
-        /**
-         * Call this function to switch to webVR mode
-         * Will do nothing if webVR is not supported or if there is no webVR device
-         * @see http://doc.babylonjs.com/how_to/webvr_camera
-         */
-        enableVR(): void;
-        /**
-         * Call this function to leave webVR mode
-         * Will do nothing if webVR is not supported or if there is no webVR device
-         * @see http://doc.babylonjs.com/how_to/webvr_camera
-         */
-        disableVR(): void;
-        private _onVRFullScreenTriggered;
-        private _getVRDisplaysAsync;
-        /**
          * Binds the frame buffer to the specified texture.
          * @param texture The texture to render to or null for the default canvas
          * @param faceIndex The face of the texture to render to in case of cube texture
@@ -31480,6 +31511,131 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
+     * Class used to manage all inputs for the scene.
+     */
+    export class InputManager {
+        /** The distance in pixel that you have to move to prevent some events */
+        static DragMovementThreshold: number;
+        /** Time in milliseconds to wait to raise long press events if button is still pressed */
+        static LongPressDelay: number;
+        /** Time in milliseconds with two consecutive clicks will be considered as a double click */
+        static DoubleClickDelay: number;
+        /** If you need to check double click without raising a single click at first click, enable this flag */
+        static ExclusiveDoubleClickMode: boolean;
+        private _wheelEventName;
+        private _onPointerMove;
+        private _onPointerDown;
+        private _onPointerUp;
+        private _initClickEvent;
+        private _initActionManager;
+        private _delayedSimpleClick;
+        private _delayedSimpleClickTimeout;
+        private _previousDelayedSimpleClickTimeout;
+        private _meshPickProceed;
+        private _previousButtonPressed;
+        private _currentPickResult;
+        private _previousPickResult;
+        private _totalPointersPressed;
+        private _doubleClickOccured;
+        private _pointerOverMesh;
+        private _pickedDownMesh;
+        private _pickedUpMesh;
+        private _pointerX;
+        private _pointerY;
+        private _unTranslatedPointerX;
+        private _unTranslatedPointerY;
+        private _startingPointerPosition;
+        private _previousStartingPointerPosition;
+        private _startingPointerTime;
+        private _previousStartingPointerTime;
+        private _pointerCaptures;
+        private _onKeyDown;
+        private _onKeyUp;
+        private _onCanvasFocusObserver;
+        private _onCanvasBlurObserver;
+        private _scene;
+        /**
+         * Creates a new InputManager
+         * @param scene defines the hosting scene
+         */
+        constructor(scene: Scene);
+        /**
+        * Gets the mesh that is currently under the pointer
+        */
+        readonly meshUnderPointer: Nullable<AbstractMesh>;
+        /**
+         * Gets the pointer coordinates in 2D without any translation (ie. straight out of the pointer event)
+         */
+        readonly unTranslatedPointer: Vector2;
+        /**
+         * Gets or sets the current on-screen X position of the pointer
+         */
+        pointerX: number;
+        /**
+         * Gets or sets the current on-screen Y position of the pointer
+         */
+        pointerY: number;
+        private _updatePointerPosition;
+        private _processPointerMove;
+        private _setRayOnPointerInfo;
+        private _checkPrePointerObservable;
+        /**
+         * Use this method to simulate a pointer move on a mesh
+         * The pickResult parameter can be obtained from a scene.pick or scene.pickWithRay
+         * @param pickResult pickingInfo of the object wished to simulate pointer event on
+         * @param pointerEventInit pointer event state to be used when simulating the pointer event (eg. pointer id for multitouch)
+         */
+        simulatePointerMove(pickResult: PickingInfo, pointerEventInit?: PointerEventInit): void;
+        /**
+         * Use this method to simulate a pointer down on a mesh
+         * The pickResult parameter can be obtained from a scene.pick or scene.pickWithRay
+         * @param pickResult pickingInfo of the object wished to simulate pointer event on
+         * @param pointerEventInit pointer event state to be used when simulating the pointer event (eg. pointer id for multitouch)
+         */
+        simulatePointerDown(pickResult: PickingInfo, pointerEventInit?: PointerEventInit): void;
+        private _processPointerDown;
+        /** @hidden */
+        _isPointerSwiping(): boolean;
+        /**
+         * Use this method to simulate a pointer up on a mesh
+         * The pickResult parameter can be obtained from a scene.pick or scene.pickWithRay
+         * @param pickResult pickingInfo of the object wished to simulate pointer event on
+         * @param pointerEventInit pointer event state to be used when simulating the pointer event (eg. pointer id for multitouch)
+         * @param doubleTap indicates that the pointer up event should be considered as part of a double click (false by default)
+         */
+        simulatePointerUp(pickResult: PickingInfo, pointerEventInit?: PointerEventInit, doubleTap?: boolean): void;
+        private _processPointerUp;
+        /**
+         * Gets a boolean indicating if the current pointer event is captured (meaning that the scene has already handled the pointer down)
+         * @param pointerId defines the pointer id to use in a multi-touch scenario (0 by default)
+         * @returns true if the pointer was captured
+         */
+        isPointerCaptured(pointerId?: number): boolean;
+        /**
+        * Attach events to the canvas (To handle actionManagers triggers and raise onPointerMove, onPointerDown and onPointerUp
+        * @param attachUp defines if you want to attach events to pointerup
+        * @param attachDown defines if you want to attach events to pointerdown
+        * @param attachMove defines if you want to attach events to pointermove
+        */
+        attachControl(attachUp?: boolean, attachDown?: boolean, attachMove?: boolean): void;
+        /**
+         * Detaches all event handlers
+         */
+        detachControl(): void;
+        /**
+         * Force the value of meshUnderPointer
+         * @param mesh defines the mesh to use
+         */
+        setPointerOverMesh(mesh: Nullable<AbstractMesh>): void;
+        /**
+         * Gets the mesh under the pointer
+         * @returns a Mesh or null if no mesh is under the pointer
+         */
+        getPointerOverMesh(): Nullable<AbstractMesh>;
+    }
+}
+declare module BABYLON {
+    /**
      * This class defines the direct association between an animation and a target
      */
     export class TargetedAnimation {
@@ -31739,6 +31895,10 @@ declare module BABYLON {
          */
         static CollisionCoordinatorFactory(): ICollisionCoordinator;
         /** @hidden */
+        _inputManager: InputManager;
+        /** Define this parameter if you are using multiple cameras and you want to specify which one should be used for pointer position */
+        cameraToUseForPointers: Nullable<Camera>;
+        /** @hidden */
         readonly _isScene: boolean;
         /**
          * Gets or sets a boolean that indicates if the scene must clear the render buffer before rendering a frame
@@ -32066,9 +32226,6 @@ declare module BABYLON {
          * Gets or sets a predicate used to select candidate meshes for a pointer move event
          */
         pointerMovePredicate: (Mesh: AbstractMesh) => boolean;
-        private _onPointerMove;
-        private _onPointerDown;
-        private _onPointerUp;
         /** Callback called when a pointer move is detected */
         onPointerMove: (evt: PointerEvent, pickInfo: PickingInfo, type: PointerEventTypes) => void;
         /** Callback called when a pointer down is detected  */
@@ -32090,39 +32247,20 @@ declare module BABYLON {
          * Gets the pointer coordinates without any translation (ie. straight out of the pointer event)
          */
         readonly unTranslatedPointer: Vector2;
-        /** The distance in pixel that you have to move to prevent some events */
+        /**
+         * Gets or sets the distance in pixel that you have to move to prevent some events. Default is 10 pixels
+         */
         static DragMovementThreshold: number;
-        /** Time in milliseconds to wait to raise long press events if button is still pressed */
+        /**
+         * Time in milliseconds to wait to raise long press events if button is still pressed. Default is 500 ms
+         */
         static LongPressDelay: number;
-        /** Time in milliseconds with two consecutive clicks will be considered as a double click */
+        /**
+         * Time in milliseconds to wait to raise long press events if button is still pressed. Default is 300 ms
+         */
         static DoubleClickDelay: number;
         /** If you need to check double click without raising a single click at first click, enable this flag */
         static ExclusiveDoubleClickMode: boolean;
-        private _initClickEvent;
-        private _initActionManager;
-        private _delayedSimpleClick;
-        private _delayedSimpleClickTimeout;
-        private _previousDelayedSimpleClickTimeout;
-        private _meshPickProceed;
-        private _previousButtonPressed;
-        private _currentPickResult;
-        private _previousPickResult;
-        private _totalPointersPressed;
-        private _doubleClickOccured;
-        /** Define this parameter if you are using multiple cameras and you want to specify which one should be used for pointer position */
-        cameraToUseForPointers: Nullable<Camera>;
-        private _pointerX;
-        private _pointerY;
-        private _unTranslatedPointerX;
-        private _unTranslatedPointerY;
-        private _startingPointerPosition;
-        private _previousStartingPointerPosition;
-        private _startingPointerTime;
-        private _previousStartingPointerTime;
-        private _pointerCaptures;
-        private _timeAccumulator;
-        private _currentStepId;
-        private _currentInternalStep;
         /** @hidden */
         _mirroredCameraPosition: Nullable<Vector3>;
         /**
@@ -32134,15 +32272,14 @@ declare module BABYLON {
          * Observable event triggered each time an keyboard event is received from the hosting window
          */
         onKeyboardObservable: Observable<KeyboardInfo>;
-        private _onKeyDown;
-        private _onKeyUp;
-        private _onCanvasFocusObserver;
-        private _onCanvasBlurObserver;
         private _useRightHandedSystem;
         /**
         * Gets or sets a boolean indicating if the scene must use right-handed coordinates system
         */
         useRightHandedSystem: boolean;
+        private _timeAccumulator;
+        private _currentStepId;
+        private _currentInternalStep;
         /**
          * Sets the step Id used by deterministic lock step
          * @see http://doc.babylonjs.com/babylon101/animations#deterministic-lockstep
@@ -32368,7 +32505,6 @@ declare module BABYLON {
         /** @hidden */
         _viewMatrix: Matrix;
         private _projectionMatrix;
-        private _wheelEventName;
         /** @hidden */
         _forcedViewPosition: Nullable<Vector3>;
         /** @hidden */
@@ -32386,9 +32522,6 @@ declare module BABYLON {
         readonly useMaterialMeshMap: boolean;
         /** @hidden */
         readonly useClonedMeshhMap: boolean;
-        private _pointerOverMesh;
-        private _pickedDownMesh;
-        private _pickedUpMesh;
         private _externalData;
         private _uid;
         /**
@@ -32662,9 +32795,7 @@ declare module BABYLON {
         getFrameId(): number;
         /** Call this function if you want to manually increment the render Id*/
         incrementRenderId(): void;
-        private _updatePointerPosition;
         private _createUbo;
-        private _setRayOnPointerInfo;
         /**
          * Use this method to simulate a pointer move on a mesh
          * The pickResult parameter can be obtained from a scene.pick or scene.pickWithRay
@@ -32673,8 +32804,6 @@ declare module BABYLON {
          * @returns the current scene
          */
         simulatePointerMove(pickResult: PickingInfo, pointerEventInit?: PointerEventInit): Scene;
-        private _processPointerMove;
-        private _checkPrePointerObservable;
         /**
          * Use this method to simulate a pointer down on a mesh
          * The pickResult parameter can be obtained from a scene.pick or scene.pickWithRay
@@ -32683,7 +32812,6 @@ declare module BABYLON {
          * @returns the current scene
          */
         simulatePointerDown(pickResult: PickingInfo, pointerEventInit?: PointerEventInit): Scene;
-        private _processPointerDown;
         /**
          * Use this method to simulate a pointer up on a mesh
          * The pickResult parameter can be obtained from a scene.pick or scene.pickWithRay
@@ -32693,15 +32821,12 @@ declare module BABYLON {
          * @returns the current scene
          */
         simulatePointerUp(pickResult: PickingInfo, pointerEventInit?: PointerEventInit, doubleTap?: boolean): Scene;
-        private _processPointerUp;
         /**
          * Gets a boolean indicating if the current pointer event is captured (meaning that the scene has already handled the pointer down)
          * @param pointerId defines the pointer id to use in a multi-touch scenario (0 by default)
          * @returns true if the pointer was captured
          */
         isPointerCaptured(pointerId?: number): boolean;
-        /** @hidden */
-        _isPointerSwiping(): boolean;
         /**
         * Attach events to the canvas (To handle actionManagers triggers and raise onPointerMove, onPointerDown and onPointerUp
         * @param attachUp defines if you want to attach events to pointerup
@@ -40371,7 +40496,7 @@ declare module BABYLON {
      */
     export class OctreeSceneComponent {
         /**
-         * The component name helpfull to identify the component in the list of scene components.
+         * The component name help to identify the component in the list of scene components.
          */
         readonly name: string;
         /**

Fichier diff supprimé car celui-ci est trop grand
+ 2 - 2
dist/preview release/babylon.js


Fichier diff supprimé car celui-ci est trop grand
+ 1241 - 982
dist/preview release/babylon.max.js


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/babylon.max.js.map


Fichier diff supprimé car celui-ci est trop grand
+ 507 - 244
dist/preview release/babylon.module.d.ts


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

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

Fichier diff supprimé car celui-ci est trop grand
+ 7 - 7
dist/preview release/inspector/babylon.inspector.bundle.js


Fichier diff supprimé car celui-ci est trop grand
+ 1224 - 338
dist/preview release/inspector/babylon.inspector.bundle.max.js


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.max.js.map


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

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

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

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

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

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/materialsLibrary/babylon.cellMaterial.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/materialsLibrary/babylon.customMaterial.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/materialsLibrary/babylon.fireMaterial.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/materialsLibrary/babylon.furMaterial.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/materialsLibrary/babylon.gradientMaterial.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/materialsLibrary/babylon.gridMaterial.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/materialsLibrary/babylon.lavaMaterial.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/materialsLibrary/babylon.mixMaterial.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/materialsLibrary/babylon.normalMaterial.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/materialsLibrary/babylon.simpleMaterial.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/materialsLibrary/babylon.skyMaterial.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/materialsLibrary/babylon.terrainMaterial.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/materialsLibrary/babylon.triPlanarMaterial.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/materialsLibrary/babylon.waterMaterial.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/materialsLibrary/babylonjs.materials.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

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

@@ -1 +1 @@
-{"engineOnly":292624,"sceneOnly":496901,"minGridMaterial":621922,"minStandardMaterial":745018}
+{"engineOnly":288960,"sceneOnly":495379,"minGridMaterial":620400,"minStandardMaterial":743496}

+ 1 - 1
dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/postProcessesLibrary/babylon.oceanPostProcess.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/postProcessesLibrary/babylonjs.postProcess.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/proceduralTexturesLibrary/babylon.brickProceduralTexture.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/proceduralTexturesLibrary/babylon.cloudProceduralTexture.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/proceduralTexturesLibrary/babylon.fireProceduralTexture.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/proceduralTexturesLibrary/babylon.grassProceduralTexture.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/proceduralTexturesLibrary/babylon.marbleProceduralTexture.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/proceduralTexturesLibrary/babylon.normalMapProceduralTexture.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/proceduralTexturesLibrary/babylon.perlinNoiseProceduralTexture.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/proceduralTexturesLibrary/babylon.roadProceduralTexture.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/proceduralTexturesLibrary/babylon.starfieldProceduralTexture.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/proceduralTexturesLibrary/babylon.woodProceduralTexture.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

+ 1 - 1
dist/preview release/proceduralTexturesLibrary/babylonjs.proceduralTextures.js

@@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
 /*!***********************************************************!*\
-  !*** D:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  !*** E:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
   \***********************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {

Fichier diff supprimé car celui-ci est trop grand
+ 507 - 244
dist/preview release/viewer/babylon.module.d.ts


+ 15 - 1
dist/preview release/viewer/babylon.viewer.d.ts

@@ -951,7 +951,7 @@ declare module BabylonViewer {
       * @param name the name of the custom optimizer configuration
       * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
       */
-    export function getCustomOptimizerByName(name: string, upgrade?: boolean): (sceneManager: SceneManager) => boolean;
+    export function getCustomOptimizerByName(name: string, upgrade?: boolean): typeof extendedUpgrade;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
 declare module BabylonViewer {
@@ -1594,6 +1594,20 @@ declare module BabylonViewer {
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
 }
 declare module BabylonViewer {
+    /**
+        * A custom upgrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedUpgrade(sceneManager: SceneManager): boolean;
+    /**
+        * A custom degrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedDegrade(sceneManager: SceneManager): boolean;
+}
+declare module BabylonViewer {
     export interface IEnvironmentMapConfiguration {
             /**
                 * Environment map texture path in relative to the asset folder.

Fichier diff supprimé car celui-ci est trop grand
+ 27 - 19
dist/preview release/viewer/babylon.viewer.js


Fichier diff supprimé car celui-ci est trop grand
+ 5 - 5
dist/preview release/viewer/babylon.viewer.max.js


+ 18 - 1
dist/preview release/viewer/babylon.viewer.module.d.ts

@@ -1031,13 +1031,14 @@ declare module 'babylonjs-viewer/templating/viewerTemplatePlugin' {
 }
 
 declare module 'babylonjs-viewer/optimizer/custom' {
+    import { extendedUpgrade } from "babylonjs-viewer/optimizer/custom/extended";
     import { SceneManager } from "babylonjs-viewer/managers/sceneManager";
     /**
       *
       * @param name the name of the custom optimizer configuration
       * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
       */
-    export function getCustomOptimizerByName(name: string, upgrade?: boolean): (sceneManager: SceneManager) => boolean;
+    export function getCustomOptimizerByName(name: string, upgrade?: boolean): typeof extendedUpgrade;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
 
@@ -1737,6 +1738,22 @@ declare module 'babylonjs-viewer/loader/plugins' {
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
 }
 
+declare module 'babylonjs-viewer/optimizer/custom/extended' {
+    import { SceneManager } from 'babylonjs-viewer/managers/sceneManager';
+    /**
+        * A custom upgrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedUpgrade(sceneManager: SceneManager): boolean;
+    /**
+        * A custom degrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedDegrade(sceneManager: SceneManager): boolean;
+}
+
 declare module 'babylonjs-viewer/configuration/interfaces' {
     export * from 'babylonjs-viewer/configuration/interfaces/cameraConfiguration';
     export * from 'babylonjs-viewer/configuration/interfaces/colorGradingConfiguration';

+ 4 - 1
src/Cameras/VR/webVRCamera.ts

@@ -19,6 +19,9 @@ import { VRMultiviewToSingleviewPostProcess } from '../../PostProcesses/vrMultiv
 // Side effect import to define the stereoscopic mode.
 import "../RigModes/webVRRigMode";
 
+// Side effect import to add webvr support to engine
+import "../../Engines/Extensions/engine.webVR";
+
 Node.AddNodeConstructor("WebVRFreeCamera", (name, scene) => {
     return () => new WebVRFreeCamera(name, Vector3.Zero(), scene);
 });
@@ -287,7 +290,7 @@ export class WebVRFreeCamera extends FreeCamera implements PoseControlled {
             if (!this.getScene().getEngine().getCaps().multiview) {
                 Logger.Warn("Multiview is not supported, falling back to standard rendering");
                 this._useMultiviewToSingleView = false;
-            }else {
+            } else {
                 this._useMultiviewToSingleView = true;
                 this._rigPostProcess = new VRMultiviewToSingleviewPostProcess("VRMultiviewToSingleview", this, 1.0);
             }

+ 1 - 1
src/Culling/Octrees/octreeSceneComponent.ts

@@ -121,7 +121,7 @@ AbstractMesh.prototype.createOrUpdateSubmeshesOctree = function(maxCapacity = 64
  */
 export class OctreeSceneComponent {
     /**
-     * The component name helpfull to identify the component in the list of scene components.
+     * The component name help to identify the component in the list of scene components.
      */
     public readonly name = SceneComponentConstants.NAME_OCTREE;
 

+ 280 - 0
src/Engines/Extensions/engine.webVR.ts

@@ -0,0 +1,280 @@
+import { Nullable } from "../../types";
+import { Engine, IDisplayChangedEventArgs } from "../../Engines/engine";
+import { _TimeToken } from "../../Instrumentation/timeToken";
+import { Size } from '../../Maths/math';
+import { Observable } from '../../Misc/observable';
+import { Tools } from '../../Misc/tools';
+import { DomManagement } from '../../Misc/domManagement';
+
+declare module "../../Engines/engine" {
+    /**
+     * Defines the interface used by display changed events
+     */
+    export interface IDisplayChangedEventArgs {
+        /** Gets the vrDisplay object (if any) */
+        vrDisplay: Nullable<any>;
+        /** Gets a boolean indicating if webVR is supported */
+        vrSupported: boolean;
+    }
+
+    export interface Engine {
+        /** @hidden */
+        _vrDisplay: any;
+        /** @hidden */
+        _vrSupported: boolean;
+        /** @hidden */
+        _oldSize: Size;
+        /** @hidden */
+        _oldHardwareScaleFactor: number;
+        /** @hidden */
+        _vrExclusivePointerMode: boolean;
+        /** @hidden */
+        _webVRInitPromise: Promise<IDisplayChangedEventArgs>;
+
+        /** @hidden */
+        _onVRDisplayPointerRestricted: () => void;
+        /** @hidden */
+        _onVRDisplayPointerUnrestricted: () => void;
+
+        /** @hidden */
+        _onVrDisplayConnect: Nullable<(display: any) => void>;
+        /** @hidden */
+        _onVrDisplayDisconnect: Nullable<() => void>;
+        /** @hidden */
+        _onVrDisplayPresentChange: Nullable<() => void>;
+
+        /**
+         * Observable signaled when VR display mode changes
+         */
+        onVRDisplayChangedObservable: Observable<IDisplayChangedEventArgs>;
+        /**
+         * Observable signaled when VR request present is complete
+         */
+        onVRRequestPresentComplete: Observable<boolean>;
+        /**
+         * Observable signaled when VR request present starts
+         */
+        onVRRequestPresentStart: Observable<Engine>;
+
+        /**
+         * Gets a boolean indicating that the engine is currently in VR exclusive mode for the pointers
+         * @see https://docs.microsoft.com/en-us/microsoft-edge/webvr/essentials#mouse-input
+         */
+        isInVRExclusivePointerMode: boolean;
+
+        /**
+         * Gets a boolean indicating if a webVR device was detected
+         * @returns true if a webVR device was detected
+         */
+        isVRDevicePresent(): boolean;
+
+        /**
+         * Gets the current webVR device
+         * @returns the current webVR device (or null)
+         */
+        getVRDevice(): any;
+
+        /**
+         * Initializes a webVR display and starts listening to display change events
+         * The onVRDisplayChangedObservable will be notified upon these changes
+         * @returns A promise containing a VRDisplay and if vr is supported
+         */
+        initWebVRAsync(): Promise<IDisplayChangedEventArgs>;
+
+        /** @hidden */
+        _getVRDisplaysAsync(): Promise<IDisplayChangedEventArgs>;
+
+        /**
+         * Call this function to switch to webVR mode
+         * Will do nothing if webVR is not supported or if there is no webVR device
+         * @see http://doc.babylonjs.com/how_to/webvr_camera
+         */
+        enableVR(): void;
+
+        /** @hidden */
+        _onVRFullScreenTriggered(): void;
+    }
+}
+
+Object.defineProperty(Engine.prototype, "isInVRExclusivePointerMode", {
+    get: function(this: Engine) {
+        return this._vrExclusivePointerMode;
+    },
+    enumerable: true,
+    configurable: true
+});
+
+Engine.prototype._prepareVRComponent = function() {
+    this._vrSupported = false;
+    this._vrExclusivePointerMode = false;
+    this.onVRDisplayChangedObservable = new Observable<IDisplayChangedEventArgs>();
+    this.onVRRequestPresentComplete = new Observable<boolean>();
+    this.onVRRequestPresentStart = new Observable<Engine>();
+};
+
+Engine.prototype.isVRDevicePresent = function() {
+    return !!this._vrDisplay;
+};
+
+Engine.prototype.getVRDevice = function(): any {
+    return this._vrDisplay;
+};
+
+Engine.prototype.initWebVR = function(): Observable<IDisplayChangedEventArgs> {
+    this.initWebVRAsync();
+    return this.onVRDisplayChangedObservable;
+};
+
+Engine.prototype.initWebVRAsync = function(): Promise<IDisplayChangedEventArgs> {
+    var notifyObservers = () => {
+        var eventArgs = {
+            vrDisplay: this._vrDisplay,
+            vrSupported: this._vrSupported
+        };
+        this.onVRDisplayChangedObservable.notifyObservers(eventArgs);
+        this._webVRInitPromise = new Promise((res) => { res(eventArgs); });
+    };
+
+    if (!this._onVrDisplayConnect) {
+        this._onVrDisplayConnect = (event) => {
+            this._vrDisplay = event.display;
+            notifyObservers();
+        };
+        this._onVrDisplayDisconnect = () => {
+            this._vrDisplay.cancelAnimationFrame(this._frameHandler);
+            this._vrDisplay = undefined;
+            this._frameHandler = Tools.QueueNewFrame(this._bindedRenderFunction);
+            notifyObservers();
+        };
+        this._onVrDisplayPresentChange = () => {
+            this._vrExclusivePointerMode = this._vrDisplay && this._vrDisplay.isPresenting;
+        };
+        window.addEventListener('vrdisplayconnect', this._onVrDisplayConnect);
+        window.addEventListener('vrdisplaydisconnect', this._onVrDisplayDisconnect);
+        window.addEventListener('vrdisplaypresentchange', this._onVrDisplayPresentChange);
+    }
+    this._webVRInitPromise = this._webVRInitPromise || this._getVRDisplaysAsync();
+    this._webVRInitPromise.then(notifyObservers);
+    return this._webVRInitPromise;
+};
+
+Engine.prototype._getVRDisplaysAsync = function(): Promise<IDisplayChangedEventArgs> {
+    return new Promise((res) => {
+        if (navigator.getVRDisplays) {
+            navigator.getVRDisplays().then((devices: Array<any>) => {
+                this._vrSupported = true;
+                // note that devices may actually be an empty array. This is fine;
+                // we expect this._vrDisplay to be undefined in this case.
+                this._vrDisplay = devices[0];
+                res({
+                    vrDisplay: this._vrDisplay,
+                    vrSupported: this._vrSupported
+                });
+            });
+        } else {
+            this._vrDisplay = undefined;
+            this._vrSupported = false;
+            res({
+                vrDisplay: this._vrDisplay,
+                vrSupported: this._vrSupported
+            });
+        }
+    });
+};
+
+Engine.prototype.enableVR = function() {
+    if (this._vrDisplay && !this._vrDisplay.isPresenting) {
+        var onResolved = () => {
+            this.onVRRequestPresentComplete.notifyObservers(true);
+            this._onVRFullScreenTriggered();
+        };
+        var onRejected = () => {
+            this.onVRRequestPresentComplete.notifyObservers(false);
+        };
+
+        this.onVRRequestPresentStart.notifyObservers(this);
+        this._vrDisplay.requestPresent([{ source: this.getRenderingCanvas() }]).then(onResolved).catch(onRejected);
+    }
+};
+
+Engine.prototype._onVRFullScreenTriggered = function() {
+    if (this._vrDisplay && this._vrDisplay.isPresenting) {
+        //get the old size before we change
+        this._oldSize = new Size(this.getRenderWidth(), this.getRenderHeight());
+        this._oldHardwareScaleFactor = this.getHardwareScalingLevel();
+
+        //get the width and height, change the render size
+        var leftEye = this._vrDisplay.getEyeParameters('left');
+        this.setHardwareScalingLevel(1);
+        this.setSize(leftEye.renderWidth * 2, leftEye.renderHeight);
+    } else {
+        this.setHardwareScalingLevel(this._oldHardwareScaleFactor);
+        this.setSize(this._oldSize.width, this._oldSize.height);
+    }
+};
+
+Engine.prototype.disableVR = function() {
+    if (this._vrDisplay && this._vrDisplay.isPresenting) {
+        this._vrDisplay.exitPresent()
+            .then(() => this._onVRFullScreenTriggered())
+            .catch(() => this._onVRFullScreenTriggered());
+    }
+
+    if (DomManagement.IsWindowObjectExist()) {
+        window.removeEventListener('vrdisplaypointerrestricted', this._onVRDisplayPointerRestricted);
+        window.removeEventListener('vrdisplaypointerunrestricted', this._onVRDisplayPointerUnrestricted);
+
+        if (this._onVrDisplayConnect) {
+            window.removeEventListener('vrdisplayconnect', this._onVrDisplayConnect);
+            if (this._onVrDisplayDisconnect) {
+                window.removeEventListener('vrdisplaydisconnect', this._onVrDisplayDisconnect);
+            }
+
+            if (this._onVrDisplayPresentChange) {
+                window.removeEventListener('vrdisplaypresentchange', this._onVrDisplayPresentChange);
+            }
+            this._onVrDisplayConnect = null;
+            this._onVrDisplayDisconnect = null;
+        }
+    }
+};
+
+Engine.prototype._connectVREvents = function(canvas: HTMLCanvasElement, document: any) {
+    this._onVRDisplayPointerRestricted = () => {
+        if (canvas) {
+            canvas.requestPointerLock();
+        }
+    };
+
+    this._onVRDisplayPointerUnrestricted = () => {
+        if (!document.exitPointerLock) {
+            return;
+        }
+        document.exitPointerLock();
+    };
+
+    if (DomManagement.IsWindowObjectExist()) {
+        window.addEventListener('vrdisplaypointerrestricted', this._onVRDisplayPointerRestricted, false);
+        window.addEventListener('vrdisplaypointerunrestricted', this._onVRDisplayPointerUnrestricted, false);
+    }
+};
+
+Engine.prototype._submitVRFrame = function() {
+    // Submit frame to the vr device, if enabled
+    if (this._vrDisplay && this._vrDisplay.isPresenting) {
+        // TODO: We should only submit the frame if we read frameData successfully.
+        try {
+            this._vrDisplay.submitFrame();
+        } catch (e) {
+            Tools.Warn("webVR submitFrame has had an unexpected failure: " + e);
+        }
+    }
+};
+
+Engine.prototype.isVRPresenting = function() {
+    return this._vrDisplay && this._vrDisplay.isPresenting;
+};
+
+Engine.prototype._requestVRFrame = function() {
+    this._frameHandler = Tools.QueueNewFrame(this._bindedRenderFunction, this._vrDisplay);
+};

+ 2 - 1
src/Engines/Extensions/index.ts

@@ -4,4 +4,5 @@ export * from "./engine.multiview";
 export * from "./engine.rawTexture";
 export * from "./engine.multiRender";
 export * from "./engine.cubeTexture";
-export * from "./engine.renderTarget";
+export * from "./engine.renderTarget";
+export * from "./engine.webVR";

+ 56 - 231
src/Engines/engine.ts

@@ -6,7 +6,7 @@ import { Tools, ICustomAnimationFrameRequester, PerfCounter, IFileRequest } from
 import { Nullable, FloatArray, DataArray, IndicesArray } from "../types";
 import { Camera } from "../Cameras/camera";
 import { Scene } from "../scene";
-import { Matrix, Color3, Color4, Viewport, Size, Vector4 } from "../Maths/math";
+import { Matrix, Color3, Color4, Viewport, Vector4 } from "../Maths/math";
 import { Scalar } from "../Maths/math.scalar";
 import { IDisplayChangedEventArgs } from "../Engines/engine";
 import { VertexBuffer } from "../Meshes/buffer";
@@ -230,16 +230,6 @@ export interface EngineOptions extends WebGLContextAttributes {
 }
 
 /**
- * Defines the interface used by display changed events
- */
-export interface IDisplayChangedEventArgs {
-    /** Gets the vrDisplay object (if any) */
-    vrDisplay: Nullable<any>;
-    /** Gets a boolean indicating if webVR is supported */
-    vrSupported: boolean;
-}
-
-/**
  * The engine class is responsible for interfacing with all lower-level APIs such as WebGL and Audio
  */
 export class Engine {
@@ -643,23 +633,6 @@ export class Engine {
      */
     public onBeforeTextureInitObservable = new Observable<Texture>();
 
-    //WebVR
-
-    private _vrDisplay: any = undefined;
-    private _vrSupported: boolean = false;
-    private _oldSize: Size;
-    private _oldHardwareScaleFactor: number;
-    private _vrExclusivePointerMode = false;
-    private _webVRInitPromise: Promise<IDisplayChangedEventArgs>;
-
-    /**
-     * Gets a boolean indicating that the engine is currently in VR exclusive mode for the pointers
-     * @see https://docs.microsoft.com/en-us/microsoft-edge/webvr/essentials#mouse-input
-     */
-    public get isInVRExclusivePointerMode(): boolean {
-        return this._vrExclusivePointerMode;
-    }
-
     // Uniform buffers list
 
     /**
@@ -762,27 +735,6 @@ export class Engine {
     private _onFullscreenChange: () => void;
     private _onPointerLockChange: () => void;
 
-    private _onVRDisplayPointerRestricted: () => void;
-    private _onVRDisplayPointerUnrestricted: () => void;
-
-    // VRDisplay connection
-    private _onVrDisplayConnect: Nullable<(display: any) => void>;
-    private _onVrDisplayDisconnect: Nullable<() => void>;
-    private _onVrDisplayPresentChange: Nullable<() => void>;
-
-    /**
-     * Observable signaled when VR display mode changes
-     */
-    public onVRDisplayChangedObservable = new Observable<IDisplayChangedEventArgs>();
-    /**
-     * Observable signaled when VR request present is complete
-     */
-    public onVRRequestPresentComplete = new Observable<boolean>();
-    /**
-     * Observable signaled when VR request present starts
-     */
-    public onVRRequestPresentStart = new Observable<Engine>();
-
     private _hardwareScalingLevel: number;
     /** @hidden */
     public _caps: EngineCapabilities;
@@ -911,7 +863,8 @@ export class Engine {
     private _dummyFramebuffer: WebGLFramebuffer;
 
     private _externalData: StringDictionary<Object>;
-    private _bindedRenderFunction: any;
+    /** @hidden */
+    public _bindedRenderFunction: any;
 
     private _vaoRecordInProgress = false;
     private _mustWipeVertexAttributes = false;
@@ -1273,23 +1226,7 @@ export class Engine {
             document.addEventListener("mozpointerlockchange", this._onPointerLockChange, false);
             document.addEventListener("webkitpointerlockchange", this._onPointerLockChange, false);
 
-            this._onVRDisplayPointerRestricted = () => {
-                if (canvas) {
-                    canvas.requestPointerLock();
-                }
-            };
-
-            this._onVRDisplayPointerUnrestricted = () => {
-                if (!anyDoc.exitPointerLock) {
-                    return;
-                }
-                anyDoc.exitPointerLock();
-            };
-
-            if (DomManagement.IsWindowObjectExist()) {
-                window.addEventListener('vrdisplaypointerrestricted', this._onVRDisplayPointerRestricted, false);
-                window.addEventListener('vrdisplaypointerunrestricted', this._onVRDisplayPointerUnrestricted, false);
-            }
+            this._connectVREvents(canvas, anyDoc);
         }
 
         // Create Audio Engine if needed.
@@ -1303,6 +1240,7 @@ export class Engine {
         }
 
         // Load WebVR Devices
+        this._prepareVRComponent();
         if (options.autoEnableWebVR) {
             this.initWebVR();
         }
@@ -1318,6 +1256,53 @@ export class Engine {
         this.enableOfflineSupport = Engine.OfflineProviderFactory !== undefined;
     }
 
+    // WebVR
+
+    /**
+     * Initializes a webVR display and starts listening to display change events
+     * The onVRDisplayChangedObservable will be notified upon these changes
+     * @returns The onVRDisplayChangedObservable
+     */
+    public initWebVR(): Observable<IDisplayChangedEventArgs> {
+        throw _DevTools.WarnImport("WebVRCamera");
+    }
+
+    /** @hidden */
+    public _prepareVRComponent() {
+        // Do nothing as the engine side effect will overload it
+    }
+
+    /** @hidden */
+    public _connectVREvents(canvas: HTMLCanvasElement, document: any) {
+        // Do nothing as the engine side effect will overload it
+    }
+
+    /** @hidden */
+    public _submitVRFrame() {
+        // Do nothing as the engine side effect will overload it
+    }
+    /**
+     * Call this function to leave webVR mode
+     * Will do nothing if webVR is not supported or if there is no webVR device
+     * @see http://doc.babylonjs.com/how_to/webvr_camera
+     */
+    public disableVR() {
+        // Do nothing as the engine side effect will overload it
+    }
+
+    /**
+     * Gets a boolean indicating that the system is in VR mode and is presenting
+     * @returns true if VR mode is engaged
+     */
+    public isVRPresenting() {
+        return false;
+    }
+
+    /** @hidden */
+    public _requestVRFrame() {
+        // Do nothing as the engine side effect will overload it
+    }
+
     private _disableTouchAction(): void {
         if (!this._renderingCanvas) {
             return;
@@ -2007,8 +1992,8 @@ export class Engine {
             if (this.customAnimationFrameRequester) {
                 this.customAnimationFrameRequester.requestID = Tools.QueueNewFrame(this.customAnimationFrameRequester.renderFunction || this._bindedRenderFunction, this.customAnimationFrameRequester);
                 this._frameHandler = this.customAnimationFrameRequester.requestID;
-            } else if (this._vrDisplay && this._vrDisplay.isPresenting) {
-                this._frameHandler = Tools.QueueNewFrame(this._bindedRenderFunction, this._vrDisplay);
+            } else if (this.isVRPresenting()) {
+                this._requestVRFrame();
             } else {
                 this._frameHandler = Tools.QueueNewFrame(this._bindedRenderFunction);
             }
@@ -2201,15 +2186,7 @@ export class Engine {
             this.flushFramebuffer();
         }
 
-        // Submit frame to the vr device, if enabled
-        if (this._vrDisplay && this._vrDisplay.isPresenting) {
-            // TODO: We should only submit the frame if we read frameData successfully.
-            try {
-                this._vrDisplay.submitFrame();
-            } catch (e) {
-                Tools.Warn("webVR submitFrame has had an unexpected failure: " + e);
-            }
-        }
+        this._submitVRFrame();
 
         this.onEndFrameObservable.notifyObservers(this);
     }
@@ -2219,7 +2196,7 @@ export class Engine {
      */
     public resize(): void {
         // We're not resizing the size of the canvas while in VR mode & presenting
-        if (!(this._vrDisplay && this._vrDisplay.isPresenting)) {
+        if (!this.isVRPresenting()) {
             var width = this._renderingCanvas ? this._renderingCanvas.clientWidth : window.innerWidth;
             var height = this._renderingCanvas ? this._renderingCanvas.clientHeight : window.innerHeight;
 
@@ -2259,143 +2236,6 @@ export class Engine {
         }
     }
 
-    // WebVR functions
-
-    /**
-     * Gets a boolean indicating if a webVR device was detected
-     * @returns true if a webVR device was detected
-     */
-    public isVRDevicePresent(): boolean {
-        return !!this._vrDisplay;
-    }
-
-    /**
-     * Gets the current webVR device
-     * @returns the current webVR device (or null)
-     */
-    public getVRDevice(): any {
-        return this._vrDisplay;
-    }
-
-    /**
-     * Initializes a webVR display and starts listening to display change events
-     * The onVRDisplayChangedObservable will be notified upon these changes
-     * @returns The onVRDisplayChangedObservable
-     */
-    public initWebVR(): Observable<IDisplayChangedEventArgs> {
-        this.initWebVRAsync();
-        return this.onVRDisplayChangedObservable;
-    }
-
-    /**
-     * Initializes a webVR display and starts listening to display change events
-     * The onVRDisplayChangedObservable will be notified upon these changes
-     * @returns A promise containing a VRDisplay and if vr is supported
-     */
-    public initWebVRAsync(): Promise<IDisplayChangedEventArgs> {
-        var notifyObservers = () => {
-            var eventArgs = {
-                vrDisplay: this._vrDisplay,
-                vrSupported: this._vrSupported
-            };
-            this.onVRDisplayChangedObservable.notifyObservers(eventArgs);
-            this._webVRInitPromise = new Promise((res) => { res(eventArgs); });
-        };
-
-        if (!this._onVrDisplayConnect) {
-            this._onVrDisplayConnect = (event) => {
-                this._vrDisplay = event.display;
-                notifyObservers();
-            };
-            this._onVrDisplayDisconnect = () => {
-                this._vrDisplay.cancelAnimationFrame(this._frameHandler);
-                this._vrDisplay = undefined;
-                this._frameHandler = Tools.QueueNewFrame(this._bindedRenderFunction);
-                notifyObservers();
-            };
-            this._onVrDisplayPresentChange = () => {
-                this._vrExclusivePointerMode = this._vrDisplay && this._vrDisplay.isPresenting;
-            };
-            window.addEventListener('vrdisplayconnect', this._onVrDisplayConnect);
-            window.addEventListener('vrdisplaydisconnect', this._onVrDisplayDisconnect);
-            window.addEventListener('vrdisplaypresentchange', this._onVrDisplayPresentChange);
-        }
-        this._webVRInitPromise = this._webVRInitPromise || this._getVRDisplaysAsync();
-        this._webVRInitPromise.then(notifyObservers);
-        return this._webVRInitPromise;
-    }
-
-    /**
-     * Call this function to switch to webVR mode
-     * Will do nothing if webVR is not supported or if there is no webVR device
-     * @see http://doc.babylonjs.com/how_to/webvr_camera
-     */
-    public enableVR() {
-        if (this._vrDisplay && !this._vrDisplay.isPresenting) {
-            var onResolved = () => {
-                this.onVRRequestPresentComplete.notifyObservers(true);
-                this._onVRFullScreenTriggered();
-            };
-            var onRejected = () => {
-                this.onVRRequestPresentComplete.notifyObservers(false);
-            };
-
-            this.onVRRequestPresentStart.notifyObservers(this);
-            this._vrDisplay.requestPresent([{ source: this.getRenderingCanvas() }]).then(onResolved).catch(onRejected);
-        }
-    }
-
-    /**
-     * Call this function to leave webVR mode
-     * Will do nothing if webVR is not supported or if there is no webVR device
-     * @see http://doc.babylonjs.com/how_to/webvr_camera
-     */
-    public disableVR() {
-        if (this._vrDisplay && this._vrDisplay.isPresenting) {
-            this._vrDisplay.exitPresent().then(this._onVRFullScreenTriggered).catch(this._onVRFullScreenTriggered);
-        }
-    }
-
-    private _onVRFullScreenTriggered = () => {
-        if (this._vrDisplay && this._vrDisplay.isPresenting) {
-            //get the old size before we change
-            this._oldSize = new Size(this.getRenderWidth(), this.getRenderHeight());
-            this._oldHardwareScaleFactor = this.getHardwareScalingLevel();
-
-            //get the width and height, change the render size
-            var leftEye = this._vrDisplay.getEyeParameters('left');
-            this.setHardwareScalingLevel(1);
-            this.setSize(leftEye.renderWidth * 2, leftEye.renderHeight);
-        } else {
-            this.setHardwareScalingLevel(this._oldHardwareScaleFactor);
-            this.setSize(this._oldSize.width, this._oldSize.height);
-        }
-    }
-
-    private _getVRDisplaysAsync(): Promise<IDisplayChangedEventArgs> {
-        return new Promise((res) => {
-            if (navigator.getVRDisplays) {
-                navigator.getVRDisplays().then((devices: Array<any>) => {
-                    this._vrSupported = true;
-                    // note that devices may actually be an empty array. This is fine;
-                    // we expect this._vrDisplay to be undefined in this case.
-                    this._vrDisplay = devices[0];
-                    res({
-                        vrDisplay: this._vrDisplay,
-                        vrSupported: this._vrSupported
-                    });
-                });
-            } else {
-                this._vrDisplay = undefined;
-                this._vrSupported = false;
-                res({
-                    vrDisplay: this._vrDisplay,
-                    vrSupported: this._vrSupported
-                });
-            }
-        });
-    }
-
     /**
      * Binds the frame buffer to the specified texture.
      * @param texture The texture to render to or null for the default canvas
@@ -5915,8 +5755,6 @@ export class Engine {
         if (DomManagement.IsWindowObjectExist()) {
             window.removeEventListener("blur", this._onBlur);
             window.removeEventListener("focus", this._onFocus);
-            window.removeEventListener('vrdisplaypointerrestricted', this._onVRDisplayPointerRestricted);
-            window.removeEventListener('vrdisplaypointerunrestricted', this._onVRDisplayPointerUnrestricted);
             if (this._renderingCanvas) {
                 this._renderingCanvas.removeEventListener("focus", this._onCanvasFocus);
                 this._renderingCanvas.removeEventListener("blur", this._onCanvasBlur);
@@ -5935,19 +5773,6 @@ export class Engine {
             document.removeEventListener("mspointerlockchange", this._onPointerLockChange);
             document.removeEventListener("mozpointerlockchange", this._onPointerLockChange);
             document.removeEventListener("webkitpointerlockchange", this._onPointerLockChange);
-
-            if (this._onVrDisplayConnect) {
-                window.removeEventListener('vrdisplayconnect', this._onVrDisplayConnect);
-                if (this._onVrDisplayDisconnect) {
-                    window.removeEventListener('vrdisplaydisconnect', this._onVrDisplayDisconnect);
-                }
-
-                if (this._onVrDisplayPresentChange) {
-                    window.removeEventListener('vrdisplaypresentchange', this._onVrDisplayPresentChange);
-                }
-                this._onVrDisplayConnect = null;
-                this._onVrDisplayDisconnect = null;
-            }
         }
 
         // Remove from Instances

+ 871 - 0
src/Inputs/scene.inputManager.ts

@@ -0,0 +1,871 @@
+import { Observable, Observer } from '../Misc/observable';
+import { PointerInfoPre, PointerInfo, PointerEventTypes } from '../Events/pointerEvents';
+import { Nullable } from '../types';
+import { AbstractActionManager } from '../Actions/abstractActionManager';
+import { PickingInfo } from '../Collisions/pickingInfo';
+import { Vector2, Matrix } from '../Maths/math';
+import { AbstractMesh } from '../Meshes/abstractMesh';
+import { Constants } from '../Engines/constants';
+import { ActionEvent } from '../Actions/actionEvent';
+import { Tools } from '../Misc/tools';
+import { Engine } from '../Engines/engine';
+import { KeyboardEventTypes, KeyboardInfoPre, KeyboardInfo } from '../Events/keyboardEvents';
+
+declare type Scene = import("../scene").Scene;
+
+/** @hidden */
+class _ClickInfo {
+    private _singleClick = false;
+    private _doubleClick = false;
+    private _hasSwiped = false;
+    private _ignore = false;
+
+    public get singleClick(): boolean {
+        return this._singleClick;
+    }
+    public get doubleClick(): boolean {
+        return this._doubleClick;
+    }
+    public get hasSwiped(): boolean {
+        return this._hasSwiped;
+    }
+    public get ignore(): boolean {
+        return this._ignore;
+    }
+
+    public set singleClick(b: boolean) {
+        this._singleClick = b;
+    }
+    public set doubleClick(b: boolean) {
+        this._doubleClick = b;
+    }
+    public set hasSwiped(b: boolean) {
+        this._hasSwiped = b;
+    }
+    public set ignore(b: boolean) {
+        this._ignore = b;
+    }
+}
+
+/**
+ * Class used to manage all inputs for the scene.
+ */
+export class InputManager {
+    /** The distance in pixel that you have to move to prevent some events */
+    public static DragMovementThreshold = 10; // in pixels
+    /** Time in milliseconds to wait to raise long press events if button is still pressed */
+    public static LongPressDelay = 500; // in milliseconds
+    /** Time in milliseconds with two consecutive clicks will be considered as a double click */
+    public static DoubleClickDelay = 300; // in milliseconds
+    /** If you need to check double click without raising a single click at first click, enable this flag */
+    public static ExclusiveDoubleClickMode = false;
+
+    // Pointers
+    private _wheelEventName = "";
+    private _onPointerMove: (evt: PointerEvent) => void;
+    private _onPointerDown: (evt: PointerEvent) => void;
+    private _onPointerUp: (evt: PointerEvent) => void;
+
+    private _initClickEvent: (obs1: Observable<PointerInfoPre>, obs2: Observable<PointerInfo>, evt: PointerEvent, cb: (clickInfo: _ClickInfo, pickResult: Nullable<PickingInfo>) => void) => void;
+    private _initActionManager: (act: Nullable<AbstractActionManager>, clickInfo: _ClickInfo) => Nullable<AbstractActionManager>;
+    private _delayedSimpleClick: (btn: number, clickInfo: _ClickInfo, cb: (clickInfo: _ClickInfo, pickResult: Nullable<PickingInfo>) => void) => void;
+    private _delayedSimpleClickTimeout: number;
+    private _previousDelayedSimpleClickTimeout: number;
+    private _meshPickProceed = false;
+
+    private _previousButtonPressed: number;
+    private _currentPickResult: Nullable<PickingInfo> = null;
+    private _previousPickResult: Nullable<PickingInfo> = null;
+    private _totalPointersPressed = 0;
+    private _doubleClickOccured = false;
+
+    private _pointerOverMesh: Nullable<AbstractMesh>;
+
+    private _pickedDownMesh: Nullable<AbstractMesh>;
+    private _pickedUpMesh: Nullable<AbstractMesh>;
+
+    private _pointerX: number = 0;
+    private _pointerY: number = 0;
+    private _unTranslatedPointerX: number;
+    private _unTranslatedPointerY: number;
+    private _startingPointerPosition = new Vector2(0, 0);
+    private _previousStartingPointerPosition = new Vector2(0, 0);
+    private _startingPointerTime = 0;
+    private _previousStartingPointerTime = 0;
+    private _pointerCaptures: { [pointerId: number]: boolean } = {};
+
+    // Keyboard
+    private _onKeyDown: (evt: KeyboardEvent) => void;
+    private _onKeyUp: (evt: KeyboardEvent) => void;
+    private _onCanvasFocusObserver: Nullable<Observer<Engine>>;
+    private _onCanvasBlurObserver: Nullable<Observer<Engine>>;
+
+    private _scene: Scene;
+
+    /**
+     * Creates a new InputManager
+     * @param scene defines the hosting scene
+     */
+    public constructor(scene: Scene) {
+        this._scene = scene;
+    }
+
+    /**
+    * Gets the mesh that is currently under the pointer
+    */
+    public get meshUnderPointer(): Nullable<AbstractMesh> {
+        return this._pointerOverMesh;
+    }
+
+    /**
+     * Gets the pointer coordinates in 2D without any translation (ie. straight out of the pointer event)
+     */
+    public get unTranslatedPointer(): Vector2 {
+        return new Vector2(this._unTranslatedPointerX, this._unTranslatedPointerY);
+    }
+
+    /**
+     * Gets or sets the current on-screen X position of the pointer
+     */
+    public get pointerX(): number {
+        return this._pointerX;
+    }
+
+    public set pointerX(value: number) {
+        this._pointerX = value;
+    }
+
+    /**
+     * Gets or sets the current on-screen Y position of the pointer
+     */
+    public get pointerY(): number {
+        return this._pointerY;
+    }
+
+    public set pointerY(value: number) {
+        this._pointerY = value;
+    }
+
+    private _updatePointerPosition(evt: PointerEvent): void {
+        var canvasRect = this._scene.getEngine().getRenderingCanvasClientRect();
+
+        if (!canvasRect) {
+            return;
+        }
+
+        this._pointerX = evt.clientX - canvasRect.left;
+        this._pointerY = evt.clientY - canvasRect.top;
+
+        this._unTranslatedPointerX = this._pointerX;
+        this._unTranslatedPointerY = this._pointerY;
+    }
+
+    private _processPointerMove(pickResult: Nullable<PickingInfo>, evt: PointerEvent) {
+        let scene = this._scene;
+        var canvas = scene.getEngine().getRenderingCanvas();
+
+        if (!canvas) {
+            return;
+        }
+
+        canvas.tabIndex = 1;
+
+        // Restore pointer
+        canvas.style.cursor = scene.defaultCursor;
+
+        var isMeshPicked = (pickResult && pickResult.hit && pickResult.pickedMesh) ? true : false;
+        if (isMeshPicked) {
+            scene.setPointerOverMesh(pickResult!.pickedMesh);
+
+            if (this._pointerOverMesh && this._pointerOverMesh.actionManager && this._pointerOverMesh.actionManager.hasPointerTriggers) {
+                if (this._pointerOverMesh.actionManager.hoverCursor) {
+                    canvas.style.cursor = this._pointerOverMesh.actionManager.hoverCursor;
+                } else {
+                    canvas.style.cursor = scene.hoverCursor;
+                }
+            }
+        } else {
+            scene.setPointerOverMesh(null);
+        }
+
+        for (let step of scene._pointerMoveStage) {
+            pickResult = step.action(this._unTranslatedPointerX, this._unTranslatedPointerY, pickResult, isMeshPicked, canvas);
+        }
+
+        if (pickResult) {
+            let type = evt.type === this._wheelEventName ? PointerEventTypes.POINTERWHEEL : PointerEventTypes.POINTERMOVE;
+
+            if (scene.onPointerMove) {
+                scene.onPointerMove(evt, pickResult, type);
+            }
+
+            if (scene.onPointerObservable.hasObservers()) {
+                let pi = new PointerInfo(type, evt, pickResult);
+                this._setRayOnPointerInfo(pi);
+                scene.onPointerObservable.notifyObservers(pi, type);
+            }
+        }
+    }
+
+    // Pointers handling
+    private _setRayOnPointerInfo(pointerInfo: PointerInfo) {
+        let scene = this._scene;
+        if (pointerInfo.pickInfo && !pointerInfo.pickInfo._pickingUnavailable) {
+            if (!pointerInfo.pickInfo.ray) {
+                pointerInfo.pickInfo.ray = scene.createPickingRay(pointerInfo.event.offsetX, pointerInfo.event.offsetY, Matrix.Identity(), scene.activeCamera);
+            }
+        }
+    }
+
+    private _checkPrePointerObservable(pickResult: Nullable<PickingInfo>, evt: PointerEvent, type: number) {
+        let scene = this._scene;
+        let pi = new PointerInfoPre(type, evt, this._unTranslatedPointerX, this._unTranslatedPointerY);
+        if (pickResult) {
+            pi.ray = pickResult.ray;
+        }
+        scene.onPrePointerObservable.notifyObservers(pi, type);
+        if (pi.skipOnPointerObservable) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Use this method to simulate a pointer move on a mesh
+     * The pickResult parameter can be obtained from a scene.pick or scene.pickWithRay
+     * @param pickResult pickingInfo of the object wished to simulate pointer event on
+     * @param pointerEventInit pointer event state to be used when simulating the pointer event (eg. pointer id for multitouch)
+     */
+    public simulatePointerMove(pickResult: PickingInfo, pointerEventInit?: PointerEventInit): void {
+        let evt = new PointerEvent("pointermove", pointerEventInit);
+
+        if (this._checkPrePointerObservable(pickResult, evt, PointerEventTypes.POINTERMOVE)) {
+            return;
+        }
+        this._processPointerMove(pickResult, evt);
+    }
+
+    /**
+     * Use this method to simulate a pointer down on a mesh
+     * The pickResult parameter can be obtained from a scene.pick or scene.pickWithRay
+     * @param pickResult pickingInfo of the object wished to simulate pointer event on
+     * @param pointerEventInit pointer event state to be used when simulating the pointer event (eg. pointer id for multitouch)
+     */
+    public simulatePointerDown(pickResult: PickingInfo, pointerEventInit?: PointerEventInit): void {
+        let evt = new PointerEvent("pointerdown", pointerEventInit);
+
+        if (this._checkPrePointerObservable(pickResult, evt, PointerEventTypes.POINTERDOWN)) {
+            return;
+        }
+
+        this._processPointerDown(pickResult, evt);
+    }
+
+    private _processPointerDown(pickResult: Nullable<PickingInfo>, evt: PointerEvent): void {
+        let scene = this._scene;
+        if (pickResult && pickResult.hit && pickResult.pickedMesh) {
+            this._pickedDownMesh = pickResult.pickedMesh;
+            var actionManager = pickResult.pickedMesh.actionManager;
+            if (actionManager) {
+                if (actionManager.hasPickTriggers) {
+                    actionManager.processTrigger(Constants.ACTION_OnPickDownTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
+                    switch (evt.button) {
+                        case 0:
+                            actionManager.processTrigger(Constants.ACTION_OnLeftPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
+                            break;
+                        case 1:
+                            actionManager.processTrigger(Constants.ACTION_OnCenterPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
+                            break;
+                        case 2:
+                            actionManager.processTrigger(Constants.ACTION_OnRightPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
+                            break;
+                    }
+                }
+
+                if (actionManager.hasSpecificTrigger(Constants.ACTION_OnLongPressTrigger)) {
+                    window.setTimeout(() => {
+                        var pickResult = scene.pick(this._unTranslatedPointerX, this._unTranslatedPointerY,
+                            (mesh: AbstractMesh): boolean => (<boolean>(mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.actionManager && mesh.actionManager.hasSpecificTrigger(Constants.ACTION_OnLongPressTrigger) && mesh == this._pickedDownMesh)),
+                            false, scene.cameraToUseForPointers);
+
+                        if (pickResult && pickResult.hit && pickResult.pickedMesh && actionManager) {
+                            if (this._totalPointersPressed !== 0 &&
+                                ((Date.now() - this._startingPointerTime) > InputManager.LongPressDelay) &&
+                                !this._isPointerSwiping()) {
+                                this._startingPointerTime = 0;
+                                actionManager.processTrigger(Constants.ACTION_OnLongPressTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
+                            }
+                        }
+                    }, InputManager.LongPressDelay);
+                }
+            }
+        }
+        else {
+            for (let step of scene._pointerDownStage) {
+                pickResult = step.action(this._unTranslatedPointerX, this._unTranslatedPointerY, pickResult, evt);
+            }
+        }
+
+        if (pickResult) {
+            let type = PointerEventTypes.POINTERDOWN;
+
+            if (scene.onPointerDown) {
+                scene.onPointerDown(evt, pickResult, type);
+            }
+
+            if (scene.onPointerObservable.hasObservers()) {
+                let pi = new PointerInfo(type, evt, pickResult);
+                this._setRayOnPointerInfo(pi);
+                scene.onPointerObservable.notifyObservers(pi, type);
+            }
+        }
+    }
+
+    /** @hidden */
+    public _isPointerSwiping(): boolean {
+        return Math.abs(this._startingPointerPosition.x - this._pointerX) > InputManager.DragMovementThreshold ||
+            Math.abs(this._startingPointerPosition.y - this._pointerY) > InputManager.DragMovementThreshold;
+    }
+
+    /**
+     * Use this method to simulate a pointer up on a mesh
+     * The pickResult parameter can be obtained from a scene.pick or scene.pickWithRay
+     * @param pickResult pickingInfo of the object wished to simulate pointer event on
+     * @param pointerEventInit pointer event state to be used when simulating the pointer event (eg. pointer id for multitouch)
+     * @param doubleTap indicates that the pointer up event should be considered as part of a double click (false by default)
+     */
+    public simulatePointerUp(pickResult: PickingInfo, pointerEventInit?: PointerEventInit, doubleTap?: boolean): void {
+        let evt = new PointerEvent("pointerup", pointerEventInit);
+        let clickInfo = new _ClickInfo();
+
+        if (doubleTap) {
+            clickInfo.doubleClick = true;
+        } else {
+            clickInfo.singleClick = true;
+        }
+
+        if (this._checkPrePointerObservable(pickResult, evt, PointerEventTypes.POINTERUP)) {
+            return;
+        }
+
+        this._processPointerUp(pickResult, evt, clickInfo);
+    }
+
+    private _processPointerUp(pickResult: Nullable<PickingInfo>, evt: PointerEvent, clickInfo: _ClickInfo): void {
+        let scene = this._scene;
+        if (pickResult && pickResult && pickResult.pickedMesh) {
+            this._pickedUpMesh = pickResult.pickedMesh;
+            if (this._pickedDownMesh === this._pickedUpMesh) {
+                if (scene.onPointerPick) {
+                    scene.onPointerPick(evt, pickResult);
+                }
+                if (clickInfo.singleClick && !clickInfo.ignore && scene.onPointerObservable.hasObservers()) {
+                    let type = PointerEventTypes.POINTERPICK;
+                    let pi = new PointerInfo(type, evt, pickResult);
+                    this._setRayOnPointerInfo(pi);
+                    scene.onPointerObservable.notifyObservers(pi, type);
+                }
+            }
+            let actionManager = pickResult.pickedMesh._getActionManagerForTrigger();
+            if (actionManager && !clickInfo.ignore) {
+                actionManager.processTrigger(Constants.ACTION_OnPickUpTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
+
+                if (!clickInfo.hasSwiped && clickInfo.singleClick) {
+                    actionManager.processTrigger(Constants.ACTION_OnPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
+                }
+
+                let doubleClickActionManager = pickResult.pickedMesh._getActionManagerForTrigger(Constants.ACTION_OnDoublePickTrigger);
+                if (clickInfo.doubleClick && doubleClickActionManager) {
+                    doubleClickActionManager.processTrigger(Constants.ACTION_OnDoublePickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
+                }
+            }
+        }
+        else {
+            if (!clickInfo.ignore) {
+                for (let step of scene._pointerUpStage) {
+                    pickResult = step.action(this._unTranslatedPointerX, this._unTranslatedPointerY, pickResult, evt);
+                }
+            }
+        }
+
+        if (this._pickedDownMesh && this._pickedDownMesh !== this._pickedUpMesh) {
+            let pickedDownActionManager = this._pickedDownMesh._getActionManagerForTrigger(Constants.ACTION_OnPickOutTrigger);
+            if (pickedDownActionManager) {
+                pickedDownActionManager.processTrigger(Constants.ACTION_OnPickOutTrigger, ActionEvent.CreateNew(this._pickedDownMesh, evt));
+            }
+        }
+
+        let type = 0;
+        if (scene.onPointerObservable.hasObservers()) {
+            if (!clickInfo.ignore && !clickInfo.hasSwiped) {
+                if (clickInfo.singleClick && scene.onPointerObservable.hasSpecificMask(PointerEventTypes.POINTERTAP)) {
+                    type = PointerEventTypes.POINTERTAP;
+                }
+                else if (clickInfo.doubleClick && scene.onPointerObservable.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP)) {
+                    type = PointerEventTypes.POINTERDOUBLETAP;
+                }
+                if (type) {
+                    let pi = new PointerInfo(type, evt, pickResult);
+                    this._setRayOnPointerInfo(pi);
+                    scene.onPointerObservable.notifyObservers(pi, type);
+                }
+            }
+
+            if (!clickInfo.ignore) {
+                type = PointerEventTypes.POINTERUP;
+
+                let pi = new PointerInfo(type, evt, pickResult);
+                this._setRayOnPointerInfo(pi);
+                scene.onPointerObservable.notifyObservers(pi, type);
+            }
+        }
+
+        if (scene.onPointerUp && !clickInfo.ignore) {
+            scene.onPointerUp(evt, pickResult, type);
+        }
+    }
+
+    /**
+     * Gets a boolean indicating if the current pointer event is captured (meaning that the scene has already handled the pointer down)
+     * @param pointerId defines the pointer id to use in a multi-touch scenario (0 by default)
+     * @returns true if the pointer was captured
+     */
+    public isPointerCaptured(pointerId = 0): boolean {
+        return this._pointerCaptures[pointerId];
+    }
+
+    /**
+    * Attach events to the canvas (To handle actionManagers triggers and raise onPointerMove, onPointerDown and onPointerUp
+    * @param attachUp defines if you want to attach events to pointerup
+    * @param attachDown defines if you want to attach events to pointerdown
+    * @param attachMove defines if you want to attach events to pointermove
+    */
+    public attachControl(attachUp = true, attachDown = true, attachMove = true): void {
+        let scene = this._scene;
+        var canvas = scene.getEngine().getRenderingCanvas();
+
+        if (!canvas) {
+            return;
+        }
+
+        let engine = scene.getEngine();
+
+        this._initActionManager = (act: Nullable<AbstractActionManager>, clickInfo: _ClickInfo): Nullable<AbstractActionManager> => {
+            if (!this._meshPickProceed) {
+                let pickResult = scene.pick(this._unTranslatedPointerX, this._unTranslatedPointerY, scene.pointerDownPredicate, false, scene.cameraToUseForPointers);
+                this._currentPickResult = pickResult;
+                if (pickResult) {
+                    act = (pickResult.hit && pickResult.pickedMesh) ? pickResult.pickedMesh._getActionManagerForTrigger() : null;
+                }
+                this._meshPickProceed = true;
+            }
+            return act;
+        };
+
+        this._delayedSimpleClick = (btn: number, clickInfo: _ClickInfo, cb: (clickInfo: _ClickInfo, pickResult: Nullable<PickingInfo>) => void) => {
+            // double click delay is over and that no double click has been raised since, or the 2 consecutive keys pressed are different
+            if ((Date.now() - this._previousStartingPointerTime > InputManager.DoubleClickDelay && !this._doubleClickOccured) ||
+                btn !== this._previousButtonPressed) {
+                this._doubleClickOccured = false;
+                clickInfo.singleClick = true;
+                clickInfo.ignore = false;
+                cb(clickInfo, this._currentPickResult);
+            }
+        };
+
+        this._initClickEvent = (obs1: Observable<PointerInfoPre>, obs2: Observable<PointerInfo>, evt: PointerEvent, cb: (clickInfo: _ClickInfo, pickResult: Nullable<PickingInfo>) => void): void => {
+            let clickInfo = new _ClickInfo();
+            this._currentPickResult = null;
+            let act: Nullable<AbstractActionManager> = null;
+
+            let checkPicking = obs1.hasSpecificMask(PointerEventTypes.POINTERPICK) || obs2.hasSpecificMask(PointerEventTypes.POINTERPICK)
+                || obs1.hasSpecificMask(PointerEventTypes.POINTERTAP) || obs2.hasSpecificMask(PointerEventTypes.POINTERTAP)
+                || obs1.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP) || obs2.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP);
+            if (!checkPicking && AbstractActionManager) {
+                act = this._initActionManager(act, clickInfo);
+                if (act) {
+                    checkPicking = act.hasPickTriggers;
+                }
+            }
+
+            let needToIgnoreNext = false;
+
+            if (checkPicking) {
+                let btn = evt.button;
+                clickInfo.hasSwiped = this._isPointerSwiping();
+
+                if (!clickInfo.hasSwiped) {
+                    let checkSingleClickImmediately = !InputManager.ExclusiveDoubleClickMode;
+
+                    if (!checkSingleClickImmediately) {
+                        checkSingleClickImmediately = !obs1.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP) &&
+                            !obs2.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP);
+
+                        if (checkSingleClickImmediately && !AbstractActionManager.HasSpecificTrigger(Constants.ACTION_OnDoublePickTrigger)) {
+                            act = this._initActionManager(act, clickInfo);
+                            if (act) {
+                                checkSingleClickImmediately = !act.hasSpecificTrigger(Constants.ACTION_OnDoublePickTrigger);
+                            }
+                        }
+                    }
+
+                    if (checkSingleClickImmediately) {
+                        // single click detected if double click delay is over or two different successive keys pressed without exclusive double click or no double click required
+                        if (Date.now() - this._previousStartingPointerTime > InputManager.DoubleClickDelay ||
+                            btn !== this._previousButtonPressed) {
+                            clickInfo.singleClick = true;
+                            cb(clickInfo, this._currentPickResult);
+                            needToIgnoreNext = true;
+                        }
+                    }
+                    // at least one double click is required to be check and exclusive double click is enabled
+                    else {
+                        // wait that no double click has been raised during the double click delay
+                        this._previousDelayedSimpleClickTimeout = this._delayedSimpleClickTimeout;
+                        this._delayedSimpleClickTimeout = window.setTimeout(this._delayedSimpleClick.bind(this, btn, clickInfo, cb), InputManager.DoubleClickDelay);
+                    }
+
+                    let checkDoubleClick = obs1.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP) ||
+                        obs2.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP);
+                    if (!checkDoubleClick && AbstractActionManager.HasSpecificTrigger(Constants.ACTION_OnDoublePickTrigger)) {
+                        act = this._initActionManager(act, clickInfo);
+                        if (act) {
+                            checkDoubleClick = act.hasSpecificTrigger(Constants.ACTION_OnDoublePickTrigger);
+                        }
+                    }
+                    if (checkDoubleClick) {
+                        // two successive keys pressed are equal, double click delay is not over and double click has not just occurred
+                        if (btn === this._previousButtonPressed &&
+                            Date.now() - this._previousStartingPointerTime < InputManager.DoubleClickDelay &&
+                            !this._doubleClickOccured
+                        ) {
+                            // pointer has not moved for 2 clicks, it's a double click
+                            if (!clickInfo.hasSwiped &&
+                                !this._isPointerSwiping()) {
+                                this._previousStartingPointerTime = 0;
+                                this._doubleClickOccured = true;
+                                clickInfo.doubleClick = true;
+                                clickInfo.ignore = false;
+                                if (InputManager.ExclusiveDoubleClickMode && this._previousDelayedSimpleClickTimeout) {
+                                    clearTimeout(this._previousDelayedSimpleClickTimeout);
+                                }
+                                this._previousDelayedSimpleClickTimeout = this._delayedSimpleClickTimeout;
+                                cb(clickInfo, this._currentPickResult);
+                            }
+                            // if the two successive clicks are too far, it's just two simple clicks
+                            else {
+                                this._doubleClickOccured = false;
+                                this._previousStartingPointerTime = this._startingPointerTime;
+                                this._previousStartingPointerPosition.x = this._startingPointerPosition.x;
+                                this._previousStartingPointerPosition.y = this._startingPointerPosition.y;
+                                this._previousButtonPressed = btn;
+                                if (InputManager.ExclusiveDoubleClickMode) {
+                                    if (this._previousDelayedSimpleClickTimeout) {
+                                        clearTimeout(this._previousDelayedSimpleClickTimeout);
+                                    }
+                                    this._previousDelayedSimpleClickTimeout = this._delayedSimpleClickTimeout;
+
+                                    cb(clickInfo, this._previousPickResult);
+                                }
+                                else {
+                                    cb(clickInfo, this._currentPickResult);
+                                }
+                            }
+                            needToIgnoreNext = true;
+                        }
+                        // just the first click of the double has been raised
+                        else {
+                            this._doubleClickOccured = false;
+                            this._previousStartingPointerTime = this._startingPointerTime;
+                            this._previousStartingPointerPosition.x = this._startingPointerPosition.x;
+                            this._previousStartingPointerPosition.y = this._startingPointerPosition.y;
+                            this._previousButtonPressed = btn;
+                        }
+                    }
+                }
+            }
+
+            if (!needToIgnoreNext) {
+                cb(clickInfo, this._currentPickResult);
+            }
+        };
+
+        this._onPointerMove = (evt: PointerEvent) => {
+
+            this._updatePointerPosition(evt);
+
+            // PreObservable support
+            if (this._checkPrePointerObservable(null, evt, evt.type === this._wheelEventName ? PointerEventTypes.POINTERWHEEL : PointerEventTypes.POINTERMOVE)) {
+                return;
+            }
+
+            if (!scene.cameraToUseForPointers && !scene.activeCamera) {
+                return;
+            }
+
+            if (!scene.pointerMovePredicate) {
+                scene.pointerMovePredicate = (mesh: AbstractMesh): boolean => (mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.isEnabled() && (mesh.enablePointerMoveEvents || scene.constantlyUpdateMeshUnderPointer || (mesh.actionManager !== null && mesh.actionManager !== undefined)) && (!scene.cameraToUseForPointers || (scene.cameraToUseForPointers.layerMask & mesh.layerMask) !== 0));
+            }
+
+            // Meshes
+            var pickResult = scene.pick(this._unTranslatedPointerX, this._unTranslatedPointerY, scene.pointerMovePredicate, false, scene.cameraToUseForPointers);
+
+            this._processPointerMove(pickResult, evt);
+        };
+
+        this._onPointerDown = (evt: PointerEvent) => {
+            this._totalPointersPressed++;
+            this._pickedDownMesh = null;
+            this._meshPickProceed = false;
+
+            this._updatePointerPosition(evt);
+
+            if (scene.preventDefaultOnPointerDown && canvas) {
+                evt.preventDefault();
+                canvas.focus();
+            }
+
+            this._startingPointerPosition.x = this._pointerX;
+            this._startingPointerPosition.y = this._pointerY;
+            this._startingPointerTime = Date.now();
+
+            // PreObservable support
+            if (this._checkPrePointerObservable(null, evt, PointerEventTypes.POINTERDOWN)) {
+                return;
+            }
+
+            if (!scene.cameraToUseForPointers && !scene.activeCamera) {
+                return;
+            }
+
+            this._pointerCaptures[evt.pointerId] = true;
+
+            if (!scene.pointerDownPredicate) {
+                scene.pointerDownPredicate = (mesh: AbstractMesh): boolean => {
+                    return mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.isEnabled() && (!scene.cameraToUseForPointers || (scene.cameraToUseForPointers.layerMask & mesh.layerMask) !== 0);
+                };
+            }
+
+            // Meshes
+            this._pickedDownMesh = null;
+            var pickResult = scene.pick(this._unTranslatedPointerX, this._unTranslatedPointerY, scene.pointerDownPredicate, false, scene.cameraToUseForPointers);
+
+            this._processPointerDown(pickResult, evt);
+        };
+
+        this._onPointerUp = (evt: PointerEvent) => {
+            if (this._totalPointersPressed === 0) {  // We are attaching the pointer up to windows because of a bug in FF
+                return;                             // So we need to test it the pointer down was pressed before.
+            }
+
+            this._totalPointersPressed--;
+            this._pickedUpMesh = null;
+            this._meshPickProceed = false;
+
+            this._updatePointerPosition(evt);
+
+            if (scene.preventDefaultOnPointerUp && canvas) {
+                evt.preventDefault();
+                canvas.focus();
+            }
+
+            this._initClickEvent(scene.onPrePointerObservable, scene.onPointerObservable, evt, (clickInfo: _ClickInfo, pickResult: Nullable<PickingInfo>) => {
+                // PreObservable support
+                if (scene.onPrePointerObservable.hasObservers()) {
+                    if (!clickInfo.ignore) {
+                        if (!clickInfo.hasSwiped) {
+                            if (clickInfo.singleClick && scene.onPrePointerObservable.hasSpecificMask(PointerEventTypes.POINTERTAP)) {
+                                if (this._checkPrePointerObservable(null, evt, PointerEventTypes.POINTERTAP)) {
+                                    return;
+                                }
+                            }
+                            if (clickInfo.doubleClick && scene.onPrePointerObservable.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP)) {
+                                if (this._checkPrePointerObservable(null, evt, PointerEventTypes.POINTERDOUBLETAP)) {
+                                    return;
+                                }
+                            }
+                        }
+                        if (this._checkPrePointerObservable(null, evt, PointerEventTypes.POINTERUP)) {
+                            return;
+                        }
+                    }
+                }
+
+                if (!this._pointerCaptures[evt.pointerId]) {
+                    return;
+                }
+
+                this._pointerCaptures[evt.pointerId] = false;
+                if (!scene.cameraToUseForPointers && !scene.activeCamera) {
+                    return;
+                }
+
+                if (!scene.pointerUpPredicate) {
+                    scene.pointerUpPredicate = (mesh: AbstractMesh): boolean => {
+                        return mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.isEnabled() && (!scene.cameraToUseForPointers || (scene.cameraToUseForPointers.layerMask & mesh.layerMask) !== 0);
+                    };
+                }
+
+                // Meshes
+                if (!this._meshPickProceed && (AbstractActionManager && AbstractActionManager.HasTriggers || scene.onPointerObservable.hasObservers())) {
+                    this._initActionManager(null, clickInfo);
+                }
+                if (!pickResult) {
+                    pickResult = this._currentPickResult;
+                }
+
+                this._processPointerUp(pickResult, evt, clickInfo);
+
+                this._previousPickResult = this._currentPickResult;
+            });
+        };
+
+        this._onKeyDown = (evt: KeyboardEvent) => {
+            let type = KeyboardEventTypes.KEYDOWN;
+            if (scene.onPreKeyboardObservable.hasObservers()) {
+                let pi = new KeyboardInfoPre(type, evt);
+                scene.onPreKeyboardObservable.notifyObservers(pi, type);
+                if (pi.skipOnPointerObservable) {
+                    return;
+                }
+            }
+
+            if (scene.onKeyboardObservable.hasObservers()) {
+                let pi = new KeyboardInfo(type, evt);
+                scene.onKeyboardObservable.notifyObservers(pi, type);
+            }
+
+            if (scene.actionManager) {
+                scene.actionManager.processTrigger(Constants.ACTION_OnKeyDownTrigger, ActionEvent.CreateNewFromScene(scene, evt));
+            }
+        };
+
+        this._onKeyUp = (evt: KeyboardEvent) => {
+            let type = KeyboardEventTypes.KEYUP;
+            if (scene.onPreKeyboardObservable.hasObservers()) {
+                let pi = new KeyboardInfoPre(type, evt);
+                scene.onPreKeyboardObservable.notifyObservers(pi, type);
+                if (pi.skipOnPointerObservable) {
+                    return;
+                }
+            }
+
+            if (scene.onKeyboardObservable.hasObservers()) {
+                let pi = new KeyboardInfo(type, evt);
+                scene.onKeyboardObservable.notifyObservers(pi, type);
+            }
+
+            if (scene.actionManager) {
+                scene.actionManager.processTrigger(Constants.ACTION_OnKeyUpTrigger, ActionEvent.CreateNewFromScene(scene, evt));
+            }
+        };
+
+        // Keyboard events
+        this._onCanvasFocusObserver = engine.onCanvasFocusObservable.add(() => {
+            if (!canvas) {
+                return;
+            }
+            canvas.addEventListener("keydown", this._onKeyDown, false);
+            canvas.addEventListener("keyup", this._onKeyUp, false);
+        });
+
+        this._onCanvasBlurObserver = engine.onCanvasBlurObservable.add(() => {
+            if (!canvas) {
+                return;
+            }
+            canvas.removeEventListener("keydown", this._onKeyDown);
+            canvas.removeEventListener("keyup", this._onKeyUp);
+        });
+
+        // Pointer events
+        var eventPrefix = Tools.GetPointerPrefix();
+
+        if (attachMove) {
+            canvas.addEventListener(eventPrefix + "move", <any>this._onPointerMove, false);
+
+            // Wheel
+            this._wheelEventName = "onwheel" in document.createElement("div") ? "wheel" :       // Modern browsers support "wheel"
+                (<any>document).onmousewheel !== undefined ? "mousewheel" :                     // Webkit and IE support at least "mousewheel"
+                    "DOMMouseScroll";                                                           // let's assume that remaining browsers are older Firefox
+
+            canvas.addEventListener(this._wheelEventName, <any>this._onPointerMove, false);
+        }
+
+        if (attachDown) {
+            canvas.addEventListener(eventPrefix + "down", <any>this._onPointerDown, false);
+        }
+
+        if (attachUp) {
+            window.addEventListener(eventPrefix + "up", <any>this._onPointerUp, false);
+        }
+    }
+
+    /**
+     * Detaches all event handlers
+     */
+    public detachControl() {
+        const eventPrefix = Tools.GetPointerPrefix();
+        const canvas = this._scene.getEngine().getRenderingCanvas();
+        const engine = this._scene.getEngine();
+
+        if (!canvas) {
+            return;
+        }
+
+        // Pointer
+        canvas.removeEventListener(eventPrefix + "move", <any>this._onPointerMove);
+        canvas.removeEventListener(eventPrefix + "down", <any>this._onPointerDown);
+        window.removeEventListener(eventPrefix + "up", <any>this._onPointerUp);
+
+        // Blur / Focus
+        if (this._onCanvasBlurObserver) {
+            engine.onCanvasBlurObservable.remove(this._onCanvasBlurObserver);
+        }
+
+        if (this._onCanvasFocusObserver) {
+            engine.onCanvasFocusObservable.remove(this._onCanvasFocusObserver);
+        }
+
+        // Keyboard
+        canvas.removeEventListener("keydown", this._onKeyDown);
+        canvas.removeEventListener("keyup", this._onKeyUp);
+
+        // Cursor
+        canvas.style.cursor = this._scene.defaultCursor;
+    }
+
+    /**
+     * Force the value of meshUnderPointer
+     * @param mesh defines the mesh to use
+     */
+    public setPointerOverMesh(mesh: Nullable<AbstractMesh>): void {
+        if (this._pointerOverMesh === mesh) {
+            return;
+        }
+
+        let actionManager: Nullable<AbstractActionManager>;
+        if (this._pointerOverMesh) {
+            actionManager = this._pointerOverMesh._getActionManagerForTrigger(Constants.ACTION_OnPointerOutTrigger);
+            if (actionManager) {
+                actionManager.processTrigger(Constants.ACTION_OnPointerOutTrigger, ActionEvent.CreateNew(this._pointerOverMesh));
+            }
+        }
+
+        this._pointerOverMesh = mesh;
+        if (this._pointerOverMesh) {
+            actionManager = this._pointerOverMesh._getActionManagerForTrigger(Constants.ACTION_OnPointerOverTrigger);
+            if (actionManager) {
+                actionManager.processTrigger(Constants.ACTION_OnPointerOverTrigger, ActionEvent.CreateNew(this._pointerOverMesh));
+            }
+        }
+    }
+
+    /**
+     * Gets the mesh under the pointer
+     * @returns a Mesh or null if no mesh is under the pointer
+     */
+    public getPointerOverMesh(): Nullable<AbstractMesh> {
+        return this._pointerOverMesh;
+    }
+}

+ 5 - 1
src/Meshes/Compression/dracoCompression.ts

@@ -117,7 +117,11 @@ export class DracoCompression implements IDisposable {
     public static DefaultNumWorkers = DracoCompression.GetDefaultNumWorkers();
 
     private static GetDefaultNumWorkers(): number {
-        const hardwareConcurrency = navigator && navigator.hardwareConcurrency;
+        if (typeof navigator === "undefined") {
+            return 1;
+        }
+
+        const hardwareConcurrency =  navigator.hardwareConcurrency;
         if (!hardwareConcurrency) {
             return 1;
         }

+ 1 - 1
src/Sprites/spriteSceneComponent.ts

@@ -295,7 +295,7 @@ export class SpriteSceneComponent implements ISceneComponent {
                     if (spritePickResult.pickedSprite.actionManager) {
                         spritePickResult.pickedSprite.actionManager.processTrigger(Constants.ACTION_OnPickUpTrigger, ActionEvent.CreateNewFromSprite(spritePickResult.pickedSprite, scene, evt));
                         if (spritePickResult.pickedSprite.actionManager) {
-                            if (!this.scene._isPointerSwiping()) {
+                            if (!this.scene._inputManager._isPointerSwiping()) {
                                 spritePickResult.pickedSprite.actionManager.processTrigger(Constants.ACTION_OnPickTrigger, ActionEvent.CreateNewFromSprite(spritePickResult.pickedSprite, scene, evt));
                             }
                         }

+ 64 - 740
src/scene.ts

@@ -29,7 +29,7 @@ import { Light } from "./Lights/light";
 import { PickingInfo } from "./Collisions/pickingInfo";
 import { ICollisionCoordinator } from "./Collisions/collisionCoordinator";
 import { PointerEventTypes, PointerInfoPre, PointerInfo } from "./Events/pointerEvents";
-import { KeyboardInfoPre, KeyboardInfo, KeyboardEventTypes } from "./Events/keyboardEvents";
+import { KeyboardInfoPre, KeyboardInfo } from "./Events/keyboardEvents";
 import { ActionEvent } from "./Actions/actionEvent";
 import { PostProcess } from "./PostProcesses/postProcess";
 import { PostProcessManager } from "./PostProcesses/postProcessManager";
@@ -46,6 +46,7 @@ import { EngineStore } from "./Engines/engineStore";
 import { AbstractActionManager } from './Actions/abstractActionManager';
 import { _DevTools } from './Misc/devTools';
 import { WebRequest } from './Misc/webRequest';
+import { InputManager } from './Inputs/scene.inputManager';
 
 declare type Ray = import("./Culling/ray").Ray;
 declare type TrianglePickingPredicate = import("./Culling/ray").TrianglePickingPredicate;
@@ -65,40 +66,6 @@ export interface IDisposable {
     dispose(): void;
 }
 
-/** @hidden */
-class ClickInfo {
-    private _singleClick = false;
-    private _doubleClick = false;
-    private _hasSwiped = false;
-    private _ignore = false;
-
-    public get singleClick(): boolean {
-        return this._singleClick;
-    }
-    public get doubleClick(): boolean {
-        return this._doubleClick;
-    }
-    public get hasSwiped(): boolean {
-        return this._hasSwiped;
-    }
-    public get ignore(): boolean {
-        return this._ignore;
-    }
-
-    public set singleClick(b: boolean) {
-        this._singleClick = b;
-    }
-    public set doubleClick(b: boolean) {
-        this._doubleClick = b;
-    }
-    public set hasSwiped(b: boolean) {
-        this._hasSwiped = b;
-    }
-    public set ignore(b: boolean) {
-        this._ignore = b;
-    }
-}
-
 /** Interface defining initialization parameters for Scene class */
 export interface SceneOptions {
     /**
@@ -169,6 +136,12 @@ export class Scene extends AbstractScene implements IAnimatable {
     // Members
 
     /** @hidden */
+    public _inputManager = new InputManager(this);
+
+    /** Define this parameter if you are using multiple cameras and you want to specify which one should be used for pointer position */
+    public cameraToUseForPointers: Nullable<Camera> = null;
+
+    /** @hidden */
     public readonly _isScene = true;
 
     /**
@@ -634,9 +607,6 @@ export class Scene extends AbstractScene implements IAnimatable {
      * Gets or sets a predicate used to select candidate meshes for a pointer move event
      */
     public pointerMovePredicate: (Mesh: AbstractMesh) => boolean;
-    private _onPointerMove: (evt: PointerEvent) => void;
-    private _onPointerDown: (evt: PointerEvent) => void;
-    private _onPointerUp: (evt: PointerEvent) => void;
 
     /** Callback called when a pointer move is detected */
     public onPointerMove: (evt: PointerEvent, pickInfo: PickingInfo, type: PointerEventTypes) => void;
@@ -662,47 +632,50 @@ export class Scene extends AbstractScene implements IAnimatable {
      * Gets the pointer coordinates without any translation (ie. straight out of the pointer event)
      */
     public get unTranslatedPointer(): Vector2 {
-        return new Vector2(this._unTranslatedPointerX, this._unTranslatedPointerY);
+        return this._inputManager.unTranslatedPointer;
     }
 
-    /** The distance in pixel that you have to move to prevent some events */
-    public static DragMovementThreshold = 10; // in pixels
-    /** Time in milliseconds to wait to raise long press events if button is still pressed */
-    public static LongPressDelay = 500; // in milliseconds
-    /** Time in milliseconds with two consecutive clicks will be considered as a double click */
-    public static DoubleClickDelay = 300; // in milliseconds
-    /** If you need to check double click without raising a single click at first click, enable this flag */
-    public static ExclusiveDoubleClickMode = false;
+    /**
+     * Gets or sets the distance in pixel that you have to move to prevent some events. Default is 10 pixels
+     */
+    public static get DragMovementThreshold() {
+        return InputManager.DragMovementThreshold;
+    }
 
-    private _initClickEvent: (obs1: Observable<PointerInfoPre>, obs2: Observable<PointerInfo>, evt: PointerEvent, cb: (clickInfo: ClickInfo, pickResult: Nullable<PickingInfo>) => void) => void;
-    private _initActionManager: (act: Nullable<AbstractActionManager>, clickInfo: ClickInfo) => Nullable<AbstractActionManager>;
-    private _delayedSimpleClick: (btn: number, clickInfo: ClickInfo, cb: (clickInfo: ClickInfo, pickResult: Nullable<PickingInfo>) => void) => void;
-    private _delayedSimpleClickTimeout: number;
-    private _previousDelayedSimpleClickTimeout: number;
-    private _meshPickProceed = false;
+    public static set DragMovementThreshold(value: number) {
+        InputManager.DragMovementThreshold = value;
+    }
 
-    private _previousButtonPressed: number;
-    private _currentPickResult: Nullable<PickingInfo> = null;
-    private _previousPickResult: Nullable<PickingInfo> = null;
-    private _totalPointersPressed = 0;
-    private _doubleClickOccured = false;
+    /**
+     * Time in milliseconds to wait to raise long press events if button is still pressed. Default is 500 ms
+     */
+    public static get LongPressDelay() {
+        return InputManager.LongPressDelay;
+    }
 
-    /** Define this parameter if you are using multiple cameras and you want to specify which one should be used for pointer position */
-    public cameraToUseForPointers: Nullable<Camera> = null;
-    private _pointerX: number = 0;
-    private _pointerY: number = 0;
-    private _unTranslatedPointerX: number;
-    private _unTranslatedPointerY: number;
-    private _startingPointerPosition = new Vector2(0, 0);
-    private _previousStartingPointerPosition = new Vector2(0, 0);
-    private _startingPointerTime = 0;
-    private _previousStartingPointerTime = 0;
-    private _pointerCaptures: { [pointerId: number]: boolean } = {};
+    public static set LongPressDelay(value: number) {
+        InputManager.LongPressDelay = value;
+    }
 
-    // Deterministic lockstep
-    private _timeAccumulator: number = 0;
-    private _currentStepId: number = 0;
-    private _currentInternalStep: number = 0;
+    /**
+     * Time in milliseconds to wait to raise long press events if button is still pressed. Default is 300 ms
+     */
+    public static get DoubleClickDelay() {
+        return InputManager.DoubleClickDelay;
+    }
+
+    public static set DoubleClickDelay(value: number) {
+        InputManager.DoubleClickDelay = value;
+    }
+
+    /** If you need to check double click without raising a single click at first click, enable this flag */
+    public static get ExclusiveDoubleClickMode() {
+        return InputManager.ExclusiveDoubleClickMode;
+    }
+
+    public static set ExclusiveDoubleClickMode(value: boolean) {
+        InputManager.ExclusiveDoubleClickMode = value;
+    }
 
     // Mirror
     /** @hidden */
@@ -720,10 +693,6 @@ export class Scene extends AbstractScene implements IAnimatable {
      * Observable event triggered each time an keyboard event is received from the hosting window
      */
     public onKeyboardObservable = new Observable<KeyboardInfo>();
-    private _onKeyDown: (evt: KeyboardEvent) => void;
-    private _onKeyUp: (evt: KeyboardEvent) => void;
-    private _onCanvasFocusObserver: Nullable<Observer<Engine>>;
-    private _onCanvasBlurObserver: Nullable<Observer<Engine>>;
 
     // Coordinates system
 
@@ -742,6 +711,11 @@ export class Scene extends AbstractScene implements IAnimatable {
         return this._useRightHandedSystem;
     }
 
+    // Deterministic lockstep
+    private _timeAccumulator: number = 0;
+    private _currentStepId: number = 0;
+    private _currentInternalStep: number = 0;
+
     /**
      * Sets the step Id used by deterministic lock step
      * @see http://doc.babylonjs.com/babylon101/animations#deterministic-lockstep
@@ -1119,7 +1093,6 @@ export class Scene extends AbstractScene implements IAnimatable {
     /** @hidden */
     public _viewMatrix: Matrix;
     private _projectionMatrix: Matrix;
-    private _wheelEventName = "";
     /** @hidden */
     public _forcedViewPosition: Nullable<Vector3>;
 
@@ -1143,10 +1116,6 @@ export class Scene extends AbstractScene implements IAnimatable {
     /** @hidden */
     public readonly useClonedMeshhMap: boolean;
 
-    private _pointerOverMesh: Nullable<AbstractMesh>;
-
-    private _pickedDownMesh: Nullable<AbstractMesh>;
-    private _pickedUpMesh: Nullable<AbstractMesh>;
     private _externalData: StringDictionary<Object>;
     private _uid: Nullable<string>;
 
@@ -1418,29 +1387,29 @@ export class Scene extends AbstractScene implements IAnimatable {
      * Gets the mesh that is currently under the pointer
      */
     public get meshUnderPointer(): Nullable<AbstractMesh> {
-        return this._pointerOverMesh;
+        return this._inputManager.meshUnderPointer;
     }
 
     /**
      * Gets or sets the current on-screen X position of the pointer
      */
     public get pointerX(): number {
-        return this._pointerX;
+        return this._inputManager.pointerX;
     }
 
     public set pointerX(value: number) {
-        this._pointerX = value;
+        this._inputManager.pointerX = value;
     }
 
     /**
      * Gets or sets the current on-screen Y position of the pointer
      */
     public get pointerY(): number {
-        return this._pointerY;
+        return this._inputManager.pointerY;
     }
 
     public set pointerY(value: number) {
-        this._pointerY = value;
+        this._inputManager.pointerY = value;
     }
 
     /**
@@ -1587,35 +1556,12 @@ export class Scene extends AbstractScene implements IAnimatable {
         this._renderId++;
     }
 
-    private _updatePointerPosition(evt: PointerEvent): void {
-        var canvasRect = this._engine.getRenderingCanvasClientRect();
-
-        if (!canvasRect) {
-            return;
-        }
-
-        this._pointerX = evt.clientX - canvasRect.left;
-        this._pointerY = evt.clientY - canvasRect.top;
-
-        this._unTranslatedPointerX = this._pointerX;
-        this._unTranslatedPointerY = this._pointerY;
-    }
-
     private _createUbo(): void {
         this._sceneUbo = new UniformBuffer(this._engine, undefined, true);
         this._sceneUbo.addUniform("viewProjection", 16);
         this._sceneUbo.addUniform("view", 16);
     }
 
-    // Pointers handling
-    private _setRayOnPointerInfo(pointerInfo: PointerInfo) {
-        if (pointerInfo.pickInfo && !pointerInfo.pickInfo._pickingUnavailable) {
-            if (!pointerInfo.pickInfo.ray) {
-                pointerInfo.pickInfo.ray = this.createPickingRay(pointerInfo.event.offsetX, pointerInfo.event.offsetY, Matrix.Identity(), this.activeCamera);
-            }
-        }
-    }
-
     /**
      * Use this method to simulate a pointer move on a mesh
      * The pickResult parameter can be obtained from a scene.pick or scene.pickWithRay
@@ -1624,74 +1570,10 @@ export class Scene extends AbstractScene implements IAnimatable {
      * @returns the current scene
      */
     public simulatePointerMove(pickResult: PickingInfo, pointerEventInit?: PointerEventInit): Scene {
-        let evt = new PointerEvent("pointermove", pointerEventInit);
-
-        if (this._checkPrePointerObservable(pickResult, evt, PointerEventTypes.POINTERMOVE)) {
-            return this;
-        }
-        return this._processPointerMove(pickResult, evt);
-    }
-
-    private _processPointerMove(pickResult: Nullable<PickingInfo>, evt: PointerEvent): Scene {
-
-        var canvas = this._engine.getRenderingCanvas();
-
-        if (!canvas) {
-            return this;
-        }
-
-        // Restore pointer
-        canvas.style.cursor = this.defaultCursor;
-
-        var isMeshPicked = (pickResult && pickResult.hit && pickResult.pickedMesh) ? true : false;
-        if (isMeshPicked) {
-            this.setPointerOverMesh(pickResult!.pickedMesh);
-
-            if (this._pointerOverMesh && this._pointerOverMesh.actionManager && this._pointerOverMesh.actionManager.hasPointerTriggers) {
-                if (this._pointerOverMesh.actionManager.hoverCursor) {
-                    canvas.style.cursor = this._pointerOverMesh.actionManager.hoverCursor;
-                } else {
-                    canvas.style.cursor = this.hoverCursor;
-                }
-            }
-        } else {
-            this.setPointerOverMesh(null);
-        }
-
-        for (let step of this._pointerMoveStage) {
-            pickResult = step.action(this._unTranslatedPointerX, this._unTranslatedPointerY, pickResult, isMeshPicked, canvas);
-        }
-
-        if (pickResult) {
-            let type = evt.type === this._wheelEventName ? PointerEventTypes.POINTERWHEEL : PointerEventTypes.POINTERMOVE;
-
-            if (this.onPointerMove) {
-                this.onPointerMove(evt, pickResult, type);
-            }
-
-            if (this.onPointerObservable.hasObservers()) {
-                let pi = new PointerInfo(type, evt, pickResult);
-                this._setRayOnPointerInfo(pi);
-                this.onPointerObservable.notifyObservers(pi, type);
-            }
-        }
-
+        this._inputManager.simulatePointerMove(pickResult, pointerEventInit);
         return this;
     }
 
-    private _checkPrePointerObservable(pickResult: Nullable<PickingInfo>, evt: PointerEvent, type: number) {
-        let pi = new PointerInfoPre(type, evt, this._unTranslatedPointerX, this._unTranslatedPointerY);
-        if (pickResult) {
-            pi.ray = pickResult.ray;
-        }
-        this.onPrePointerObservable.notifyObservers(pi, type);
-        if (pi.skipOnPointerObservable) {
-            return true;
-        } else {
-            return false;
-        }
-    }
-
     /**
      * Use this method to simulate a pointer down on a mesh
      * The pickResult parameter can be obtained from a scene.pick or scene.pickWithRay
@@ -1700,73 +1582,7 @@ export class Scene extends AbstractScene implements IAnimatable {
      * @returns the current scene
      */
     public simulatePointerDown(pickResult: PickingInfo, pointerEventInit?: PointerEventInit): Scene {
-        let evt = new PointerEvent("pointerdown", pointerEventInit);
-
-        if (this._checkPrePointerObservable(pickResult, evt, PointerEventTypes.POINTERDOWN)) {
-            return this;
-        }
-
-        return this._processPointerDown(pickResult, evt);
-    }
-
-    private _processPointerDown(pickResult: Nullable<PickingInfo>, evt: PointerEvent): Scene {
-        if (pickResult && pickResult.hit && pickResult.pickedMesh) {
-            this._pickedDownMesh = pickResult.pickedMesh;
-            var actionManager = pickResult.pickedMesh.actionManager;
-            if (actionManager) {
-                if (actionManager.hasPickTriggers) {
-                    actionManager.processTrigger(Constants.ACTION_OnPickDownTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
-                    switch (evt.button) {
-                        case 0:
-                            actionManager.processTrigger(Constants.ACTION_OnLeftPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
-                            break;
-                        case 1:
-                            actionManager.processTrigger(Constants.ACTION_OnCenterPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
-                            break;
-                        case 2:
-                            actionManager.processTrigger(Constants.ACTION_OnRightPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
-                            break;
-                    }
-                }
-
-                if (actionManager.hasSpecificTrigger(Constants.ACTION_OnLongPressTrigger)) {
-                    window.setTimeout(() => {
-                        var pickResult = this.pick(this._unTranslatedPointerX, this._unTranslatedPointerY,
-                            (mesh: AbstractMesh): boolean => (<boolean>(mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.actionManager && mesh.actionManager.hasSpecificTrigger(Constants.ACTION_OnLongPressTrigger) && mesh == this._pickedDownMesh)),
-                            false, this.cameraToUseForPointers);
-
-                        if (pickResult && pickResult.hit && pickResult.pickedMesh && actionManager) {
-                            if (this._totalPointersPressed !== 0 &&
-                                ((Date.now() - this._startingPointerTime) > Scene.LongPressDelay) &&
-                                !this._isPointerSwiping()) {
-                                this._startingPointerTime = 0;
-                                actionManager.processTrigger(Constants.ACTION_OnLongPressTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
-                            }
-                        }
-                    }, Scene.LongPressDelay);
-                }
-            }
-        }
-        else {
-            for (let step of this._pointerDownStage) {
-                pickResult = step.action(this._unTranslatedPointerX, this._unTranslatedPointerY, pickResult, evt);
-            }
-        }
-
-        if (pickResult) {
-            let type = PointerEventTypes.POINTERDOWN;
-
-            if (this.onPointerDown) {
-                this.onPointerDown(evt, pickResult, type);
-            }
-
-            if (this.onPointerObservable.hasObservers()) {
-                let pi = new PointerInfo(type, evt, pickResult);
-                this._setRayOnPointerInfo(pi);
-                this.onPointerObservable.notifyObservers(pi, type);
-            }
-        }
-
+        this._inputManager.simulatePointerDown(pickResult, pointerEventInit);
         return this;
     }
 
@@ -1779,94 +1595,7 @@ export class Scene extends AbstractScene implements IAnimatable {
      * @returns the current scene
      */
     public simulatePointerUp(pickResult: PickingInfo, pointerEventInit?: PointerEventInit, doubleTap?: boolean): Scene {
-        let evt = new PointerEvent("pointerup", pointerEventInit);
-        let clickInfo = new ClickInfo();
-
-        if (doubleTap) {
-            clickInfo.doubleClick = true;
-        } else {
-            clickInfo.singleClick = true;
-        }
-
-        if (this._checkPrePointerObservable(pickResult, evt, PointerEventTypes.POINTERUP)) {
-            return this;
-        }
-
-        return this._processPointerUp(pickResult, evt, clickInfo);
-    }
-
-    private _processPointerUp(pickResult: Nullable<PickingInfo>, evt: PointerEvent, clickInfo: ClickInfo): Scene {
-        if (pickResult && pickResult && pickResult.pickedMesh) {
-            this._pickedUpMesh = pickResult.pickedMesh;
-            if (this._pickedDownMesh === this._pickedUpMesh) {
-                if (this.onPointerPick) {
-                    this.onPointerPick(evt, pickResult);
-                }
-                if (clickInfo.singleClick && !clickInfo.ignore && this.onPointerObservable.hasObservers()) {
-                    let type = PointerEventTypes.POINTERPICK;
-                    let pi = new PointerInfo(type, evt, pickResult);
-                    this._setRayOnPointerInfo(pi);
-                    this.onPointerObservable.notifyObservers(pi, type);
-                }
-            }
-            let actionManager = pickResult.pickedMesh._getActionManagerForTrigger();
-            if (actionManager && !clickInfo.ignore) {
-                actionManager.processTrigger(Constants.ACTION_OnPickUpTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
-
-                if (!clickInfo.hasSwiped && clickInfo.singleClick) {
-                    actionManager.processTrigger(Constants.ACTION_OnPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
-                }
-
-                let doubleClickActionManager = pickResult.pickedMesh._getActionManagerForTrigger(Constants.ACTION_OnDoublePickTrigger);
-                if (clickInfo.doubleClick && doubleClickActionManager) {
-                    doubleClickActionManager.processTrigger(Constants.ACTION_OnDoublePickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
-                }
-            }
-        }
-        else {
-            if (!clickInfo.ignore) {
-                for (let step of this._pointerUpStage) {
-                    pickResult = step.action(this._unTranslatedPointerX, this._unTranslatedPointerY, pickResult, evt);
-                }
-            }
-        }
-
-        if (this._pickedDownMesh && this._pickedDownMesh !== this._pickedUpMesh) {
-            let pickedDownActionManager = this._pickedDownMesh._getActionManagerForTrigger(Constants.ACTION_OnPickOutTrigger);
-            if (pickedDownActionManager) {
-                pickedDownActionManager.processTrigger(Constants.ACTION_OnPickOutTrigger, ActionEvent.CreateNew(this._pickedDownMesh, evt));
-            }
-        }
-
-        let type = 0;
-        if (this.onPointerObservable.hasObservers()) {
-            if (!clickInfo.ignore && !clickInfo.hasSwiped) {
-                if (clickInfo.singleClick && this.onPointerObservable.hasSpecificMask(PointerEventTypes.POINTERTAP)) {
-                    type = PointerEventTypes.POINTERTAP;
-                }
-                else if (clickInfo.doubleClick && this.onPointerObservable.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP)) {
-                    type = PointerEventTypes.POINTERDOUBLETAP;
-                }
-                if (type) {
-                    let pi = new PointerInfo(type, evt, pickResult);
-                    this._setRayOnPointerInfo(pi);
-                    this.onPointerObservable.notifyObservers(pi, type);
-                }
-            }
-
-            if (!clickInfo.ignore) {
-                type = PointerEventTypes.POINTERUP;
-
-                let pi = new PointerInfo(type, evt, pickResult);
-                this._setRayOnPointerInfo(pi);
-                this.onPointerObservable.notifyObservers(pi, type);
-            }
-        }
-
-        if (this.onPointerUp && !clickInfo.ignore) {
-            this.onPointerUp(evt, pickResult, type);
-        }
-
+        this._inputManager.simulatePointerUp(pickResult, pointerEventInit, doubleTap);
         return this;
     }
 
@@ -1876,13 +1605,7 @@ export class Scene extends AbstractScene implements IAnimatable {
      * @returns true if the pointer was captured
      */
     public isPointerCaptured(pointerId = 0): boolean {
-        return this._pointerCaptures[pointerId];
-    }
-
-    /** @hidden */
-    public _isPointerSwiping(): boolean {
-        return Math.abs(this._startingPointerPosition.x - this._pointerX) > Scene.DragMovementThreshold ||
-            Math.abs(this._startingPointerPosition.y - this._pointerY) > Scene.DragMovementThreshold;
+        return this._inputManager.isPointerCaptured(pointerId);
     }
 
     /**
@@ -1892,393 +1615,12 @@ export class Scene extends AbstractScene implements IAnimatable {
     * @param attachMove defines if you want to attach events to pointermove
     */
     public attachControl(attachUp = true, attachDown = true, attachMove = true): void {
-        this._initActionManager = (act: Nullable<AbstractActionManager>, clickInfo: ClickInfo): Nullable<AbstractActionManager> => {
-            if (!this._meshPickProceed) {
-                let pickResult = this.pick(this._unTranslatedPointerX, this._unTranslatedPointerY, this.pointerDownPredicate, false, this.cameraToUseForPointers);
-                this._currentPickResult = pickResult;
-                if (pickResult) {
-                    act = (pickResult.hit && pickResult.pickedMesh) ? pickResult.pickedMesh._getActionManagerForTrigger() : null;
-                }
-                this._meshPickProceed = true;
-            }
-            return act;
-        };
-
-        this._delayedSimpleClick = (btn: number, clickInfo: ClickInfo, cb: (clickInfo: ClickInfo, pickResult: Nullable<PickingInfo>) => void) => {
-            // double click delay is over and that no double click has been raised since, or the 2 consecutive keys pressed are different
-            if ((Date.now() - this._previousStartingPointerTime > Scene.DoubleClickDelay && !this._doubleClickOccured) ||
-                btn !== this._previousButtonPressed) {
-                this._doubleClickOccured = false;
-                clickInfo.singleClick = true;
-                clickInfo.ignore = false;
-                cb(clickInfo, this._currentPickResult);
-            }
-        };
-
-        this._initClickEvent = (obs1: Observable<PointerInfoPre>, obs2: Observable<PointerInfo>, evt: PointerEvent, cb: (clickInfo: ClickInfo, pickResult: Nullable<PickingInfo>) => void): void => {
-            let clickInfo = new ClickInfo();
-            this._currentPickResult = null;
-            let act: Nullable<AbstractActionManager> = null;
-
-            let checkPicking = obs1.hasSpecificMask(PointerEventTypes.POINTERPICK) || obs2.hasSpecificMask(PointerEventTypes.POINTERPICK)
-                || obs1.hasSpecificMask(PointerEventTypes.POINTERTAP) || obs2.hasSpecificMask(PointerEventTypes.POINTERTAP)
-                || obs1.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP) || obs2.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP);
-            if (!checkPicking && AbstractActionManager) {
-                act = this._initActionManager(act, clickInfo);
-                if (act) {
-                    checkPicking = act.hasPickTriggers;
-                }
-            }
-
-            let needToIgnoreNext = false;
-
-            if (checkPicking) {
-                let btn = evt.button;
-                clickInfo.hasSwiped = this._isPointerSwiping();
-
-                if (!clickInfo.hasSwiped) {
-                    let checkSingleClickImmediately = !Scene.ExclusiveDoubleClickMode;
-
-                    if (!checkSingleClickImmediately) {
-                        checkSingleClickImmediately = !obs1.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP) &&
-                            !obs2.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP);
-
-                        if (checkSingleClickImmediately && !AbstractActionManager.HasSpecificTrigger(Constants.ACTION_OnDoublePickTrigger)) {
-                            act = this._initActionManager(act, clickInfo);
-                            if (act) {
-                                checkSingleClickImmediately = !act.hasSpecificTrigger(Constants.ACTION_OnDoublePickTrigger);
-                            }
-                        }
-                    }
-
-                    if (checkSingleClickImmediately) {
-                        // single click detected if double click delay is over or two different successive keys pressed without exclusive double click or no double click required
-                        if (Date.now() - this._previousStartingPointerTime > Scene.DoubleClickDelay ||
-                            btn !== this._previousButtonPressed) {
-                            clickInfo.singleClick = true;
-                            cb(clickInfo, this._currentPickResult);
-                            needToIgnoreNext = true;
-                        }
-                    }
-                    // at least one double click is required to be check and exclusive double click is enabled
-                    else {
-                        // wait that no double click has been raised during the double click delay
-                        this._previousDelayedSimpleClickTimeout = this._delayedSimpleClickTimeout;
-                        this._delayedSimpleClickTimeout = window.setTimeout(this._delayedSimpleClick.bind(this, btn, clickInfo, cb), Scene.DoubleClickDelay);
-                    }
-
-                    let checkDoubleClick = obs1.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP) ||
-                        obs2.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP);
-                    if (!checkDoubleClick && AbstractActionManager.HasSpecificTrigger(Constants.ACTION_OnDoublePickTrigger)) {
-                        act = this._initActionManager(act, clickInfo);
-                        if (act) {
-                            checkDoubleClick = act.hasSpecificTrigger(Constants.ACTION_OnDoublePickTrigger);
-                        }
-                    }
-                    if (checkDoubleClick) {
-                        // two successive keys pressed are equal, double click delay is not over and double click has not just occurred
-                        if (btn === this._previousButtonPressed &&
-                            Date.now() - this._previousStartingPointerTime < Scene.DoubleClickDelay &&
-                            !this._doubleClickOccured
-                        ) {
-                            // pointer has not moved for 2 clicks, it's a double click
-                            if (!clickInfo.hasSwiped &&
-                                !this._isPointerSwiping()) {
-                                this._previousStartingPointerTime = 0;
-                                this._doubleClickOccured = true;
-                                clickInfo.doubleClick = true;
-                                clickInfo.ignore = false;
-                                if (Scene.ExclusiveDoubleClickMode && this._previousDelayedSimpleClickTimeout) {
-                                    clearTimeout(this._previousDelayedSimpleClickTimeout);
-                                }
-                                this._previousDelayedSimpleClickTimeout = this._delayedSimpleClickTimeout;
-                                cb(clickInfo, this._currentPickResult);
-                            }
-                            // if the two successive clicks are too far, it's just two simple clicks
-                            else {
-                                this._doubleClickOccured = false;
-                                this._previousStartingPointerTime = this._startingPointerTime;
-                                this._previousStartingPointerPosition.x = this._startingPointerPosition.x;
-                                this._previousStartingPointerPosition.y = this._startingPointerPosition.y;
-                                this._previousButtonPressed = btn;
-                                if (Scene.ExclusiveDoubleClickMode) {
-                                    if (this._previousDelayedSimpleClickTimeout) {
-                                        clearTimeout(this._previousDelayedSimpleClickTimeout);
-                                    }
-                                    this._previousDelayedSimpleClickTimeout = this._delayedSimpleClickTimeout;
-
-                                    cb(clickInfo, this._previousPickResult);
-                                }
-                                else {
-                                    cb(clickInfo, this._currentPickResult);
-                                }
-                            }
-                            needToIgnoreNext = true;
-                        }
-                        // just the first click of the double has been raised
-                        else {
-                            this._doubleClickOccured = false;
-                            this._previousStartingPointerTime = this._startingPointerTime;
-                            this._previousStartingPointerPosition.x = this._startingPointerPosition.x;
-                            this._previousStartingPointerPosition.y = this._startingPointerPosition.y;
-                            this._previousButtonPressed = btn;
-                        }
-                    }
-                }
-            }
-
-            if (!needToIgnoreNext) {
-                cb(clickInfo, this._currentPickResult);
-            }
-        };
-
-        this._onPointerMove = (evt: PointerEvent) => {
-
-            this._updatePointerPosition(evt);
-
-            // PreObservable support
-            if (this._checkPrePointerObservable(null, evt, evt.type === this._wheelEventName ? PointerEventTypes.POINTERWHEEL : PointerEventTypes.POINTERMOVE)) {
-                return;
-            }
-
-            if (!this.cameraToUseForPointers && !this.activeCamera) {
-                return;
-            }
-
-            if (!this.pointerMovePredicate) {
-                this.pointerMovePredicate = (mesh: AbstractMesh): boolean => (mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.isEnabled() && (mesh.enablePointerMoveEvents || this.constantlyUpdateMeshUnderPointer || (mesh.actionManager !== null && mesh.actionManager !== undefined)) && (!this.cameraToUseForPointers || (this.cameraToUseForPointers.layerMask & mesh.layerMask) !== 0));
-            }
-
-            // Meshes
-            var pickResult = this.pick(this._unTranslatedPointerX, this._unTranslatedPointerY, this.pointerMovePredicate, false, this.cameraToUseForPointers);
-
-            this._processPointerMove(pickResult, evt);
-        };
-
-        this._onPointerDown = (evt: PointerEvent) => {
-            this._totalPointersPressed++;
-            this._pickedDownMesh = null;
-            this._meshPickProceed = false;
-
-            this._updatePointerPosition(evt);
-
-            if (this.preventDefaultOnPointerDown && canvas) {
-                evt.preventDefault();
-                canvas.focus();
-            }
-
-            this._startingPointerPosition.x = this._pointerX;
-            this._startingPointerPosition.y = this._pointerY;
-            this._startingPointerTime = Date.now();
-
-            // PreObservable support
-            if (this._checkPrePointerObservable(null, evt, PointerEventTypes.POINTERDOWN)) {
-                return;
-            }
-
-            if (!this.cameraToUseForPointers && !this.activeCamera) {
-                return;
-            }
-
-            this._pointerCaptures[evt.pointerId] = true;
-
-            if (!this.pointerDownPredicate) {
-                this.pointerDownPredicate = (mesh: AbstractMesh): boolean => {
-                    return mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.isEnabled() && (!this.cameraToUseForPointers || (this.cameraToUseForPointers.layerMask & mesh.layerMask) !== 0);
-                };
-            }
-
-            // Meshes
-            this._pickedDownMesh = null;
-            var pickResult = this.pick(this._unTranslatedPointerX, this._unTranslatedPointerY, this.pointerDownPredicate, false, this.cameraToUseForPointers);
-
-            this._processPointerDown(pickResult, evt);
-        };
-
-        this._onPointerUp = (evt: PointerEvent) => {
-            if (this._totalPointersPressed === 0) {  // We are attaching the pointer up to windows because of a bug in FF
-                return;                             // So we need to test it the pointer down was pressed before.
-            }
-
-            this._totalPointersPressed--;
-            this._pickedUpMesh = null;
-            this._meshPickProceed = false;
-
-            this._updatePointerPosition(evt);
-
-            if (this.preventDefaultOnPointerUp && canvas) {
-                evt.preventDefault();
-                canvas.focus();
-            }
-
-            this._initClickEvent(this.onPrePointerObservable, this.onPointerObservable, evt, (clickInfo: ClickInfo, pickResult: Nullable<PickingInfo>) => {
-                // PreObservable support
-                if (this.onPrePointerObservable.hasObservers()) {
-                    if (!clickInfo.ignore) {
-                        if (!clickInfo.hasSwiped) {
-                            if (clickInfo.singleClick && this.onPrePointerObservable.hasSpecificMask(PointerEventTypes.POINTERTAP)) {
-                                if (this._checkPrePointerObservable(null, evt, PointerEventTypes.POINTERTAP)) {
-                                    return;
-                                }
-                            }
-                            if (clickInfo.doubleClick && this.onPrePointerObservable.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP)) {
-                                if (this._checkPrePointerObservable(null, evt, PointerEventTypes.POINTERDOUBLETAP)) {
-                                    return;
-                                }
-                            }
-                        }
-                        if (this._checkPrePointerObservable(null, evt, PointerEventTypes.POINTERUP)) {
-                            return;
-                        }
-                    }
-                }
-
-                if (!this._pointerCaptures[evt.pointerId]) {
-                    return;
-                }
-
-                this._pointerCaptures[evt.pointerId] = false;
-                if (!this.cameraToUseForPointers && !this.activeCamera) {
-                    return;
-                }
-
-                if (!this.pointerUpPredicate) {
-                    this.pointerUpPredicate = (mesh: AbstractMesh): boolean => {
-                        return mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.isEnabled() && (!this.cameraToUseForPointers || (this.cameraToUseForPointers.layerMask & mesh.layerMask) !== 0);
-                    };
-                }
-
-                // Meshes
-                if (!this._meshPickProceed && (AbstractActionManager && AbstractActionManager.HasTriggers || this.onPointerObservable.hasObservers())) {
-                    this._initActionManager(null, clickInfo);
-                }
-                if (!pickResult) {
-                    pickResult = this._currentPickResult;
-                }
-
-                this._processPointerUp(pickResult, evt, clickInfo);
-
-                this._previousPickResult = this._currentPickResult;
-            });
-        };
-
-        this._onKeyDown = (evt: KeyboardEvent) => {
-            let type = KeyboardEventTypes.KEYDOWN;
-            if (this.onPreKeyboardObservable.hasObservers()) {
-                let pi = new KeyboardInfoPre(type, evt);
-                this.onPreKeyboardObservable.notifyObservers(pi, type);
-                if (pi.skipOnPointerObservable) {
-                    return;
-                }
-            }
-
-            if (this.onKeyboardObservable.hasObservers()) {
-                let pi = new KeyboardInfo(type, evt);
-                this.onKeyboardObservable.notifyObservers(pi, type);
-            }
-
-            if (this.actionManager) {
-                this.actionManager.processTrigger(Constants.ACTION_OnKeyDownTrigger, ActionEvent.CreateNewFromScene(this, evt));
-            }
-        };
-
-        this._onKeyUp = (evt: KeyboardEvent) => {
-            let type = KeyboardEventTypes.KEYUP;
-            if (this.onPreKeyboardObservable.hasObservers()) {
-                let pi = new KeyboardInfoPre(type, evt);
-                this.onPreKeyboardObservable.notifyObservers(pi, type);
-                if (pi.skipOnPointerObservable) {
-                    return;
-                }
-            }
-
-            if (this.onKeyboardObservable.hasObservers()) {
-                let pi = new KeyboardInfo(type, evt);
-                this.onKeyboardObservable.notifyObservers(pi, type);
-            }
-
-            if (this.actionManager) {
-                this.actionManager.processTrigger(Constants.ACTION_OnKeyUpTrigger, ActionEvent.CreateNewFromScene(this, evt));
-            }
-        };
-
-        let engine = this.getEngine();
-        this._onCanvasFocusObserver = engine.onCanvasFocusObservable.add(() => {
-            if (!canvas) {
-                return;
-            }
-            canvas.addEventListener("keydown", this._onKeyDown, false);
-            canvas.addEventListener("keyup", this._onKeyUp, false);
-        });
-
-        this._onCanvasBlurObserver = engine.onCanvasBlurObservable.add(() => {
-            if (!canvas) {
-                return;
-            }
-            canvas.removeEventListener("keydown", this._onKeyDown);
-            canvas.removeEventListener("keyup", this._onKeyUp);
-        });
-
-        var eventPrefix = Tools.GetPointerPrefix();
-        var canvas = this._engine.getRenderingCanvas();
-
-        if (!canvas) {
-            return;
-        }
-
-        if (attachMove) {
-            canvas.addEventListener(eventPrefix + "move", <any>this._onPointerMove, false);
-
-            // Wheel
-            this._wheelEventName = "onwheel" in document.createElement("div") ? "wheel" :       // Modern browsers support "wheel"
-                (<any>document).onmousewheel !== undefined ? "mousewheel" :                     // Webkit and IE support at least "mousewheel"
-                    "DOMMouseScroll";                                                           // let's assume that remaining browsers are older Firefox
-
-            canvas.addEventListener(this._wheelEventName, <any>this._onPointerMove, false);
-        }
-
-        if (attachDown) {
-            canvas.addEventListener(eventPrefix + "down", <any>this._onPointerDown, false);
-        }
-
-        if (attachUp) {
-            window.addEventListener(eventPrefix + "up", <any>this._onPointerUp, false);
-        }
-
-        canvas.tabIndex = 1;
+        this._inputManager.attachControl(attachUp, attachDown, attachMove);
     }
 
     /** Detaches all event handlers*/
     public detachControl() {
-        let engine = this.getEngine();
-        var eventPrefix = Tools.GetPointerPrefix();
-        var canvas = engine.getRenderingCanvas();
-
-        if (!canvas) {
-            return;
-        }
-
-        canvas.removeEventListener(eventPrefix + "move", <any>this._onPointerMove);
-        canvas.removeEventListener(eventPrefix + "down", <any>this._onPointerDown);
-        window.removeEventListener(eventPrefix + "up", <any>this._onPointerUp);
-
-        if (this._onCanvasBlurObserver) {
-            engine.onCanvasBlurObservable.remove(this._onCanvasBlurObserver);
-        }
-
-        if (this._onCanvasFocusObserver) {
-            engine.onCanvasFocusObservable.remove(this._onCanvasFocusObserver);
-        }
-
-        // Wheel
-        canvas.removeEventListener(this._wheelEventName, <any>this._onPointerMove);
-
-        // Keyboard
-        canvas.removeEventListener("keydown", this._onKeyDown);
-        canvas.removeEventListener("keyup", this._onKeyUp);
-
-        // Cursor
-        canvas.style.cursor = this.defaultCursor;
+        this._inputManager.detachControl();
     }
 
     /**
@@ -4875,25 +4217,7 @@ export class Scene extends AbstractScene implements IAnimatable {
      * @param mesh defines the mesh to use
      */
     public setPointerOverMesh(mesh: Nullable<AbstractMesh>): void {
-        if (this._pointerOverMesh === mesh) {
-            return;
-        }
-
-        let actionManager: Nullable<AbstractActionManager>;
-        if (this._pointerOverMesh) {
-            actionManager = this._pointerOverMesh._getActionManagerForTrigger(Constants.ACTION_OnPointerOutTrigger);
-            if (actionManager) {
-                actionManager.processTrigger(Constants.ACTION_OnPointerOutTrigger, ActionEvent.CreateNew(this._pointerOverMesh));
-            }
-        }
-
-        this._pointerOverMesh = mesh;
-        if (this._pointerOverMesh) {
-            actionManager = this._pointerOverMesh._getActionManagerForTrigger(Constants.ACTION_OnPointerOverTrigger);
-            if (actionManager) {
-                actionManager.processTrigger(Constants.ACTION_OnPointerOverTrigger, ActionEvent.CreateNew(this._pointerOverMesh));
-            }
-        }
+        this._inputManager.setPointerOverMesh(mesh);
     }
 
     /**
@@ -4901,7 +4225,7 @@ export class Scene extends AbstractScene implements IAnimatable {
      * @returns a Mesh or null if no mesh is under the pointer
      */
     public getPointerOverMesh(): Nullable<AbstractMesh> {
-        return this._pointerOverMesh;
+        return this._inputManager.getPointerOverMesh();
     }
 
     // Misc.