Преглед изворни кода

Merge pull request #1030 from gleborgne/master

Input management for cameras
David Catuhe пре 9 година
родитељ
комит
ab97dcabdc
52 измењених фајлова са 32828 додато и 29726 уклоњено
  1. 16 1
      Tools/Gulp/config.json
  2. 778 565
      dist/preview release/babylon.d.ts
  3. 41 30
      dist/preview release/babylon.js
  4. 28539 27565
      dist/preview release/babylon.max.js
  5. 58 0
      src/Cameras/Inputs/babylon.arcrotatecamera.input.gamepad.js
  6. 61 0
      src/Cameras/Inputs/babylon.arcrotatecamera.input.gamepad.ts
  7. 108 0
      src/Cameras/Inputs/babylon.arcrotatecamera.input.keyboard.js
  8. 108 0
      src/Cameras/Inputs/babylon.arcrotatecamera.input.keyboard.ts
  9. 55 0
      src/Cameras/Inputs/babylon.arcrotatecamera.input.mousewheel.js
  10. 53 0
      src/Cameras/Inputs/babylon.arcrotatecamera.input.mousewheel.ts
  11. 193 0
      src/Cameras/Inputs/babylon.arcrotatecamera.input.pointers.js
  12. 229 0
      src/Cameras/Inputs/babylon.arcrotatecamera.input.pointers.ts
  13. 75 0
      src/Cameras/Inputs/babylon.freecamera.input.deviceorientation.js
  14. 84 0
      src/Cameras/Inputs/babylon.freecamera.input.deviceorientation.ts
  15. 64 0
      src/Cameras/Inputs/babylon.freecamera.input.gamepad.js
  16. 67 0
      src/Cameras/Inputs/babylon.freecamera.input.gamepad.ts
  17. 111 0
      src/Cameras/Inputs/babylon.freecamera.input.keyboard.js
  18. 110 0
      src/Cameras/Inputs/babylon.freecamera.input.keyboard.ts
  19. 102 0
      src/Cameras/Inputs/babylon.freecamera.input.mouse.js
  20. 117 0
      src/Cameras/Inputs/babylon.freecamera.input.mouse.ts
  21. 139 0
      src/Cameras/Inputs/babylon.freecamera.input.touch.js
  22. 166 0
      src/Cameras/Inputs/babylon.freecamera.input.touch.ts
  23. 52 0
      src/Cameras/Inputs/babylon.freecamera.input.virtualjoystick.js
  24. 61 0
      src/Cameras/Inputs/babylon.freecamera.input.virtualjoystick.ts
  25. 43 0
      src/Cameras/Inputs/babylon.freecamera.input.vrdeviceorientation.js
  26. 55 0
      src/Cameras/Inputs/babylon.freecamera.input.vrdeviceorientation.ts
  27. 1 28
      src/Cameras/VR/babylon.vrDeviceOrientationCamera.js
  28. 2 39
      src/Cameras/VR/babylon.vrDeviceOrientationCamera.ts
  29. 195 266
      src/Cameras/babylon.arcRotateCamera.js
  30. 191 311
      src/Cameras/babylon.arcRotateCamera.ts
  31. 38 0
      src/Cameras/babylon.arcRotateCameraInputsManager.js
  32. 34 0
      src/Cameras/babylon.arcRotateCameraInputsManager.ts
  33. 7 0
      src/Cameras/babylon.camera.js
  34. 11 0
      src/Cameras/babylon.camera.ts
  35. 97 0
      src/Cameras/babylon.cameraInputsManager.js
  36. 132 0
      src/Cameras/babylon.cameraInputsManager.ts
  37. 39 67
      src/Cameras/babylon.deviceOrientationCamera.js
  38. 34 73
      src/Cameras/babylon.deviceOrientationCamera.ts
  39. 103 150
      src/Cameras/babylon.freeCamera.js
  40. 109 176
      src/Cameras/babylon.freeCamera.ts
  41. 50 0
      src/Cameras/babylon.freeCameraInputsManager.js
  42. 49 0
      src/Cameras/babylon.freeCameraInputsManager.ts
  43. 38 0
      src/Cameras/babylon.gamepadCamera.js
  44. 35 0
      src/Cameras/babylon.gamepadCamera.ts
  45. 39 115
      src/Cameras/babylon.touchCamera.js
  46. 33 143
      src/Cameras/babylon.touchCamera.ts
  47. 39 52
      src/Cameras/babylon.universalCamera.js
  48. 33 52
      src/Cameras/babylon.universalCamera.ts
  49. 1 37
      src/Cameras/babylon.virtualJoysticksCamera.js
  50. 2 46
      src/Cameras/babylon.virtualJoysticksCamera.ts
  51. 12 4
      src/Tools/babylon.gamepads.js
  52. 19 6
      src/Tools/babylon.gamepads.ts

+ 16 - 1
Tools/Gulp/config.json

@@ -41,12 +41,27 @@
       "../../src/Lights/Shadows/babylon.shadowGenerator.js",
       "../../src/Collisions/babylon.collider.js",
       "../../src/Collisions/babylon.collisionCoordinator.js",
+
       "../../src/Cameras/babylon.camera.js",
+      "../../src/cameras/babylon.camerainputsmanager.js",
+      "../../src/cameras/inputs/babylon.freecamera.input.mouse.js",
+      "../../src/cameras/inputs/babylon.freecamera.input.keyboard.js",
+      "../../src/cameras/inputs/babylon.freecamera.input.touch.js",
+      "../../src/cameras/inputs/babylon.freecamera.input.deviceorientation.js",
+      "../../src/cameras/inputs/babylon.freecamera.input.vrdeviceorientation.js",
+      "../../src/cameras/inputs/babylon.freecamera.input.gamepad.js",
+      "../../src/cameras/inputs/babylon.freecamera.input.virtualjoystick.js",
+      "../../src/cameras/inputs/babylon.arcrotatecamera.input.keyboard.js",
+      "../../src/cameras/inputs/babylon.arcrotatecamera.input.mousewheel.js",
+      "../../src/cameras/inputs/babylon.arcrotatecamera.input.pointers.js",
+      "../../src/cameras/inputs/babylon.arcrotatecamera.input.gamepad.js",
       "../../src/Cameras/babylon.targetCamera.js",
       "../../src/Cameras/babylon.freeCamera.js",
+      "../../src/Cameras/babylon.freeCameraInputsManager.js",
       "../../src/Cameras/babylon.followCamera.js",
       "../../src/Cameras/babylon.touchCamera.js",
       "../../src/Cameras/babylon.arcRotateCamera.js",
+      "../../src/Cameras/babylon.arcRotateCameraInputsManager.js",
       "../../src/Rendering/babylon.renderingManager.js",
       "../../src/Rendering/babylon.renderingGroup.js",
       "../../src/babylon.scene.js",
@@ -193,7 +208,7 @@
       "../../src/tools/hdr/babylon.tools.hdr.js",
       "../../src/tools/hdr/babylon.tools.pmremGenerator.js",
       "../../src/materials/textures/babylon.hdrcubetexture.js",
-      "../../src/debug/babylon.skeletonViewer.js"
+      "../../src/debug/babylon.skeletonViewer.js"      
     ]
   }
 }

Разлика између датотеке није приказан због своје велике величине
+ 778 - 565
dist/preview release/babylon.d.ts


Разлика између датотеке није приказан због своје велике величине
+ 41 - 30
dist/preview release/babylon.js


Разлика између датотеке није приказан због своје велике величине
+ 28539 - 27565
dist/preview release/babylon.max.js


+ 58 - 0
src/Cameras/Inputs/babylon.arcrotatecamera.input.gamepad.js

@@ -0,0 +1,58 @@
+var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
+    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
+    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
+    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
+    return c > 3 && r && Object.defineProperty(target, key, r), r;
+};
+var BABYLON;
+(function (BABYLON) {
+    var ArcRotateCameraGamepadInput = (function () {
+        function ArcRotateCameraGamepadInput() {
+            var _this = this;
+            this.gamepadRotationSensibility = 80;
+            this._gamepads = new BABYLON.Gamepads(function (gamepad) { _this._onNewGameConnected(gamepad); });
+        }
+        ArcRotateCameraGamepadInput.prototype.attachCamera = function (camera) {
+            this.camera = camera;
+        };
+        ArcRotateCameraGamepadInput.prototype.detach = function () {
+            this._gamepads.dispose();
+        };
+        ArcRotateCameraGamepadInput.prototype.checkInputs = function () {
+            if (this.gamepad) {
+                var camera = this.camera;
+                var LSValues = this.gamepad.leftStick;
+                if (LSValues.x != 0) {
+                    var normalizedLX = LSValues.x / this.gamepadRotationSensibility;
+                    if (normalizedLX != 0 && Math.abs(normalizedLX) > 0.005) {
+                        camera.inertialAlphaOffset += normalizedLX;
+                    }
+                }
+                if (LSValues.y != 0) {
+                    var normalizedLY = LSValues.y / this.gamepadRotationSensibility;
+                    if (normalizedLY != 0 && Math.abs(normalizedLY) > 0.005) {
+                        camera.inertialBetaOffset += normalizedLY;
+                    }
+                }
+            }
+        };
+        ArcRotateCameraGamepadInput.prototype._onNewGameConnected = function (gamepad) {
+            // Only the first gamepad can control the camera
+            if (gamepad.index === 0) {
+                this.gamepad = gamepad;
+            }
+        };
+        ArcRotateCameraGamepadInput.prototype.getTypeName = function () {
+            return "ArcRotateCameraGamepadInput";
+        };
+        ArcRotateCameraGamepadInput.prototype.getSimpleName = function () {
+            return "gamepad";
+        };
+        __decorate([
+            BABYLON.serialize()
+        ], ArcRotateCameraGamepadInput.prototype, "gamepadRotationSensibility", void 0);
+        return ArcRotateCameraGamepadInput;
+    })();
+    BABYLON.ArcRotateCameraGamepadInput = ArcRotateCameraGamepadInput;
+    BABYLON.CameraInputTypes["ArcRotateCameraGamepadInput"] = ArcRotateCameraGamepadInput;
+})(BABYLON || (BABYLON = {}));

+ 61 - 0
src/Cameras/Inputs/babylon.arcrotatecamera.input.gamepad.ts

@@ -0,0 +1,61 @@
+module BABYLON {       
+    export class ArcRotateCameraGamepadInput implements ICameraInput<ArcRotateCamera> {
+        camera : ArcRotateCamera;
+        
+        public gamepad: Gamepad;
+        private _gamepads: Gamepads;        
+
+        @serialize()
+        public gamepadRotationSensibility = 80;
+        
+        constructor(){
+            this._gamepads = new Gamepads((gamepad: Gamepad) => { this._onNewGameConnected(gamepad); });
+        }
+        
+        attachCamera(camera : ArcRotateCamera){
+            this.camera = camera;
+        }
+        
+        detach(){
+            this._gamepads.dispose();
+        }
+        
+        checkInputs(){
+            if (this.gamepad) {
+                var camera = this.camera;
+                var LSValues = this.gamepad.leftStick;
+                
+                if (LSValues.x != 0){
+                    var normalizedLX = LSValues.x / this.gamepadRotationSensibility;                
+                    if (normalizedLX != 0 && Math.abs(normalizedLX) > 0.005) {
+                        camera.inertialAlphaOffset += normalizedLX;
+                    }
+                }
+                
+                if (LSValues.y != 0){
+                    var normalizedLY = LSValues.y / this.gamepadRotationSensibility;
+                    if (normalizedLY != 0 && Math.abs(normalizedLY) > 0.005) {
+                        camera.inertialBetaOffset += normalizedLY;
+                    }
+                }                               
+            }
+        }
+        
+        private _onNewGameConnected(gamepad: Gamepad) {
+            // Only the first gamepad can control the camera
+            if (gamepad.index === 0) {
+                this.gamepad = gamepad;
+            }
+        }
+        
+        getTypeName(): string{
+            return "ArcRotateCameraGamepadInput";
+        }
+        
+        getSimpleName(){
+            return "gamepad";
+        }
+    }
+    
+    CameraInputTypes["ArcRotateCameraGamepadInput"] = ArcRotateCameraGamepadInput;
+}

+ 108 - 0
src/Cameras/Inputs/babylon.arcrotatecamera.input.keyboard.js

@@ -0,0 +1,108 @@
+var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
+    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
+    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
+    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
+    return c > 3 && r && Object.defineProperty(target, key, r), r;
+};
+var BABYLON;
+(function (BABYLON) {
+    var ArcRotateCameraKeyboardMoveInput = (function () {
+        function ArcRotateCameraKeyboardMoveInput() {
+            this._keys = [];
+            this.keysUp = [38];
+            this.keysDown = [40];
+            this.keysLeft = [37];
+            this.keysRight = [39];
+        }
+        ArcRotateCameraKeyboardMoveInput.prototype.attachCamera = function (camera) {
+            var _this = this;
+            this.camera = camera;
+            this._onKeyDown = function (evt) {
+                if (_this.keysUp.indexOf(evt.keyCode) !== -1 ||
+                    _this.keysDown.indexOf(evt.keyCode) !== -1 ||
+                    _this.keysLeft.indexOf(evt.keyCode) !== -1 ||
+                    _this.keysRight.indexOf(evt.keyCode) !== -1) {
+                    var index = _this._keys.indexOf(evt.keyCode);
+                    if (index === -1) {
+                        _this._keys.push(evt.keyCode);
+                    }
+                    if (evt.preventDefault) {
+                        if (!camera._noPreventDefault) {
+                            evt.preventDefault();
+                        }
+                    }
+                }
+            };
+            this._onKeyUp = function (evt) {
+                if (_this.keysUp.indexOf(evt.keyCode) !== -1 ||
+                    _this.keysDown.indexOf(evt.keyCode) !== -1 ||
+                    _this.keysLeft.indexOf(evt.keyCode) !== -1 ||
+                    _this.keysRight.indexOf(evt.keyCode) !== -1) {
+                    var index = _this._keys.indexOf(evt.keyCode);
+                    if (index >= 0) {
+                        _this._keys.splice(index, 1);
+                    }
+                    if (evt.preventDefault) {
+                        if (!camera._noPreventDefault) {
+                            evt.preventDefault();
+                        }
+                    }
+                }
+            };
+            this._onLostFocus = function () {
+                _this._keys = [];
+            };
+            BABYLON.Tools.RegisterTopRootEvents([
+                { name: "keydown", handler: this._onKeyDown },
+                { name: "keyup", handler: this._onKeyUp },
+                { name: "blur", handler: this._onLostFocus }
+            ]);
+        };
+        ArcRotateCameraKeyboardMoveInput.prototype.detach = function () {
+            BABYLON.Tools.UnregisterTopRootEvents([
+                { name: "keydown", handler: this._onKeyDown },
+                { name: "keyup", handler: this._onKeyUp },
+                { name: "blur", handler: this._onLostFocus }
+            ]);
+        };
+        ArcRotateCameraKeyboardMoveInput.prototype.checkInputs = function () {
+            var camera = this.camera;
+            for (var index = 0; index < this._keys.length; index++) {
+                var keyCode = this._keys[index];
+                if (this.keysLeft.indexOf(keyCode) !== -1) {
+                    camera.inertialAlphaOffset -= 0.01;
+                }
+                else if (this.keysUp.indexOf(keyCode) !== -1) {
+                    camera.inertialBetaOffset -= 0.01;
+                }
+                else if (this.keysRight.indexOf(keyCode) !== -1) {
+                    camera.inertialAlphaOffset += 0.01;
+                }
+                else if (this.keysDown.indexOf(keyCode) !== -1) {
+                    camera.inertialBetaOffset += 0.01;
+                }
+            }
+        };
+        ArcRotateCameraKeyboardMoveInput.prototype.getTypeName = function () {
+            return "ArcRotateCameraKeyboardMoveInput";
+        };
+        ArcRotateCameraKeyboardMoveInput.prototype.getSimpleName = function () {
+            return "keyboard";
+        };
+        __decorate([
+            BABYLON.serialize()
+        ], ArcRotateCameraKeyboardMoveInput.prototype, "keysUp", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], ArcRotateCameraKeyboardMoveInput.prototype, "keysDown", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], ArcRotateCameraKeyboardMoveInput.prototype, "keysLeft", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], ArcRotateCameraKeyboardMoveInput.prototype, "keysRight", void 0);
+        return ArcRotateCameraKeyboardMoveInput;
+    })();
+    BABYLON.ArcRotateCameraKeyboardMoveInput = ArcRotateCameraKeyboardMoveInput;
+    BABYLON.CameraInputTypes["ArcRotateCameraKeyboardMoveInput"] = ArcRotateCameraKeyboardMoveInput;
+})(BABYLON || (BABYLON = {}));

+ 108 - 0
src/Cameras/Inputs/babylon.arcrotatecamera.input.keyboard.ts

@@ -0,0 +1,108 @@
+module BABYLON {
+    export class ArcRotateCameraKeyboardMoveInput implements ICameraInput<ArcRotateCamera> {
+        camera: ArcRotateCamera;
+        private _keys = [];
+        private _onKeyDown: (e: KeyboardEvent) => any;
+        private _onKeyUp: (e: KeyboardEvent) => any;
+        private _onLostFocus: (e: FocusEvent) => any;
+        
+        @serialize()
+        public keysUp = [38];
+
+        @serialize()
+        public keysDown = [40];
+
+        @serialize()
+        public keysLeft = [37];
+
+        @serialize()
+        public keysRight = [39];
+
+        public attachCamera(camera: ArcRotateCamera) {
+            this.camera = camera;
+
+            this._onKeyDown = evt => {
+                if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
+                    this.keysDown.indexOf(evt.keyCode) !== -1 ||
+                    this.keysLeft.indexOf(evt.keyCode) !== -1 ||
+                    this.keysRight.indexOf(evt.keyCode) !== -1) {
+                    var index = this._keys.indexOf(evt.keyCode);
+
+                    if (index === -1) {
+                        this._keys.push(evt.keyCode);
+                    }
+
+                    if (evt.preventDefault) {
+                        if (!camera._noPreventDefault) {
+                            evt.preventDefault();
+                        }
+                    }
+                }
+            };
+
+            this._onKeyUp = evt => {
+                if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
+                    this.keysDown.indexOf(evt.keyCode) !== -1 ||
+                    this.keysLeft.indexOf(evt.keyCode) !== -1 ||
+                    this.keysRight.indexOf(evt.keyCode) !== -1) {
+                    var index = this._keys.indexOf(evt.keyCode);
+
+                    if (index >= 0) {
+                        this._keys.splice(index, 1);
+                    }
+
+                    if (evt.preventDefault) {
+                        if (!camera._noPreventDefault) {
+                            evt.preventDefault();
+                        }
+                    }
+                }
+            };
+
+            this._onLostFocus = () => {
+                this._keys = [];
+            };
+
+            Tools.RegisterTopRootEvents([
+                { name: "keydown", handler: this._onKeyDown },
+                { name: "keyup", handler: this._onKeyUp },
+                { name: "blur", handler: this._onLostFocus }
+            ]);
+        }
+
+        public detach() {
+            Tools.UnregisterTopRootEvents([
+                { name: "keydown", handler: this._onKeyDown },
+                { name: "keyup", handler: this._onKeyUp },
+                { name: "blur", handler: this._onLostFocus }
+            ]);
+        }
+
+        public checkInputs() {
+            var camera = this.camera;
+
+            for (var index = 0; index < this._keys.length; index++) {
+                var keyCode = this._keys[index];
+                if (this.keysLeft.indexOf(keyCode) !== -1) {
+                    camera.inertialAlphaOffset -= 0.01;
+                } else if (this.keysUp.indexOf(keyCode) !== -1) {
+                    camera.inertialBetaOffset -= 0.01;
+                } else if (this.keysRight.indexOf(keyCode) !== -1) {
+                    camera.inertialAlphaOffset += 0.01;
+                } else if (this.keysDown.indexOf(keyCode) !== -1) {
+                    camera.inertialBetaOffset += 0.01;
+                }
+            }
+        }
+
+        getTypeName(): string {
+            return "ArcRotateCameraKeyboardMoveInput";
+        }
+        
+        getSimpleName(){
+            return "keyboard";
+        }
+    }
+    
+    CameraInputTypes["ArcRotateCameraKeyboardMoveInput"] = ArcRotateCameraKeyboardMoveInput;
+}

+ 55 - 0
src/Cameras/Inputs/babylon.arcrotatecamera.input.mousewheel.js

@@ -0,0 +1,55 @@
+var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
+    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
+    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
+    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
+    return c > 3 && r && Object.defineProperty(target, key, r), r;
+};
+var BABYLON;
+(function (BABYLON) {
+    var ArcRotateCameraMouseWheelInput = (function () {
+        function ArcRotateCameraMouseWheelInput() {
+            this.wheelPrecision = 3.0;
+        }
+        ArcRotateCameraMouseWheelInput.prototype.attachCamera = function (camera) {
+            this.camera = camera;
+        };
+        ArcRotateCameraMouseWheelInput.prototype.attachElement = function (element) {
+            var _this = this;
+            this.attachedElement = element;
+            this._wheel = function (event) {
+                var delta = 0;
+                if (event.wheelDelta) {
+                    delta = event.wheelDelta / (_this.wheelPrecision * 40);
+                }
+                else if (event.detail) {
+                    delta = -event.detail / _this.wheelPrecision;
+                }
+                if (delta)
+                    _this.camera.inertialRadiusOffset += delta;
+                if (event.preventDefault) {
+                    if (!_this.camera._noPreventDefault) {
+                        event.preventDefault();
+                    }
+                }
+            };
+            element.addEventListener('mousewheel', this._wheel, false);
+            element.addEventListener('DOMMouseScroll', this._wheel, false);
+        };
+        ArcRotateCameraMouseWheelInput.prototype.detach = function () {
+            this.attachedElement.removeEventListener('mousewheel', this._wheel);
+            this.attachedElement.removeEventListener('DOMMouseScroll', this._wheel);
+        };
+        ArcRotateCameraMouseWheelInput.prototype.getTypeName = function () {
+            return "ArcRotateCameraMouseWheelInput";
+        };
+        ArcRotateCameraMouseWheelInput.prototype.getSimpleName = function () {
+            return "mousewheel";
+        };
+        __decorate([
+            BABYLON.serialize()
+        ], ArcRotateCameraMouseWheelInput.prototype, "wheelPrecision", void 0);
+        return ArcRotateCameraMouseWheelInput;
+    })();
+    BABYLON.ArcRotateCameraMouseWheelInput = ArcRotateCameraMouseWheelInput;
+    BABYLON.CameraInputTypes["ArcRotateCameraMouseWheelInput"] = ArcRotateCameraMouseWheelInput;
+})(BABYLON || (BABYLON = {}));

+ 53 - 0
src/Cameras/Inputs/babylon.arcrotatecamera.input.mousewheel.ts

@@ -0,0 +1,53 @@
+module BABYLON {
+    export class ArcRotateCameraMouseWheelInput implements ICameraInput<ArcRotateCamera> {
+        camera: ArcRotateCamera;
+        attachedElement: HTMLElement;
+
+        private _wheel: (e: MouseWheelEvent) => void;
+
+        @serialize()
+        public wheelPrecision = 3.0;
+
+        public attachCamera(camera: ArcRotateCamera) {
+            this.camera = camera;
+        }
+
+        public attachElement(element: HTMLElement) {
+            this.attachedElement = element;
+            this._wheel = event => {
+                var delta = 0;
+                if (event.wheelDelta) {
+                    delta = event.wheelDelta / (this.wheelPrecision * 40);
+                } else if (event.detail) {
+                    delta = -event.detail / this.wheelPrecision;
+                }
+
+                if (delta)
+                    this.camera.inertialRadiusOffset += delta;
+
+                if (event.preventDefault) {
+                    if (!this.camera._noPreventDefault) {
+                        event.preventDefault();
+                    }
+                }
+            };
+            element.addEventListener('mousewheel', this._wheel, false);
+            element.addEventListener('DOMMouseScroll', this._wheel, false);
+        }
+
+        public detach() {
+            this.attachedElement.removeEventListener('mousewheel', this._wheel);
+            this.attachedElement.removeEventListener('DOMMouseScroll', this._wheel);
+        }
+
+        getTypeName(): string {
+            return "ArcRotateCameraMouseWheelInput";
+        }
+        
+        getSimpleName(){
+            return "mousewheel";
+        }
+    }
+    
+    CameraInputTypes["ArcRotateCameraMouseWheelInput"] = ArcRotateCameraMouseWheelInput;
+}

+ 193 - 0
src/Cameras/Inputs/babylon.arcrotatecamera.input.pointers.js

@@ -0,0 +1,193 @@
+var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
+    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
+    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
+    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
+    return c > 3 && r && Object.defineProperty(target, key, r), r;
+};
+var BABYLON;
+(function (BABYLON) {
+    var eventPrefix = BABYLON.Tools.GetPointerPrefix();
+    var ArcRotateCameraPointersInput = (function () {
+        function ArcRotateCameraPointersInput() {
+            this._isRightClick = false;
+            this._isCtrlPushed = false;
+            this.pinchInwards = true;
+            this.angularSensibilityX = 1000.0;
+            this.angularSensibilityY = 1000.0;
+            this.pinchPrecision = 6.0;
+            this.panningSensibility = 50.0;
+        }
+        ArcRotateCameraPointersInput.prototype.attachCamera = function (camera) {
+            this.camera = camera;
+        };
+        ArcRotateCameraPointersInput.prototype.attachElement = function (element, noPreventDefault) {
+            var _this = this;
+            this.attachedElement = element;
+            var engine = this.camera.getEngine();
+            var cacheSoloPointer; // cache pointer object for better perf on camera rotation
+            var pointers = new BABYLON.SmartCollection();
+            var previousPinchDistance = 0;
+            if (this._onPointerDown === undefined) {
+                if (!this.camera._useCtrlForPanning) {
+                    element.addEventListener("contextmenu", this._onContextMenu, false);
+                }
+                this._onLostFocus = function () {
+                    //this._keys = [];
+                    pointers.empty();
+                    previousPinchDistance = 0;
+                    cacheSoloPointer = null;
+                };
+                this._onKeyDown = function (evt) {
+                    _this._isCtrlPushed = evt.ctrlKey;
+                };
+                this._onKeyUp = function (evt) {
+                    _this._isCtrlPushed = evt.ctrlKey;
+                };
+                this._onPointerDown = function (evt) {
+                    // Manage panning with right click
+                    _this._isRightClick = evt.button === 2;
+                    // manage pointers
+                    pointers.add(evt.pointerId, { x: evt.clientX, y: evt.clientY, type: evt.pointerType });
+                    cacheSoloPointer = pointers.item(evt.pointerId);
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                };
+                this._onPointerUp = function (evt) {
+                    cacheSoloPointer = null;
+                    previousPinchDistance = 0;
+                    //would be better to use pointers.remove(evt.pointerId) for multitouch gestures, 
+                    //but emptying completly pointers collection is required to fix a bug on iPhone : 
+                    //when changing orientation while pinching camera, one pointer stay pressed forever if we don't release all pointers  
+                    //will be ok to put back pointers.remove(evt.pointerId); when iPhone bug corrected
+                    pointers.empty();
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                };
+                this._onContextMenu = function (evt) {
+                    evt.preventDefault();
+                };
+                this._onPointerMove = function (evt) {
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                    switch (pointers.count) {
+                        case 1:
+                            if (_this.panningSensibility !== 0 && ((_this._isCtrlPushed && _this.camera._useCtrlForPanning) || (!_this.camera._useCtrlForPanning && _this._isRightClick))) {
+                                _this.camera.inertialPanningX += -(evt.clientX - cacheSoloPointer.x) / _this.panningSensibility;
+                                _this.camera.inertialPanningY += (evt.clientY - cacheSoloPointer.y) / _this.panningSensibility;
+                            }
+                            else {
+                                var offsetX = evt.clientX - cacheSoloPointer.x;
+                                var offsetY = evt.clientY - cacheSoloPointer.y;
+                                _this.camera.inertialAlphaOffset -= offsetX / _this.angularSensibilityX;
+                                _this.camera.inertialBetaOffset -= offsetY / _this.angularSensibilityY;
+                            }
+                            cacheSoloPointer.x = evt.clientX;
+                            cacheSoloPointer.y = evt.clientY;
+                            break;
+                        case 2:
+                            //if (noPreventDefault) { evt.preventDefault(); } //if pinch gesture, could be usefull to force preventDefault to avoid html page scroll/zoom in some mobile browsers
+                            pointers.item(evt.pointerId).x = evt.clientX;
+                            pointers.item(evt.pointerId).y = evt.clientY;
+                            var direction = _this.pinchInwards ? 1 : -1;
+                            var distX = pointers.getItemByIndex(0).x - pointers.getItemByIndex(1).x;
+                            var distY = pointers.getItemByIndex(0).y - pointers.getItemByIndex(1).y;
+                            var pinchSquaredDistance = (distX * distX) + (distY * distY);
+                            if (previousPinchDistance === 0) {
+                                previousPinchDistance = pinchSquaredDistance;
+                                return;
+                            }
+                            if (pinchSquaredDistance !== previousPinchDistance) {
+                                _this.camera.inertialRadiusOffset += (pinchSquaredDistance - previousPinchDistance) / (_this.pinchPrecision * ((_this.angularSensibilityX + _this.angularSensibilityY) / 2) * direction);
+                                previousPinchDistance = pinchSquaredDistance;
+                            }
+                            break;
+                        default:
+                            if (pointers.item(evt.pointerId)) {
+                                pointers.item(evt.pointerId).x = evt.clientX;
+                                pointers.item(evt.pointerId).y = evt.clientY;
+                            }
+                    }
+                };
+                this._onMouseMove = function (evt) {
+                    if (!engine.isPointerLock) {
+                        return;
+                    }
+                    var offsetX = evt.movementX || evt.mozMovementX || evt.webkitMovementX || evt.msMovementX || 0;
+                    var offsetY = evt.movementY || evt.mozMovementY || evt.webkitMovementY || evt.msMovementY || 0;
+                    _this.camera.inertialAlphaOffset -= offsetX / _this.angularSensibilityX;
+                    _this.camera.inertialBetaOffset -= offsetY / _this.angularSensibilityY;
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                };
+                this._onGestureStart = function (e) {
+                    if (window.MSGesture === undefined) {
+                        return;
+                    }
+                    if (!_this._MSGestureHandler) {
+                        _this._MSGestureHandler = new MSGesture();
+                        _this._MSGestureHandler.target = element;
+                    }
+                    _this._MSGestureHandler.addPointer(e.pointerId);
+                };
+                this._onGesture = function (e) {
+                    _this.camera.radius *= e.scale;
+                    if (e.preventDefault) {
+                        if (!noPreventDefault) {
+                            e.stopPropagation();
+                            e.preventDefault();
+                        }
+                    }
+                };
+            }
+            this.attachedElement.addEventListener(eventPrefix + "down", this._onPointerDown, false);
+            this.attachedElement.addEventListener(eventPrefix + "up", this._onPointerUp, false);
+            this.attachedElement.addEventListener(eventPrefix + "out", this._onPointerUp, false);
+            this.attachedElement.addEventListener(eventPrefix + "move", this._onPointerMove, false);
+            this.attachedElement.addEventListener("mousemove", this._onMouseMove, false);
+            this.attachedElement.addEventListener("MSPointerDown", this._onGestureStart, false);
+            this.attachedElement.addEventListener("MSGestureChange", this._onGesture, false);
+            BABYLON.Tools.RegisterTopRootEvents([
+                { name: "blur", handler: this._onLostFocus }
+            ]);
+        };
+        ArcRotateCameraPointersInput.prototype.detach = function () {
+            this._MSGestureHandler = null;
+            this.attachedElement.removeEventListener("contextmenu", this._onContextMenu);
+            this.attachedElement.removeEventListener(eventPrefix + "down", this._onPointerDown);
+            this.attachedElement.removeEventListener(eventPrefix + "up", this._onPointerUp);
+            this.attachedElement.removeEventListener(eventPrefix + "out", this._onPointerUp);
+            this.attachedElement.removeEventListener(eventPrefix + "move", this._onPointerMove);
+            this.attachedElement.removeEventListener("mousemove", this._onMouseMove);
+            this.attachedElement.removeEventListener("MSPointerDown", this._onGestureStart);
+            this.attachedElement.removeEventListener("MSGestureChange", this._onGesture);
+            BABYLON.Tools.UnregisterTopRootEvents([
+                { name: "blur", handler: this._onLostFocus }
+            ]);
+        };
+        ArcRotateCameraPointersInput.prototype.getTypeName = function () {
+            return "ArcRotateCameraPointersInput";
+        };
+        ArcRotateCameraPointersInput.prototype.getSimpleName = function () {
+            return "pointers";
+        };
+        __decorate([
+            BABYLON.serialize()
+        ], ArcRotateCameraPointersInput.prototype, "angularSensibilityX", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], ArcRotateCameraPointersInput.prototype, "angularSensibilityY", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], ArcRotateCameraPointersInput.prototype, "pinchPrecision", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], ArcRotateCameraPointersInput.prototype, "panningSensibility", void 0);
+        return ArcRotateCameraPointersInput;
+    })();
+    BABYLON.ArcRotateCameraPointersInput = ArcRotateCameraPointersInput;
+    BABYLON.CameraInputTypes["ArcRotateCameraPointersInput"] = ArcRotateCameraPointersInput;
+})(BABYLON || (BABYLON = {}));

+ 229 - 0
src/Cameras/Inputs/babylon.arcrotatecamera.input.pointers.ts

@@ -0,0 +1,229 @@
+module BABYLON {
+    var eventPrefix = Tools.GetPointerPrefix();
+
+    export class ArcRotateCameraPointersInput implements ICameraInput<ArcRotateCamera> {
+        camera: ArcRotateCamera;
+        attachedElement: HTMLElement;
+        private _isRightClick: boolean = false;
+        private _isCtrlPushed: boolean = false;
+        public pinchInwards = true;
+        
+        @serialize()
+        public angularSensibilityX = 1000.0;
+
+        @serialize()
+        public angularSensibilityY = 1000.0;
+
+        @serialize()
+        public pinchPrecision = 6.0;
+
+        @serialize()
+        public panningSensibility: number = 50.0;       
+
+        private _onKeyDown: (e: KeyboardEvent) => any;
+        private _onKeyUp: (e: KeyboardEvent) => any;
+        private _onPointerDown: (e: PointerEvent) => void;
+        private _onPointerUp: (e: PointerEvent) => void;
+        private _onPointerMove: (e: PointerEvent) => void;
+        private _onMouseMove: (e: MouseEvent) => any;
+        private _onGestureStart: (e: PointerEvent) => void;
+        private _onGesture: (e: MSGestureEvent) => void;
+        private _MSGestureHandler: MSGesture;
+        private _onLostFocus: (e: FocusEvent) => any;
+        private _onContextMenu: (e: PointerEvent) => void;
+        
+        public attachCamera(camera: ArcRotateCamera) {
+            this.camera = camera;
+
+        }
+
+        public attachElement(element: HTMLElement, noPreventDefault?: boolean) {
+            this.attachedElement = element;
+
+            var engine = this.camera.getEngine();
+            var cacheSoloPointer; // cache pointer object for better perf on camera rotation
+            var pointers = new SmartCollection();
+            var previousPinchDistance = 0;
+
+            if (this._onPointerDown === undefined) {
+                if (!this.camera._useCtrlForPanning) {
+                    element.addEventListener("contextmenu", this._onContextMenu, false);
+                }
+                
+                this._onLostFocus = () => {
+                    //this._keys = [];
+                    pointers.empty();
+                    previousPinchDistance = 0;
+                    cacheSoloPointer = null;
+                };
+
+                this._onKeyDown = evt => {
+                    this._isCtrlPushed = evt.ctrlKey;
+                };
+
+                this._onKeyUp = evt => {
+                    this._isCtrlPushed = evt.ctrlKey;
+                };
+
+                this._onPointerDown = evt => {
+                    // Manage panning with right click
+                    this._isRightClick = evt.button === 2;
+
+                    // manage pointers
+                    pointers.add(evt.pointerId, { x: evt.clientX, y: evt.clientY, type: evt.pointerType });
+                    cacheSoloPointer = pointers.item(evt.pointerId);
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                };
+
+                this._onPointerUp = evt => {
+                    cacheSoloPointer = null;
+                    previousPinchDistance = 0;
+
+                    //would be better to use pointers.remove(evt.pointerId) for multitouch gestures, 
+                    //but emptying completly pointers collection is required to fix a bug on iPhone : 
+                    //when changing orientation while pinching camera, one pointer stay pressed forever if we don't release all pointers  
+                    //will be ok to put back pointers.remove(evt.pointerId); when iPhone bug corrected
+                    pointers.empty();
+
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                };
+
+                this._onContextMenu = evt => {
+                    evt.preventDefault();
+                };
+
+                this._onPointerMove = evt => {
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+
+                    switch (pointers.count) {
+
+                        case 1: //normal camera rotation
+                            if (this.panningSensibility !== 0 && ((this._isCtrlPushed && this.camera._useCtrlForPanning) || (!this.camera._useCtrlForPanning && this._isRightClick))) {
+                                this.camera.inertialPanningX += -(evt.clientX - cacheSoloPointer.x) / this.panningSensibility;
+                                this.camera.inertialPanningY += (evt.clientY - cacheSoloPointer.y) / this.panningSensibility;
+                            } else {
+                                var offsetX = evt.clientX - cacheSoloPointer.x;
+                                var offsetY = evt.clientY - cacheSoloPointer.y;
+                                this.camera.inertialAlphaOffset -= offsetX / this.angularSensibilityX;
+                                this.camera.inertialBetaOffset -= offsetY / this.angularSensibilityY;
+                            }
+                            cacheSoloPointer.x = evt.clientX;
+                            cacheSoloPointer.y = evt.clientY;
+                            break;
+
+                        case 2: //pinch
+                            //if (noPreventDefault) { evt.preventDefault(); } //if pinch gesture, could be usefull to force preventDefault to avoid html page scroll/zoom in some mobile browsers
+                            pointers.item(evt.pointerId).x = evt.clientX;
+                            pointers.item(evt.pointerId).y = evt.clientY;
+                            var direction = this.pinchInwards ? 1 : -1;
+                            var distX = pointers.getItemByIndex(0).x - pointers.getItemByIndex(1).x;
+                            var distY = pointers.getItemByIndex(0).y - pointers.getItemByIndex(1).y;
+                            var pinchSquaredDistance = (distX * distX) + (distY * distY);
+                            if (previousPinchDistance === 0) {
+                                previousPinchDistance = pinchSquaredDistance;
+                                return;
+                            }
+
+                            if (pinchSquaredDistance !== previousPinchDistance) {
+                                this.camera.inertialRadiusOffset += (pinchSquaredDistance - previousPinchDistance) / (this.pinchPrecision * ((this.angularSensibilityX + this.angularSensibilityY) / 2) * direction);
+                                previousPinchDistance = pinchSquaredDistance;
+                            }
+                            break;
+
+                        default:
+                            if (pointers.item(evt.pointerId)) {
+                                pointers.item(evt.pointerId).x = evt.clientX;
+                                pointers.item(evt.pointerId).y = evt.clientY;
+                            }
+                    }
+                };
+
+                this._onMouseMove = evt => {
+                    if (!engine.isPointerLock) {
+                        return;
+                    }
+
+                    var offsetX = evt.movementX || evt.mozMovementX || evt.webkitMovementX || evt.msMovementX || 0;
+                    var offsetY = evt.movementY || evt.mozMovementY || evt.webkitMovementY || evt.msMovementY || 0;
+
+                    this.camera.inertialAlphaOffset -= offsetX / this.angularSensibilityX;
+                    this.camera.inertialBetaOffset -= offsetY / this.angularSensibilityY;
+
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                };
+
+                this._onGestureStart = e => {
+                    if (window.MSGesture === undefined) {
+                        return;
+                    }
+
+                    if (!this._MSGestureHandler) {
+                        this._MSGestureHandler = new MSGesture();
+                        this._MSGestureHandler.target = element;
+                    }
+
+                    this._MSGestureHandler.addPointer(e.pointerId);
+                };
+
+                this._onGesture = e => {
+                    this.camera.radius *= e.scale;
+
+
+                    if (e.preventDefault) {
+                        if (!noPreventDefault) {
+                            e.stopPropagation();
+                            e.preventDefault();
+                        }
+                    }
+                };
+            }
+
+            this.attachedElement.addEventListener(eventPrefix + "down", this._onPointerDown, false);
+            this.attachedElement.addEventListener(eventPrefix + "up", this._onPointerUp, false);
+            this.attachedElement.addEventListener(eventPrefix + "out", this._onPointerUp, false);
+            this.attachedElement.addEventListener(eventPrefix + "move", this._onPointerMove, false);
+            this.attachedElement.addEventListener("mousemove", this._onMouseMove, false);
+            this.attachedElement.addEventListener("MSPointerDown", this._onGestureStart, false);
+            this.attachedElement.addEventListener("MSGestureChange", this._onGesture, false);
+
+            Tools.RegisterTopRootEvents([
+                { name: "blur", handler: this._onLostFocus }
+            ]);
+        }
+
+        public detach() {
+            this._MSGestureHandler = null;
+
+            this.attachedElement.removeEventListener("contextmenu", this._onContextMenu);
+            this.attachedElement.removeEventListener(eventPrefix + "down", this._onPointerDown);
+            this.attachedElement.removeEventListener(eventPrefix + "up", this._onPointerUp);
+            this.attachedElement.removeEventListener(eventPrefix + "out", this._onPointerUp);
+            this.attachedElement.removeEventListener(eventPrefix + "move", this._onPointerMove);
+            this.attachedElement.removeEventListener("mousemove", this._onMouseMove);
+            this.attachedElement.removeEventListener("MSPointerDown", this._onGestureStart);
+            this.attachedElement.removeEventListener("MSGestureChange", this._onGesture);
+
+            Tools.UnregisterTopRootEvents([
+                { name: "blur", handler: this._onLostFocus }
+            ]);
+        }        
+
+        getTypeName(): string {
+            return "ArcRotateCameraPointersInput";
+        }
+                
+        getSimpleName(){
+            return "pointers";
+        }
+    }
+    
+    CameraInputTypes["ArcRotateCameraPointersInput"] = ArcRotateCameraPointersInput;
+}

+ 75 - 0
src/Cameras/Inputs/babylon.freecamera.input.deviceorientation.js

@@ -0,0 +1,75 @@
+var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
+    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
+    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
+    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
+    return c > 3 && r && Object.defineProperty(target, key, r), r;
+};
+var BABYLON;
+(function (BABYLON) {
+    var FreeCameraDeviceOrientationInput = (function () {
+        function FreeCameraDeviceOrientationInput() {
+            this._offsetX = null;
+            this._offsetY = null;
+            this._orientationGamma = 0;
+            this._orientationBeta = 0;
+            this._initialOrientationGamma = 0;
+            this._initialOrientationBeta = 0;
+            this.angularSensibility = 10000.0;
+            this.moveSensibility = 50.0;
+            this._resetOrientationGamma = this.resetOrientationGamma.bind(this);
+            this._orientationChanged = this.orientationChanged.bind(this);
+        }
+        FreeCameraDeviceOrientationInput.prototype.attachCamera = function (camera) {
+            this.camera = camera;
+            window.addEventListener("resize", this._resetOrientationGamma, false);
+            window.addEventListener("deviceorientation", this._orientationChanged);
+        };
+        FreeCameraDeviceOrientationInput.prototype.resetOrientationGamma = function () {
+            this._initialOrientationGamma = null;
+        };
+        FreeCameraDeviceOrientationInput.prototype.orientationChanged = function (evt) {
+            if (!this._initialOrientationGamma) {
+                this._initialOrientationGamma = evt.gamma;
+                this._initialOrientationBeta = evt.beta;
+            }
+            this._orientationGamma = evt.gamma;
+            this._orientationBeta = evt.beta;
+            this._offsetY = (this._initialOrientationBeta - this._orientationBeta);
+            this._offsetX = (this._initialOrientationGamma - this._orientationGamma);
+        };
+        FreeCameraDeviceOrientationInput.prototype.detach = function () {
+            window.removeEventListener("resize", this._resetOrientationGamma);
+            window.removeEventListener("deviceorientation", this._orientationChanged);
+            this._orientationGamma = 0;
+            this._orientationBeta = 0;
+            this._initialOrientationGamma = 0;
+            this._initialOrientationBeta = 0;
+        };
+        FreeCameraDeviceOrientationInput.prototype.checkInputs = function () {
+            if (!this._offsetX) {
+                return;
+            }
+            var camera = this.camera;
+            camera.cameraRotation.y -= this._offsetX / this.angularSensibility;
+            var speed = camera._computeLocalCameraSpeed();
+            var direction = new BABYLON.Vector3(0, 0, speed * this._offsetY / this.moveSensibility);
+            BABYLON.Matrix.RotationYawPitchRollToRef(camera.rotation.y, camera.rotation.x, 0, camera._cameraRotationMatrix);
+            camera.cameraDirection.addInPlace(BABYLON.Vector3.TransformCoordinates(direction, camera._cameraRotationMatrix));
+        };
+        FreeCameraDeviceOrientationInput.prototype.getTypeName = function () {
+            return "FreeCameraDeviceOrientationInput";
+        };
+        FreeCameraDeviceOrientationInput.prototype.getSimpleName = function () {
+            return "deviceOrientation";
+        };
+        __decorate([
+            BABYLON.serialize()
+        ], FreeCameraDeviceOrientationInput.prototype, "angularSensibility", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], FreeCameraDeviceOrientationInput.prototype, "moveSensibility", void 0);
+        return FreeCameraDeviceOrientationInput;
+    })();
+    BABYLON.FreeCameraDeviceOrientationInput = FreeCameraDeviceOrientationInput;
+    BABYLON.CameraInputTypes["FreeCameraDeviceOrientationInput"] = FreeCameraDeviceOrientationInput;
+})(BABYLON || (BABYLON = {}));

+ 84 - 0
src/Cameras/Inputs/babylon.freecamera.input.deviceorientation.ts

@@ -0,0 +1,84 @@
+module BABYLON {
+    export class FreeCameraDeviceOrientationInput implements ICameraInput<FreeCamera> {
+        camera: FreeCamera;
+
+        private _offsetX: number = null;
+        private _offsetY: number = null;
+        private _orientationGamma: number = 0;
+        private _orientationBeta: number = 0;
+        private _initialOrientationGamma: number = 0;
+        private _initialOrientationBeta: number = 0;
+        private _orientationChanged: (e: DeviceOrientationEvent) => any;
+        private _resetOrientationGamma: () => any;
+
+        @serialize()
+        public angularSensibility: number = 10000.0;
+
+        @serialize()
+        public moveSensibility: number = 50.0;
+
+        constructor() {
+            this._resetOrientationGamma = this.resetOrientationGamma.bind(this);
+            this._orientationChanged = this.orientationChanged.bind(this);
+        }
+
+        attachCamera(camera: FreeCamera) {
+            this.camera = camera;
+
+            window.addEventListener("resize", this._resetOrientationGamma, false);
+            window.addEventListener("deviceorientation", this._orientationChanged);
+        }
+
+        resetOrientationGamma() {
+            this._initialOrientationGamma = null;
+        }
+
+        orientationChanged(evt) {
+            if (!this._initialOrientationGamma) {
+                this._initialOrientationGamma = evt.gamma;
+                this._initialOrientationBeta = evt.beta;
+            }
+
+            this._orientationGamma = evt.gamma;
+            this._orientationBeta = evt.beta;
+
+            this._offsetY = (this._initialOrientationBeta - this._orientationBeta);
+            this._offsetX = (this._initialOrientationGamma - this._orientationGamma);
+        }
+
+        detach() {
+            window.removeEventListener("resize", this._resetOrientationGamma);
+            window.removeEventListener("deviceorientation", this._orientationChanged);
+            
+            this._orientationGamma = 0;
+            this._orientationBeta = 0;
+            this._initialOrientationGamma = 0;
+            this._initialOrientationBeta = 0;
+        }
+
+        public checkInputs() {
+            if (!this._offsetX) {
+                return;
+            }
+            
+            var camera = this.camera;
+            camera.cameraRotation.y -= this._offsetX / this.angularSensibility;
+
+            var speed = camera._computeLocalCameraSpeed();
+            var direction = new Vector3(0, 0, speed * this._offsetY / this.moveSensibility);
+
+            Matrix.RotationYawPitchRollToRef(camera.rotation.y, camera.rotation.x, 0, camera._cameraRotationMatrix);
+            camera.cameraDirection.addInPlace(Vector3.TransformCoordinates(direction, camera._cameraRotationMatrix));
+        }
+
+        getTypeName(): string {
+            return "FreeCameraDeviceOrientationInput";
+        }
+        
+        getSimpleName(){
+            return "deviceOrientation";
+        }
+    }
+    
+    CameraInputTypes["FreeCameraDeviceOrientationInput"] = FreeCameraDeviceOrientationInput;
+}

+ 64 - 0
src/Cameras/Inputs/babylon.freecamera.input.gamepad.js

@@ -0,0 +1,64 @@
+var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
+    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
+    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
+    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
+    return c > 3 && r && Object.defineProperty(target, key, r), r;
+};
+var BABYLON;
+(function (BABYLON) {
+    var FreeCameraGamepadInput = (function () {
+        function FreeCameraGamepadInput() {
+            var _this = this;
+            this.gamepadAngularSensibility = 200;
+            this.gamepadMoveSensibility = 40;
+            this._gamepads = new BABYLON.Gamepads(function (gamepad) { _this._onNewGameConnected(gamepad); });
+        }
+        FreeCameraGamepadInput.prototype.attachCamera = function (camera) {
+            this.camera = camera;
+        };
+        FreeCameraGamepadInput.prototype.detach = function () {
+            this._gamepads.dispose();
+        };
+        FreeCameraGamepadInput.prototype.checkInputs = function () {
+            if (this.gamepad) {
+                var camera = this.camera;
+                var LSValues = this.gamepad.leftStick;
+                var normalizedLX = LSValues.x / this.gamepadMoveSensibility;
+                var normalizedLY = LSValues.y / this.gamepadMoveSensibility;
+                LSValues.x = Math.abs(normalizedLX) > 0.005 ? 0 + normalizedLX : 0;
+                LSValues.y = Math.abs(normalizedLY) > 0.005 ? 0 + normalizedLY : 0;
+                var RSValues = this.gamepad.rightStick;
+                var normalizedRX = RSValues.x / this.gamepadAngularSensibility;
+                var normalizedRY = RSValues.y / this.gamepadAngularSensibility;
+                RSValues.x = Math.abs(normalizedRX) > 0.001 ? 0 + normalizedRX : 0;
+                RSValues.y = Math.abs(normalizedRY) > 0.001 ? 0 + normalizedRY : 0;
+                var cameraTransform = BABYLON.Matrix.RotationYawPitchRoll(camera.rotation.y, camera.rotation.x, 0);
+                var speed = camera._computeLocalCameraSpeed() * 50.0;
+                var deltaTransform = BABYLON.Vector3.TransformCoordinates(new BABYLON.Vector3(LSValues.x * speed, 0, -LSValues.y * speed), cameraTransform);
+                camera.cameraDirection = camera.cameraDirection.add(deltaTransform);
+                camera.cameraRotation = camera.cameraRotation.add(new BABYLON.Vector2(RSValues.y, RSValues.x));
+            }
+        };
+        FreeCameraGamepadInput.prototype._onNewGameConnected = function (gamepad) {
+            // Only the first gamepad can control the camera
+            if (gamepad.index === 0) {
+                this.gamepad = gamepad;
+            }
+        };
+        FreeCameraGamepadInput.prototype.getTypeName = function () {
+            return "FreeCameraGamepadInput";
+        };
+        FreeCameraGamepadInput.prototype.getSimpleName = function () {
+            return "gamepad";
+        };
+        __decorate([
+            BABYLON.serialize()
+        ], FreeCameraGamepadInput.prototype, "gamepadAngularSensibility", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], FreeCameraGamepadInput.prototype, "gamepadMoveSensibility", void 0);
+        return FreeCameraGamepadInput;
+    })();
+    BABYLON.FreeCameraGamepadInput = FreeCameraGamepadInput;
+    BABYLON.CameraInputTypes["FreeCameraGamepadInput"] = FreeCameraGamepadInput;
+})(BABYLON || (BABYLON = {}));

+ 67 - 0
src/Cameras/Inputs/babylon.freecamera.input.gamepad.ts

@@ -0,0 +1,67 @@
+module BABYLON {       
+    export class FreeCameraGamepadInput implements ICameraInput<FreeCamera> {
+        camera : FreeCamera;
+        
+        public gamepad: Gamepad;
+        private _gamepads: Gamepads;
+
+        @serialize()
+        public gamepadAngularSensibility = 200;
+
+        @serialize()
+        public gamepadMoveSensibility = 40;
+        
+        constructor(){
+            this._gamepads = new Gamepads((gamepad: Gamepad) => { this._onNewGameConnected(gamepad); });
+        }
+        
+        attachCamera(camera : FreeCamera){
+            this.camera = camera;
+        }
+        
+        detach(){
+            this._gamepads.dispose();
+        }
+        
+        checkInputs(){
+            if (this.gamepad) {
+                var camera = this.camera;
+                var LSValues = this.gamepad.leftStick;
+                var normalizedLX = LSValues.x / this.gamepadMoveSensibility;
+                var normalizedLY = LSValues.y / this.gamepadMoveSensibility;
+                LSValues.x = Math.abs(normalizedLX) > 0.005 ? 0 + normalizedLX : 0;
+                LSValues.y = Math.abs(normalizedLY) > 0.005 ? 0 + normalizedLY : 0;
+
+                var RSValues = this.gamepad.rightStick;
+                var normalizedRX = RSValues.x / this.gamepadAngularSensibility;
+                var normalizedRY = RSValues.y / this.gamepadAngularSensibility;
+                RSValues.x = Math.abs(normalizedRX) > 0.001 ? 0 + normalizedRX : 0;
+                RSValues.y = Math.abs(normalizedRY) > 0.001 ? 0 + normalizedRY : 0;
+
+                var cameraTransform = Matrix.RotationYawPitchRoll(camera.rotation.y, camera.rotation.x, 0);
+
+                var speed = camera._computeLocalCameraSpeed() * 50.0;
+                var deltaTransform = Vector3.TransformCoordinates(new Vector3(LSValues.x * speed, 0, -LSValues.y * speed), cameraTransform);
+                camera.cameraDirection = camera.cameraDirection.add(deltaTransform);
+                camera.cameraRotation = camera.cameraRotation.add(new Vector2(RSValues.y, RSValues.x));
+            }
+        }
+        
+        private _onNewGameConnected(gamepad: Gamepad) {
+            // Only the first gamepad can control the camera
+            if (gamepad.index === 0) {
+                this.gamepad = gamepad;
+            }
+        }
+        
+        getTypeName(): string{
+            return "FreeCameraGamepadInput";
+        }
+        
+        getSimpleName(){
+            return "gamepad";
+        }
+    }
+    
+    CameraInputTypes["FreeCameraGamepadInput"] = FreeCameraGamepadInput;
+}

+ 111 - 0
src/Cameras/Inputs/babylon.freecamera.input.keyboard.js

@@ -0,0 +1,111 @@
+var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
+    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
+    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
+    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
+    return c > 3 && r && Object.defineProperty(target, key, r), r;
+};
+var BABYLON;
+(function (BABYLON) {
+    var FreeCameraKeyboardMoveInput = (function () {
+        function FreeCameraKeyboardMoveInput() {
+            this._keys = [];
+            this.keysUp = [38];
+            this.keysDown = [40];
+            this.keysLeft = [37];
+            this.keysRight = [39];
+        }
+        FreeCameraKeyboardMoveInput.prototype.attachCamera = function (camera) {
+            var _this = this;
+            this.camera = camera;
+            if (this._onKeyDown === undefined) {
+                this._onKeyDown = function (evt) {
+                    if (_this.keysUp.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysDown.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysLeft.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysRight.indexOf(evt.keyCode) !== -1) {
+                        var index = _this._keys.indexOf(evt.keyCode);
+                        if (index === -1) {
+                            _this._keys.push(evt.keyCode);
+                        }
+                        if (!camera._noPreventDefault) {
+                            evt.preventDefault();
+                        }
+                    }
+                };
+                this._onKeyUp = function (evt) {
+                    if (_this.keysUp.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysDown.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysLeft.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysRight.indexOf(evt.keyCode) !== -1) {
+                        var index = _this._keys.indexOf(evt.keyCode);
+                        if (index >= 0) {
+                            _this._keys.splice(index, 1);
+                        }
+                        if (!camera._noPreventDefault) {
+                            evt.preventDefault();
+                        }
+                    }
+                };
+                BABYLON.Tools.RegisterTopRootEvents([
+                    { name: "keydown", handler: this._onKeyDown },
+                    { name: "keyup", handler: this._onKeyUp },
+                    { name: "blur", handler: this._onLostFocus }
+                ]);
+            }
+        };
+        FreeCameraKeyboardMoveInput.prototype.detach = function () {
+            BABYLON.Tools.UnregisterTopRootEvents([
+                { name: "keydown", handler: this._onKeyDown },
+                { name: "keyup", handler: this._onKeyUp },
+                { name: "blur", handler: this._onLostFocus }
+            ]);
+        };
+        FreeCameraKeyboardMoveInput.prototype.checkInputs = function () {
+            var camera = this.camera;
+            // Keyboard
+            for (var index = 0; index < this._keys.length; index++) {
+                var keyCode = this._keys[index];
+                var speed = camera._computeLocalCameraSpeed();
+                if (this.keysLeft.indexOf(keyCode) !== -1) {
+                    camera._localDirection.copyFromFloats(-speed, 0, 0);
+                }
+                else if (this.keysUp.indexOf(keyCode) !== -1) {
+                    camera._localDirection.copyFromFloats(0, 0, speed);
+                }
+                else if (this.keysRight.indexOf(keyCode) !== -1) {
+                    camera._localDirection.copyFromFloats(speed, 0, 0);
+                }
+                else if (this.keysDown.indexOf(keyCode) !== -1) {
+                    camera._localDirection.copyFromFloats(0, 0, -speed);
+                }
+                camera.getViewMatrix().invertToRef(camera._cameraTransformMatrix);
+                BABYLON.Vector3.TransformNormalToRef(camera._localDirection, camera._cameraTransformMatrix, camera._transformedDirection);
+                camera.cameraDirection.addInPlace(camera._transformedDirection);
+            }
+        };
+        FreeCameraKeyboardMoveInput.prototype.getTypeName = function () {
+            return "FreeCameraKeyboardMoveInput";
+        };
+        FreeCameraKeyboardMoveInput.prototype._onLostFocus = function (e) {
+            this._keys = [];
+        };
+        FreeCameraKeyboardMoveInput.prototype.getSimpleName = function () {
+            return "keyboard";
+        };
+        __decorate([
+            BABYLON.serialize()
+        ], FreeCameraKeyboardMoveInput.prototype, "keysUp", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], FreeCameraKeyboardMoveInput.prototype, "keysDown", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], FreeCameraKeyboardMoveInput.prototype, "keysLeft", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], FreeCameraKeyboardMoveInput.prototype, "keysRight", void 0);
+        return FreeCameraKeyboardMoveInput;
+    })();
+    BABYLON.FreeCameraKeyboardMoveInput = FreeCameraKeyboardMoveInput;
+    BABYLON.CameraInputTypes["FreeCameraKeyboardMoveInput"] = FreeCameraKeyboardMoveInput;
+})(BABYLON || (BABYLON = {}));

+ 110 - 0
src/Cameras/Inputs/babylon.freecamera.input.keyboard.ts

@@ -0,0 +1,110 @@
+module BABYLON {
+    export class FreeCameraKeyboardMoveInput implements ICameraInput<FreeCamera> {
+        camera: FreeCamera;
+        private _keys = [];
+        private _onKeyDown: (e: KeyboardEvent) => any;
+        private _onKeyUp: (e: KeyboardEvent) => any;
+
+        @serialize()
+        public keysUp = [38];
+
+        @serialize()
+        public keysDown = [40];
+
+        @serialize()
+        public keysLeft = [37];
+
+        @serialize()
+        public keysRight = [39];
+
+        attachCamera(camera: FreeCamera) {
+            this.camera = camera;
+            
+            if (this._onKeyDown === undefined) {
+
+                this._onKeyDown = evt => {
+                    if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
+                        this.keysDown.indexOf(evt.keyCode) !== -1 ||
+                        this.keysLeft.indexOf(evt.keyCode) !== -1 ||
+                        this.keysRight.indexOf(evt.keyCode) !== -1) {
+                        var index = this._keys.indexOf(evt.keyCode);
+
+                        if (index === -1) {
+                            this._keys.push(evt.keyCode);
+                        }
+                        if (!camera._noPreventDefault) {
+                            evt.preventDefault();
+                        }
+                    }
+                };
+
+                this._onKeyUp = evt => {
+                    if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
+                        this.keysDown.indexOf(evt.keyCode) !== -1 ||
+                        this.keysLeft.indexOf(evt.keyCode) !== -1 ||
+                        this.keysRight.indexOf(evt.keyCode) !== -1) {
+                        var index = this._keys.indexOf(evt.keyCode);
+
+                        if (index >= 0) {
+                            this._keys.splice(index, 1);
+                        }
+                        if (!camera._noPreventDefault) {
+                            evt.preventDefault();
+                        }
+                    }
+                };
+
+                Tools.RegisterTopRootEvents([
+                    { name: "keydown", handler: this._onKeyDown },
+                    { name: "keyup", handler: this._onKeyUp },
+                    { name: "blur", handler: this._onLostFocus }
+                ]);
+            }
+        }
+
+        detach() {
+            Tools.UnregisterTopRootEvents([
+                { name: "keydown", handler: this._onKeyDown },
+                { name: "keyup", handler: this._onKeyUp },
+                { name: "blur", handler: this._onLostFocus }
+            ]);
+        }
+        
+        public checkInputs() {
+            var camera = this.camera;
+            // Keyboard
+            for (var index = 0; index < this._keys.length; index++) {
+                var keyCode = this._keys[index];
+                var speed = camera._computeLocalCameraSpeed();
+
+                if (this.keysLeft.indexOf(keyCode) !== -1) {
+                    camera._localDirection.copyFromFloats(-speed, 0, 0);
+                } else if (this.keysUp.indexOf(keyCode) !== -1) {
+                    camera._localDirection.copyFromFloats(0, 0, speed);
+                } else if (this.keysRight.indexOf(keyCode) !== -1) {
+                    camera._localDirection.copyFromFloats(speed, 0, 0);
+                } else if (this.keysDown.indexOf(keyCode) !== -1) {
+                    camera._localDirection.copyFromFloats(0, 0, -speed);
+                }
+
+                camera.getViewMatrix().invertToRef(camera._cameraTransformMatrix);
+                Vector3.TransformNormalToRef(camera._localDirection, camera._cameraTransformMatrix, camera._transformedDirection);
+                camera.cameraDirection.addInPlace(camera._transformedDirection);
+            }
+        }
+
+        getTypeName(): string {
+            return "FreeCameraKeyboardMoveInput";
+        }
+
+        public _onLostFocus(e: FocusEvent): void {
+            this._keys = [];
+        }
+        
+        getSimpleName(){
+            return "keyboard";
+        }
+    }
+    
+    CameraInputTypes["FreeCameraKeyboardMoveInput"] = FreeCameraKeyboardMoveInput;
+}

+ 102 - 0
src/Cameras/Inputs/babylon.freecamera.input.mouse.js

@@ -0,0 +1,102 @@
+var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
+    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
+    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
+    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
+    return c > 3 && r && Object.defineProperty(target, key, r), r;
+};
+var BABYLON;
+(function (BABYLON) {
+    var FreeCameraMouseInput = (function () {
+        function FreeCameraMouseInput() {
+            this.angularSensibility = 2000.0;
+        }
+        FreeCameraMouseInput.prototype.attachCamera = function (camera) {
+            this.camera = camera;
+        };
+        FreeCameraMouseInput.prototype.attachElement = function (element, noPreventDefault) {
+            var _this = this;
+            var previousPosition;
+            this.attachedElement = element;
+            if (this._onMouseDown === undefined) {
+                var camera = this.camera;
+                var engine = this.camera.getEngine();
+                this._onMouseDown = function (evt) {
+                    previousPosition = {
+                        x: evt.clientX,
+                        y: evt.clientY
+                    };
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                };
+                this._onMouseUp = function (evt) {
+                    previousPosition = null;
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                };
+                this._onMouseOut = function (evt) {
+                    previousPosition = null;
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                };
+                this._onMouseMove = function (evt) {
+                    if (!previousPosition && !engine.isPointerLock) {
+                        return;
+                    }
+                    var offsetX;
+                    var offsetY;
+                    if (!engine.isPointerLock) {
+                        offsetX = evt.clientX - previousPosition.x;
+                        offsetY = evt.clientY - previousPosition.y;
+                    }
+                    else {
+                        offsetX = evt.movementX || evt.mozMovementX || evt.webkitMovementX || evt.msMovementX || 0;
+                        offsetY = evt.movementY || evt.mozMovementY || evt.webkitMovementY || evt.msMovementY || 0;
+                    }
+                    camera.cameraRotation.y += offsetX / _this.angularSensibility;
+                    camera.cameraRotation.x += offsetY / _this.angularSensibility;
+                    previousPosition = {
+                        x: evt.clientX,
+                        y: evt.clientY
+                    };
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                };
+            }
+            element.addEventListener("mousedown", this._onMouseDown, false);
+            element.addEventListener("mouseup", this._onMouseUp, false);
+            element.addEventListener("mouseout", this._onMouseOut, false);
+            element.addEventListener("mousemove", this._onMouseMove, false);
+        };
+        FreeCameraMouseInput.prototype.detachElement = function (element) {
+            if (this.attachedElement !== element) {
+                return;
+            }
+            element.removeEventListener("mousedown", this._onMouseDown);
+            element.removeEventListener("mouseup", this._onMouseUp);
+            element.removeEventListener("mouseout", this._onMouseOut);
+            element.removeEventListener("mousemove", this._onMouseMove);
+            this.attachedElement = null;
+        };
+        FreeCameraMouseInput.prototype.detach = function () {
+            if (this.attachedElement) {
+                this.detachElement(this.attachedElement);
+            }
+        };
+        FreeCameraMouseInput.prototype.getTypeName = function () {
+            return "FreeCameraMouseInput";
+        };
+        FreeCameraMouseInput.prototype.getSimpleName = function () {
+            return "mouse";
+        };
+        __decorate([
+            BABYLON.serialize()
+        ], FreeCameraMouseInput.prototype, "angularSensibility", void 0);
+        return FreeCameraMouseInput;
+    })();
+    BABYLON.FreeCameraMouseInput = FreeCameraMouseInput;
+    BABYLON.CameraInputTypes["FreeCameraMouseInput"] = FreeCameraMouseInput;
+})(BABYLON || (BABYLON = {}));

+ 117 - 0
src/Cameras/Inputs/babylon.freecamera.input.mouse.ts

@@ -0,0 +1,117 @@
+module BABYLON {       
+    export class FreeCameraMouseInput implements ICameraInput<FreeCamera> {
+        camera : FreeCamera;
+        attachedElement : HTMLElement;
+        
+        @serialize()
+        public angularSensibility = 2000.0;
+        
+        private _onMouseDown: (e: MouseEvent) => any;
+        private _onMouseUp: (e: MouseEvent) => any;
+        private _onMouseOut: (e: MouseEvent) => any;
+        private _onMouseMove: (e: MouseEvent) => any;
+        
+        attachCamera(camera : FreeCamera){
+            this.camera = camera;
+        }
+        
+        attachElement(element: HTMLElement, noPreventDefault?: boolean){     
+            var previousPosition;
+            this.attachedElement = element;
+                
+            if (this._onMouseDown === undefined) {
+                var camera = this.camera;
+                var engine = this.camera.getEngine();
+                
+                this._onMouseDown = evt => {
+                    previousPosition = {
+                        x: evt.clientX,
+                        y: evt.clientY
+                    };
+
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                };
+
+                this._onMouseUp = evt => {
+                    previousPosition = null;
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                };
+
+                this._onMouseOut = evt => {
+                    previousPosition = null;
+                    
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                };
+
+                this._onMouseMove = evt => {
+                    if (!previousPosition && !engine.isPointerLock) {
+                        return;
+                    }
+
+                    var offsetX;
+                    var offsetY;
+
+                    if (!engine.isPointerLock) {
+                        offsetX = evt.clientX - previousPosition.x;
+                        offsetY = evt.clientY - previousPosition.y;
+                    } else {
+                        offsetX = evt.movementX || evt.mozMovementX || evt.webkitMovementX || evt.msMovementX || 0;
+                        offsetY = evt.movementY || evt.mozMovementY || evt.webkitMovementY || evt.msMovementY || 0;
+                    }
+
+                    camera.cameraRotation.y += offsetX / this.angularSensibility;
+                    camera.cameraRotation.x += offsetY / this.angularSensibility;
+
+                    previousPosition = {
+                        x: evt.clientX,
+                        y: evt.clientY
+                    };
+                    
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                };
+            }
+
+            element.addEventListener("mousedown", this._onMouseDown, false);
+            element.addEventListener("mouseup", this._onMouseUp, false);
+            element.addEventListener("mouseout", this._onMouseOut, false);
+            element.addEventListener("mousemove", this._onMouseMove, false);
+   
+        }
+        
+        detachElement(element : HTMLElement){   
+            if (this.attachedElement !== element) {
+                return;
+            }
+
+            element.removeEventListener("mousedown", this._onMouseDown);
+            element.removeEventListener("mouseup", this._onMouseUp);
+            element.removeEventListener("mouseout", this._onMouseOut);
+            element.removeEventListener("mousemove", this._onMouseMove); 
+            this.attachedElement = null;        
+        }
+        
+        detach(){          
+            if (this.attachedElement){
+                this.detachElement(this.attachedElement);
+            }  
+        }
+        
+        getTypeName(): string{
+            return "FreeCameraMouseInput";
+        }
+        
+        getSimpleName(){
+            return "mouse";
+        }
+    }
+    
+    CameraInputTypes["FreeCameraMouseInput"] = FreeCameraMouseInput;
+}

+ 139 - 0
src/Cameras/Inputs/babylon.freecamera.input.touch.js

@@ -0,0 +1,139 @@
+var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
+    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
+    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
+    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
+    return c > 3 && r && Object.defineProperty(target, key, r), r;
+};
+var BABYLON;
+(function (BABYLON) {
+    var FreeCameraTouchInput = (function () {
+        function FreeCameraTouchInput() {
+            this._offsetX = null;
+            this._offsetY = null;
+            this._pointerCount = 0;
+            this._pointerPressed = [];
+            this.touchAngularSensibility = 200000.0;
+            this.touchMoveSensibility = 250.0;
+        }
+        FreeCameraTouchInput.prototype.attachCamera = function (camera) {
+            this.camera = camera;
+        };
+        FreeCameraTouchInput.prototype.attachElement = function (element, noPreventDefault) {
+            var _this = this;
+            var previousPosition;
+            if (this._attachedElement) {
+                return;
+            }
+            this._attachedElement = element;
+            if (this._onPointerDown === undefined) {
+                this._onLostFocus = function (evt) {
+                    _this._offsetX = null;
+                    _this._offsetY = null;
+                };
+                this._onPointerDown = function (evt) {
+                    if (evt.pointerType === "mouse") {
+                        return;
+                    }
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                    _this._pointerPressed.push(evt.pointerId);
+                    if (_this._pointerPressed.length !== 1) {
+                        return;
+                    }
+                    previousPosition = {
+                        x: evt.clientX,
+                        y: evt.clientY
+                    };
+                };
+                this._onPointerUp = function (evt) {
+                    if (evt.pointerType === "mouse") {
+                        return;
+                    }
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                    var index = _this._pointerPressed.indexOf(evt.pointerId);
+                    if (index === -1) {
+                        return;
+                    }
+                    _this._pointerPressed.splice(index, 1);
+                    if (index != 0) {
+                        return;
+                    }
+                    previousPosition = null;
+                    _this._offsetX = null;
+                    _this._offsetY = null;
+                };
+                this._onPointerMove = function (evt) {
+                    if (evt.pointerType === "mouse") {
+                        return;
+                    }
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+                    if (!previousPosition) {
+                        return;
+                    }
+                    var index = _this._pointerPressed.indexOf(evt.pointerId);
+                    if (index != 0) {
+                        return;
+                    }
+                    _this._offsetX = evt.clientX - previousPosition.x;
+                    _this._offsetY = -(evt.clientY - previousPosition.y);
+                };
+            }
+            element.addEventListener("blur", this._onLostFocus);
+            element.addEventListener("pointerdown", this._onPointerDown);
+            element.addEventListener("pointerup", this._onPointerUp);
+            element.addEventListener("pointerout", this._onPointerUp);
+            element.addEventListener("pointermove", this._onPointerMove);
+        };
+        FreeCameraTouchInput.prototype.detachElement = function (element) {
+            if (this._attachedElement !== element) {
+                return;
+            }
+            element.removeEventListener("blur", this._onLostFocus);
+            element.removeEventListener("pointerdown", this._onPointerDown);
+            element.removeEventListener("pointerup", this._onPointerUp);
+            element.removeEventListener("pointerout", this._onPointerUp);
+            element.removeEventListener("pointermove", this._onPointerMove);
+            this._attachedElement = null;
+        };
+        FreeCameraTouchInput.prototype.checkInputs = function () {
+            if (this._offsetX) {
+                var camera = this.camera;
+                camera.cameraRotation.y += this._offsetX / this.touchAngularSensibility;
+                if (this._pointerPressed.length > 1) {
+                    camera.cameraRotation.x += -this._offsetY / this.touchAngularSensibility;
+                }
+                else {
+                    var speed = camera._computeLocalCameraSpeed();
+                    var direction = new BABYLON.Vector3(0, 0, speed * this._offsetY / this.touchMoveSensibility);
+                    BABYLON.Matrix.RotationYawPitchRollToRef(camera.rotation.y, camera.rotation.x, 0, camera._cameraRotationMatrix);
+                    camera.cameraDirection.addInPlace(BABYLON.Vector3.TransformCoordinates(direction, camera._cameraRotationMatrix));
+                }
+            }
+        };
+        FreeCameraTouchInput.prototype.detach = function () {
+            if (this._attachedElement) {
+                this.detachElement(this._attachedElement);
+            }
+        };
+        FreeCameraTouchInput.prototype.getTypeName = function () {
+            return "FreeCameraTouchInput";
+        };
+        FreeCameraTouchInput.prototype.getSimpleName = function () {
+            return "touch";
+        };
+        __decorate([
+            BABYLON.serialize()
+        ], FreeCameraTouchInput.prototype, "touchAngularSensibility", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], FreeCameraTouchInput.prototype, "touchMoveSensibility", void 0);
+        return FreeCameraTouchInput;
+    })();
+    BABYLON.FreeCameraTouchInput = FreeCameraTouchInput;
+    BABYLON.CameraInputTypes["FreeCameraTouchInput"] = FreeCameraTouchInput;
+})(BABYLON || (BABYLON = {}));

+ 166 - 0
src/Cameras/Inputs/babylon.freecamera.input.touch.ts

@@ -0,0 +1,166 @@
+module BABYLON {
+    export class FreeCameraTouchInput implements ICameraInput<FreeCamera> {
+        camera: FreeCamera;
+
+        private _offsetX: number = null;
+        private _offsetY: number = null;
+        private _pointerCount: number = 0;
+        private _pointerPressed = [];
+        private _attachedElement: HTMLElement;
+        private _onPointerDown: (e: PointerEvent) => any;
+        private _onPointerUp: (e: PointerEvent) => any;
+        private _onPointerMove: (e: PointerEvent) => any;
+        private _onLostFocus: (e: FocusEvent) => any;
+
+        @serialize()
+        public touchAngularSensibility: number = 200000.0;
+
+        @serialize()
+        public touchMoveSensibility: number = 250.0;
+
+        attachCamera(camera: FreeCamera) {
+            this.camera = camera;
+        }
+        
+        attachElement(element: HTMLElement, noPreventDefault?: boolean) {
+            var previousPosition;
+
+            if (this._attachedElement) {
+                return;
+            }
+
+            this._attachedElement = element;
+
+            if (this._onPointerDown === undefined) {
+                this._onLostFocus = (evt) => {
+                    this._offsetX = null;
+                    this._offsetY = null;
+                }
+                
+                this._onPointerDown = (evt) => {
+
+                    if (evt.pointerType === "mouse") {
+                        return;
+                    }
+
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+
+                    this._pointerPressed.push(evt.pointerId);
+
+                    if (this._pointerPressed.length !== 1) {
+                        return;
+                    }
+
+                    previousPosition = {
+                        x: evt.clientX,
+                        y: evt.clientY
+                    };
+                };
+
+                this._onPointerUp = (evt) => {
+
+                    if (evt.pointerType === "mouse") {
+                        return;
+                    }
+
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+
+                    var index: number = this._pointerPressed.indexOf(evt.pointerId);
+
+                    if (index === -1) {
+                        return;
+                    }
+                    this._pointerPressed.splice(index, 1);
+
+                    if (index != 0) {
+                        return;
+                    }
+                    previousPosition = null;
+                    this._offsetX = null;
+                    this._offsetY = null;
+                };
+
+                this._onPointerMove = (evt) => {
+
+                    if (evt.pointerType === "mouse") {
+                        return;
+                    }
+
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
+
+                    if (!previousPosition) {
+                        return;
+                    }
+
+                    var index: number = this._pointerPressed.indexOf(evt.pointerId);
+
+                    if (index != 0) {
+                        return;
+                    }
+
+                    this._offsetX = evt.clientX - previousPosition.x;
+                    this._offsetY = -(evt.clientY - previousPosition.y);
+                };
+
+
+            }
+            element.addEventListener("blur", this._onLostFocus);
+            element.addEventListener("pointerdown", this._onPointerDown);
+            element.addEventListener("pointerup", this._onPointerUp);
+            element.addEventListener("pointerout", this._onPointerUp);
+            element.addEventListener("pointermove", this._onPointerMove);
+        }
+
+        detachElement(element: HTMLElement) {
+            if (this._attachedElement !== element) {
+                return;
+            }
+
+            element.removeEventListener("blur", this._onLostFocus);
+            element.removeEventListener("pointerdown", this._onPointerDown);
+            element.removeEventListener("pointerup", this._onPointerUp);
+            element.removeEventListener("pointerout", this._onPointerUp);
+            element.removeEventListener("pointermove", this._onPointerMove);
+            this._attachedElement = null;
+        }
+
+        checkInputs() {
+            if (this._offsetX) {
+                var camera = this.camera;
+                camera.cameraRotation.y += this._offsetX / this.touchAngularSensibility;
+
+                if (this._pointerPressed.length > 1) {
+                    camera.cameraRotation.x += -this._offsetY / this.touchAngularSensibility;
+                } else {
+                    var speed = camera._computeLocalCameraSpeed();
+                    var direction = new Vector3(0, 0, speed * this._offsetY / this.touchMoveSensibility);
+
+                    Matrix.RotationYawPitchRollToRef(camera.rotation.y, camera.rotation.x, 0, camera._cameraRotationMatrix);
+                    camera.cameraDirection.addInPlace(Vector3.TransformCoordinates(direction, camera._cameraRotationMatrix));
+                }
+            }
+        }
+
+        detach() {
+            if (this._attachedElement) {
+                this.detachElement(this._attachedElement);
+            }
+        }
+
+        getTypeName(): string {
+            return "FreeCameraTouchInput";
+        }
+        
+        getSimpleName(){
+            return "touch";
+        }
+    }
+    
+    CameraInputTypes["FreeCameraTouchInput"] = FreeCameraTouchInput;
+}

+ 52 - 0
src/Cameras/Inputs/babylon.freecamera.input.virtualjoystick.js

@@ -0,0 +1,52 @@
+var BABYLON;
+(function (BABYLON) {
+    var FreeCameraVirtualJoystickInput = (function () {
+        function FreeCameraVirtualJoystickInput() {
+        }
+        FreeCameraVirtualJoystickInput.prototype.getLeftJoystick = function () {
+            return this._leftjoystick;
+        };
+        FreeCameraVirtualJoystickInput.prototype.getRightJoystick = function () {
+            return this._rightjoystick;
+        };
+        FreeCameraVirtualJoystickInput.prototype.checkInputs = function () {
+            var camera = this.camera;
+            var speed = camera._computeLocalCameraSpeed() * 50;
+            var cameraTransform = BABYLON.Matrix.RotationYawPitchRoll(camera.rotation.y, camera.rotation.x, 0);
+            var deltaTransform = BABYLON.Vector3.TransformCoordinates(new BABYLON.Vector3(this._leftjoystick.deltaPosition.x * speed, this._leftjoystick.deltaPosition.y * speed, this._leftjoystick.deltaPosition.z * speed), cameraTransform);
+            camera.cameraDirection = camera.cameraDirection.add(deltaTransform);
+            camera.cameraRotation = camera.cameraRotation.addVector3(this._rightjoystick.deltaPosition);
+            if (!this._leftjoystick.pressed) {
+                this._leftjoystick.deltaPosition = this._leftjoystick.deltaPosition.scale(0.9);
+            }
+            if (!this._rightjoystick.pressed) {
+                this._rightjoystick.deltaPosition = this._rightjoystick.deltaPosition.scale(0.9);
+            }
+        };
+        FreeCameraVirtualJoystickInput.prototype.attachCamera = function (camera) {
+            this.camera = camera;
+            this._leftjoystick = new BABYLON.VirtualJoystick(true);
+            this._leftjoystick.setAxisForUpDown(BABYLON.JoystickAxis.Z);
+            this._leftjoystick.setAxisForLeftRight(BABYLON.JoystickAxis.X);
+            this._leftjoystick.setJoystickSensibility(0.15);
+            this._rightjoystick = new BABYLON.VirtualJoystick(false);
+            this._rightjoystick.setAxisForUpDown(BABYLON.JoystickAxis.X);
+            this._rightjoystick.setAxisForLeftRight(BABYLON.JoystickAxis.Y);
+            this._rightjoystick.reverseUpDown = true;
+            this._rightjoystick.setJoystickSensibility(0.05);
+            this._rightjoystick.setJoystickColor("yellow");
+        };
+        FreeCameraVirtualJoystickInput.prototype.detach = function () {
+            this._leftjoystick.releaseCanvas();
+        };
+        FreeCameraVirtualJoystickInput.prototype.getTypeName = function () {
+            return "FreeCameraVirtualJoystickInput";
+        };
+        FreeCameraVirtualJoystickInput.prototype.getSimpleName = function () {
+            return "virtualJoystick";
+        };
+        return FreeCameraVirtualJoystickInput;
+    })();
+    BABYLON.FreeCameraVirtualJoystickInput = FreeCameraVirtualJoystickInput;
+    BABYLON.CameraInputTypes["FreeCameraVirtualJoystickInput"] = FreeCameraVirtualJoystickInput;
+})(BABYLON || (BABYLON = {}));

+ 61 - 0
src/Cameras/Inputs/babylon.freecamera.input.virtualjoystick.ts

@@ -0,0 +1,61 @@
+module BABYLON {
+    export class FreeCameraVirtualJoystickInput implements ICameraInput<FreeCamera> {
+        camera: FreeCamera;
+
+        private _leftjoystick: VirtualJoystick;
+        private _rightjoystick: VirtualJoystick;
+        
+        public getLeftJoystick(): VirtualJoystick {
+            return this._leftjoystick;
+        }
+
+        public getRightJoystick(): VirtualJoystick {
+            return this._rightjoystick;
+        }
+
+        public checkInputs() {
+            var camera = this.camera;
+            var speed = camera._computeLocalCameraSpeed() * 50;
+            var cameraTransform = Matrix.RotationYawPitchRoll(camera.rotation.y, camera.rotation.x, 0);
+            var deltaTransform = Vector3.TransformCoordinates(new Vector3(this._leftjoystick.deltaPosition.x * speed, this._leftjoystick.deltaPosition.y * speed, this._leftjoystick.deltaPosition.z * speed), cameraTransform);
+            camera.cameraDirection = camera.cameraDirection.add(deltaTransform);
+            camera.cameraRotation = camera.cameraRotation.addVector3(this._rightjoystick.deltaPosition);
+            
+            if (!this._leftjoystick.pressed) {
+                this._leftjoystick.deltaPosition = this._leftjoystick.deltaPosition.scale(0.9);
+            }
+            if (!this._rightjoystick.pressed) {
+                this._rightjoystick.deltaPosition = this._rightjoystick.deltaPosition.scale(0.9);
+            }
+        }
+        
+        attachCamera(camera: FreeCamera) {
+            this.camera = camera;
+            
+            this._leftjoystick = new VirtualJoystick(true);
+            this._leftjoystick.setAxisForUpDown(JoystickAxis.Z);
+            this._leftjoystick.setAxisForLeftRight(JoystickAxis.X);
+            this._leftjoystick.setJoystickSensibility(0.15);
+            this._rightjoystick = new VirtualJoystick(false);
+            this._rightjoystick.setAxisForUpDown(JoystickAxis.X);
+            this._rightjoystick.setAxisForLeftRight(JoystickAxis.Y);
+            this._rightjoystick.reverseUpDown = true;
+            this._rightjoystick.setJoystickSensibility(0.05);
+            this._rightjoystick.setJoystickColor("yellow");
+        }
+
+        detach() {
+            this._leftjoystick.releaseCanvas();
+        }
+
+        getTypeName(): string {
+            return "FreeCameraVirtualJoystickInput";
+        }
+        
+        getSimpleName(){
+            return "virtualJoystick";
+        }
+    }
+    
+    CameraInputTypes["FreeCameraVirtualJoystickInput"] = FreeCameraVirtualJoystickInput;
+}

+ 43 - 0
src/Cameras/Inputs/babylon.freecamera.input.vrdeviceorientation.js

@@ -0,0 +1,43 @@
+var BABYLON;
+(function (BABYLON) {
+    var FreeCameraVRDeviceOrientationInput = (function () {
+        function FreeCameraVRDeviceOrientationInput() {
+            this._alpha = 0;
+            this._beta = 0;
+            this._gamma = 0;
+            this._deviceOrientationHandler = this._onOrientationEvent.bind(this);
+        }
+        FreeCameraVRDeviceOrientationInput.prototype.attachCamera = function (camera) {
+            this.camera = camera;
+            window.addEventListener("deviceorientation", this._deviceOrientationHandler);
+        };
+        FreeCameraVRDeviceOrientationInput.prototype._onOrientationEvent = function (evt) {
+            var camera = this.camera;
+            this._alpha = +evt.alpha | 0;
+            this._beta = +evt.beta | 0;
+            this._gamma = +evt.gamma | 0;
+            if (this._gamma < 0) {
+                this._gamma = 90 + this._gamma;
+            }
+            else {
+                // Incline it in the correct angle.
+                this._gamma = 270 - this._gamma;
+            }
+            camera.rotation.x = this._gamma / 180.0 * Math.PI;
+            camera.rotation.y = -this._alpha / 180.0 * Math.PI;
+            camera.rotation.z = this._beta / 180.0 * Math.PI;
+        };
+        FreeCameraVRDeviceOrientationInput.prototype.detach = function () {
+            window.removeEventListener("deviceorientation", this._deviceOrientationHandler);
+        };
+        FreeCameraVRDeviceOrientationInput.prototype.getTypeName = function () {
+            return "FreeCameraVRDeviceOrientationInput";
+        };
+        FreeCameraVRDeviceOrientationInput.prototype.getSimpleName = function () {
+            return "VRDeviceOrientation";
+        };
+        return FreeCameraVRDeviceOrientationInput;
+    })();
+    BABYLON.FreeCameraVRDeviceOrientationInput = FreeCameraVRDeviceOrientationInput;
+    BABYLON.CameraInputTypes["FreeCameraVRDeviceOrientationInput"] = FreeCameraVRDeviceOrientationInput;
+})(BABYLON || (BABYLON = {}));

+ 55 - 0
src/Cameras/Inputs/babylon.freecamera.input.vrdeviceorientation.ts

@@ -0,0 +1,55 @@
+module BABYLON {
+    export class FreeCameraVRDeviceOrientationInput implements ICameraInput<FreeCamera> {
+        camera: FreeCamera;
+
+        public _alpha = 0;
+        public _beta = 0;
+        public _gamma = 0;
+    
+        private _offsetOrientation: { yaw: number; pitch: number; roll: number };
+        private _deviceOrientationHandler;
+        
+        constructor() {
+            this._deviceOrientationHandler = this._onOrientationEvent.bind(this);
+        }
+
+        attachCamera(camera: FreeCamera) {
+            this.camera = camera;
+
+            window.addEventListener("deviceorientation", this._deviceOrientationHandler);
+        }
+
+        public _onOrientationEvent(evt: DeviceOrientationEvent): void {
+            var camera = this.camera;
+            this._alpha = +evt.alpha|0;
+            this._beta = +evt.beta|0;
+            this._gamma = +evt.gamma|0;
+
+            if (this._gamma < 0) {
+                this._gamma = 90 + this._gamma;
+            }
+            else {
+                // Incline it in the correct angle.
+                this._gamma = 270 - this._gamma;
+            }
+
+            camera.rotation.x = this._gamma / 180.0 * Math.PI;   
+            camera.rotation.y = -this._alpha / 180.0 * Math.PI;   
+            camera.rotation.z = this._beta / 180.0 * Math.PI;     
+        }
+
+        detach() {
+            window.removeEventListener("deviceorientation", this._deviceOrientationHandler);
+        }
+
+        getTypeName(): string {
+            return "FreeCameraVRDeviceOrientationInput";
+        }
+        
+        getSimpleName(){
+            return "VRDeviceOrientation";
+        }
+    }
+    
+    CameraInputTypes["FreeCameraVRDeviceOrientationInput"] = FreeCameraVRDeviceOrientationInput;
+}

+ 1 - 28
src/Cameras/VR/babylon.vrDeviceOrientationCamera.js

@@ -10,38 +10,11 @@ var BABYLON;
         function VRDeviceOrientationFreeCamera(name, position, scene, compensateDistortion) {
             if (compensateDistortion === void 0) { compensateDistortion = true; }
             _super.call(this, name, position, scene);
-            this._alpha = 0;
-            this._beta = 0;
-            this._gamma = 0;
             var metrics = BABYLON.VRCameraMetrics.GetDefault();
             metrics.compensateDistortion = compensateDistortion;
             this.setCameraRigMode(BABYLON.Camera.RIG_MODE_VR, { vrCameraMetrics: metrics });
-            this._deviceOrientationHandler = this._onOrientationEvent.bind(this);
+            this.inputs.addVRDeviceOrientation();
         }
-        VRDeviceOrientationFreeCamera.prototype._onOrientationEvent = function (evt) {
-            this._alpha = +evt.alpha | 0;
-            this._beta = +evt.beta | 0;
-            this._gamma = +evt.gamma | 0;
-            if (this._gamma < 0) {
-                this._gamma = 90 + this._gamma;
-            }
-            else {
-                // Incline it in the correct angle.
-                this._gamma = 270 - this._gamma;
-            }
-            this.rotation.x = this._gamma / 180.0 * Math.PI;
-            this.rotation.y = -this._alpha / 180.0 * Math.PI;
-            this.rotation.z = this._beta / 180.0 * Math.PI;
-        };
-        VRDeviceOrientationFreeCamera.prototype.attachControl = function (element, noPreventDefault) {
-            _super.prototype.attachControl.call(this, element, noPreventDefault);
-            noPreventDefault = BABYLON.Camera.ForceAttachControlToAlwaysPreventDefault ? false : noPreventDefault;
-            window.addEventListener("deviceorientation", this._deviceOrientationHandler);
-        };
-        VRDeviceOrientationFreeCamera.prototype.detachControl = function (element) {
-            _super.prototype.detachControl.call(this, element);
-            window.removeEventListener("deviceorientation", this._deviceOrientationHandler);
-        };
         VRDeviceOrientationFreeCamera.prototype.getTypeName = function () {
             return "VRDeviceOrientationFreeCamera";
         };

+ 2 - 39
src/Cameras/VR/babylon.vrDeviceOrientationCamera.ts

@@ -1,11 +1,5 @@
 module BABYLON {
-    export class VRDeviceOrientationFreeCamera extends FreeCamera {
-        public _alpha = 0;
-        public _beta = 0;
-        public _gamma = 0;
-    
-        private _offsetOrientation: { yaw: number; pitch: number; roll: number };
-        private _deviceOrientationHandler;
+    export class VRDeviceOrientationFreeCamera extends FreeCamera {        
 
         constructor(name: string, position: Vector3, scene: Scene, compensateDistortion = true) {
             super(name, position, scene);
@@ -14,40 +8,9 @@ module BABYLON {
             metrics.compensateDistortion = compensateDistortion;
             this.setCameraRigMode(Camera.RIG_MODE_VR, { vrCameraMetrics: metrics });
 
-            this._deviceOrientationHandler = this._onOrientationEvent.bind(this);
+            this.inputs.addVRDeviceOrientation();
         }
 
-        public _onOrientationEvent(evt: DeviceOrientationEvent): void {
-            this._alpha = +evt.alpha|0;
-            this._beta = +evt.beta|0;
-            this._gamma = +evt.gamma|0;
-
-            if (this._gamma < 0) {
-                this._gamma = 90 + this._gamma;
-            }
-            else {
-                // Incline it in the correct angle.
-                this._gamma = 270 - this._gamma;
-            }
-
-            this.rotation.x = this._gamma / 180.0 * Math.PI;   
-            this.rotation.y = -this._alpha / 180.0 * Math.PI;   
-            this.rotation.z = this._beta / 180.0 * Math.PI;     
-        }
-
-        public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
-            super.attachControl(element, noPreventDefault);
-
-            noPreventDefault = Camera.ForceAttachControlToAlwaysPreventDefault ? false : noPreventDefault;
-
-            window.addEventListener("deviceorientation", this._deviceOrientationHandler);
-        }
-
-        public detachControl(element: HTMLElement): void {
-            super.detachControl(element);
-
-            window.removeEventListener("deviceorientation", this._deviceOrientationHandler);
-        }
 
         public getTypeName(): string {
             return "VRDeviceOrientationFreeCamera";

+ 195 - 266
src/Cameras/babylon.arcRotateCamera.js

@@ -11,7 +11,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
 };
 var BABYLON;
 (function (BABYLON) {
-    var eventPrefix = BABYLON.Tools.GetPointerPrefix();
+    // var eventPrefix = Tools.GetPointerPrefix();
     var ArcRotateCamera = (function (_super) {
         __extends(ArcRotateCamera, _super);
         function ArcRotateCamera(name, alpha, beta, radius, target, scene) {
@@ -26,27 +26,15 @@ var BABYLON;
             this.upperBetaLimit = Math.PI;
             this.lowerRadiusLimit = null;
             this.upperRadiusLimit = null;
-            this.angularSensibilityX = 1000.0;
-            this.angularSensibilityY = 1000.0;
-            this.wheelPrecision = 3.0;
-            this.pinchPrecision = 2.0;
-            this.panningSensibility = 50.0;
             this.inertialPanningX = 0;
             this.inertialPanningY = 0;
-            this.keysUp = [38];
-            this.keysDown = [40];
-            this.keysLeft = [37];
-            this.keysRight = [39];
+            //-- end properties for backward compatibility for inputs        
             this.zoomOnFactor = 1;
             this.targetScreenOffset = BABYLON.Vector2.Zero();
-            this.pinchInwards = true;
             this.allowUpsideDown = true;
-            this._keys = [];
             this._viewMatrix = new BABYLON.Matrix();
             // Panning
             this.panningAxis = new BABYLON.Vector3(1, 1, 0);
-            this._isRightClick = false;
-            this._isCtrlPushed = false;
             this.checkCollisions = false;
             this.collisionRadius = new BABYLON.Vector3(0.5, 0.5, 0.5);
             this._collider = new BABYLON.Collider();
@@ -98,18 +86,192 @@ var BABYLON;
             this.beta = beta;
             this.radius = radius;
             this.getViewMatrix();
+            this.inputs = new BABYLON.ArcRotateCameraInputsManager(this);
+            this.inputs.addKeyboard().addMouseWheel().addPointers().addGamepad();
         }
         Object.defineProperty(ArcRotateCamera.prototype, "angularSensibility", {
+            //-- 2016-03-08 properties for backward compatibility for inputs
             //deprecated angularSensibility support
             get: function () {
-                BABYLON.Tools.Warn("Warning: angularSensibility is deprecated, use angularSensibilityX and angularSensibilityY instead.");
-                return Math.max(this.angularSensibilityX, this.angularSensibilityY);
+                BABYLON.Tools.Warn("Warning: angularSensibility is deprecated on ArcRotateCamera, use camera.inputs.attached.pointers.angularSensibilityX and camera.inputs.attached.pointers.angularSensibilityY instead.");
+                var pointers = this.inputs.attached["pointers"];
+                if (pointers)
+                    return Math.max(pointers.angularSensibilityX, pointers.angularSensibilityY);
             },
             //deprecated angularSensibility support
             set: function (value) {
-                BABYLON.Tools.Warn("Warning: angularSensibility is deprecated, use angularSensibilityX and angularSensibilityY instead.");
-                this.angularSensibilityX = value;
-                this.angularSensibilityY = value;
+                BABYLON.Tools.Warn("Warning: angularSensibility is deprecated on ArcRotateCamera, use camera.inputs.attached.pointers.angularSensibilityX and camera.inputs.attached.pointers.angularSensibilityY instead.");
+                var pointers = this.inputs.attached["pointers"];
+                if (pointers) {
+                    pointers.angularSensibilityX = value;
+                    pointers.angularSensibilityY = value;
+                }
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(ArcRotateCamera.prototype, "angularSensibilityX", {
+            //deprecated angularSensibilityX support
+            get: function () {
+                BABYLON.Tools.Warn("Warning: angularSensibilityX is deprecated on ArcRotateCamera, use camera.inputs.attached.pointers.angularSensibilityX instead.");
+                var pointers = this.inputs.attached["pointers"];
+                if (pointers)
+                    return pointers.angularSensibilityX;
+            },
+            //deprecated angularSensibilityX support
+            set: function (value) {
+                BABYLON.Tools.Warn("Warning: angularSensibilityX is deprecated on ArcRotateCamera, use camera.inputs.attached.pointers.angularSensibilityX instead.");
+                var pointers = this.inputs.attached["pointers"];
+                if (pointers) {
+                    pointers.angularSensibilityX = value;
+                }
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(ArcRotateCamera.prototype, "angularSensibilityY", {
+            //deprecated angularSensibilityY support
+            get: function () {
+                BABYLON.Tools.Warn("Warning: angularSensibilityY is deprecated on ArcRotateCamera, use camera.inputs.attached.pointers.angularSensibilityY instead.");
+                var pointers = this.inputs.attached["pointers"];
+                if (pointers)
+                    return pointers.angularSensibilityY;
+            },
+            //deprecated angularSensibilityY support
+            set: function (value) {
+                BABYLON.Tools.Warn("Warning: angularSensibilityY is deprecated on ArcRotateCamera, use camera.inputs.attached.pointers.angularSensibilityY instead.");
+                var pointers = this.inputs.attached["pointers"];
+                if (pointers) {
+                    pointers.angularSensibilityY = value;
+                }
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(ArcRotateCamera.prototype, "pinchPrecision", {
+            //deprecated pinchPrecision support
+            get: function () {
+                BABYLON.Tools.Warn("Warning: pinchPrecision is deprecated on ArcRotateCamera, use camera.inputs.attached.pointers.pinchPrecision instead.");
+                var pointers = this.inputs.attached["pointers"];
+                if (pointers)
+                    return pointers.pinchPrecision;
+            },
+            //deprecated pinchPrecision support
+            set: function (value) {
+                BABYLON.Tools.Warn("Warning: pinchPrecision is deprecated on ArcRotateCamera, use camera.inputs.attached.pointers.pinchPrecision instead.");
+                var pointers = this.inputs.attached["pointers"];
+                if (pointers) {
+                    pointers.pinchPrecision = value;
+                }
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(ArcRotateCamera.prototype, "panningSensibility", {
+            //deprecated panningSensibility support
+            get: function () {
+                BABYLON.Tools.Warn("Warning: panningSensibility is deprecated on ArcRotateCamera, use camera.inputs.attached.pointers.panningSensibility instead.");
+                var pointers = this.inputs.attached["pointers"];
+                if (pointers)
+                    return pointers.panningSensibility;
+            },
+            //deprecated pinchPrecision support
+            set: function (value) {
+                BABYLON.Tools.Warn("Warning: panningSensibility is deprecated on ArcRotateCamera, use camera.inputs.attached.pointers.panningSensibility instead.");
+                var pointers = this.inputs.attached["pointers"];
+                if (pointers) {
+                    pointers.panningSensibility = value;
+                }
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(ArcRotateCamera.prototype, "keysUp", {
+            //deprecated
+            get: function () {
+                BABYLON.Tools.Warn("Warning: keysUp is deprecated on ArcRotateCamera, use camera.inputs.attached.keyboard.keysUp instead.");
+                var keyboard = this.inputs.attached["keyboard"];
+                if (keyboard)
+                    return keyboard.keysUp;
+            },
+            //deprecated
+            set: function (value) {
+                BABYLON.Tools.Warn("Warning: keysUp is deprecated on ArcRotateCamera, use camera.inputs.attached.keyboard.keysUp instead.");
+                var keyboard = this.inputs.attached["keyboard"];
+                if (keyboard)
+                    keyboard.keysUp = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(ArcRotateCamera.prototype, "keysDown", {
+            //deprecated
+            get: function () {
+                BABYLON.Tools.Warn("Warning: keysDown is deprecated on ArcRotateCamera, use camera.inputs.attached.keyboard.keysDown instead.");
+                var keyboard = this.inputs.attached["keyboard"];
+                if (keyboard)
+                    return keyboard.keysDown;
+            },
+            //deprecated
+            set: function (value) {
+                BABYLON.Tools.Warn("Warning: keysDown is deprecated on ArcRotateCamera, use camera.inputs.attached.keyboard.keysDown instead.");
+                var keyboard = this.inputs.attached["keyboard"];
+                if (keyboard)
+                    keyboard.keysDown = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(ArcRotateCamera.prototype, "keysLeft", {
+            //deprecated
+            get: function () {
+                BABYLON.Tools.Warn("Warning: keysLeft is deprecated on ArcRotateCamera, use camera.inputs.attached.keyboard.keysLeft instead.");
+                var keyboard = this.inputs.attached["keyboard"];
+                if (keyboard)
+                    return keyboard.keysLeft;
+            },
+            //deprecated
+            set: function (value) {
+                BABYLON.Tools.Warn("Warning: keysLeft is deprecated on ArcRotateCamera, use camera.inputs.attached.keyboard.keysLeft instead.");
+                var keyboard = this.inputs.attached["keyboard"];
+                if (keyboard)
+                    keyboard.keysLeft = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(ArcRotateCamera.prototype, "keysRight", {
+            //deprecated
+            get: function () {
+                BABYLON.Tools.Warn("Warning: keysRight is deprecated on ArcRotateCamera, use camera.inputs.attached.keyboard.keysRight instead.");
+                var keyboard = this.inputs.attached["keyboard"];
+                if (keyboard)
+                    return keyboard.keysRight;
+            },
+            //deprecated
+            set: function (value) {
+                BABYLON.Tools.Warn("Warning: keysRight is deprecated on ArcRotateCamera, use camera.inputs.attached.keyboard.keysRight instead.");
+                var keyboard = this.inputs.attached["keyboard"];
+                if (keyboard)
+                    keyboard.keysRight = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(ArcRotateCamera.prototype, "wheelPrecision", {
+            //deprecated
+            get: function () {
+                BABYLON.Tools.Warn("Warning: wheelPrecision is deprecated on ArcRotateCamera, use camera.inputs.attached.mousewheel.wheelPrecision instead.");
+                var mousewheel = this.inputs.attached["mousewheel"];
+                if (mousewheel)
+                    return mousewheel.wheelPrecision;
+            },
+            //deprecated
+            set: function (value) {
+                BABYLON.Tools.Warn("Warning: wheelPrecision is deprecated on ArcRotateCamera, use camera.inputs.attached.mousewheel.wheelPrecision instead.");
+                var mousewheel = this.inputs.attached["mousewheel"];
+                if (mousewheel)
+                    mousewheel.wheelPrecision = value;
             },
             enumerable: true,
             configurable: true
@@ -153,219 +315,24 @@ var BABYLON;
         ArcRotateCamera.prototype.attachControl = function (element, noPreventDefault, useCtrlForPanning) {
             var _this = this;
             if (useCtrlForPanning === void 0) { useCtrlForPanning = true; }
-            var cacheSoloPointer; // cache pointer object for better perf on camera rotation
-            var previousPinchDistance = 0;
-            var pointers = new BABYLON.SmartCollection();
             if (this._attachedElement) {
                 return;
             }
             this._attachedElement = element;
-            noPreventDefault = BABYLON.Camera.ForceAttachControlToAlwaysPreventDefault ? false : noPreventDefault;
-            var engine = this.getEngine();
-            if (this._onPointerDown === undefined) {
-                this._onPointerDown = function (evt) {
-                    // Manage panning with right click
-                    _this._isRightClick = evt.button === 2;
-                    // manage pointers
-                    pointers.add(evt.pointerId, { x: evt.clientX, y: evt.clientY, type: evt.pointerType });
-                    cacheSoloPointer = pointers.item(evt.pointerId);
-                    if (!noPreventDefault) {
-                        evt.preventDefault();
-                    }
-                };
-                this._onPointerUp = function (evt) {
-                    cacheSoloPointer = null;
-                    previousPinchDistance = 0;
-                    //would be better to use pointers.remove(evt.pointerId) for multitouch gestures, 
-                    //but emptying completly pointers collection is required to fix a bug on iPhone : 
-                    //when changing orientation while pinching camera, one pointer stay pressed forever if we don't release all pointers  
-                    //will be ok to put back pointers.remove(evt.pointerId); when iPhone bug corrected
-                    pointers.empty();
-                    if (!noPreventDefault) {
-                        evt.preventDefault();
-                    }
-                };
-                this._onContextMenu = function (evt) {
-                    evt.preventDefault();
-                };
-                this._onPointerMove = function (evt) {
-                    if (!noPreventDefault) {
-                        evt.preventDefault();
-                    }
-                    switch (pointers.count) {
-                        case 1:
-                            if (_this.panningSensibility !== 0 && ((_this._isCtrlPushed && useCtrlForPanning) || (!useCtrlForPanning && _this._isRightClick))) {
-                                _this.inertialPanningX += -(evt.clientX - cacheSoloPointer.x) / _this.panningSensibility;
-                                _this.inertialPanningY += (evt.clientY - cacheSoloPointer.y) / _this.panningSensibility;
-                            }
-                            else {
-                                var offsetX = evt.clientX - cacheSoloPointer.x;
-                                var offsetY = evt.clientY - cacheSoloPointer.y;
-                                _this.inertialAlphaOffset -= offsetX / _this.angularSensibilityX;
-                                _this.inertialBetaOffset -= offsetY / _this.angularSensibilityY;
-                            }
-                            cacheSoloPointer.x = evt.clientX;
-                            cacheSoloPointer.y = evt.clientY;
-                            break;
-                        case 2:
-                            //if (noPreventDefault) { evt.preventDefault(); } //if pinch gesture, could be usefull to force preventDefault to avoid html page scroll/zoom in some mobile browsers
-                            pointers.item(evt.pointerId).x = evt.clientX;
-                            pointers.item(evt.pointerId).y = evt.clientY;
-                            var direction = _this.pinchInwards ? 1 : -1;
-                            var distX = pointers.getItemByIndex(0).x - pointers.getItemByIndex(1).x;
-                            var distY = pointers.getItemByIndex(0).y - pointers.getItemByIndex(1).y;
-                            var pinchSquaredDistance = (distX * distX) + (distY * distY);
-                            if (previousPinchDistance === 0) {
-                                previousPinchDistance = pinchSquaredDistance;
-                                return;
-                            }
-                            if (pinchSquaredDistance !== previousPinchDistance) {
-                                _this.inertialRadiusOffset += (pinchSquaredDistance - previousPinchDistance) / (_this.pinchPrecision * _this.wheelPrecision * ((_this.angularSensibilityX + _this.angularSensibilityY) / 2) * direction);
-                                previousPinchDistance = pinchSquaredDistance;
-                            }
-                            break;
-                        default:
-                            if (pointers.item(evt.pointerId)) {
-                                pointers.item(evt.pointerId).x = evt.clientX;
-                                pointers.item(evt.pointerId).y = evt.clientY;
-                            }
-                    }
-                };
-                this._onMouseMove = function (evt) {
-                    if (!engine.isPointerLock) {
-                        return;
-                    }
-                    var offsetX = evt.movementX || evt.mozMovementX || evt.webkitMovementX || evt.msMovementX || 0;
-                    var offsetY = evt.movementY || evt.mozMovementY || evt.webkitMovementY || evt.msMovementY || 0;
-                    _this.inertialAlphaOffset -= offsetX / _this.angularSensibilityX;
-                    _this.inertialBetaOffset -= offsetY / _this.angularSensibilityY;
-                    if (!noPreventDefault) {
-                        evt.preventDefault();
-                    }
-                };
-                this._wheel = function (event) {
-                    var delta = 0;
-                    if (event.wheelDelta) {
-                        delta = event.wheelDelta / (_this.wheelPrecision * 40);
-                    }
-                    else if (event.detail) {
-                        delta = -event.detail / _this.wheelPrecision;
-                    }
-                    if (delta)
-                        _this.inertialRadiusOffset += delta;
-                    if (event.preventDefault) {
-                        if (!noPreventDefault) {
-                            event.preventDefault();
-                        }
-                    }
-                };
-                this._onKeyDown = function (evt) {
-                    _this._isCtrlPushed = evt.ctrlKey;
-                    if (_this.keysUp.indexOf(evt.keyCode) !== -1 ||
-                        _this.keysDown.indexOf(evt.keyCode) !== -1 ||
-                        _this.keysLeft.indexOf(evt.keyCode) !== -1 ||
-                        _this.keysRight.indexOf(evt.keyCode) !== -1) {
-                        var index = _this._keys.indexOf(evt.keyCode);
-                        if (index === -1) {
-                            _this._keys.push(evt.keyCode);
-                        }
-                        if (evt.preventDefault) {
-                            if (!noPreventDefault) {
-                                evt.preventDefault();
-                            }
-                        }
-                    }
-                };
-                this._onKeyUp = function (evt) {
-                    _this._isCtrlPushed = evt.ctrlKey;
-                    if (_this.keysUp.indexOf(evt.keyCode) !== -1 ||
-                        _this.keysDown.indexOf(evt.keyCode) !== -1 ||
-                        _this.keysLeft.indexOf(evt.keyCode) !== -1 ||
-                        _this.keysRight.indexOf(evt.keyCode) !== -1) {
-                        var index = _this._keys.indexOf(evt.keyCode);
-                        if (index >= 0) {
-                            _this._keys.splice(index, 1);
-                        }
-                        if (evt.preventDefault) {
-                            if (!noPreventDefault) {
-                                evt.preventDefault();
-                            }
-                        }
-                    }
-                };
-                this._onLostFocus = function () {
-                    _this._keys = [];
-                    pointers.empty();
-                    previousPinchDistance = 0;
-                    cacheSoloPointer = null;
-                };
-                this._onGestureStart = function (e) {
-                    if (window.MSGesture === undefined) {
-                        return;
-                    }
-                    if (!_this._MSGestureHandler) {
-                        _this._MSGestureHandler = new MSGesture();
-                        _this._MSGestureHandler.target = element;
-                    }
-                    _this._MSGestureHandler.addPointer(e.pointerId);
-                };
-                this._onGesture = function (e) {
-                    _this.radius *= e.scale;
-                    if (e.preventDefault) {
-                        if (!noPreventDefault) {
-                            e.stopPropagation();
-                            e.preventDefault();
-                        }
-                    }
-                };
-                this._reset = function () {
-                    _this._keys = [];
-                    _this.inertialAlphaOffset = 0;
-                    _this.inertialBetaOffset = 0;
-                    _this.inertialRadiusOffset = 0;
-                    pointers.empty();
-                    previousPinchDistance = 0;
-                    cacheSoloPointer = null;
-                };
-            }
-            if (!useCtrlForPanning) {
-                element.addEventListener("contextmenu", this._onContextMenu, false);
-            }
-            element.addEventListener(eventPrefix + "down", this._onPointerDown, false);
-            element.addEventListener(eventPrefix + "up", this._onPointerUp, false);
-            element.addEventListener(eventPrefix + "out", this._onPointerUp, false);
-            element.addEventListener(eventPrefix + "move", this._onPointerMove, false);
-            element.addEventListener("mousemove", this._onMouseMove, false);
-            element.addEventListener("MSPointerDown", this._onGestureStart, false);
-            element.addEventListener("MSGestureChange", this._onGesture, false);
-            element.addEventListener('mousewheel', this._wheel, false);
-            element.addEventListener('DOMMouseScroll', this._wheel, false);
-            BABYLON.Tools.RegisterTopRootEvents([
-                { name: "keydown", handler: this._onKeyDown },
-                { name: "keyup", handler: this._onKeyUp },
-                { name: "blur", handler: this._onLostFocus }
-            ]);
+            this._noPreventDefault = noPreventDefault;
+            this._useCtrlForPanning = useCtrlForPanning;
+            this.inputs.attachElement(element, noPreventDefault);
+            this._reset = function () {
+                _this.inertialAlphaOffset = 0;
+                _this.inertialBetaOffset = 0;
+                _this.inertialRadiusOffset = 0;
+            };
         };
         ArcRotateCamera.prototype.detachControl = function (element) {
             if (this._attachedElement !== element) {
                 return;
             }
-            element.removeEventListener("contextmenu", this._onContextMenu);
-            element.removeEventListener(eventPrefix + "down", this._onPointerDown);
-            element.removeEventListener(eventPrefix + "up", this._onPointerUp);
-            element.removeEventListener(eventPrefix + "out", this._onPointerUp);
-            element.removeEventListener(eventPrefix + "move", this._onPointerMove);
-            element.removeEventListener("mousemove", this._onMouseMove);
-            element.removeEventListener("MSPointerDown", this._onGestureStart);
-            element.removeEventListener("MSGestureChange", this._onGesture);
-            element.removeEventListener('mousewheel', this._wheel);
-            element.removeEventListener('DOMMouseScroll', this._wheel);
-            BABYLON.Tools.UnregisterTopRootEvents([
-                { name: "keydown", handler: this._onKeyDown },
-                { name: "keyup", handler: this._onKeyUp },
-                { name: "blur", handler: this._onLostFocus }
-            ]);
-            this._MSGestureHandler = null;
+            this.inputs.detachElement(this._attachedElement);
             this._attachedElement = null;
             if (this._reset) {
                 this._reset();
@@ -376,22 +343,7 @@ var BABYLON;
             if (this._collisionTriggered) {
                 return;
             }
-            // Keyboard
-            for (var index = 0; index < this._keys.length; index++) {
-                var keyCode = this._keys[index];
-                if (this.keysLeft.indexOf(keyCode) !== -1) {
-                    this.inertialAlphaOffset -= 0.01;
-                }
-                else if (this.keysUp.indexOf(keyCode) !== -1) {
-                    this.inertialBetaOffset -= 0.01;
-                }
-                else if (this.keysRight.indexOf(keyCode) !== -1) {
-                    this.inertialAlphaOffset += 0.01;
-                }
-                else if (this.keysDown.indexOf(keyCode) !== -1) {
-                    this.inertialBetaOffset += 0.01;
-                }
-            }
+            this.inputs.checkInputs();
             // Inertia
             if (this.inertialAlphaOffset !== 0 || this.inertialBetaOffset !== 0 || this.inertialRadiusOffset !== 0) {
                 this.alpha += this.beta <= 0 ? -this.inertialAlphaOffset : this.inertialAlphaOffset;
@@ -586,6 +538,10 @@ var BABYLON;
             }
             _super.prototype._updateRigCameras.call(this);
         };
+        ArcRotateCamera.prototype.dispose = function () {
+            this.inputs.clear();
+            _super.prototype.dispose.call(this);
+        };
         ArcRotateCamera.prototype.getTypeName = function () {
             return "ArcRotateCamera";
         };
@@ -630,39 +586,12 @@ var BABYLON;
         ], ArcRotateCamera.prototype, "upperRadiusLimit", void 0);
         __decorate([
             BABYLON.serialize()
-        ], ArcRotateCamera.prototype, "angularSensibilityX", void 0);
-        __decorate([
-            BABYLON.serialize()
-        ], ArcRotateCamera.prototype, "angularSensibilityY", void 0);
-        __decorate([
-            BABYLON.serialize()
-        ], ArcRotateCamera.prototype, "wheelPrecision", void 0);
-        __decorate([
-            BABYLON.serialize()
-        ], ArcRotateCamera.prototype, "pinchPrecision", void 0);
-        __decorate([
-            BABYLON.serialize()
-        ], ArcRotateCamera.prototype, "panningSensibility", void 0);
-        __decorate([
-            BABYLON.serialize()
         ], ArcRotateCamera.prototype, "inertialPanningX", void 0);
         __decorate([
             BABYLON.serialize()
         ], ArcRotateCamera.prototype, "inertialPanningY", void 0);
         __decorate([
             BABYLON.serialize()
-        ], ArcRotateCamera.prototype, "keysUp", void 0);
-        __decorate([
-            BABYLON.serialize()
-        ], ArcRotateCamera.prototype, "keysDown", void 0);
-        __decorate([
-            BABYLON.serialize()
-        ], ArcRotateCamera.prototype, "keysLeft", void 0);
-        __decorate([
-            BABYLON.serialize()
-        ], ArcRotateCamera.prototype, "keysRight", void 0);
-        __decorate([
-            BABYLON.serialize()
         ], ArcRotateCamera.prototype, "zoomOnFactor", void 0);
         __decorate([
             BABYLON.serialize()

+ 191 - 311
src/Cameras/babylon.arcRotateCamera.ts

@@ -1,5 +1,5 @@
 module BABYLON {
-    var eventPrefix = Tools.GetPointerPrefix();
+    // var eventPrefix = Tools.GetPointerPrefix();
 
     export class ArcRotateCamera extends TargetCamera {
         @serialize()
@@ -40,73 +40,202 @@
 
         @serialize()
         public upperRadiusLimit = null;
-
-        @serialize()
-        public angularSensibilityX = 1000.0;
-
-        @serialize()
-        public angularSensibilityY = 1000.0;
-
-        @serialize()
-        public wheelPrecision = 3.0;
-
-        @serialize()
-        public pinchPrecision = 2.0;
-
-        @serialize()
-        public panningSensibility: number = 50.0;
-
+        
         @serialize()
         public inertialPanningX: number = 0;
 
         @serialize()
         public inertialPanningY: number = 0;
 
-        @serialize()
-        public keysUp = [38];
-
-        @serialize()
-        public keysDown = [40];
-
-        @serialize()
-        public keysLeft = [37];
-
-        @serialize()
-        public keysRight = [39];
+        //-- 2016-03-08 properties for backward compatibility for inputs
+        //deprecated angularSensibility support
+        public get angularSensibility() {
+            Tools.Warn("Warning: angularSensibility is deprecated on ArcRotateCamera, use camera.inputs.attached.pointers.angularSensibilityX and camera.inputs.attached.pointers.angularSensibilityY instead.");
+            var pointers = <ArcRotateCameraPointersInput>this.inputs.attached["pointers"];
+            if (pointers)
+                return Math.max(pointers.angularSensibilityX, pointers.angularSensibilityY);
+        }
+        
+        //deprecated angularSensibility support
+        public set angularSensibility(value) {
+            Tools.Warn("Warning: angularSensibility is deprecated on ArcRotateCamera, use camera.inputs.attached.pointers.angularSensibilityX and camera.inputs.attached.pointers.angularSensibilityY instead.");
+            var pointers = <ArcRotateCameraPointersInput>this.inputs.attached["pointers"];
+            if (pointers){
+                pointers.angularSensibilityX = value;
+                pointers.angularSensibilityY = value;
+            }
+        }
+        
+        //deprecated angularSensibilityX support
+        public get angularSensibilityX() {
+            Tools.Warn("Warning: angularSensibilityX is deprecated on ArcRotateCamera, use camera.inputs.attached.pointers.angularSensibilityX instead.");
+            var pointers = <ArcRotateCameraPointersInput>this.inputs.attached["pointers"];
+            if (pointers)
+                return pointers.angularSensibilityX;
+        }
+        
+        //deprecated angularSensibilityX support
+        public set angularSensibilityX(value) {
+            Tools.Warn("Warning: angularSensibilityX is deprecated on ArcRotateCamera, use camera.inputs.attached.pointers.angularSensibilityX instead.");
+            var pointers = <ArcRotateCameraPointersInput>this.inputs.attached["pointers"];
+            if (pointers){
+                pointers.angularSensibilityX = value;
+            }
+        }
+        
+        //deprecated angularSensibilityY support
+        public get angularSensibilityY() {
+            Tools.Warn("Warning: angularSensibilityY is deprecated on ArcRotateCamera, use camera.inputs.attached.pointers.angularSensibilityY instead.");
+            var pointers = <ArcRotateCameraPointersInput>this.inputs.attached["pointers"];
+            if (pointers)
+                return pointers.angularSensibilityY;
+        }
+        
+        //deprecated angularSensibilityY support
+        public set angularSensibilityY(value) {
+            Tools.Warn("Warning: angularSensibilityY is deprecated on ArcRotateCamera, use camera.inputs.attached.pointers.angularSensibilityY instead.");
+            var pointers = <ArcRotateCameraPointersInput>this.inputs.attached["pointers"];
+            if (pointers){
+                pointers.angularSensibilityY = value;
+            }
+        }
+        
+        //deprecated pinchPrecision support
+        public get pinchPrecision() {
+            Tools.Warn("Warning: pinchPrecision is deprecated on ArcRotateCamera, use camera.inputs.attached.pointers.pinchPrecision instead.");
+            var pointers = <ArcRotateCameraPointersInput>this.inputs.attached["pointers"];
+            if (pointers)
+                return pointers.pinchPrecision;
+        }
+        
+        //deprecated pinchPrecision support
+        public set pinchPrecision(value) {
+            Tools.Warn("Warning: pinchPrecision is deprecated on ArcRotateCamera, use camera.inputs.attached.pointers.pinchPrecision instead.");
+            var pointers = <ArcRotateCameraPointersInput>this.inputs.attached["pointers"];
+            if (pointers){
+                pointers.pinchPrecision = value;
+            }
+        }
+        
+        //deprecated panningSensibility support
+        public get panningSensibility() {
+            Tools.Warn("Warning: panningSensibility is deprecated on ArcRotateCamera, use camera.inputs.attached.pointers.panningSensibility instead.");
+            var pointers = <ArcRotateCameraPointersInput>this.inputs.attached["pointers"];
+            if (pointers)
+                return pointers.panningSensibility;
+        }
+        
+        //deprecated pinchPrecision support
+        public set panningSensibility(value) {
+            Tools.Warn("Warning: panningSensibility is deprecated on ArcRotateCamera, use camera.inputs.attached.pointers.panningSensibility instead.");
+            var pointers = <ArcRotateCameraPointersInput>this.inputs.attached["pointers"];
+            if (pointers){
+                pointers.panningSensibility = value;
+            }
+        }
+        
+        //deprecated
+        public get keysUp() {
+            Tools.Warn("Warning: keysUp is deprecated on ArcRotateCamera, use camera.inputs.attached.keyboard.keysUp instead.");
+            var keyboard = <ArcRotateCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
+            if (keyboard)
+                return keyboard.keysUp;
+        }
+        
+        //deprecated
+        public set keysUp(value) {
+            Tools.Warn("Warning: keysUp is deprecated on ArcRotateCamera, use camera.inputs.attached.keyboard.keysUp instead.");
+            var keyboard = <ArcRotateCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
+            if (keyboard)
+                keyboard.keysUp = value;
+        }
+        
+        //deprecated
+        public get keysDown() {
+            Tools.Warn("Warning: keysDown is deprecated on ArcRotateCamera, use camera.inputs.attached.keyboard.keysDown instead.");
+            var keyboard = <ArcRotateCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
+            if (keyboard)
+                return keyboard.keysDown;
+        }
+        
+        //deprecated
+        public set keysDown(value) {
+            Tools.Warn("Warning: keysDown is deprecated on ArcRotateCamera, use camera.inputs.attached.keyboard.keysDown instead.");
+            var keyboard = <ArcRotateCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
+            if (keyboard)
+                keyboard.keysDown = value;
+        }
+        
+        //deprecated
+        public get keysLeft() {
+            Tools.Warn("Warning: keysLeft is deprecated on ArcRotateCamera, use camera.inputs.attached.keyboard.keysLeft instead.");
+            var keyboard = <ArcRotateCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
+            if (keyboard)
+                return keyboard.keysLeft;
+        }
+        
+        //deprecated
+        public set keysLeft(value) {
+            Tools.Warn("Warning: keysLeft is deprecated on ArcRotateCamera, use camera.inputs.attached.keyboard.keysLeft instead.");
+            var keyboard = <ArcRotateCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
+            if (keyboard)
+                keyboard.keysLeft = value;
+        }
+        
+        //deprecated
+        public get keysRight() {
+            Tools.Warn("Warning: keysRight is deprecated on ArcRotateCamera, use camera.inputs.attached.keyboard.keysRight instead.");
+            var keyboard = <ArcRotateCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
+            if (keyboard)
+                return keyboard.keysRight;
+        }
+        
+        //deprecated
+        public set keysRight(value) {
+            Tools.Warn("Warning: keysRight is deprecated on ArcRotateCamera, use camera.inputs.attached.keyboard.keysRight instead.");
+            var keyboard = <ArcRotateCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
+            if (keyboard)
+                keyboard.keysRight = value;
+        }
+        
+        //deprecated
+        public get wheelPrecision() {
+            Tools.Warn("Warning: wheelPrecision is deprecated on ArcRotateCamera, use camera.inputs.attached.mousewheel.wheelPrecision instead.");
+            var mousewheel = <ArcRotateCameraMouseWheelInput>this.inputs.attached["mousewheel"];
+            if (mousewheel)
+                return mousewheel.wheelPrecision;
+        }
+        
+        //deprecated
+        public set wheelPrecision(value) {
+            Tools.Warn("Warning: wheelPrecision is deprecated on ArcRotateCamera, use camera.inputs.attached.mousewheel.wheelPrecision instead.");
+            var mousewheel = <ArcRotateCameraMouseWheelInput>this.inputs.attached["mousewheel"];
+            if (mousewheel)
+                mousewheel.wheelPrecision = value;
+        }
+        
+        //-- end properties for backward compatibility for inputs        
 
         @serialize()
         public zoomOnFactor = 1;
 
         public targetScreenOffset = Vector2.Zero();
-        public pinchInwards = true;
-
+        
         @serialize()
         public allowUpsideDown = true;
 
-        private _keys = [];
         public _viewMatrix = new Matrix();
-        private _attachedElement: HTMLElement;
-
-        private _onContextMenu: (e: PointerEvent) => void;
-        private _onPointerDown: (e: PointerEvent) => void;
-        private _onPointerUp: (e: PointerEvent) => void;
-        private _onPointerMove: (e: PointerEvent) => void;
-        private _wheel: (e: MouseWheelEvent) => void;
-        private _onMouseMove: (e: MouseEvent) => any;
-        private _onKeyDown: (e: KeyboardEvent) => any;
-        private _onKeyUp: (e: KeyboardEvent) => any;
-        private _onLostFocus: (e: FocusEvent) => any;
+        public _attachedElement: HTMLElement;
+        public _noPreventDefault : boolean;
+        public _useCtrlForPanning : boolean;
+        public inputs : ArcRotateCameraInputsManager;
+        
         public _reset: () => void;
-        private _onGestureStart: (e: PointerEvent) => void;
-        private _onGesture: (e: MSGestureEvent) => void;
-        private _MSGestureHandler: MSGesture;
-
+        
         // Panning
         public panningAxis: Vector3 = new Vector3(1, 1, 0);
         private _localDirection: Vector3;
         private _transformedDirection: Vector3;
-        private _isRightClick: boolean = false;
-        private _isCtrlPushed: boolean = false;
 
         // Collisions
         public onCollide: (collidedMesh: AbstractMesh) => void;
@@ -122,19 +251,6 @@
         //due to async collision inspection
         private _collisionTriggered: boolean;
         
-        //deprecated angularSensibility support
-        public get angularSensibility() {
-            Tools.Warn("Warning: angularSensibility is deprecated, use angularSensibilityX and angularSensibilityY instead.");
-            return Math.max(this.angularSensibilityX, this.angularSensibilityY);
-        }
-        
-        //deprecated angularSensibility support
-        public set angularSensibility(value) {
-            Tools.Warn("Warning: angularSensibility is deprecated, use angularSensibilityX and angularSensibilityY instead.");
-            this.angularSensibilityX = value;
-            this.angularSensibilityY = value;
-        }
-
         constructor(name: string, alpha: number, beta: number, radius: number, target: Vector3, scene: Scene) {
             super(name, Vector3.Zero(), scene);
 
@@ -149,6 +265,8 @@
             this.radius = radius;
 
             this.getViewMatrix();
+            this.inputs = new ArcRotateCameraInputsManager(this);
+            this.inputs.addKeyboard().addMouseWheel().addPointers().addGamepad();
         }
 
         // Cache
@@ -195,236 +313,21 @@
 
         // Methods
         public attachControl(element: HTMLElement, noPreventDefault?: boolean, useCtrlForPanning: boolean = true): void {
-            var cacheSoloPointer; // cache pointer object for better perf on camera rotation
-            var previousPinchDistance = 0;
-            var pointers = new SmartCollection();
-
             if (this._attachedElement) {
                 return;
             }
             this._attachedElement = element;
+            this._noPreventDefault = noPreventDefault;
+            this._useCtrlForPanning = useCtrlForPanning;
 
-            noPreventDefault = Camera.ForceAttachControlToAlwaysPreventDefault ? false : noPreventDefault;
-
-            var engine = this.getEngine();
-
-            if (this._onPointerDown === undefined) {
-                this._onPointerDown = evt => {
-                    // Manage panning with right click
-                    this._isRightClick = evt.button === 2;
-
-                    // manage pointers
-                    pointers.add(evt.pointerId, { x: evt.clientX, y: evt.clientY, type: evt.pointerType });
-                    cacheSoloPointer = pointers.item(evt.pointerId);
-                    if (!noPreventDefault) {
-                        evt.preventDefault();
-                    }
-                };
-
-                this._onPointerUp = evt => {
-                    cacheSoloPointer = null;
-                    previousPinchDistance = 0;
-                    
-                    //would be better to use pointers.remove(evt.pointerId) for multitouch gestures, 
-                    //but emptying completly pointers collection is required to fix a bug on iPhone : 
-                    //when changing orientation while pinching camera, one pointer stay pressed forever if we don't release all pointers  
-                    //will be ok to put back pointers.remove(evt.pointerId); when iPhone bug corrected
-                    pointers.empty();
-
-                    if (!noPreventDefault) {
-                        evt.preventDefault();
-                    }
-                };
-
-                this._onContextMenu = evt => {
-                    evt.preventDefault();
-                };
-
-                this._onPointerMove = evt => {
-                    if (!noPreventDefault) {
-                        evt.preventDefault();
-                    }
-
-                    switch (pointers.count) {
-
-                        case 1: //normal camera rotation
-                            if (this.panningSensibility !== 0 && ((this._isCtrlPushed && useCtrlForPanning) || (!useCtrlForPanning && this._isRightClick))) {
-                                this.inertialPanningX += -(evt.clientX - cacheSoloPointer.x) / this.panningSensibility;
-                                this.inertialPanningY += (evt.clientY - cacheSoloPointer.y) / this.panningSensibility;
-                            } else {
-                                var offsetX = evt.clientX - cacheSoloPointer.x;
-                                var offsetY = evt.clientY - cacheSoloPointer.y;
-                                this.inertialAlphaOffset -= offsetX / this.angularSensibilityX;
-                                this.inertialBetaOffset -= offsetY / this.angularSensibilityY;
-                            }
-                            cacheSoloPointer.x = evt.clientX;
-                            cacheSoloPointer.y = evt.clientY;
-                            break;
-
-                        case 2: //pinch
-                            //if (noPreventDefault) { evt.preventDefault(); } //if pinch gesture, could be usefull to force preventDefault to avoid html page scroll/zoom in some mobile browsers
-                            pointers.item(evt.pointerId).x = evt.clientX;
-                            pointers.item(evt.pointerId).y = evt.clientY;
-                            var direction = this.pinchInwards ? 1 : -1;
-                            var distX = pointers.getItemByIndex(0).x - pointers.getItemByIndex(1).x;
-                            var distY = pointers.getItemByIndex(0).y - pointers.getItemByIndex(1).y;
-                            var pinchSquaredDistance = (distX * distX) + (distY * distY);
-                            if (previousPinchDistance === 0) {
-                                previousPinchDistance = pinchSquaredDistance;
-                                return;
-                            }
-
-                            if (pinchSquaredDistance !== previousPinchDistance) {
-                                this.inertialRadiusOffset += (pinchSquaredDistance - previousPinchDistance) / (this.pinchPrecision * this.wheelPrecision * ((this.angularSensibilityX + this.angularSensibilityY) / 2) * direction);
-                                previousPinchDistance = pinchSquaredDistance;
-                            }
-                            break;
-
-                        default:
-                            if (pointers.item(evt.pointerId)) {
-                                pointers.item(evt.pointerId).x = evt.clientX;
-                                pointers.item(evt.pointerId).y = evt.clientY;
-                            }
-                    }
-                };
-
-                this._onMouseMove = evt => {
-                    if (!engine.isPointerLock) {
-                        return;
-                    }
-
-                    var offsetX = evt.movementX || evt.mozMovementX || evt.webkitMovementX || evt.msMovementX || 0;
-                    var offsetY = evt.movementY || evt.mozMovementY || evt.webkitMovementY || evt.msMovementY || 0;
-
-                    this.inertialAlphaOffset -= offsetX / this.angularSensibilityX;
-                    this.inertialBetaOffset -= offsetY / this.angularSensibilityY;
-
-                    if (!noPreventDefault) {
-                        evt.preventDefault();
-                    }
-                };
-
-                this._wheel = event => {
-                    var delta = 0;
-                    if (event.wheelDelta) {
-                        delta = event.wheelDelta / (this.wheelPrecision * 40);
-                    } else if (event.detail) {
-                        delta = -event.detail / this.wheelPrecision;
-                    }
-
-                    if (delta)
-                        this.inertialRadiusOffset += delta;
-
-                    if (event.preventDefault) {
-                        if (!noPreventDefault) {
-                            event.preventDefault();
-                        }
-                    }
-                };
-
-                this._onKeyDown = evt => {
-                    this._isCtrlPushed = evt.ctrlKey;
-                    if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
-                        this.keysDown.indexOf(evt.keyCode) !== -1 ||
-                        this.keysLeft.indexOf(evt.keyCode) !== -1 ||
-                        this.keysRight.indexOf(evt.keyCode) !== -1) {
-                        var index = this._keys.indexOf(evt.keyCode);
-
-                        if (index === -1) {
-                            this._keys.push(evt.keyCode);
-                        }
-
-                        if (evt.preventDefault) {
-                            if (!noPreventDefault) {
-                                evt.preventDefault();
-                            }
-                        }
-                    }
-                };
-
-                this._onKeyUp = evt => {
-                    this._isCtrlPushed = evt.ctrlKey;
-                    if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
-                        this.keysDown.indexOf(evt.keyCode) !== -1 ||
-                        this.keysLeft.indexOf(evt.keyCode) !== -1 ||
-                        this.keysRight.indexOf(evt.keyCode) !== -1) {
-                        var index = this._keys.indexOf(evt.keyCode);
-
-                        if (index >= 0) {
-                            this._keys.splice(index, 1);
-                        }
-
-                        if (evt.preventDefault) {
-                            if (!noPreventDefault) {
-                                evt.preventDefault();
-                            }
-                        }
-                    }
-                };
-
-                this._onLostFocus = () => {
-                    this._keys = [];
-                    pointers.empty();
-                    previousPinchDistance = 0;
-                    cacheSoloPointer = null;
-                };
-
-                this._onGestureStart = e => {
-                    if (window.MSGesture === undefined) {
-                        return;
-                    }
-
-                    if (!this._MSGestureHandler) {
-                        this._MSGestureHandler = new MSGesture();
-                        this._MSGestureHandler.target = element;
-                    }
-
-                    this._MSGestureHandler.addPointer(e.pointerId);
-                };
-
-                this._onGesture = e => {
-                    this.radius *= e.scale;
-
-
-                    if (e.preventDefault) {
-                        if (!noPreventDefault) {
-                            e.stopPropagation();
-                            e.preventDefault();
-                        }
-                    }
-                };
+            this.inputs.attachElement(element, noPreventDefault);
+            
 
                 this._reset = () => {
-                    this._keys = [];
                     this.inertialAlphaOffset = 0;
                     this.inertialBetaOffset = 0;
                     this.inertialRadiusOffset = 0;
-                    pointers.empty();
-                    previousPinchDistance = 0;
-                    cacheSoloPointer = null;
                 };
-
-
-            }
-
-            if (!useCtrlForPanning) {
-                element.addEventListener("contextmenu", this._onContextMenu, false);
-            }
-            element.addEventListener(eventPrefix + "down", this._onPointerDown, false);
-            element.addEventListener(eventPrefix + "up", this._onPointerUp, false);
-            element.addEventListener(eventPrefix + "out", this._onPointerUp, false);
-            element.addEventListener(eventPrefix + "move", this._onPointerMove, false);
-            element.addEventListener("mousemove", this._onMouseMove, false);
-            element.addEventListener("MSPointerDown", this._onGestureStart, false);
-            element.addEventListener("MSGestureChange", this._onGesture, false);
-            element.addEventListener('mousewheel', this._wheel, false);
-            element.addEventListener('DOMMouseScroll', this._wheel, false);
-
-            Tools.RegisterTopRootEvents([
-                { name: "keydown", handler: this._onKeyDown },
-                { name: "keyup", handler: this._onKeyUp },
-                { name: "blur", handler: this._onLostFocus }
-            ]);
         }
 
         public detachControl(element: HTMLElement): void {
@@ -432,24 +335,7 @@
                 return;
             }
 
-            element.removeEventListener("contextmenu", this._onContextMenu);
-            element.removeEventListener(eventPrefix + "down", this._onPointerDown);
-            element.removeEventListener(eventPrefix + "up", this._onPointerUp);
-            element.removeEventListener(eventPrefix + "out", this._onPointerUp);
-            element.removeEventListener(eventPrefix + "move", this._onPointerMove);
-            element.removeEventListener("mousemove", this._onMouseMove);
-            element.removeEventListener("MSPointerDown", this._onGestureStart);
-            element.removeEventListener("MSGestureChange", this._onGesture);
-            element.removeEventListener('mousewheel', this._wheel);
-            element.removeEventListener('DOMMouseScroll', this._wheel);
-
-            Tools.UnregisterTopRootEvents([
-                { name: "keydown", handler: this._onKeyDown },
-                { name: "keyup", handler: this._onKeyUp },
-                { name: "blur", handler: this._onLostFocus }
-            ]);
-
-            this._MSGestureHandler = null;
+            this.inputs.detachElement(this._attachedElement);
             this._attachedElement = null;
 
             if (this._reset) {
@@ -462,19 +348,8 @@
             if (this._collisionTriggered) {
                 return;
             }
-            // Keyboard
-            for (var index = 0; index < this._keys.length; index++) {
-                var keyCode = this._keys[index];
-                if (this.keysLeft.indexOf(keyCode) !== -1) {
-                    this.inertialAlphaOffset -= 0.01;
-                } else if (this.keysUp.indexOf(keyCode) !== -1) {
-                    this.inertialBetaOffset -= 0.01;
-                } else if (this.keysRight.indexOf(keyCode) !== -1) {
-                    this.inertialAlphaOffset += 0.01;
-                } else if (this.keysDown.indexOf(keyCode) !== -1) {
-                    this.inertialBetaOffset += 0.01;
-                }
-            }			
+            
+            this.inputs.checkInputs();            
 			
             // Inertia
             if (this.inertialAlphaOffset !== 0 || this.inertialBetaOffset !== 0 || this.inertialRadiusOffset !== 0) {
@@ -742,6 +617,11 @@
             super._updateRigCameras();
         }
 
+        public dispose(): void {
+            this.inputs.clear();
+            super.dispose();
+        }
+        
         public getTypeName(): string {
             return "ArcRotateCamera";
         }

+ 38 - 0
src/Cameras/babylon.arcRotateCameraInputsManager.js

@@ -0,0 +1,38 @@
+var __extends = (this && this.__extends) || function (d, b) {
+    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
+    function __() { this.constructor = d; }
+    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+};
+var BABYLON;
+(function (BABYLON) {
+    var ArcRotateCameraInputsManager = (function (_super) {
+        __extends(ArcRotateCameraInputsManager, _super);
+        function ArcRotateCameraInputsManager(camera) {
+            _super.call(this, camera);
+        }
+        ArcRotateCameraInputsManager.prototype.add = function (input) {
+            _super.prototype.add.call(this, input);
+            if (this.camera._attachedElement && input.attachElement) {
+                input.attachElement(this.camera._attachedElement, this.camera._noPreventDefault);
+            }
+        };
+        ArcRotateCameraInputsManager.prototype.addMouseWheel = function () {
+            this.add(new BABYLON.ArcRotateCameraMouseWheelInput());
+            return this;
+        };
+        ArcRotateCameraInputsManager.prototype.addPointers = function () {
+            this.add(new BABYLON.ArcRotateCameraPointersInput());
+            return this;
+        };
+        ArcRotateCameraInputsManager.prototype.addKeyboard = function () {
+            this.add(new BABYLON.ArcRotateCameraKeyboardMoveInput());
+            return this;
+        };
+        ArcRotateCameraInputsManager.prototype.addGamepad = function () {
+            this.add(new BABYLON.ArcRotateCameraGamepadInput());
+            return this;
+        };
+        return ArcRotateCameraInputsManager;
+    })(BABYLON.CameraInputsManager);
+    BABYLON.ArcRotateCameraInputsManager = ArcRotateCameraInputsManager;
+})(BABYLON || (BABYLON = {}));

+ 34 - 0
src/Cameras/babylon.arcRotateCameraInputsManager.ts

@@ -0,0 +1,34 @@
+module BABYLON {
+    export class ArcRotateCameraInputsManager extends CameraInputsManager<ArcRotateCamera> {
+        constructor(camera : ArcRotateCamera){
+            super(camera);    
+        }
+        
+        add(input: ICameraInput<ArcRotateCamera>){
+            super.add(input);
+            if (this.camera._attachedElement && input.attachElement) {
+                input.attachElement(this.camera._attachedElement, this.camera._noPreventDefault);
+            }
+        }
+        
+        public addMouseWheel(){
+            this.add(new ArcRotateCameraMouseWheelInput());
+            return this;
+        }
+        
+        public addPointers(){
+            this.add(new ArcRotateCameraPointersInput());
+            return this;
+        }
+        
+        public addKeyboard(){
+            this.add(new ArcRotateCameraKeyboardMoveInput());
+            return this;
+        }
+        
+        public addGamepad(){
+            this.add(new ArcRotateCameraGamepadInput());
+            return this;
+        }
+    }
+}

+ 7 - 0
src/Cameras/babylon.camera.js

@@ -475,6 +475,9 @@ var BABYLON;
             if (this.parent) {
                 serializationObject.parentId = this.parent.id;
             }
+            if (this.inputs) {
+                this.inputs.serialize(serializationObject);
+            }
             // Animations
             BABYLON.Animation.AppendSerializedAnimations(this, serializationObject);
             serializationObject.ranges = this.serializeAnimationRanges();
@@ -538,6 +541,10 @@ var BABYLON;
             if (parsedCamera.parentId) {
                 camera._waitingParentId = parsedCamera.parentId;
             }
+            //Input manager
+            if (parsedCamera.inputs) {
+                camera.inputs.parse(parsedCamera);
+            }
             // Target
             if (parsedCamera.target) {
                 if (camera.setTarget) {

+ 11 - 0
src/Cameras/babylon.camera.ts

@@ -1,5 +1,7 @@
 module BABYLON {
     export class Camera extends Node {
+        public inputs : CameraInputsManager<Camera>;
+        
         // Statics
         private static _PERSPECTIVE_CAMERA = 0;
         private static _ORTHOGRAPHIC_CAMERA = 1;
@@ -585,6 +587,10 @@
             if (this.parent) {
                 serializationObject.parentId = this.parent.id;
             }
+            
+            if (this.inputs){
+                this.inputs.serialize(serializationObject);
+            }
             // Animations
             Animation.AppendSerializedAnimations(this, serializationObject);
             serializationObject.ranges = this.serializeAnimationRanges();
@@ -653,6 +659,11 @@
             if (parsedCamera.parentId) {
                 camera._waitingParentId = parsedCamera.parentId;
             }
+            
+            //Input manager
+            if (parsedCamera.inputs){
+                camera.inputs.parse(parsedCamera);
+            }
 
             // Target
             if (parsedCamera.target) {

+ 97 - 0
src/Cameras/babylon.cameraInputsManager.js

@@ -0,0 +1,97 @@
+var BABYLON;
+(function (BABYLON) {
+    BABYLON.CameraInputTypes = {};
+    var CameraInputsManager = (function () {
+        function CameraInputsManager(camera) {
+            this.attached = {};
+            this.camera = camera;
+            this.checkInputs = function () { };
+        }
+        CameraInputsManager.prototype.add = function (input) {
+            var type = input.getSimpleName();
+            if (this.attached[type]) {
+                BABYLON.Tools.Warn("camera input of type " + type + " already exists on camera");
+                return;
+            }
+            this.attached[type] = input;
+            input.attachCamera(this.camera);
+            //for checkInputs, we are dynamically creating a function
+            //the goal is to avoid the performance penalty of looping for inputs in the render loop
+            if (input.checkInputs) {
+                this.checkInputs = this._addCheckInputs(input.checkInputs.bind(input));
+            }
+        };
+        CameraInputsManager.prototype._addCheckInputs = function (fn) {
+            var current = this.checkInputs;
+            return function () {
+                current();
+                fn();
+            };
+        };
+        CameraInputsManager.prototype.attachElement = function (element, noPreventDefault) {
+            for (var cam in this.attached) {
+                var input = this.attached[cam];
+                if (input.attachElement)
+                    this.attached[cam].attachElement(element, noPreventDefault);
+            }
+        };
+        CameraInputsManager.prototype.detachElement = function (element) {
+            for (var cam in this.attached) {
+                var input = this.attached[cam];
+                if (input.detachElement)
+                    this.attached[cam].detachElement(element);
+            }
+        };
+        CameraInputsManager.prototype.rebuildInputCheck = function (element) {
+            this.checkInputs = function () { };
+            for (var cam in this.attached) {
+                var input = this.attached[cam];
+                if (input.checkInputs) {
+                    this.checkInputs = this._addCheckInputs(input.checkInputs.bind(input));
+                }
+            }
+        };
+        CameraInputsManager.prototype.clear = function () {
+            for (var cam in this.attached) {
+                this.attached[cam].detach();
+            }
+            this.attached = {};
+            this.checkInputs = function () { };
+        };
+        CameraInputsManager.prototype.serialize = function (serializedCamera) {
+            var inputs = {};
+            for (var cam in this.attached) {
+                var input = this.attached[cam];
+                var res = BABYLON.SerializationHelper.Serialize(input, serializedCamera);
+                inputs[input.getTypeName()] = res;
+            }
+            serializedCamera.inputsmgr = inputs;
+        };
+        CameraInputsManager.prototype.parse = function (parsedCamera) {
+            var parsedInputs = parsedCamera.inputsmgr;
+            if (parsedInputs) {
+                this.clear();
+                for (var n in parsedInputs) {
+                    var construct = BABYLON.CameraInputTypes[n];
+                    if (construct) {
+                        var parsedinput = parsedInputs[n];
+                        var input = BABYLON.SerializationHelper.Parse(function () { return new construct(); }, parsedinput, null);
+                        this.add(input);
+                    }
+                }
+            }
+            else {
+                //2016-03-08 this part is for managing backward compatibility
+                for (var n in this.attached) {
+                    var construct = BABYLON.CameraInputTypes[this.attached[n].getTypeName()];
+                    if (construct) {
+                        var input = BABYLON.SerializationHelper.Parse(function () { return new construct(); }, parsedCamera, null);
+                        this.add(input);
+                    }
+                }
+            }
+        };
+        return CameraInputsManager;
+    })();
+    BABYLON.CameraInputsManager = CameraInputsManager;
+})(BABYLON || (BABYLON = {}));

+ 132 - 0
src/Cameras/babylon.cameraInputsManager.ts

@@ -0,0 +1,132 @@
+module BABYLON {
+    export var CameraInputTypes = {};
+    
+    export interface ICameraInput<TCamera extends BABYLON.Camera> {
+        camera: TCamera;
+        attachCamera(camera: TCamera);
+        detach();        
+        getTypeName(): string;
+        getSimpleName(): string;
+        
+        attachElement? : (element: HTMLElement, noPreventDefault?: boolean) => void;
+        detachElement? : (element: HTMLElement) => void;
+        checkInputs?: () => void;
+    }
+
+    export interface CameraInputsMap<TCamera extends BABYLON.Camera> {
+        [name: string]: ICameraInput<TCamera>;
+        [idx: number]: ICameraInput<TCamera>;
+    }
+
+    export class CameraInputsManager<TCamera extends BABYLON.Camera> {
+        attached: CameraInputsMap<TCamera>;
+        camera: TCamera;
+        checkInputs: () => void;
+
+        constructor(camera: TCamera) {
+            this.attached = {};
+            this.camera = camera;
+            this.checkInputs = () => { };
+        }
+
+        public add(input: ICameraInput<TCamera>) {
+            var type = input.getSimpleName();
+            if (this.attached[type]) {
+                Tools.Warn("camera input of type " + type + " already exists on camera");
+                return;
+            }
+
+            this.attached[type] = input;
+            input.attachCamera(this.camera);
+            
+            //for checkInputs, we are dynamically creating a function
+            //the goal is to avoid the performance penalty of looping for inputs in the render loop
+            if (input.checkInputs) {
+                this.checkInputs = this._addCheckInputs(input.checkInputs.bind(input));
+            }
+        }
+        
+        private _addCheckInputs(fn){
+            var current = this.checkInputs;
+            return () => {
+                current();
+                fn();
+            }
+        }
+
+        public attachElement(element: HTMLElement, noPreventDefault?: boolean) {
+            for (var cam in this.attached) {
+                var input = this.attached[cam];
+                if (input.attachElement)
+                    this.attached[cam].attachElement(element, noPreventDefault);
+            }
+        }
+
+        public detachElement(element: HTMLElement) {
+            for (var cam in this.attached) {
+                var input = this.attached[cam];
+                if (input.detachElement)
+                    this.attached[cam].detachElement(element);
+            }
+        }
+
+        public rebuildInputCheck(element: HTMLElement) {
+            this.checkInputs = () => { };
+
+            for (var cam in this.attached) {
+                var input = this.attached[cam];
+                if (input.checkInputs) {
+                    this.checkInputs = this._addCheckInputs(input.checkInputs.bind(input));
+                }
+            }
+        }
+
+        public clear() {
+            for (var cam in this.attached) {
+                this.attached[cam].detach();
+            }
+
+            this.attached = {};
+            this.checkInputs = () => { };
+        }
+        
+        public serialize(serializedCamera){
+            var inputs = {};
+            for (var cam in this.attached) {
+                var input = this.attached[cam];
+                var res = SerializationHelper.Serialize(input, serializedCamera);
+                inputs[input.getTypeName()] = res;
+            }
+            
+            serializedCamera.inputsmgr = inputs;
+        }
+        
+        public parse(parsedCamera){
+            var parsedInputs = parsedCamera.inputsmgr;
+            if (parsedInputs){
+                this.clear();
+                
+                for (var n in parsedInputs) {
+                    var construct = CameraInputTypes[n];
+                    if (construct){
+                        var parsedinput = parsedInputs[n];
+                        var input = SerializationHelper.Parse(() => { return new construct() }, parsedinput, null);
+                        this.add(input as any);
+                    }
+                }
+            } else { 
+                //2016-03-08 this part is for managing backward compatibility
+                for (var n in this.attached) {                    
+                    var construct = CameraInputTypes[this.attached[n].getTypeName()];
+                    if (construct){                        
+                        var input = SerializationHelper.Parse(() => { return new construct() }, parsedCamera, null);
+                        this.add(input as any);
+                    }
+                }
+            }
+        }
+        
+    }
+    
+    
+} 

+ 39 - 67
src/Cameras/babylon.deviceOrientationCamera.js

@@ -3,84 +3,56 @@ var __extends = (this && this.__extends) || function (d, b) {
     function __() { this.constructor = d; }
     d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
 };
-var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
-    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
-    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
-    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
-    return c > 3 && r && Object.defineProperty(target, key, r), r;
-};
 var BABYLON;
 (function (BABYLON) {
     // We're mainly based on the logic defined into the FreeCamera code
     var DeviceOrientationCamera = (function (_super) {
         __extends(DeviceOrientationCamera, _super);
+        //-- end properties for backward compatibility for inputs
         function DeviceOrientationCamera(name, position, scene) {
-            var _this = this;
             _super.call(this, name, position, scene);
-            this._offsetX = null;
-            this._offsetY = null;
-            this._orientationGamma = 0;
-            this._orientationBeta = 0;
-            this._initialOrientationGamma = 0;
-            this._initialOrientationBeta = 0;
-            this.angularSensibility = 10000.0;
-            this.moveSensibility = 50.0;
-            window.addEventListener("resize", function () {
-                _this._initialOrientationGamma = null;
-            }, false);
+            this.inputs.addDeviceOrientation();
         }
-        DeviceOrientationCamera.prototype.attachControl = function (canvas, noPreventDefault) {
-            var _this = this;
-            if (this._attachedCanvas) {
-                return;
-            }
-            this._attachedCanvas = canvas;
-            noPreventDefault = BABYLON.Camera.ForceAttachControlToAlwaysPreventDefault ? false : noPreventDefault;
-            if (!this._orientationChanged) {
-                this._orientationChanged = function (evt) {
-                    if (!_this._initialOrientationGamma) {
-                        _this._initialOrientationGamma = evt.gamma;
-                        _this._initialOrientationBeta = evt.beta;
-                    }
-                    _this._orientationGamma = evt.gamma;
-                    _this._orientationBeta = evt.beta;
-                    _this._offsetY = (_this._initialOrientationBeta - _this._orientationBeta);
-                    _this._offsetX = (_this._initialOrientationGamma - _this._orientationGamma);
-                };
-            }
-            window.addEventListener("deviceorientation", this._orientationChanged);
-        };
-        DeviceOrientationCamera.prototype.detachControl = function (canvas) {
-            if (this._attachedCanvas !== canvas) {
-                return;
-            }
-            window.removeEventListener("deviceorientation", this._orientationChanged);
-            this._attachedCanvas = null;
-            this._orientationGamma = 0;
-            this._orientationBeta = 0;
-            this._initialOrientationGamma = 0;
-            this._initialOrientationBeta = 0;
-        };
-        DeviceOrientationCamera.prototype._checkInputs = function () {
-            if (!this._offsetX) {
-                return;
-            }
-            this.cameraRotation.y -= this._offsetX / this.angularSensibility;
-            var speed = this._computeLocalCameraSpeed();
-            var direction = new BABYLON.Vector3(0, 0, speed * this._offsetY / this.moveSensibility);
-            BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, 0, this._cameraRotationMatrix);
-            this.cameraDirection.addInPlace(BABYLON.Vector3.TransformCoordinates(direction, this._cameraRotationMatrix));
-            _super.prototype._checkInputs.call(this);
-        };
+        Object.defineProperty(DeviceOrientationCamera.prototype, "angularSensibility", {
+            //-- 2016-03-08 properties for backward compatibility for inputs
+            //deprecated
+            get: function () {
+                BABYLON.Tools.Warn("Warning: angularSensibility is deprecated on DeviceOrientationCamera, use camera.inputs.attached.deviceOrientation.angularSensibility instead.");
+                var gamepad = this.inputs.attached["deviceOrientation"];
+                if (gamepad)
+                    return gamepad.angularSensibility;
+            },
+            //deprecated
+            set: function (value) {
+                BABYLON.Tools.Warn("Warning: angularSensibility is deprecated on DeviceOrientationCamera, use camera.inputs.attached.deviceOrientation.angularSensibility instead.");
+                var gamepad = this.inputs.attached["deviceOrientation"];
+                if (gamepad)
+                    gamepad.angularSensibility = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(DeviceOrientationCamera.prototype, "moveSensibility", {
+            //deprecated
+            get: function () {
+                BABYLON.Tools.Warn("Warning: moveSensibility is deprecated on DeviceOrientationCamera, use camera.inputs.attached.deviceOrientation.moveSensibility instead.");
+                var gamepad = this.inputs.attached["deviceOrientation"];
+                if (gamepad)
+                    return gamepad.moveSensibility;
+            },
+            //deprecated
+            set: function (value) {
+                BABYLON.Tools.Warn("Warning: moveSensibility is deprecated on DeviceOrientationCamera, use camera.inputs.attached.deviceOrientation.moveSensibility instead.");
+                var gamepad = this.inputs.attached["deviceOrientation"];
+                if (gamepad)
+                    gamepad.moveSensibility = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
         DeviceOrientationCamera.prototype.getTypeName = function () {
             return "DeviceOrientationCamera";
         };
-        __decorate([
-            BABYLON.serialize()
-        ], DeviceOrientationCamera.prototype, "angularSensibility", void 0);
-        __decorate([
-            BABYLON.serialize()
-        ], DeviceOrientationCamera.prototype, "moveSensibility", void 0);
         return DeviceOrientationCamera;
     })(BABYLON.FreeCamera);
     BABYLON.DeviceOrientationCamera = DeviceOrientationCamera;

+ 34 - 73
src/Cameras/babylon.deviceOrientationCamera.ts

@@ -1,82 +1,43 @@
 module BABYLON {
     // We're mainly based on the logic defined into the FreeCamera code
     export class DeviceOrientationCamera extends FreeCamera {
-        private _offsetX: number = null;
-        private _offsetY: number = null;
-        private _orientationGamma: number = 0;
-        private _orientationBeta: number = 0;
-        private _initialOrientationGamma: number = 0;
-        private _initialOrientationBeta: number = 0;
-        private _attachedCanvas: HTMLCanvasElement;
-        private _orientationChanged: (e: DeviceOrientationEvent) => any;
-
-        @serialize()
-        public angularSensibility: number = 10000.0;
-
-        @serialize()
-        public moveSensibility: number = 50.0;
-
-        constructor(name: string, position: Vector3, scene: Scene) {
-            super(name, position, scene);
-
-            window.addEventListener("resize", () => {
-                this._initialOrientationGamma = null;
-            }, false);
+        //-- 2016-03-08 properties for backward compatibility for inputs
+        //deprecated
+        public get angularSensibility() {
+            Tools.Warn("Warning: angularSensibility is deprecated on DeviceOrientationCamera, use camera.inputs.attached.deviceOrientation.angularSensibility instead.");
+            var gamepad = <FreeCameraDeviceOrientationInput>this.inputs.attached["deviceOrientation"];
+            if (gamepad)
+                return gamepad.angularSensibility;
         }
-
-        public attachControl(canvas: HTMLCanvasElement, noPreventDefault?: boolean): void {
-            if (this._attachedCanvas) {
-                return;
-            }
-            this._attachedCanvas = canvas;
-            noPreventDefault = Camera.ForceAttachControlToAlwaysPreventDefault ? false : noPreventDefault;
-
-            if (!this._orientationChanged) {
-                this._orientationChanged = (evt) => {
-
-                    if (!this._initialOrientationGamma) {
-                            this._initialOrientationGamma = evt.gamma;
-                            this._initialOrientationBeta = evt.beta;
-                    }
-
-                    this._orientationGamma = evt.gamma;
-                    this._orientationBeta = evt.beta;
- 
-                    this._offsetY = (this._initialOrientationBeta - this._orientationBeta);
-                    this._offsetX = (this._initialOrientationGamma - this._orientationGamma);
-                };
-            }
-
-            window.addEventListener("deviceorientation", this._orientationChanged);
+        
+        //deprecated
+        public set angularSensibility(value) {
+            Tools.Warn("Warning: angularSensibility is deprecated on DeviceOrientationCamera, use camera.inputs.attached.deviceOrientation.angularSensibility instead.");
+            var gamepad = <FreeCameraDeviceOrientationInput>this.inputs.attached["deviceOrientation"];
+            if (gamepad)
+                gamepad.angularSensibility = value;
         }
-
-        public detachControl(canvas: HTMLCanvasElement): void {
-            if (this._attachedCanvas !== canvas) {
-                return;
-            }
-
-            window.removeEventListener("deviceorientation", this._orientationChanged);
-
-            this._attachedCanvas = null;
-            this._orientationGamma = 0;
-            this._orientationBeta = 0;
-            this._initialOrientationGamma = 0;
-            this._initialOrientationBeta = 0;
+        
+        //deprecated
+        public get moveSensibility() {
+            Tools.Warn("Warning: moveSensibility is deprecated on DeviceOrientationCamera, use camera.inputs.attached.deviceOrientation.moveSensibility instead.");
+            var gamepad = <FreeCameraDeviceOrientationInput>this.inputs.attached["deviceOrientation"];
+            if (gamepad)
+                return gamepad.moveSensibility;
         }
-
-        public _checkInputs(): void {
-            if (!this._offsetX) {
-                return;
-            }
-            this.cameraRotation.y -= this._offsetX / this.angularSensibility;
-
-            var speed = this._computeLocalCameraSpeed();
-            var direction = new Vector3(0, 0, speed * this._offsetY / this.moveSensibility);
-
-            Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, 0, this._cameraRotationMatrix);
-            this.cameraDirection.addInPlace(Vector3.TransformCoordinates(direction, this._cameraRotationMatrix));
-
-            super._checkInputs();
+        
+        //deprecated
+        public set moveSensibility(value) {
+            Tools.Warn("Warning: moveSensibility is deprecated on DeviceOrientationCamera, use camera.inputs.attached.deviceOrientation.moveSensibility instead.");
+            var gamepad = <FreeCameraDeviceOrientationInput>this.inputs.attached["deviceOrientation"];
+            if (gamepad)
+                gamepad.moveSensibility = value;
+        }
+        //-- end properties for backward compatibility for inputs
+        
+        constructor(name: string, position: Vector3, scene: Scene) {
+            super(name, position, scene);
+            this.inputs.addDeviceOrientation();
         }
 
         public getTypeName(): string {

+ 103 - 150
src/Cameras/babylon.freeCamera.js

@@ -17,14 +17,8 @@ var BABYLON;
             var _this = this;
             _super.call(this, name, position, scene);
             this.ellipsoid = new BABYLON.Vector3(0.5, 1, 0.5);
-            this.keysUp = [38];
-            this.keysDown = [40];
-            this.keysLeft = [37];
-            this.keysRight = [39];
             this.checkCollisions = false;
             this.applyGravity = false;
-            this.angularSensibility = 2000.0;
-            this._keys = [];
             this._collider = new BABYLON.Collider();
             this._needMoveForGravity = false;
             this._oldPosition = BABYLON.Vector3.Zero();
@@ -48,129 +42,118 @@ var BABYLON;
                 };
                 updatePosition(newPosition);
             };
+            this.inputs = new BABYLON.FreeCameraInputsManager(this);
+            this.inputs.addKeyboard().addMouse();
         }
-        FreeCamera.prototype._onLostFocus = function (e) {
-            this._keys = [];
-        };
+        Object.defineProperty(FreeCamera.prototype, "angularSensibility", {
+            //-- 2016-03-08 properties for backward compatibility for inputs
+            //deprecated
+            get: function () {
+                BABYLON.Tools.Warn("Warning: angularSensibility is deprecated on FreeCamera, use camera.inputs.attached.mouse.angularSensibility instead.");
+                var mouse = this.inputs.attached["mouse"];
+                if (mouse)
+                    return mouse.angularSensibility;
+            },
+            //deprecated
+            set: function (value) {
+                BABYLON.Tools.Warn("Warning: angularSensibility is deprecated on FreeCamera, use camera.inputs.attached.mouse.angularSensibility instead.");
+                var mouse = this.inputs.attached["mouse"];
+                if (mouse)
+                    mouse.angularSensibility = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(FreeCamera.prototype, "keysUp", {
+            //deprecated
+            get: function () {
+                BABYLON.Tools.Warn("Warning: keysUp is deprecated on FreeCamera, use camera.inputs.attached.keyboard.keysUp instead.");
+                var keyboard = this.inputs.attached["keyboard"];
+                if (keyboard)
+                    return keyboard.keysUp;
+            },
+            //deprecated
+            set: function (value) {
+                BABYLON.Tools.Warn("Warning: keysUp is deprecated on FreeCamera, use camera.inputs.attached.keyboard.keysUp instead.");
+                var keyboard = this.inputs.attached["keyboard"];
+                if (keyboard)
+                    keyboard.keysUp = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(FreeCamera.prototype, "keysDown", {
+            //deprecated
+            get: function () {
+                BABYLON.Tools.Warn("Warning: keysDown is deprecated on FreeCamera, use camera.inputs.attached.keyboard.keysDown instead.");
+                var keyboard = this.inputs.attached["keyboard"];
+                if (keyboard)
+                    return keyboard.keysDown;
+            },
+            //deprecated
+            set: function (value) {
+                BABYLON.Tools.Warn("Warning: keysDown is deprecated on FreeCamera, use camera.inputs.attached.keyboard.keysDown instead.");
+                var keyboard = this.inputs.attached["keyboard"];
+                if (keyboard)
+                    keyboard.keysDown = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(FreeCamera.prototype, "keysLeft", {
+            //deprecated
+            get: function () {
+                BABYLON.Tools.Warn("Warning: keysLeft is deprecated on FreeCamera, use camera.inputs.attached.keyboard.keysLeft instead.");
+                var keyboard = this.inputs.attached["keyboard"];
+                if (keyboard)
+                    return keyboard.keysLeft;
+            },
+            //deprecated
+            set: function (value) {
+                BABYLON.Tools.Warn("Warning: keysLeft is deprecated on FreeCamera, use camera.inputs.attached.keyboard.keysLeft instead.");
+                var keyboard = this.inputs.attached["keyboard"];
+                if (keyboard)
+                    keyboard.keysLeft = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(FreeCamera.prototype, "keysRight", {
+            //deprecated
+            get: function () {
+                BABYLON.Tools.Warn("Warning: keysRight is deprecated on FreeCamera, use camera.inputs.attached.keyboard.keysRight instead.");
+                var keyboard = this.inputs.attached["keyboard"];
+                if (keyboard)
+                    return keyboard.keysRight;
+            },
+            //deprecated
+            set: function (value) {
+                BABYLON.Tools.Warn("Warning: keysRight is deprecated on FreeCamera, use camera.inputs.attached.keyboard.keysRight instead.");
+                var keyboard = this.inputs.attached["keyboard"];
+                if (keyboard)
+                    keyboard.keysRight = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
         // Controls
         FreeCamera.prototype.attachControl = function (element, noPreventDefault) {
-            var _this = this;
-            var previousPosition;
-            var engine = this.getEngine();
             if (this._attachedElement) {
                 return;
             }
+            this._noPreventDefault = noPreventDefault;
             this._attachedElement = element;
             noPreventDefault = BABYLON.Camera.ForceAttachControlToAlwaysPreventDefault ? false : noPreventDefault;
-            if (this._onMouseDown === undefined) {
-                this._onMouseDown = function (evt) {
-                    previousPosition = {
-                        x: evt.clientX,
-                        y: evt.clientY
-                    };
-                    if (!noPreventDefault) {
-                        evt.preventDefault();
-                    }
-                };
-                this._onMouseUp = function (evt) {
-                    previousPosition = null;
-                    if (!noPreventDefault) {
-                        evt.preventDefault();
-                    }
-                };
-                this._onMouseOut = function (evt) {
-                    previousPosition = null;
-                    _this._keys = [];
-                    if (!noPreventDefault) {
-                        evt.preventDefault();
-                    }
-                };
-                this._onMouseMove = function (evt) {
-                    if (!previousPosition && !engine.isPointerLock) {
-                        return;
-                    }
-                    var offsetX;
-                    var offsetY;
-                    if (!engine.isPointerLock) {
-                        offsetX = evt.clientX - previousPosition.x;
-                        offsetY = evt.clientY - previousPosition.y;
-                    }
-                    else {
-                        offsetX = evt.movementX || evt.mozMovementX || evt.webkitMovementX || evt.msMovementX || 0;
-                        offsetY = evt.movementY || evt.mozMovementY || evt.webkitMovementY || evt.msMovementY || 0;
-                    }
-                    _this.cameraRotation.y += offsetX / _this.angularSensibility;
-                    _this.cameraRotation.x += offsetY / _this.angularSensibility;
-                    previousPosition = {
-                        x: evt.clientX,
-                        y: evt.clientY
-                    };
-                    if (!noPreventDefault) {
-                        evt.preventDefault();
-                    }
-                };
-                this._onKeyDown = function (evt) {
-                    if (_this.keysUp.indexOf(evt.keyCode) !== -1 ||
-                        _this.keysDown.indexOf(evt.keyCode) !== -1 ||
-                        _this.keysLeft.indexOf(evt.keyCode) !== -1 ||
-                        _this.keysRight.indexOf(evt.keyCode) !== -1) {
-                        var index = _this._keys.indexOf(evt.keyCode);
-                        if (index === -1) {
-                            _this._keys.push(evt.keyCode);
-                        }
-                        if (!noPreventDefault) {
-                            evt.preventDefault();
-                        }
-                    }
-                };
-                this._onKeyUp = function (evt) {
-                    if (_this.keysUp.indexOf(evt.keyCode) !== -1 ||
-                        _this.keysDown.indexOf(evt.keyCode) !== -1 ||
-                        _this.keysLeft.indexOf(evt.keyCode) !== -1 ||
-                        _this.keysRight.indexOf(evt.keyCode) !== -1) {
-                        var index = _this._keys.indexOf(evt.keyCode);
-                        if (index >= 0) {
-                            _this._keys.splice(index, 1);
-                        }
-                        if (!noPreventDefault) {
-                            evt.preventDefault();
-                        }
-                    }
-                };
-                this._reset = function () {
-                    _this._keys = [];
-                    previousPosition = null;
-                    _this.cameraDirection = new BABYLON.Vector3(0, 0, 0);
-                    _this.cameraRotation = new BABYLON.Vector2(0, 0);
-                };
-            }
-            element.addEventListener("mousedown", this._onMouseDown, false);
-            element.addEventListener("mouseup", this._onMouseUp, false);
-            element.addEventListener("mouseout", this._onMouseOut, false);
-            element.addEventListener("mousemove", this._onMouseMove, false);
-            BABYLON.Tools.RegisterTopRootEvents([
-                { name: "keydown", handler: this._onKeyDown },
-                { name: "keyup", handler: this._onKeyUp },
-                { name: "blur", handler: this._onLostFocus }
-            ]);
+            this.inputs.attachElement(element, noPreventDefault);
         };
         FreeCamera.prototype.detachControl = function (element) {
             if (this._attachedElement !== element) {
                 return;
             }
-            element.removeEventListener("mousedown", this._onMouseDown);
-            element.removeEventListener("mouseup", this._onMouseUp);
-            element.removeEventListener("mouseout", this._onMouseOut);
-            element.removeEventListener("mousemove", this._onMouseMove);
-            BABYLON.Tools.UnregisterTopRootEvents([
-                { name: "keydown", handler: this._onKeyDown },
-                { name: "keyup", handler: this._onKeyUp },
-                { name: "blur", handler: this._onLostFocus }
-            ]);
+            this.inputs.detachElement(this._attachedElement);
             this._attachedElement = null;
-            if (this._reset) {
-                this._reset();
-            }
+            this.cameraDirection = new BABYLON.Vector3(0, 0, 0);
+            this.cameraRotation = new BABYLON.Vector2(0, 0);
         };
         FreeCamera.prototype._collideWithWorld = function (velocity) {
             var globalPosition;
@@ -196,26 +179,7 @@ var BABYLON;
                 this._localDirection = BABYLON.Vector3.Zero();
                 this._transformedDirection = BABYLON.Vector3.Zero();
             }
-            // Keyboard
-            for (var index = 0; index < this._keys.length; index++) {
-                var keyCode = this._keys[index];
-                var speed = this._computeLocalCameraSpeed();
-                if (this.keysLeft.indexOf(keyCode) !== -1) {
-                    this._localDirection.copyFromFloats(-speed, 0, 0);
-                }
-                else if (this.keysUp.indexOf(keyCode) !== -1) {
-                    this._localDirection.copyFromFloats(0, 0, speed);
-                }
-                else if (this.keysRight.indexOf(keyCode) !== -1) {
-                    this._localDirection.copyFromFloats(speed, 0, 0);
-                }
-                else if (this.keysDown.indexOf(keyCode) !== -1) {
-                    this._localDirection.copyFromFloats(0, 0, -speed);
-                }
-                this.getViewMatrix().invertToRef(this._cameraTransformMatrix);
-                BABYLON.Vector3.TransformNormalToRef(this._localDirection, this._cameraTransformMatrix, this._transformedDirection);
-                this.cameraDirection.addInPlace(this._transformedDirection);
-            }
+            this.inputs.checkInputs();
             _super.prototype._checkInputs.call(this);
         };
         FreeCamera.prototype._decideIfNeedsToMove = function () {
@@ -229,6 +193,10 @@ var BABYLON;
                 this.position.addInPlace(this.cameraDirection);
             }
         };
+        FreeCamera.prototype.dispose = function () {
+            this.inputs.clear();
+            _super.prototype.dispose.call(this);
+        };
         FreeCamera.prototype.getTypeName = function () {
             return "FreeCamera";
         };
@@ -237,25 +205,10 @@ var BABYLON;
         ], FreeCamera.prototype, "ellipsoid", void 0);
         __decorate([
             BABYLON.serialize()
-        ], FreeCamera.prototype, "keysUp", void 0);
-        __decorate([
-            BABYLON.serialize()
-        ], FreeCamera.prototype, "keysDown", void 0);
-        __decorate([
-            BABYLON.serialize()
-        ], FreeCamera.prototype, "keysLeft", void 0);
-        __decorate([
-            BABYLON.serialize()
-        ], FreeCamera.prototype, "keysRight", void 0);
-        __decorate([
-            BABYLON.serialize()
         ], FreeCamera.prototype, "checkCollisions", void 0);
         __decorate([
             BABYLON.serialize()
         ], FreeCamera.prototype, "applyGravity", void 0);
-        __decorate([
-            BABYLON.serialize()
-        ], FreeCamera.prototype, "angularSensibility", void 0);
         return FreeCamera;
     })(BABYLON.TargetCamera);
     BABYLON.FreeCamera = FreeCamera;

+ 109 - 176
src/Cameras/babylon.freeCamera.ts

@@ -1,194 +1,140 @@
 module BABYLON {
-    export class FreeCamera extends TargetCamera {
+    export class FreeCamera extends TargetCamera {        
         @serializeAsVector3()
         public ellipsoid = new Vector3(0.5, 1, 0.5);
 
         @serialize()
-        public keysUp = [38];
-
-        @serialize()
-        public keysDown = [40];
-
-        @serialize()
-        public keysLeft = [37];
-
-        @serialize()
-        public keysRight = [39];
-
-        @serialize()
         public checkCollisions = false;
 
         @serialize()
         public applyGravity = false;
-
-        @serialize()
-        public angularSensibility = 2000.0;
-
+                
+        public inputs : FreeCameraInputsManager;
+        
+        //-- 2016-03-08 properties for backward compatibility for inputs
+        //deprecated
+        public get angularSensibility() {
+            Tools.Warn("Warning: angularSensibility is deprecated on FreeCamera, use camera.inputs.attached.mouse.angularSensibility instead.");
+            var mouse = <FreeCameraMouseInput>this.inputs.attached["mouse"];
+            if (mouse)
+                return mouse.angularSensibility;
+        }
+        
+        //deprecated
+        public set angularSensibility(value) {
+            Tools.Warn("Warning: angularSensibility is deprecated on FreeCamera, use camera.inputs.attached.mouse.angularSensibility instead.");
+            var mouse = <FreeCameraMouseInput>this.inputs.attached["mouse"];
+            if (mouse)
+                mouse.angularSensibility = value;
+        }
+        
+        //deprecated
+        public get keysUp() {
+            Tools.Warn("Warning: keysUp is deprecated on FreeCamera, use camera.inputs.attached.keyboard.keysUp instead.");
+            var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
+            if (keyboard)
+                return keyboard.keysUp;
+        }
+        
+        //deprecated
+        public set keysUp(value) {
+            Tools.Warn("Warning: keysUp is deprecated on FreeCamera, use camera.inputs.attached.keyboard.keysUp instead.");
+            var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
+            if (keyboard)
+                keyboard.keysUp = value;
+        }
+        
+        //deprecated
+        public get keysDown() {
+            Tools.Warn("Warning: keysDown is deprecated on FreeCamera, use camera.inputs.attached.keyboard.keysDown instead.");
+            var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
+            if (keyboard)
+                return keyboard.keysDown;
+        }
+        
+        //deprecated
+        public set keysDown(value) {
+            Tools.Warn("Warning: keysDown is deprecated on FreeCamera, use camera.inputs.attached.keyboard.keysDown instead.");
+            var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
+            if (keyboard)
+                keyboard.keysDown = value;
+        }
+        
+        //deprecated
+        public get keysLeft() {
+            Tools.Warn("Warning: keysLeft is deprecated on FreeCamera, use camera.inputs.attached.keyboard.keysLeft instead.");
+            var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
+            if (keyboard)
+                return keyboard.keysLeft;
+        }
+        
+        //deprecated
+        public set keysLeft(value) {
+            Tools.Warn("Warning: keysLeft is deprecated on FreeCamera, use camera.inputs.attached.keyboard.keysLeft instead.");
+            var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
+            if (keyboard)
+                keyboard.keysLeft = value;
+        }
+        
+        //deprecated
+        public get keysRight() {
+            Tools.Warn("Warning: keysRight is deprecated on FreeCamera, use camera.inputs.attached.keyboard.keysRight instead.");
+            var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
+            if (keyboard)
+                return keyboard.keysRight;
+        }
+        
+        //deprecated
+        public set keysRight(value) {
+            Tools.Warn("Warning: keysRight is deprecated on FreeCamera, use camera.inputs.attached.keyboard.keysRight instead.");
+            var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
+            if (keyboard)
+                keyboard.keysRight = value;
+        }
+        
+        //-- end properties for backward compatibility for inputs
+        
         public onCollide: (collidedMesh: AbstractMesh) => void;
-
-        private _keys = [];
+        
         private _collider = new Collider();
         private _needMoveForGravity = false;
         private _oldPosition = Vector3.Zero();
         private _diffPosition = Vector3.Zero();
         private _newPosition = Vector3.Zero();
-        private _attachedElement: HTMLElement;
-        private _localDirection: Vector3;
-        private _transformedDirection: Vector3;
-
-        private _onMouseDown: (e: MouseEvent) => any;
-        private _onMouseUp: (e: MouseEvent) => any;
-        private _onMouseOut: (e: MouseEvent) => any;
-        private _onMouseMove: (e: MouseEvent) => any;
-        private _onKeyDown: (e: KeyboardEvent) => any;
-        private _onKeyUp: (e: KeyboardEvent) => any;        
+        public _attachedElement: HTMLElement;
+        public _noPreventDefault: boolean;
+        
+        public _localDirection: Vector3;
+        public _transformedDirection: Vector3;        
         
         constructor(name: string, position: Vector3, scene: Scene) {
             super(name, position, scene);
-        }
-
-        public _onLostFocus(e: FocusEvent): void {
-            this._keys = [];
+            this.inputs = new FreeCameraInputsManager(this);
+            this.inputs.addKeyboard().addMouse();
         }
 
         // Controls
         public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
-            var previousPosition;
-            var engine = this.getEngine();
-
             if (this._attachedElement) {
                 return;
             }
+            this._noPreventDefault = noPreventDefault;
             this._attachedElement = element;
             noPreventDefault = Camera.ForceAttachControlToAlwaysPreventDefault ? false : noPreventDefault;
 
-            if (this._onMouseDown === undefined) {
-                this._onMouseDown = evt => {
-                    previousPosition = {
-                        x: evt.clientX,
-                        y: evt.clientY
-                    };
-
-                    if (!noPreventDefault) {
-                        evt.preventDefault();
-                    }
-                };
-
-                this._onMouseUp = evt => {
-                    previousPosition = null;
-                    if (!noPreventDefault) {
-                        evt.preventDefault();
-                    }
-                };
-
-                this._onMouseOut = evt => {
-                    previousPosition = null;
-                    this._keys = [];
-                    if (!noPreventDefault) {
-                        evt.preventDefault();
-                    }
-                };
-
-                this._onMouseMove = evt => {
-                    if (!previousPosition && !engine.isPointerLock) {
-                        return;
-                    }
-
-                    var offsetX;
-                    var offsetY;
-
-                    if (!engine.isPointerLock) {
-                        offsetX = evt.clientX - previousPosition.x;
-                        offsetY = evt.clientY - previousPosition.y;
-                    } else {
-                        offsetX = evt.movementX || evt.mozMovementX || evt.webkitMovementX || evt.msMovementX || 0;
-                        offsetY = evt.movementY || evt.mozMovementY || evt.webkitMovementY || evt.msMovementY || 0;
-                    }
-
-                    this.cameraRotation.y += offsetX / this.angularSensibility;
-                    this.cameraRotation.x += offsetY / this.angularSensibility;
-
-                    previousPosition = {
-                        x: evt.clientX,
-                        y: evt.clientY
-                    };
-                    if (!noPreventDefault) {
-                        evt.preventDefault();
-                    }
-                };
-
-                this._onKeyDown = evt => {
-                    if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
-                        this.keysDown.indexOf(evt.keyCode) !== -1 ||
-                        this.keysLeft.indexOf(evt.keyCode) !== -1 ||
-                        this.keysRight.indexOf(evt.keyCode) !== -1) {
-                        var index = this._keys.indexOf(evt.keyCode);
-
-                        if (index === -1) {
-                            this._keys.push(evt.keyCode);
-                        }
-                        if (!noPreventDefault) {
-                            evt.preventDefault();
-                        }
-                    }
-                };
-
-                this._onKeyUp = evt => {
-                    if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
-                        this.keysDown.indexOf(evt.keyCode) !== -1 ||
-                        this.keysLeft.indexOf(evt.keyCode) !== -1 ||
-                        this.keysRight.indexOf(evt.keyCode) !== -1) {
-                        var index = this._keys.indexOf(evt.keyCode);
-
-                        if (index >= 0) {
-                            this._keys.splice(index, 1);
-                        }
-                        if (!noPreventDefault) {
-                            evt.preventDefault();
-                        }
-                    }
-                };
-
-                this._reset = () => {
-                    this._keys = [];
-                    previousPosition = null;
-                    this.cameraDirection = new Vector3(0, 0, 0);
-                    this.cameraRotation = new Vector2(0, 0);
-                };
-            }
-
-            element.addEventListener("mousedown", this._onMouseDown, false);
-            element.addEventListener("mouseup", this._onMouseUp, false);
-            element.addEventListener("mouseout", this._onMouseOut, false);
-            element.addEventListener("mousemove", this._onMouseMove, false);
-
-            Tools.RegisterTopRootEvents([
-                { name: "keydown", handler: this._onKeyDown },
-                { name: "keyup", handler: this._onKeyUp },
-                { name: "blur", handler: this._onLostFocus }
-            ]);
-        }
+            this.inputs.attachElement(element, noPreventDefault);
+        }        
 
         public detachControl(element: HTMLElement): void {
             if (this._attachedElement !== element) {
                 return;
             }
 
-            element.removeEventListener("mousedown", this._onMouseDown);
-            element.removeEventListener("mouseup", this._onMouseUp);
-            element.removeEventListener("mouseout", this._onMouseOut);
-            element.removeEventListener("mousemove", this._onMouseMove);
-
-            Tools.UnregisterTopRootEvents([
-                { name: "keydown", handler: this._onKeyDown },
-                { name: "keyup", handler: this._onKeyUp },
-                { name: "blur", handler: this._onLostFocus }
-            ]);
-
+            this.inputs.detachElement(this._attachedElement);
             this._attachedElement = null;
-            if (this._reset) {
-                this._reset();
-            }
+            
+            this.cameraDirection = new Vector3(0, 0, 0);
+            this.cameraRotation = new Vector2(0, 0);
         }
 
         public _collideWithWorld(velocity: Vector3): void {
@@ -244,25 +190,7 @@
                 this._transformedDirection = Vector3.Zero();
             }
 
-            // Keyboard
-            for (var index = 0; index < this._keys.length; index++) {
-                var keyCode = this._keys[index];
-                var speed = this._computeLocalCameraSpeed();
-
-                if (this.keysLeft.indexOf(keyCode) !== -1) {
-                    this._localDirection.copyFromFloats(-speed, 0, 0);
-                } else if (this.keysUp.indexOf(keyCode) !== -1) {
-                    this._localDirection.copyFromFloats(0, 0, speed);
-                } else if (this.keysRight.indexOf(keyCode) !== -1) {
-                    this._localDirection.copyFromFloats(speed, 0, 0);
-                } else if (this.keysDown.indexOf(keyCode) !== -1) {
-                    this._localDirection.copyFromFloats(0, 0, -speed);
-                }
-
-                this.getViewMatrix().invertToRef(this._cameraTransformMatrix);
-                Vector3.TransformNormalToRef(this._localDirection, this._cameraTransformMatrix, this._transformedDirection);
-                this.cameraDirection.addInPlace(this._transformedDirection);
-            }
+            this.inputs.checkInputs();
 
             super._checkInputs();
         }
@@ -279,8 +207,13 @@
             }
         }
 
+        public dispose(): void {
+            this.inputs.clear();
+            super.dispose();
+        }
+        
         public getTypeName(): string {
             return "FreeCamera";
         }
-    }
+    }    
 } 

+ 50 - 0
src/Cameras/babylon.freeCameraInputsManager.js

@@ -0,0 +1,50 @@
+var __extends = (this && this.__extends) || function (d, b) {
+    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
+    function __() { this.constructor = d; }
+    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+};
+var BABYLON;
+(function (BABYLON) {
+    var FreeCameraInputsManager = (function (_super) {
+        __extends(FreeCameraInputsManager, _super);
+        function FreeCameraInputsManager(camera) {
+            _super.call(this, camera);
+        }
+        FreeCameraInputsManager.prototype.add = function (input) {
+            _super.prototype.add.call(this, input);
+            if (this.camera._attachedElement && input.attachElement) {
+                input.attachElement(this.camera._attachedElement, this.camera._noPreventDefault);
+            }
+        };
+        FreeCameraInputsManager.prototype.addKeyboard = function () {
+            this.add(new BABYLON.FreeCameraKeyboardMoveInput());
+            return this;
+        };
+        FreeCameraInputsManager.prototype.addMouse = function () {
+            this.add(new BABYLON.FreeCameraMouseInput());
+            return this;
+        };
+        FreeCameraInputsManager.prototype.addGamepad = function () {
+            this.add(new BABYLON.FreeCameraGamepadInput());
+            return this;
+        };
+        FreeCameraInputsManager.prototype.addDeviceOrientation = function () {
+            this.add(new BABYLON.FreeCameraDeviceOrientationInput());
+            return this;
+        };
+        FreeCameraInputsManager.prototype.addVRDeviceOrientation = function () {
+            this.add(new BABYLON.FreeCameraVRDeviceOrientationInput());
+            return this;
+        };
+        FreeCameraInputsManager.prototype.addTouch = function () {
+            this.add(new BABYLON.FreeCameraTouchInput());
+            return this;
+        };
+        FreeCameraInputsManager.prototype.addVirtualJoystick = function () {
+            this.add(new BABYLON.FreeCameraVirtualJoystickInput());
+            return this;
+        };
+        return FreeCameraInputsManager;
+    })(BABYLON.CameraInputsManager);
+    BABYLON.FreeCameraInputsManager = FreeCameraInputsManager;
+})(BABYLON || (BABYLON = {}));

+ 49 - 0
src/Cameras/babylon.freeCameraInputsManager.ts

@@ -0,0 +1,49 @@
+module BABYLON {
+    export class FreeCameraInputsManager extends CameraInputsManager<FreeCamera> {
+        constructor(camera : FreeCamera){
+            super(camera);    
+        }
+        
+        add(input: ICameraInput<FreeCamera>){
+            super.add(input);
+            if (this.camera._attachedElement && input.attachElement) {
+                input.attachElement(this.camera._attachedElement, this.camera._noPreventDefault);
+            }
+        }
+        
+        addKeyboard(){
+            this.add(new FreeCameraKeyboardMoveInput());
+            return this;
+        }
+        
+        addMouse(){
+            this.add(new FreeCameraMouseInput());
+            return this;
+        }
+        
+        addGamepad(){
+            this.add(new FreeCameraGamepadInput());
+            return this;
+        }
+        
+        addDeviceOrientation(){
+            this.add(new FreeCameraDeviceOrientationInput());
+            return this;
+        }
+        
+        addVRDeviceOrientation(){
+            this.add(new FreeCameraVRDeviceOrientationInput());
+            return this;
+        }
+        
+        addTouch(){
+            this.add(new FreeCameraTouchInput());
+            return this;
+        }
+        
+        addVirtualJoystick(){
+            this.add(new FreeCameraVirtualJoystickInput());
+            return this;
+        }
+    }
+}

+ 38 - 0
src/Cameras/babylon.gamepadCamera.js

@@ -8,10 +8,48 @@ var BABYLON;
     // We're mainly based on the logic defined into the FreeCamera code
     var GamepadCamera = (function (_super) {
         __extends(GamepadCamera, _super);
+        //-- end properties for backward compatibility for inputs
         function GamepadCamera(name, position, scene) {
             BABYLON.Tools.Warn("Deprecated. Please use Universal Camera instead.");
             _super.call(this, name, position, scene);
         }
+        Object.defineProperty(GamepadCamera.prototype, "gamepadAngularSensibility", {
+            //-- 2016-03-08 properties for backward compatibility for inputs
+            //deprecated
+            get: function () {
+                BABYLON.Tools.Warn("Warning: gamepadAngularSensibility is deprecated on GamepadCamera, use camera.inputs.attached.gamepad.gamepadAngularSensibility instead.");
+                var gamepad = this.inputs.attached["gamepad"];
+                if (gamepad)
+                    return gamepad.gamepadAngularSensibility;
+            },
+            //deprecated
+            set: function (value) {
+                BABYLON.Tools.Warn("Warning: gamepadAngularSensibility is deprecated on GamepadCamera, use camera.inputs.attached.gamepad.gamepadAngularSensibility instead.");
+                var gamepad = this.inputs.attached["gamepad"];
+                if (gamepad)
+                    gamepad.gamepadAngularSensibility = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(GamepadCamera.prototype, "gamepadMoveSensibility", {
+            //deprecated
+            get: function () {
+                BABYLON.Tools.Warn("Warning: gamepadMoveSensibility is deprecated on GamepadCamera, use camera.inputs.attached.gamepad.gamepadMoveSensibility instead.");
+                var gamepad = this.inputs.attached["gamepad"];
+                if (gamepad)
+                    return gamepad.gamepadMoveSensibility;
+            },
+            //deprecated
+            set: function (value) {
+                BABYLON.Tools.Warn("Warning: gamepadMoveSensibility is deprecated on GamepadCamera, use camera.inputs.attached.gamepad.gamepadMoveSensibility instead.");
+                var gamepad = this.inputs.attached["gamepad"];
+                if (gamepad)
+                    gamepad.gamepadMoveSensibility = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
         GamepadCamera.prototype.getTypeName = function () {
             return "GamepadCamera";
         };

+ 35 - 0
src/Cameras/babylon.gamepadCamera.ts

@@ -1,6 +1,41 @@
 module BABYLON {
     // We're mainly based on the logic defined into the FreeCamera code
     export class GamepadCamera extends UniversalCamera {
+        //-- 2016-03-08 properties for backward compatibility for inputs
+        //deprecated
+        public get gamepadAngularSensibility() {
+            Tools.Warn("Warning: gamepadAngularSensibility is deprecated on GamepadCamera, use camera.inputs.attached.gamepad.gamepadAngularSensibility instead.");
+            var gamepad = <FreeCameraGamepadInput>this.inputs.attached["gamepad"];
+            if (gamepad)
+                return gamepad.gamepadAngularSensibility;
+        }
+        
+        //deprecated
+        public set gamepadAngularSensibility(value) {
+            Tools.Warn("Warning: gamepadAngularSensibility is deprecated on GamepadCamera, use camera.inputs.attached.gamepad.gamepadAngularSensibility instead.");
+            var gamepad = <FreeCameraGamepadInput>this.inputs.attached["gamepad"];
+            if (gamepad)
+                gamepad.gamepadAngularSensibility = value;
+        }
+        
+        //deprecated
+        public get gamepadMoveSensibility() {
+            Tools.Warn("Warning: gamepadMoveSensibility is deprecated on GamepadCamera, use camera.inputs.attached.gamepad.gamepadMoveSensibility instead.");
+            var gamepad = <FreeCameraGamepadInput>this.inputs.attached["gamepad"];
+            if (gamepad)
+                return gamepad.gamepadMoveSensibility;
+        }
+        
+        //deprecated
+        public set gamepadMoveSensibility(value) {
+            Tools.Warn("Warning: gamepadMoveSensibility is deprecated on GamepadCamera, use camera.inputs.attached.gamepad.gamepadMoveSensibility instead.");
+            var gamepad = <FreeCameraGamepadInput>this.inputs.attached["gamepad"];
+            if (gamepad)
+                gamepad.gamepadMoveSensibility = value;
+        }
+        //-- end properties for backward compatibility for inputs
+        
+        
         constructor(name: string, position: Vector3, scene: Scene) {
             Tools.Warn("Deprecated. Please use Universal Camera instead.");
             super(name, position, scene);

+ 39 - 115
src/Cameras/babylon.touchCamera.js

@@ -3,132 +3,56 @@ var __extends = (this && this.__extends) || function (d, b) {
     function __() { this.constructor = d; }
     d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
 };
-var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
-    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
-    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
-    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
-    return c > 3 && r && Object.defineProperty(target, key, r), r;
-};
 var BABYLON;
 (function (BABYLON) {
     // We're mainly based on the logic defined into the FreeCamera code
     var TouchCamera = (function (_super) {
         __extends(TouchCamera, _super);
+        //-- end properties for backward compatibility for inputs
         function TouchCamera(name, position, scene) {
             _super.call(this, name, position, scene);
-            this._offsetX = null;
-            this._offsetY = null;
-            this._pointerCount = 0;
-            this._pointerPressed = [];
-            this.touchAngularSensibility = 200000.0;
-            this.touchMoveSensibility = 250.0;
+            this.inputs.addTouch();
         }
-        TouchCamera.prototype._onLostFocus = function (e) {
-            this._offsetX = null;
-            this._offsetY = null;
-            _super.prototype._onLostFocus.call(this, e);
-        };
-        TouchCamera.prototype.attachControl = function (canvas, noPreventDefault) {
-            var _this = this;
-            var previousPosition;
-            if (this._attachedCanvas) {
-                return;
-            }
-            noPreventDefault = BABYLON.Camera.ForceAttachControlToAlwaysPreventDefault ? false : noPreventDefault;
-            if (this._onPointerDown === undefined) {
-                this._onPointerDown = function (evt) {
-                    if (evt.pointerType === "mouse") {
-                        return;
-                    }
-                    if (!noPreventDefault) {
-                        evt.preventDefault();
-                    }
-                    _this._pointerPressed.push(evt.pointerId);
-                    if (_this._pointerPressed.length !== 1) {
-                        return;
-                    }
-                    previousPosition = {
-                        x: evt.clientX,
-                        y: evt.clientY
-                    };
-                };
-                this._onPointerUp = function (evt) {
-                    if (evt.pointerType === "mouse") {
-                        return;
-                    }
-                    if (!noPreventDefault) {
-                        evt.preventDefault();
-                    }
-                    var index = _this._pointerPressed.indexOf(evt.pointerId);
-                    if (index === -1) {
-                        return;
-                    }
-                    _this._pointerPressed.splice(index, 1);
-                    if (index != 0) {
-                        return;
-                    }
-                    previousPosition = null;
-                    _this._offsetX = null;
-                    _this._offsetY = null;
-                };
-                this._onPointerMove = function (evt) {
-                    if (evt.pointerType === "mouse") {
-                        return;
-                    }
-                    if (!noPreventDefault) {
-                        evt.preventDefault();
-                    }
-                    if (!previousPosition) {
-                        return;
-                    }
-                    var index = _this._pointerPressed.indexOf(evt.pointerId);
-                    if (index != 0) {
-                        return;
-                    }
-                    _this._offsetX = evt.clientX - previousPosition.x;
-                    _this._offsetY = -(evt.clientY - previousPosition.y);
-                };
-            }
-            canvas.addEventListener("pointerdown", this._onPointerDown);
-            canvas.addEventListener("pointerup", this._onPointerUp);
-            canvas.addEventListener("pointerout", this._onPointerUp);
-            canvas.addEventListener("pointermove", this._onPointerMove);
-            _super.prototype.attachControl.call(this, canvas);
-        };
-        TouchCamera.prototype.detachControl = function (canvas) {
-            if (this._attachedCanvas !== canvas) {
-                return;
-            }
-            canvas.removeEventListener("pointerdown", this._onPointerDown);
-            canvas.removeEventListener("pointerup", this._onPointerUp);
-            canvas.removeEventListener("pointerout", this._onPointerUp);
-            canvas.removeEventListener("pointermove", this._onPointerMove);
-            _super.prototype.detachControl.call(this, canvas);
-        };
-        TouchCamera.prototype._checkInputs = function () {
-            if (this._offsetX) {
-                this.cameraRotation.y += this._offsetX / this.touchAngularSensibility;
-                if (this._pointerPressed.length > 1) {
-                    this.cameraRotation.x += -this._offsetY / this.touchAngularSensibility;
-                }
-                else {
-                    var speed = this._computeLocalCameraSpeed();
-                    var direction = new BABYLON.Vector3(0, 0, speed * this._offsetY / this.touchMoveSensibility);
-                    BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, 0, this._cameraRotationMatrix);
-                    this.cameraDirection.addInPlace(BABYLON.Vector3.TransformCoordinates(direction, this._cameraRotationMatrix));
-                }
-            }
-            _super.prototype._checkInputs.call(this);
-        };
+        Object.defineProperty(TouchCamera.prototype, "touchAngularSensibility", {
+            //-- 2016-03-08 properties for backward compatibility for inputs
+            //deprecated
+            get: function () {
+                BABYLON.Tools.Warn("Warning: touchAngularSensibility is deprecated on TouchCamera, use camera.inputs.attached.touch.touchAngularSensibility instead.");
+                var touch = this.inputs.attached["touch"];
+                if (touch)
+                    return touch.touchAngularSensibility;
+            },
+            //deprecated
+            set: function (value) {
+                BABYLON.Tools.Warn("Warning: touchAngularSensibility is deprecated on TouchCamera, use camera.inputs.attached.touch.touchAngularSensibility instead.");
+                var touch = this.inputs.attached["touch"];
+                if (touch)
+                    touch.touchAngularSensibility = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(TouchCamera.prototype, "touchMoveSensibility", {
+            //deprecated
+            get: function () {
+                BABYLON.Tools.Warn("Warning: touchMoveSensibility is deprecated on TouchCamera, use camera.inputs.attached.touch.touchMoveSensibility instead.");
+                var touch = this.inputs.attached["touch"];
+                if (touch)
+                    return touch.touchMoveSensibility;
+            },
+            //deprecated
+            set: function (value) {
+                BABYLON.Tools.Warn("Warning: touchMoveSensibility is deprecated on TouchCamera, use camera.inputs.attached.touch.touchMoveSensibility instead.");
+                var touch = this.inputs.attached["touch"];
+                if (touch)
+                    touch.touchMoveSensibility = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
         TouchCamera.prototype.getTypeName = function () {
             return "TouchCamera";
         };
-        __decorate([
-            BABYLON.serialize()
-        ], TouchCamera.prototype, "touchAngularSensibility", void 0);
-        __decorate([
-            BABYLON.serialize()
-        ], TouchCamera.prototype, "touchMoveSensibility", void 0);
         return TouchCamera;
     })(BABYLON.FreeCamera);
     BABYLON.TouchCamera = TouchCamera;

+ 33 - 143
src/Cameras/babylon.touchCamera.ts

@@ -1,153 +1,43 @@
 module BABYLON {
     // We're mainly based on the logic defined into the FreeCamera code
     export class TouchCamera extends FreeCamera {
-        private _offsetX: number = null;
-        private _offsetY: number = null;
-        private _pointerCount:number = 0;
-        private _pointerPressed = [];
-        private _attachedCanvas: HTMLCanvasElement;
-        private _onPointerDown: (e: PointerEvent) => any;
-        private _onPointerUp: (e: PointerEvent) => any;
-        private _onPointerMove: (e: PointerEvent) => any;
-
-        @serialize()
-        public touchAngularSensibility: number = 200000.0;
-
-        @serialize()
-        public touchMoveSensibility: number = 250.0;
-
-        constructor(name: string, position: Vector3, scene: Scene) {
-            super(name, position, scene);
+        //-- 2016-03-08 properties for backward compatibility for inputs
+        //deprecated
+        public get touchAngularSensibility() {
+            Tools.Warn("Warning: touchAngularSensibility is deprecated on TouchCamera, use camera.inputs.attached.touch.touchAngularSensibility instead.");
+            var touch = <FreeCameraTouchInput>this.inputs.attached["touch"];
+            if (touch)
+                return touch.touchAngularSensibility;
         }
-
-        public _onLostFocus(e: FocusEvent): void {
-            this._offsetX = null;
-            this._offsetY = null;
-            super._onLostFocus(e);
+        
+        //deprecated
+        public set touchAngularSensibility(value) {
+            Tools.Warn("Warning: touchAngularSensibility is deprecated on TouchCamera, use camera.inputs.attached.touch.touchAngularSensibility instead.");
+            var touch = <FreeCameraTouchInput>this.inputs.attached["touch"];
+            if (touch)
+                touch.touchAngularSensibility = value;
         }
-
-        public attachControl(canvas: HTMLCanvasElement, noPreventDefault: boolean): void {
-            var previousPosition;
-
-            if (this._attachedCanvas) {
-                return;
-            }
-            noPreventDefault = Camera.ForceAttachControlToAlwaysPreventDefault ? false : noPreventDefault;
-
-            if (this._onPointerDown === undefined) {
-
-                this._onPointerDown = (evt) => {
-
-                    if (evt.pointerType === "mouse") {
-                        return;
-                    }
-
-                    if (!noPreventDefault) {
-                        evt.preventDefault();
-                    }
-
-                    this._pointerPressed.push(evt.pointerId);
-
-                    if (this._pointerPressed.length !== 1) {
-                        return;
-                    }
-
-                    previousPosition = {
-                        x: evt.clientX,
-                        y: evt.clientY
-                    };
-                };
-
-                this._onPointerUp = (evt) => {
-
-                    if (evt.pointerType === "mouse") {
-                        return;
-                    }
-
-                    if (!noPreventDefault) {
-                        evt.preventDefault();
-                    }
-
-                    var index: number = this._pointerPressed.indexOf(evt.pointerId);
-
-                    if (index === -1) {
-                        return;
-                    }
-                    this._pointerPressed.splice(index, 1);
-
-                    if (index != 0) {
-                        return;
-                    }
-                    previousPosition = null;
-                    this._offsetX = null;
-                    this._offsetY = null;
-                };
-
-                this._onPointerMove = (evt) => {
-
-                    if (evt.pointerType === "mouse") {
-                        return;
-                    }
-
-                    if (!noPreventDefault) {
-                        evt.preventDefault();
-                    }
-
-                    if (!previousPosition) {
-                        return;
-                    }
-
-                    var index: number = this._pointerPressed.indexOf(evt.pointerId);
-
-                    if (index != 0) {
-                        return;
-                    }
-
-                    this._offsetX = evt.clientX - previousPosition.x;
-                    this._offsetY = -(evt.clientY - previousPosition.y);
-                };
-
-                
-            }
-
-            canvas.addEventListener("pointerdown", this._onPointerDown);
-            canvas.addEventListener("pointerup", this._onPointerUp);
-            canvas.addEventListener("pointerout", this._onPointerUp);
-            canvas.addEventListener("pointermove", this._onPointerMove);
-
-            super.attachControl(canvas);
+        
+        //deprecated
+        public get touchMoveSensibility() {
+            Tools.Warn("Warning: touchMoveSensibility is deprecated on TouchCamera, use camera.inputs.attached.touch.touchMoveSensibility instead.");
+            var touch = <FreeCameraTouchInput>this.inputs.attached["touch"];
+            if (touch)
+                return touch.touchMoveSensibility;
         }
-
-        public detachControl(canvas: HTMLCanvasElement): void {
-            if (this._attachedCanvas !== canvas) {
-                return;
-            }
-
-            canvas.removeEventListener("pointerdown", this._onPointerDown);
-            canvas.removeEventListener("pointerup", this._onPointerUp);
-            canvas.removeEventListener("pointerout", this._onPointerUp);
-            canvas.removeEventListener("pointermove", this._onPointerMove);
-            
-            super.detachControl(canvas);
+        
+        //deprecated
+        public set touchMoveSensibility(value) {
+            Tools.Warn("Warning: touchMoveSensibility is deprecated on TouchCamera, use camera.inputs.attached.touch.touchMoveSensibility instead.");
+            var touch = <FreeCameraTouchInput>this.inputs.attached["touch"];
+            if (touch)
+                touch.touchMoveSensibility = value;
         }
-
-        public _checkInputs(): void {
-            if (this._offsetX) {
-
-                this.cameraRotation.y += this._offsetX / this.touchAngularSensibility;
-
-                if (this._pointerPressed.length > 1) {
-                    this.cameraRotation.x += -this._offsetY / this.touchAngularSensibility;
-                } else {
-                    var speed = this._computeLocalCameraSpeed();
-                    var direction = new Vector3(0, 0, speed * this._offsetY / this.touchMoveSensibility);
-
-                    Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, 0, this._cameraRotationMatrix);
-                    this.cameraDirection.addInPlace(Vector3.TransformCoordinates(direction, this._cameraRotationMatrix));
-                }
-            }
-
-            super._checkInputs();
+        //-- end properties for backward compatibility for inputs
+        
+        constructor(name: string, position: Vector3, scene: Scene) {
+            super(name, position, scene);
+            this.inputs.addTouch();
         }
 
         public getTypeName(): string {

+ 39 - 52
src/Cameras/babylon.universalCamera.js

@@ -3,69 +3,56 @@ var __extends = (this && this.__extends) || function (d, b) {
     function __() { this.constructor = d; }
     d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
 };
-var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
-    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
-    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
-    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
-    return c > 3 && r && Object.defineProperty(target, key, r), r;
-};
 var BABYLON;
 (function (BABYLON) {
     // We're mainly based on the logic defined into the FreeCamera code
     var UniversalCamera = (function (_super) {
         __extends(UniversalCamera, _super);
+        //-- end properties for backward compatibility for inputs
         function UniversalCamera(name, position, scene) {
-            var _this = this;
             _super.call(this, name, position, scene);
-            this.gamepadAngularSensibility = 200;
-            this.gamepadMoveSensibility = 40;
-            this._gamepads = new BABYLON.Gamepads(function (gamepad) { _this._onNewGameConnected(gamepad); });
+            this.inputs.addGamepad();
         }
-        UniversalCamera.prototype._onNewGameConnected = function (gamepad) {
-            // Only the first gamepad can control the camera
-            if (gamepad.index === 0) {
-                this.gamepad = gamepad;
-            }
-        };
-        UniversalCamera.prototype.attachControl = function (canvas, noPreventDefault) {
-            _super.prototype.attachControl.call(this, canvas, false);
-        };
-        UniversalCamera.prototype.detachControl = function (canvas) {
-            _super.prototype.detachControl.call(this, canvas);
-        };
-        UniversalCamera.prototype._checkInputs = function () {
-            if (this.gamepad) {
-                var LSValues = this.gamepad.leftStick;
-                var normalizedLX = LSValues.x / this.gamepadMoveSensibility;
-                var normalizedLY = LSValues.y / this.gamepadMoveSensibility;
-                LSValues.x = Math.abs(normalizedLX) > 0.005 ? 0 + normalizedLX : 0;
-                LSValues.y = Math.abs(normalizedLY) > 0.005 ? 0 + normalizedLY : 0;
-                var RSValues = this.gamepad.rightStick;
-                var normalizedRX = RSValues.x / this.gamepadAngularSensibility;
-                var normalizedRY = RSValues.y / this.gamepadAngularSensibility;
-                RSValues.x = Math.abs(normalizedRX) > 0.001 ? 0 + normalizedRX : 0;
-                RSValues.y = Math.abs(normalizedRY) > 0.001 ? 0 + normalizedRY : 0;
-                var cameraTransform = BABYLON.Matrix.RotationYawPitchRoll(this.rotation.y, this.rotation.x, 0);
-                var speed = this._computeLocalCameraSpeed() * 50.0;
-                var deltaTransform = BABYLON.Vector3.TransformCoordinates(new BABYLON.Vector3(LSValues.x * speed, 0, -LSValues.y * speed), cameraTransform);
-                this.cameraDirection = this.cameraDirection.add(deltaTransform);
-                this.cameraRotation = this.cameraRotation.add(new BABYLON.Vector2(RSValues.y, RSValues.x));
-            }
-            _super.prototype._checkInputs.call(this);
-        };
-        UniversalCamera.prototype.dispose = function () {
-            this._gamepads.dispose();
-            _super.prototype.dispose.call(this);
-        };
+        Object.defineProperty(UniversalCamera.prototype, "gamepadAngularSensibility", {
+            //-- 2016-03-08 properties for backward compatibility for inputs
+            //deprecated
+            get: function () {
+                BABYLON.Tools.Warn("Warning: gamepadAngularSensibility is deprecated, use camera.inputs.attached.gamepad.gamepadAngularSensibility instead.");
+                var gamepad = this.inputs.attached["gamepad"];
+                if (gamepad)
+                    return gamepad.gamepadAngularSensibility;
+            },
+            //deprecated
+            set: function (value) {
+                BABYLON.Tools.Warn("Warning: gamepadAngularSensibility is deprecated, use camera.inputs.attached.gamepad.gamepadAngularSensibility instead.");
+                var gamepad = this.inputs.attached["gamepad"];
+                if (gamepad)
+                    gamepad.gamepadAngularSensibility = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(UniversalCamera.prototype, "gamepadMoveSensibility", {
+            //deprecated
+            get: function () {
+                BABYLON.Tools.Warn("Warning: gamepadMoveSensibility is deprecated, use camera.inputs.attached.gamepad.gamepadMoveSensibility instead.");
+                var gamepad = this.inputs.attached["gamepad"];
+                if (gamepad)
+                    return gamepad.gamepadMoveSensibility;
+            },
+            //deprecated
+            set: function (value) {
+                BABYLON.Tools.Warn("Warning: gamepadMoveSensibility is deprecated, use camera.inputs.attached.gamepad.gamepadMoveSensibility instead.");
+                var gamepad = this.inputs.attached["gamepad"];
+                if (gamepad)
+                    gamepad.gamepadMoveSensibility = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
         UniversalCamera.prototype.getTypeName = function () {
             return "UniversalCamera";
         };
-        __decorate([
-            BABYLON.serialize()
-        ], UniversalCamera.prototype, "gamepadAngularSensibility", void 0);
-        __decorate([
-            BABYLON.serialize()
-        ], UniversalCamera.prototype, "gamepadMoveSensibility", void 0);
         return UniversalCamera;
     })(BABYLON.TouchCamera);
     BABYLON.UniversalCamera = UniversalCamera;

+ 33 - 52
src/Cameras/babylon.universalCamera.ts

@@ -1,62 +1,43 @@
 module BABYLON {
     // We're mainly based on the logic defined into the FreeCamera code
     export class UniversalCamera extends TouchCamera {
-        public gamepad: Gamepad;
-        private _gamepads: Gamepads;
-
-        @serialize()
-        public gamepadAngularSensibility = 200;
-
-        @serialize()
-        public gamepadMoveSensibility = 40;
-
-        constructor(name: string, position: Vector3, scene: Scene) {
-            super(name, position, scene);
-            this._gamepads = new Gamepads((gamepad: Gamepad) => { this._onNewGameConnected(gamepad); });
-        }
-
-        private _onNewGameConnected(gamepad: Gamepad) {
-            // Only the first gamepad can control the camera
-            if (gamepad.index === 0) {
-                this.gamepad = gamepad;
-            }
+        //-- 2016-03-08 properties for backward compatibility for inputs
+        //deprecated
+        public get gamepadAngularSensibility() {
+            Tools.Warn("Warning: gamepadAngularSensibility is deprecated, use camera.inputs.attached.gamepad.gamepadAngularSensibility instead.");
+            var gamepad = <FreeCameraGamepadInput>this.inputs.attached["gamepad"];
+            if (gamepad)
+                return gamepad.gamepadAngularSensibility;
         }
-
-        public attachControl(canvas: HTMLCanvasElement, noPreventDefault: boolean): void {
-            super.attachControl(canvas, false);
+        
+        //deprecated
+        public set gamepadAngularSensibility(value) {
+            Tools.Warn("Warning: gamepadAngularSensibility is deprecated, use camera.inputs.attached.gamepad.gamepadAngularSensibility instead.");
+            var gamepad = <FreeCameraGamepadInput>this.inputs.attached["gamepad"];
+            if (gamepad)
+                gamepad.gamepadAngularSensibility = value;
         }
-
-        public detachControl(canvas: HTMLCanvasElement): void {
-            super.detachControl(canvas);
+        
+        //deprecated
+        public get gamepadMoveSensibility() {
+            Tools.Warn("Warning: gamepadMoveSensibility is deprecated, use camera.inputs.attached.gamepad.gamepadMoveSensibility instead.");
+            var gamepad = <FreeCameraGamepadInput>this.inputs.attached["gamepad"];
+            if (gamepad)
+                return gamepad.gamepadMoveSensibility;
         }
-
-        public _checkInputs(): void {
-            if (this.gamepad) {
-                var LSValues = this.gamepad.leftStick;
-                var normalizedLX = LSValues.x / this.gamepadMoveSensibility;
-                var normalizedLY = LSValues.y / this.gamepadMoveSensibility;
-                LSValues.x = Math.abs(normalizedLX) > 0.005 ? 0 + normalizedLX : 0;
-                LSValues.y = Math.abs(normalizedLY) > 0.005 ? 0 + normalizedLY : 0;
-
-                var RSValues = this.gamepad.rightStick;
-                var normalizedRX = RSValues.x / this.gamepadAngularSensibility;
-                var normalizedRY = RSValues.y / this.gamepadAngularSensibility;
-                RSValues.x = Math.abs(normalizedRX) > 0.001 ? 0 + normalizedRX : 0;
-                RSValues.y = Math.abs(normalizedRY) > 0.001 ? 0 + normalizedRY : 0;
-
-                var cameraTransform = Matrix.RotationYawPitchRoll(this.rotation.y, this.rotation.x, 0);
-
-                var speed = this._computeLocalCameraSpeed() * 50.0;
-                var deltaTransform = Vector3.TransformCoordinates(new Vector3(LSValues.x * speed, 0, -LSValues.y * speed), cameraTransform);
-                this.cameraDirection = this.cameraDirection.add(deltaTransform);
-                this.cameraRotation = this.cameraRotation.add(new Vector2(RSValues.y, RSValues.x));
-            }
-            super._checkInputs();
+        
+        //deprecated
+        public set gamepadMoveSensibility(value) {
+            Tools.Warn("Warning: gamepadMoveSensibility is deprecated, use camera.inputs.attached.gamepad.gamepadMoveSensibility instead.");
+            var gamepad = <FreeCameraGamepadInput>this.inputs.attached["gamepad"];
+            if (gamepad)
+                gamepad.gamepadMoveSensibility = value;
         }
-
-        public dispose(): void {
-            this._gamepads.dispose();
-            super.dispose();
+        //-- end properties for backward compatibility for inputs
+        
+        constructor(name: string, position: Vector3, scene: Scene) {
+            super(name, position, scene);
+            this.inputs.addGamepad();
         }
 
         public getTypeName(): string {

+ 1 - 37
src/Cameras/babylon.virtualJoysticksCamera.js

@@ -10,44 +10,8 @@ var BABYLON;
         __extends(VirtualJoysticksCamera, _super);
         function VirtualJoysticksCamera(name, position, scene) {
             _super.call(this, name, position, scene);
-            this._leftjoystick = new BABYLON.VirtualJoystick(true);
-            this._leftjoystick.setAxisForUpDown(BABYLON.JoystickAxis.Z);
-            this._leftjoystick.setAxisForLeftRight(BABYLON.JoystickAxis.X);
-            this._leftjoystick.setJoystickSensibility(0.15);
-            this._rightjoystick = new BABYLON.VirtualJoystick(false);
-            this._rightjoystick.setAxisForUpDown(BABYLON.JoystickAxis.X);
-            this._rightjoystick.setAxisForLeftRight(BABYLON.JoystickAxis.Y);
-            this._rightjoystick.reverseUpDown = true;
-            this._rightjoystick.setJoystickSensibility(0.05);
-            this._rightjoystick.setJoystickColor("yellow");
+            this.inputs.addVirtualJoystick();
         }
-        VirtualJoysticksCamera.prototype.getLeftJoystick = function () {
-            return this._leftjoystick;
-        };
-        VirtualJoysticksCamera.prototype.getRightJoystick = function () {
-            return this._rightjoystick;
-        };
-        VirtualJoysticksCamera.prototype._checkInputs = function () {
-            var speed = this._computeLocalCameraSpeed() * 50;
-            var cameraTransform = BABYLON.Matrix.RotationYawPitchRoll(this.rotation.y, this.rotation.x, 0);
-            var deltaTransform = BABYLON.Vector3.TransformCoordinates(new BABYLON.Vector3(this._leftjoystick.deltaPosition.x * speed, this._leftjoystick.deltaPosition.y * speed, this._leftjoystick.deltaPosition.z * speed), cameraTransform);
-            this.cameraDirection = this.cameraDirection.add(deltaTransform);
-            this.cameraRotation = this.cameraRotation.addVector3(this._rightjoystick.deltaPosition);
-            if (!this._leftjoystick.pressed) {
-                this._leftjoystick.deltaPosition = this._leftjoystick.deltaPosition.scale(0.9);
-            }
-            if (!this._rightjoystick.pressed) {
-                this._rightjoystick.deltaPosition = this._rightjoystick.deltaPosition.scale(0.9);
-            }
-            _super.prototype._checkInputs.call(this);
-        };
-        VirtualJoysticksCamera.prototype.dispose = function () {
-            this._leftjoystick.releaseCanvas();
-            _super.prototype.dispose.call(this);
-        };
-        VirtualJoysticksCamera.prototype.getTypeName = function () {
-            return "VirtualJoysticksCamera";
-        };
         return VirtualJoysticksCamera;
     })(BABYLON.FreeCamera);
     BABYLON.VirtualJoysticksCamera = VirtualJoysticksCamera;

+ 2 - 46
src/Cameras/babylon.virtualJoysticksCamera.ts

@@ -1,54 +1,10 @@
 module BABYLON {
     // We're mainly based on the logic defined into the FreeCamera code
     export class VirtualJoysticksCamera extends FreeCamera {
-        private _leftjoystick: VirtualJoystick;
-        private _rightjoystick: VirtualJoystick;
-
+        
         constructor(name: string, position: Vector3, scene: Scene) {
             super(name, position, scene);
-            this._leftjoystick = new VirtualJoystick(true);
-            this._leftjoystick.setAxisForUpDown(JoystickAxis.Z);
-            this._leftjoystick.setAxisForLeftRight(JoystickAxis.X);
-            this._leftjoystick.setJoystickSensibility(0.15);
-            this._rightjoystick = new VirtualJoystick(false);
-            this._rightjoystick.setAxisForUpDown(JoystickAxis.X);
-            this._rightjoystick.setAxisForLeftRight(JoystickAxis.Y);
-            this._rightjoystick.reverseUpDown = true;
-            this._rightjoystick.setJoystickSensibility(0.05);
-            this._rightjoystick.setJoystickColor("yellow");
-        }
-
-        public getLeftJoystick(): VirtualJoystick {
-            return this._leftjoystick;
-        }
-
-        public getRightJoystick(): VirtualJoystick {
-            return this._rightjoystick;
-        }
-
-        public _checkInputs(): void {
-            var speed = this._computeLocalCameraSpeed() * 50;
-            var cameraTransform = Matrix.RotationYawPitchRoll(this.rotation.y, this.rotation.x, 0);
-            var deltaTransform = Vector3.TransformCoordinates(new Vector3(this._leftjoystick.deltaPosition.x * speed, this._leftjoystick.deltaPosition.y * speed, this._leftjoystick.deltaPosition.z * speed), cameraTransform);
-            this.cameraDirection = this.cameraDirection.add(deltaTransform);
-            this.cameraRotation = this.cameraRotation.addVector3(this._rightjoystick.deltaPosition);
-            if (!this._leftjoystick.pressed) {
-                this._leftjoystick.deltaPosition = this._leftjoystick.deltaPosition.scale(0.9);
-            }
-            if (!this._rightjoystick.pressed) {
-                this._rightjoystick.deltaPosition = this._rightjoystick.deltaPosition.scale(0.9);
-            }
-
-            super._checkInputs();
-        }
-
-        public dispose(): void {
-            this._leftjoystick.releaseCanvas();
-            super.dispose();
-        }
-
-        public getTypeName(): string {
-            return "VirtualJoysticksCamera";
+            this.inputs.addVirtualJoystick();
         }
     }
 }

+ 12 - 4
src/Tools/babylon.gamepads.js

@@ -18,12 +18,14 @@ var BABYLON;
             if (this.gamepadSupportAvailable) {
                 // Checking if the gamepad connected event is supported (like in Firefox)
                 if (this.gamepadEventSupported) {
-                    window.addEventListener('gamepadconnected', function (evt) {
+                    this._onGamepadConnectedEvent = function (evt) {
                         _this._onGamepadConnected(evt);
-                    }, false);
-                    window.addEventListener('gamepaddisconnected', function (evt) {
+                    };
+                    this._onGamepadDisonnectedEvent = function (evt) {
                         _this._onGamepadDisconnected(evt);
-                    }, false);
+                    };
+                    window.addEventListener('gamepadconnected', this._onGamepadConnectedEvent, false);
+                    window.addEventListener('gamepaddisconnected', this._onGamepadDisonnectedEvent, false);
                 }
                 else {
                     this._startMonitoringGamepads();
@@ -34,6 +36,12 @@ var BABYLON;
             if (Gamepads.gamepadDOMInfo) {
                 document.body.removeChild(Gamepads.gamepadDOMInfo);
             }
+            if (this._onGamepadConnectedEvent) {
+                window.removeEventListener('gamepadconnected', this._onGamepadConnectedEvent, false);
+                window.removeEventListener('gamepaddisconnected', this._onGamepadDisonnectedEvent, false);
+                this._onGamepadConnectedEvent = null;
+                this._onGamepadDisonnectedEvent = null;
+            }
         };
         Gamepads.prototype._onGamepadConnected = function (evt) {
             var newGamepad = this._addNewGamepad(evt.gamepad);

+ 19 - 6
src/Tools/babylon.gamepads.ts

@@ -10,20 +10,26 @@
 
         private _callbackGamepadConnected: (gamepad: Gamepad) => void;
 
+        private _onGamepadConnectedEvent: (evt: Event) => void;
+        private _onGamepadDisonnectedEvent: (evt: Event) => void;
+
         private static gamepadDOMInfo: HTMLElement;
 
+
         constructor(ongamedpadconnected: (gamepad: Gamepad) => void) {
             this._callbackGamepadConnected = ongamedpadconnected;
             if (this.gamepadSupportAvailable) {
+
                 // Checking if the gamepad connected event is supported (like in Firefox)
                 if (this.gamepadEventSupported) {
-                    window.addEventListener('gamepadconnected', (evt) => {
+                    this._onGamepadConnectedEvent = (evt) => {
                         this._onGamepadConnected(evt);
-                    }, false);
-                    window.addEventListener('gamepaddisconnected',
-                        (evt) => {
-                            this._onGamepadDisconnected(evt);
-                        }, false);
+                    };
+                    this._onGamepadDisonnectedEvent = (evt) => {
+                        this._onGamepadDisconnected(evt);
+                    };
+                    window.addEventListener('gamepadconnected', this._onGamepadConnectedEvent, false);
+                    window.addEventListener('gamepaddisconnected', this._onGamepadDisonnectedEvent, false);
                 }
                 else {
                     this._startMonitoringGamepads();
@@ -35,6 +41,13 @@
             if (Gamepads.gamepadDOMInfo) {
                 document.body.removeChild(Gamepads.gamepadDOMInfo);
             }
+            
+            if (this._onGamepadConnectedEvent){
+                window.removeEventListener('gamepadconnected', this._onGamepadConnectedEvent, false);
+                window.removeEventListener('gamepaddisconnected', this._onGamepadDisonnectedEvent, false);
+                this._onGamepadConnectedEvent = null;
+                this._onGamepadDisonnectedEvent = null;
+            }
         }
 
         private _onGamepadConnected(evt) {