瀏覽代碼

Gamepard reworked.

David Catuhe 8 年之前
父節點
當前提交
c6ad1e1f77

+ 8 - 3
Tools/Gulp/config.json

@@ -528,9 +528,14 @@
             "files": [
                 "../../src/Cameras/Inputs/babylon.freeCameraGamepadInput.js",
                 "../../src/Cameras/Inputs/babylon.arcRotateCameraGamepadInput.js",
-                "../../src/Tools/Gamepad/babylon.gamepadManager.js",
-                "../../src/Tools/Gamepad/babylon.gamepads.js",
-                "../../src/Tools/Gamepad/babylon.extendedGamepad.js"
+                "../../src/Gamepad/babylon.gamepadManager.js",
+                "../../src/Gamepad/babylon.gamepad.js",
+                "../../src/Gamepad/babylon.xboxGamepad.js",
+                "../../src/Gamepad/Controllers/babylon.poseEnabledController.js",
+                "../../src/Gamepad/Controllers/babylon.webVRController.js",
+                "../../src/Gamepad/Controllers/babylon.oculusTouchController.js",
+                "../../src/Gamepad/Controllers/babylon.viveController.js",
+                "../../src/Gamepad/Controllers/babylon.genericController.js"
             ],
             "dependUpon" : [
                 "core"

文件差異過大導致無法顯示
+ 3746 - 3734
dist/preview release/babylon.d.ts


文件差異過大導致無法顯示
+ 16 - 16
dist/preview release/babylon.js


+ 60 - 36
dist/preview release/babylon.max.js

@@ -12668,7 +12668,7 @@ var BABYLON;
             BABYLON.Tmp.Matrix[2].multiplyToRef(BABYLON.Tmp.Matrix[0], BABYLON.Tmp.Matrix[2]);
             BABYLON.Tmp.Matrix[2].decompose(BABYLON.Tmp.Vector3[0], BABYLON.Tmp.Quaternion[0], BABYLON.Tmp.Vector3[1]);
             this.position.addInPlace(BABYLON.Tmp.Vector3[1]);
-            this.rotationQuaternion.multiplyInPlace(BABYLON.Tmp.Quaternion[0]);
+            BABYLON.Tmp.Quaternion[0].multiplyToRef(this.rotationQuaternion, this.rotationQuaternion);
             return this;
         };
         /**
@@ -14654,7 +14654,7 @@ var BABYLON;
             _this.orthoBottom = null;
             _this.orthoTop = null;
             _this.fov = 0.8;
-            _this.minZ = 0.1;
+            _this.minZ = 1;
             _this.maxZ = 10000.0;
             _this.inertia = 0.9;
             _this.mode = Camera.PERSPECTIVE_CAMERA;
@@ -50348,6 +50348,7 @@ var BABYLON;
                         var gamepadToRemove = _this._babylonGamepads[i];
                         _this._babylonGamepads[i] = null;
                         _this.onGamepadDisconnectedObservable.notifyObservers(gamepadToRemove);
+                        gamepadToRemove.dispose();
                         break;
                     }
                 }
@@ -50428,15 +50429,7 @@ var BABYLON;
                 gamepad.update();
             }
             if (this._isMonitoring) {
-                if (window.requestAnimationFrame) {
-                    window.requestAnimationFrame(function () { _this._checkGamepadsStatus(); });
-                }
-                else if (window.mozRequestAnimationFrame) {
-                    window.mozRequestAnimationFrame(function () { _this._checkGamepadsStatus(); });
-                }
-                else if (window.webkitRequestAnimationFrame) {
-                    window.webkitRequestAnimationFrame(function () { _this._checkGamepadsStatus(); });
-                }
+                BABYLON.Tools.QueueNewFrame(function () { _this._checkGamepadsStatus(); });
             }
         };
         // This function is called only on Chrome, which does not properly support
@@ -50535,6 +50528,8 @@ var BABYLON;
                 this.rightStick = { x: this.browserGamepad.axes[this._rightStickAxisX], y: this.browserGamepad.axes[this._rightStickAxisY] };
             }
         };
+        Gamepad.prototype.dispose = function () {
+        };
         Gamepad.GAMEPAD = 0;
         Gamepad.GENERIC = 1;
         Gamepad.XBOX = 2;
@@ -50576,6 +50571,13 @@ var BABYLON;
         return GenericPad;
     }(Gamepad));
     BABYLON.GenericPad = GenericPad;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.gamepad.js.map
+
+
+var BABYLON;
+(function (BABYLON) {
     var Xbox360Button;
     (function (Xbox360Button) {
         Xbox360Button[Xbox360Button["A"] = 0] = "A";
@@ -50618,7 +50620,7 @@ var BABYLON;
             _this._dPadLeft = 0;
             _this._dPadRight = 0;
             _this._isXboxOnePad = false;
-            _this.type = Gamepad.XBOX;
+            _this.type = BABYLON.Gamepad.XBOX;
             _this._isXboxOnePad = xboxOne;
             return _this;
         }
@@ -50868,11 +50870,11 @@ var BABYLON;
             }
         };
         return Xbox360Pad;
-    }(Gamepad));
+    }(BABYLON.Gamepad));
     BABYLON.Xbox360Pad = Xbox360Pad;
 })(BABYLON || (BABYLON = {}));
 
-//# sourceMappingURL=babylon.gamepads.js.map
+//# sourceMappingURL=babylon.xboxGamepad.js.map
 
 
 var BABYLON;
@@ -50890,13 +50892,13 @@ var BABYLON;
         PoseEnabledControllerHelper.InitiateController = function (vrGamepad) {
             // Oculus Touch
             if (vrGamepad.id.indexOf('Oculus Touch') !== -1) {
-                return new OculusTouchController(vrGamepad);
+                return new BABYLON.OculusTouchController(vrGamepad);
             }
             else if (vrGamepad.id.toLowerCase().indexOf('openvr') !== -1) {
-                return new ViveController(vrGamepad);
+                return new BABYLON.ViveController(vrGamepad);
             }
             else {
-                return new GenericController(vrGamepad);
+                return new BABYLON.GenericController(vrGamepad);
             }
         };
         return PoseEnabledControllerHelper;
@@ -50979,6 +50981,7 @@ var BABYLON;
                 this._mesh.dispose();
             }
             this._mesh = undefined;
+            _super.prototype.dispose.call(this);
         };
         Object.defineProperty(PoseEnabledController.prototype, "mesh", {
             get: function () {
@@ -51002,11 +51005,17 @@ var BABYLON;
         return PoseEnabledController;
     }(BABYLON.Gamepad));
     BABYLON.PoseEnabledController = PoseEnabledController;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.poseEnabledController.js.map
+
+
+var BABYLON;
+(function (BABYLON) {
     var WebVRController = (function (_super) {
         __extends(WebVRController, _super);
         function WebVRController(vrGamepad) {
             var _this = _super.call(this, vrGamepad) || this;
-            //public onTriggerStateChangedObservable = new Observable<{ state: ExtendedGamepadButton, changes: GamepadButtonChanges }>();
             _this.onTriggerStateChangedObservable = new BABYLON.Observable();
             _this.onMainButtonStateChangedObservable = new BABYLON.Observable();
             _this.onSecondaryButtonStateChangedObservable = new BABYLON.Observable();
@@ -51073,15 +51082,22 @@ var BABYLON;
             return this._changes;
         };
         return WebVRController;
-    }(PoseEnabledController));
+    }(BABYLON.PoseEnabledController));
     BABYLON.WebVRController = WebVRController;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.webVRController.js.map
+
+
+var BABYLON;
+(function (BABYLON) {
     var OculusTouchController = (function (_super) {
         __extends(OculusTouchController, _super);
         function OculusTouchController(vrGamepad) {
             var _this = _super.call(this, vrGamepad) || this;
             _this.onSecondaryTriggerStateChangedObservable = new BABYLON.Observable();
             _this.onThumbRestChangedObservable = new BABYLON.Observable();
-            _this.controllerType = PoseEnabledControllerType.OCULUS;
+            _this.controllerType = BABYLON.PoseEnabledControllerType.OCULUS;
             return _this;
         }
         OculusTouchController.prototype.initControllerMesh = function (scene, meshLoaded) {
@@ -51211,13 +51227,20 @@ var BABYLON;
             }
         };
         return OculusTouchController;
-    }(WebVRController));
+    }(BABYLON.WebVRController));
     BABYLON.OculusTouchController = OculusTouchController;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.oculusTouchController.js.map
+
+
+var BABYLON;
+(function (BABYLON) {
     var ViveController = (function (_super) {
         __extends(ViveController, _super);
         function ViveController(vrGamepad) {
             var _this = _super.call(this, vrGamepad) || this;
-            _this.controllerType = PoseEnabledControllerType.VIVE;
+            _this.controllerType = BABYLON.PoseEnabledControllerType.VIVE;
             return _this;
         }
         ViveController.prototype.initControllerMesh = function (scene, meshLoaded) {
@@ -51298,8 +51321,15 @@ var BABYLON;
             }
         };
         return ViveController;
-    }(WebVRController));
+    }(BABYLON.WebVRController));
     BABYLON.ViveController = ViveController;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.viveController.js.map
+
+
+var BABYLON;
+(function (BABYLON) {
     var GenericController = (function (_super) {
         __extends(GenericController, _super);
         function GenericController(vrGamepad) {
@@ -51320,11 +51350,11 @@ var BABYLON;
             console.dir(state);
         };
         return GenericController;
-    }(WebVRController));
+    }(BABYLON.WebVRController));
     BABYLON.GenericController = GenericController;
 })(BABYLON || (BABYLON = {}));
 
-//# sourceMappingURL=babylon.extendedGamepad.js.map
+//# sourceMappingURL=babylon.genericController.js.map
 
 /// <reference path="babylon.targetCamera.ts" />
 
@@ -64956,8 +64986,9 @@ var BABYLON;
             },
             set: function (camera) {
                 this._camera = camera;
-                if (!this._camera.rotationQuaternion)
+                if (this._camera != null && !this._camera.rotationQuaternion) {
                     this._camera.rotationQuaternion = new BABYLON.Quaternion();
+                }
             },
             enumerable: true,
             configurable: true
@@ -65144,10 +65175,9 @@ var BABYLON;
             _this.devicePosition = BABYLON.Vector3.Zero();
             _this.deviceScaleFactor = 1;
             _this.controllers = [];
-            _this.nonVRControllers = [];
             _this.onControllersAttachedObservable = new BABYLON.Observable();
-            _this.onNonVRControllersAttachedObservable = new BABYLON.Observable();
             _this.rigParenting = true; // should the rig cameras be used as parent instead of this camera.
+            _this.minZ = 0.1;
             //legacy support - the compensation boolean was removed.
             if (arguments.length === 5) {
                 _this.webVROptions = arguments[4];
@@ -65271,7 +65301,6 @@ var BABYLON;
                     //backwards comp
                     var pose = this._vrDevice.getPose();
                     this._frameData.pose = pose;
-                    // calculate view and projection matrix
                 }
                 this.updateFromDevice(this._frameData.pose);
             }
@@ -65403,8 +65432,8 @@ var BABYLON;
             }
             else {
                 var parentCamera = this.parent;
-                parentCamera._vrDevice.depthNear = this.minZ;
-                parentCamera._vrDevice.depthFar = this.maxZ;
+                parentCamera._vrDevice.depthNear = parentCamera.minZ;
+                parentCamera._vrDevice.depthFar = parentCamera.maxZ;
                 var projectionArray = this._cameraRigParams["left"] ? this._cameraRigParams["frameData"].leftProjectionMatrix : this._cameraRigParams["frameData"].rightProjectionMatrix;
                 BABYLON.Matrix.FromArrayToRef(projectionArray, 0, this._projectionMatrix);
                 //babylon compatible matrix
@@ -65429,7 +65458,6 @@ var BABYLON;
                         return;
                     }
                     _this.controllers.splice(index, 1);
-                    webVrController.dispose();
                 }
             });
             this._onGamepadConnectedObserver = manager.onGamepadConnectedObservable.add(function (gamepad) {
@@ -65473,10 +65501,6 @@ var BABYLON;
                         }
                     }
                 }
-                else {
-                    _this.nonVRControllers.push(gamepad);
-                    _this.onNonVRControllersAttachedObservable.notifyObservers(gamepad);
-                }
             });
         };
         return WebVRFreeCamera;

文件差異過大導致無法顯示
+ 3746 - 3734
dist/preview release/babylon.module.d.ts


文件差異過大導致無法顯示
+ 16 - 16
dist/preview release/babylon.worker.js


文件差異過大導致無法顯示
+ 4359 - 4347
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


文件差異過大導致無法顯示
+ 3 - 3
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js


+ 2 - 2
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js

@@ -12668,7 +12668,7 @@ var BABYLON;
             BABYLON.Tmp.Matrix[2].multiplyToRef(BABYLON.Tmp.Matrix[0], BABYLON.Tmp.Matrix[2]);
             BABYLON.Tmp.Matrix[2].decompose(BABYLON.Tmp.Vector3[0], BABYLON.Tmp.Quaternion[0], BABYLON.Tmp.Vector3[1]);
             this.position.addInPlace(BABYLON.Tmp.Vector3[1]);
-            this.rotationQuaternion.multiplyInPlace(BABYLON.Tmp.Quaternion[0]);
+            BABYLON.Tmp.Quaternion[0].multiplyToRef(this.rotationQuaternion, this.rotationQuaternion);
             return this;
         };
         /**
@@ -14654,7 +14654,7 @@ var BABYLON;
             _this.orthoBottom = null;
             _this.orthoTop = null;
             _this.fov = 0.8;
-            _this.minZ = 0.1;
+            _this.minZ = 1;
             _this.maxZ = 10000.0;
             _this.inertia = 0.9;
             _this.mode = Camera.PERSPECTIVE_CAMERA;

文件差異過大導致無法顯示
+ 4359 - 4347
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts


文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/loaders/babylon.objFileLoader.min.js


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

@@ -4,6 +4,7 @@
 - Added support for non-pow2 textures when in WebGL2 mode ([deltakosh](https://github.com/deltakosh))
 - Engine can now be initialized with an existing webgl context ([deltakosh](https://github.com/deltakosh))
 - Introduced behaviors. (Doc here)[http://doc.babylonjs.com/overviews/behaviors] ([deltakosh](https://github.com/deltakosh))
+- Added support for WebGL Occlusion queries. (Doc here)[http://doc.babylonjs.com/overviews/occlusionquery] ([Ibraheem Osama](https://github.com/IbraheemOsama))
 - New behaviors for ArcRotateCamera:
  - AutoRotation ([deltakosh](https://github.com/deltakosh))
  - Framing ([deltakosh](https://github.com/deltakosh))

+ 4 - 11
src/Cameras/VR/babylon.webVRCamera.ts

@@ -60,9 +60,7 @@ module BABYLON {
         public deviceScaleFactor: number = 1;
 
         public controllers: Array<WebVRController> = [];
-        public nonVRControllers: Array<Gamepad> = [];
         public onControllersAttachedObservable = new Observable<Array<WebVRController>>();
-        public onNonVRControllersAttachedObservable = new Observable<Gamepad>();
 
         public rigParenting: boolean = true; // should the rig cameras be used as parent instead of this camera.
 
@@ -71,6 +69,8 @@ module BABYLON {
         constructor(name: string, position: Vector3, scene: Scene, private webVROptions: WebVROptions = {}) {
             super(name, position, scene);
 
+            this.minZ = 0.1;
+
             //legacy support - the compensation boolean was removed.
             if (arguments.length === 5) {
                 this.webVROptions = arguments[4];
@@ -201,7 +201,6 @@ module BABYLON {
                     //backwards comp
                     let pose = this._vrDevice.getPose();
                     this._frameData.pose = pose;
-                    // calculate view and projection matrix
                 }
 
                 this.updateFromDevice(this._frameData.pose);
@@ -360,8 +359,8 @@ module BABYLON {
 
                 let parentCamera = <WebVRFreeCamera> this.parent;
 
-                parentCamera._vrDevice.depthNear = this.minZ;
-                parentCamera._vrDevice.depthFar = this.maxZ;
+                parentCamera._vrDevice.depthNear = parentCamera.minZ;
+                parentCamera._vrDevice.depthFar = parentCamera.maxZ;
                 
                 var projectionArray = this._cameraRigParams["left"] ? this._cameraRigParams["frameData"].leftProjectionMatrix : this._cameraRigParams["frameData"].rightProjectionMatrix;
                 Matrix.FromArrayToRef(projectionArray, 0, this._projectionMatrix);
@@ -395,8 +394,6 @@ module BABYLON {
                     }
 
                     this.controllers.splice(index, 1);
-                    
-                    webVrController.dispose();
                 }
             });
 
@@ -445,10 +442,6 @@ module BABYLON {
                         }
                     }
                 }
-                else {
-                    this.nonVRControllers.push(gamepad);
-                    this.onNonVRControllersAttachedObservable.notifyObservers(gamepad);
-                }
             });
         }
     }

+ 1 - 1
src/Cameras/babylon.camera.ts

@@ -86,7 +86,7 @@
         public fov = 0.8;
 
         @serialize()
-        public minZ = 0.1;
+        public minZ = 1;
 
         @serialize()
         public maxZ = 10000.0;

+ 26 - 0
src/Gamepad/Controllers/babylon.genericController.ts

@@ -0,0 +1,26 @@
+module BABYLON {
+    
+    export class GenericController extends WebVRController {
+        private _defaultModel: BABYLON.AbstractMesh;
+
+        constructor(vrGamepad) {
+            super(vrGamepad);
+        }
+
+        public initControllerMesh(scene: Scene, meshLoaded?: (mesh: AbstractMesh) => void) {
+            SceneLoader.ImportMesh("", "http://yoda.blob.core.windows.net/models/", "genericvrcontroller.babylon", scene, (newMeshes) => {
+                this._defaultModel = newMeshes[1];
+                if (meshLoaded) {
+                    meshLoaded(this._defaultModel);
+                }
+                this.attachToMesh(this._defaultModel);
+            });
+        }
+
+        protected handleButtonChange(buttonIdx: number, state: ExtendedGamepadButton, changes: GamepadButtonChanges) {
+            console.log("Button id: " + buttonIdx + "state: ");
+            console.dir(state);
+        }
+    }
+
+}

+ 130 - 0
src/Gamepad/Controllers/babylon.oculusTouchController.ts

@@ -0,0 +1,130 @@
+module BABYLON {
+
+    export class OculusTouchController extends WebVRController {
+        private _defaultModel: BABYLON.AbstractMesh;
+
+        public onSecondaryTriggerStateChangedObservable = new Observable<ExtendedGamepadButton>();
+
+        public onThumbRestChangedObservable = new Observable<ExtendedGamepadButton>();
+
+        constructor(vrGamepad) {
+            super(vrGamepad);
+            this.controllerType = PoseEnabledControllerType.OCULUS;
+        }
+
+        public initControllerMesh(scene: Scene, meshLoaded?: (mesh: AbstractMesh) => void) {
+            let meshName = this.hand === 'right' ? 'RightTouch.babylon' : 'LeftTouch.babylon';
+            SceneLoader.ImportMesh("", "http://yoda.blob.core.windows.net/models/", meshName, scene, (newMeshes) => {
+                /*
+                Parent Mesh name: oculus_touch_left
+                - body
+                - trigger
+                - thumbstick
+                - grip
+                - button_y 
+                - button_x
+                - button_enter
+                */
+
+                this._defaultModel = newMeshes[1];
+                if (meshLoaded) {
+                    meshLoaded(this._defaultModel);
+                }
+                this.attachToMesh(this._defaultModel);
+            });
+        }
+
+
+        // helper getters for left and right hand.
+        public get onAButtonStateChangedObservable() {
+            if (this.hand === 'right') {
+                return this.onMainButtonStateChangedObservable;
+            } else {
+                throw new Error('No A button on left hand');
+            }
+        }
+
+        public get onBButtonStateChangedObservable() {
+            if (this.hand === 'right') {
+                return this.onSecondaryButtonStateChangedObservable;
+            } else {
+                throw new Error('No B button on left hand');
+            }
+        }
+
+        public get onXButtonStateChangedObservable() {
+            if (this.hand === 'left') {
+                return this.onMainButtonStateChangedObservable;
+            } else {
+                throw new Error('No X button on right hand');
+            }
+        }
+
+        public get onYButtonStateChangedObservable() {
+            if (this.hand === 'left') {
+                return this.onSecondaryButtonStateChangedObservable;
+            } else {
+                throw new Error('No Y button on right hand');
+            }
+        }
+
+        /*
+         0) thumb stick (touch, press, value = pressed (0,1)). value is in this.leftStick
+         1) index trigger (touch (?), press (only when value > 0.1), value 0 to 1)
+         2) secondary trigger (same)
+         3) A (right) X (left), touch, pressed = value
+         4) B / Y 
+         5) thumb rest
+        */
+        protected handleButtonChange(buttonIdx: number, state: ExtendedGamepadButton, changes: GamepadButtonChanges) {
+            let notifyObject = state; //{ state: state, changes: changes };
+            let triggerDirection = this.hand === 'right' ? -1 : 1;
+            switch (buttonIdx) {
+                case 0:
+                    this.onPadStateChangedObservable.notifyObservers(notifyObject);
+                    return;
+                case 1: // index trigger
+                    if (this._defaultModel) {
+                        (<AbstractMesh>(this._defaultModel.getChildren()[3])).rotation.x = -notifyObject.value * 0.20;
+                        (<AbstractMesh>(this._defaultModel.getChildren()[3])).position.y = -notifyObject.value * 0.005;
+                        (<AbstractMesh>(this._defaultModel.getChildren()[3])).position.z = -notifyObject.value * 0.005;
+                    }
+                    this.onTriggerStateChangedObservable.notifyObservers(notifyObject);
+                    return;
+                case 2:  // secondary trigger
+                    if (this._defaultModel) {
+                        (<AbstractMesh>(this._defaultModel.getChildren()[4])).position.x = triggerDirection * notifyObject.value * 0.0035;
+                    }
+                    this.onSecondaryTriggerStateChangedObservable.notifyObservers(notifyObject);
+                    return;
+                case 3:
+                    if (this._defaultModel) {
+                        if (notifyObject.pressed) {
+                            (<AbstractMesh>(this._defaultModel.getChildren()[1])).position.y = -0.001;
+                        }
+                        else {
+                            (<AbstractMesh>(this._defaultModel.getChildren()[1])).position.y = 0;
+                        }
+                    }
+                    this.onMainButtonStateChangedObservable.notifyObservers(notifyObject);
+                    return;
+                case 4:
+                    if (this._defaultModel) {
+                        if (notifyObject.pressed) {
+                            (<AbstractMesh>(this._defaultModel.getChildren()[2])).position.y = -0.001;
+                        }
+                        else {
+                            (<AbstractMesh>(this._defaultModel.getChildren()[2])).position.y = 0;
+                        }
+                    }
+                    this.onSecondaryButtonStateChangedObservable.notifyObservers(notifyObject);
+                    return;
+                case 5:
+                    this.onThumbRestChangedObservable.notifyObservers(notifyObject);
+                    return;
+            }
+        }
+
+    }
+
+}

+ 166 - 0
src/Gamepad/Controllers/babylon.poseEnabledController.ts

@@ -0,0 +1,166 @@
+module BABYLON {
+
+    export enum PoseEnabledControllerType {
+        VIVE,
+        OCULUS,
+        WINDOWS,
+        GENERIC
+    }
+
+    export interface MutableGamepadButton {
+        value: number;
+        touched: boolean;
+        pressed: boolean;
+    }
+    
+    export interface ExtendedGamepadButton extends GamepadButton {
+        readonly pressed: boolean;
+        readonly touched: boolean;
+        readonly value: number;
+    }
+
+    export class PoseEnabledControllerHelper {
+        public static InitiateController(vrGamepad: any) {
+            // Oculus Touch
+            if (vrGamepad.id.indexOf('Oculus Touch') !== -1) {
+                return new OculusTouchController(vrGamepad);
+            }
+            // Windows Mixed Reality controllers 
+            // else if (vrGamepad.id.indexOf('Spatial Control') === 0) {
+            //     //return new WindowsMixedRealityController(vrGamepad);
+            // }
+            // HTC Vive
+            else if (vrGamepad.id.toLowerCase().indexOf('openvr') !== -1) {
+                return new ViveController(vrGamepad);
+            }
+            // Generic 
+            else {
+                return new GenericController(vrGamepad);
+            }
+        }
+    }
+
+    export class PoseEnabledController extends Gamepad implements PoseControlled {
+        devicePosition: Vector3;
+        deviceRotationQuaternion: Quaternion;
+        deviceScaleFactor: number = 1;
+
+        public position: Vector3;
+        public rotationQuaternion: Quaternion;
+        public controllerType: PoseEnabledControllerType;
+
+        private _calculatedPosition: Vector3;
+        private _calculatedRotation: Quaternion;
+
+        public rawPose: DevicePose; //GamepadPose;
+
+        public _mesh: AbstractMesh; // a node that will be attached to this Gamepad
+        private _poseControlledCamera: TargetCamera;
+
+        private _leftHandSystemQuaternion: Quaternion = new Quaternion();
+
+        constructor(public vrGamepad) {
+            super(vrGamepad.id, vrGamepad.index, vrGamepad);
+            this.type = Gamepad.POSE_ENABLED;
+            this.controllerType = PoseEnabledControllerType.GENERIC;
+            this.position = Vector3.Zero();
+            this.rotationQuaternion = new Quaternion();
+            this.devicePosition = Vector3.Zero();
+            this.deviceRotationQuaternion = new Quaternion();
+
+            this._calculatedPosition = Vector3.Zero();
+            this._calculatedRotation = new Quaternion();
+            Quaternion.RotationYawPitchRollToRef(Math.PI, 0, 0, this._leftHandSystemQuaternion);
+        }
+
+        public update() {
+            super.update();
+            var pose: GamepadPose = this.vrGamepad.pose;
+            this.updateFromDevice(pose);
+
+            if (this._mesh) {
+                this._mesh.position.copyFrom(this._calculatedPosition);
+                this._mesh.rotationQuaternion.copyFrom(this._calculatedRotation);
+            }
+        }
+
+        updateFromDevice(poseData: DevicePose) {
+            if (poseData) {
+                this.rawPose = poseData;
+                if (poseData.position) {
+                    this.devicePosition.copyFromFloats(poseData.position[0], poseData.position[1], -poseData.position[2]);
+                    if (this._mesh && this._mesh.getScene().useRightHandedSystem) {
+                        this.devicePosition.z *= -1;
+                    }
+
+                    this.devicePosition.scaleToRef(this.deviceScaleFactor, this._calculatedPosition);
+                    this._calculatedPosition.addInPlace(this.position);
+                }
+                if (poseData.orientation) {
+                    this.deviceRotationQuaternion.copyFromFloats(this.rawPose.orientation[0], this.rawPose.orientation[1], -this.rawPose.orientation[2], -this.rawPose.orientation[3]);
+                    if (this._mesh) {
+                        if (this._mesh.getScene().useRightHandedSystem) {
+                            this.deviceRotationQuaternion.z *= -1;
+                            this.deviceRotationQuaternion.w *= -1;
+                        } else {
+                            this.deviceRotationQuaternion.multiplyToRef(this._leftHandSystemQuaternion, this.deviceRotationQuaternion);
+                        }
+                    }
+
+                    // if the camera is set, rotate to the camera's rotation
+                    this.deviceRotationQuaternion.multiplyToRef(this.rotationQuaternion, this._calculatedRotation);
+                }
+            }
+        }
+
+
+        public attachToMesh(mesh: AbstractMesh) {
+            if (this._mesh) {
+                this._mesh.parent = undefined;
+            }
+            this._mesh = mesh;
+            if (this._poseControlledCamera) {
+                this._mesh.parent = this._poseControlledCamera;
+            }
+            if (!this._mesh.rotationQuaternion) {
+                this._mesh.rotationQuaternion = new Quaternion();
+            }
+        }
+
+        public attachToPoseControlledCamera(camera: TargetCamera) {
+            this._poseControlledCamera = camera;
+            if (this._mesh) {
+                this._mesh.parent = this._poseControlledCamera;
+            }
+        }
+
+        public dispose() {
+            if (this._mesh) {
+                this._mesh.dispose();
+            }
+            this._mesh = undefined;
+
+            super.dispose();
+        }
+
+        public get mesh(): AbstractMesh {
+            return this._mesh;
+        }
+
+        public getForwardRay(length = 100): Ray {
+            if (!this.mesh) {
+                return new Ray(Vector3.Zero(), new BABYLON.Vector3(0, 0, 1), length);
+            }
+
+            var m = this.mesh.getWorldMatrix();
+            var origin = m.getTranslation();
+
+            var forward = new BABYLON.Vector3(0, 0, -1);
+            var forwardWorld = BABYLON.Vector3.TransformNormal(forward, m);
+
+            var direction = BABYLON.Vector3.Normalize(forwardWorld);            
+
+            return new Ray(origin, direction, length);
+        } 
+    }
+}

+ 82 - 0
src/Gamepad/Controllers/babylon.viveController.ts

@@ -0,0 +1,82 @@
+module BABYLON {
+
+    export class ViveController extends WebVRController {
+        private _defaultModel: BABYLON.AbstractMesh;
+
+        constructor(vrGamepad) {
+            super(vrGamepad);
+            this.controllerType = PoseEnabledControllerType.VIVE;
+        }
+
+        public initControllerMesh(scene: Scene, meshLoaded?: (mesh: AbstractMesh) => void) {
+            SceneLoader.ImportMesh("", "http://yoda.blob.core.windows.net/models/", "ViveWand.babylon", scene, (newMeshes) => {
+                /*
+                Parent Mesh name: ViveWand
+                - body
+                - r_gripper
+                - l_gripper
+                - menu_button
+                - system_button
+                - trackpad
+                - trigger
+                - LED
+                */
+                this._defaultModel = newMeshes[1];
+                if (meshLoaded) {
+                    meshLoaded(this._defaultModel);
+                }
+                this.attachToMesh(this._defaultModel);
+            });
+        }
+
+
+        public get onLeftButtonStateChangedObservable() {
+            return this.onMainButtonStateChangedObservable;
+        }
+
+        public get onRightButtonStateChangedObservable() {
+            return this.onMainButtonStateChangedObservable;
+        }
+
+        public get onMenuButtonStateChangedObservable() {
+            return this.onSecondaryButtonStateChangedObservable;
+        }
+
+        /**
+         * Vive mapping:
+         * 0: touchpad
+         * 1: trigger
+         * 2: left AND right buttons
+         * 3: menu button
+         */
+        protected handleButtonChange(buttonIdx: number, state: ExtendedGamepadButton, changes: GamepadButtonChanges) {
+            let notifyObject = state; //{ state: state, changes: changes };
+            switch (buttonIdx) {
+                case 0:
+                    this.onPadStateChangedObservable.notifyObservers(notifyObject);
+                    return;
+                case 1: // index trigger
+                    if (this._defaultModel) {
+                        (<AbstractMesh>(this._defaultModel.getChildren()[6])).rotation.x = -notifyObject.value * 0.15;
+                    }
+                    this.onTriggerStateChangedObservable.notifyObservers(notifyObject);
+                    return;
+                case 2:  // left AND right button
+                    this.onMainButtonStateChangedObservable.notifyObservers(notifyObject);
+                    return;
+                case 3:
+                    if (this._defaultModel) {
+                        if (notifyObject.pressed) {
+                            (<AbstractMesh>(this._defaultModel.getChildren()[2])).position.y = -0.001;
+                        }
+                        else {
+                            (<AbstractMesh>(this._defaultModel.getChildren()[2])).position.y = 0;
+                        }
+                    }
+                    this.onSecondaryButtonStateChangedObservable.notifyObservers(notifyObject);
+                    return;
+            }
+        }
+    }
+
+}

+ 93 - 0
src/Gamepad/Controllers/babylon.webVRController.ts

@@ -0,0 +1,93 @@
+module BABYLON {
+
+    export abstract class WebVRController extends PoseEnabledController {
+
+        public onTriggerStateChangedObservable = new Observable<ExtendedGamepadButton>();
+
+        public onMainButtonStateChangedObservable = new Observable<ExtendedGamepadButton>();
+
+        public onSecondaryButtonStateChangedObservable = new Observable<ExtendedGamepadButton>();
+
+        public onPadStateChangedObservable = new Observable<ExtendedGamepadButton>();
+        public onPadValuesChangedObservable = new Observable<StickValues>();
+
+        protected _buttons: Array<MutableGamepadButton>;
+
+        private _onButtonStateChange: (controlledIndex: number, buttonIndex: number, state: ExtendedGamepadButton) => void;
+
+        public onButtonStateChange(callback: (controlledIndex: number, buttonIndex: number, state: ExtendedGamepadButton) => void) {
+            this._onButtonStateChange = callback;
+        }
+
+        public pad: StickValues = { x: 0, y: 0 };
+
+        public hand: string; // 'left' or 'right', see https://w3c.github.io/gamepad/extensions.html#gamepadhand-enum
+
+        constructor(vrGamepad) {
+            super(vrGamepad);
+            this._buttons = new Array<ExtendedGamepadButton>(vrGamepad.buttons.length);
+            this.hand = vrGamepad.hand;
+        }
+
+        public update() {
+            super.update();
+            for (var index = 0; index < this._buttons.length; index++) {
+                this._setButtonValue(this.vrGamepad.buttons[index], this._buttons[index], index);
+            };
+            if (this.leftStick.x !== this.pad.x || this.leftStick.y !== this.pad.y) {
+                this.pad.x = this.leftStick.x;
+                this.pad.y = this.leftStick.y;
+                this.onPadValuesChangedObservable.notifyObservers(this.pad);
+            }
+        }
+
+        protected abstract handleButtonChange(buttonIdx: number, value: ExtendedGamepadButton, changes: GamepadButtonChanges);
+
+        public abstract initControllerMesh(scene: Scene, meshLoaded?: (mesh: AbstractMesh) => void);
+
+        private _setButtonValue(newState: ExtendedGamepadButton, currentState: ExtendedGamepadButton, buttonIndex: number) {
+            if (!newState) {
+                newState = {
+                    pressed: false,
+                    touched: false,
+                    value: 0
+                };
+            }  
+            if (!currentState) {
+                this._buttons[buttonIndex] = {
+                    pressed: newState.pressed,
+                    touched: newState.touched,
+                    value: newState.value
+                }
+                return;
+            }
+            this._checkChanges(newState, currentState);
+            if (this._changes.changed) {
+                this._onButtonStateChange && this._onButtonStateChange(this.index, buttonIndex, newState);
+
+                this.handleButtonChange(buttonIndex, newState, this._changes);
+            }
+            this._buttons[buttonIndex].pressed = newState.pressed;
+            this._buttons[buttonIndex].touched = newState.touched;
+            // oculus triggers are never 0, thou not touched.
+            this._buttons[buttonIndex].value = newState.value < 0.00000001 ? 0 : newState.value;
+        }
+
+        // avoid GC, store state in a tmp object
+        private _changes: GamepadButtonChanges = {
+            pressChanged: false,
+            touchChanged: false,
+            valueChanged: false,
+            changed: false
+        };
+
+        private _checkChanges(newState: ExtendedGamepadButton, currentState: ExtendedGamepadButton) {
+            this._changes.pressChanged = newState.pressed !== currentState.pressed;
+            this._changes.touchChanged = newState.touched !== currentState.touched;
+            this._changes.valueChanged = newState.value !== currentState.value;
+            this._changes.changed = this._changes.pressChanged || this._changes.touchChanged || this._changes.valueChanged;
+            return this._changes;
+        }
+    }
+        
+}

+ 125 - 0
src/Gamepad/babylon.gamepad.ts

@@ -0,0 +1,125 @@
+module BABYLON {
+    export class StickValues {
+        constructor(public x, public y) {
+        }
+    }
+
+    export interface GamepadButtonChanges {
+        changed: boolean;
+        pressChanged: boolean;
+        touchChanged: boolean;
+        valueChanged: boolean;
+    }
+    
+    export class Gamepad {
+
+        public type: number;
+
+        private _leftStick: StickValues;
+        private _rightStick: StickValues;
+
+        private _leftStickAxisX: number;
+        private _leftStickAxisY: number;
+        private _rightStickAxisX: number;
+        private _rightStickAxisY: number;
+
+        private _onleftstickchanged: (values: StickValues) => void;
+        private _onrightstickchanged: (values: StickValues) => void;
+
+        public static GAMEPAD = 0;
+        public static GENERIC = 1;
+        public static XBOX = 2;
+        public static POSE_ENABLED = 3;
+
+        constructor(public id: string, public index: number, public browserGamepad, leftStickX: number = 0, leftStickY: number = 1, rightStickX: number = 2, rightStickY: number = 3) {
+            this.type = Gamepad.GAMEPAD;
+            this._leftStickAxisX = leftStickX;
+            this._leftStickAxisY = leftStickY;
+            this._rightStickAxisX = rightStickX;
+            this._rightStickAxisY = rightStickY;
+            if (this.browserGamepad.axes.length >= 2) {
+                this._leftStick = { x: this.browserGamepad.axes[this._leftStickAxisX], y: this.browserGamepad.axes[this._leftStickAxisY] };
+            }
+            if (this.browserGamepad.axes.length >= 4) {
+                this._rightStick = { x: this.browserGamepad.axes[this._rightStickAxisX], y: this.browserGamepad.axes[this._rightStickAxisY] };
+            }
+        }
+
+        public onleftstickchanged(callback: (values: StickValues) => void) {
+            this._onleftstickchanged = callback;
+        }
+
+        public onrightstickchanged(callback: (values: StickValues) => void) {
+            this._onrightstickchanged = callback;
+        }
+
+        public get leftStick(): StickValues {
+            return this._leftStick;
+        }
+        public set leftStick(newValues: StickValues) {
+            if (this._onleftstickchanged && (this._leftStick.x !== newValues.x || this._leftStick.y !== newValues.y)) {
+                this._onleftstickchanged(newValues);
+            }
+            this._leftStick = newValues;
+        }
+        public get rightStick(): StickValues {
+            return this._rightStick;
+        }
+        public set rightStick(newValues: StickValues) {
+            if (this._onrightstickchanged && (this._rightStick.x !== newValues.x || this._rightStick.y !== newValues.y)) {
+                this._onrightstickchanged(newValues);
+            }
+            this._rightStick = newValues;
+        }
+
+        public update() {
+            if (this._leftStick) {
+                this.leftStick = { x: this.browserGamepad.axes[this._leftStickAxisX], y: this.browserGamepad.axes[this._leftStickAxisY] };
+            }
+            if (this._rightStick) {
+                this.rightStick = { x: this.browserGamepad.axes[this._rightStickAxisX], y: this.browserGamepad.axes[this._rightStickAxisY] };
+            }
+        }
+
+        public dispose() {            
+        }
+    }
+
+    export class GenericPad extends Gamepad {
+        private _buttons: Array<number>;
+        private _onbuttondown: (buttonPressed: number) => void;
+        private _onbuttonup: (buttonReleased: number) => void;
+
+        public onbuttondown(callback: (buttonPressed: number) => void) {
+            this._onbuttondown = callback;
+        }
+        public onbuttonup(callback: (buttonReleased: number) => void) {
+            this._onbuttonup = callback;
+        }
+
+        constructor(id: string, index: number, browserGamepad) {
+            super(id, index, browserGamepad);
+            this.type = Gamepad.GENERIC;
+            this._buttons = new Array(browserGamepad.buttons.length);
+        }
+
+        private _setButtonValue(newValue: number, currentValue: number, buttonIndex: number): number {
+            if (newValue !== currentValue) {
+                if (this._onbuttondown && newValue === 1) {
+                    this._onbuttondown(buttonIndex);
+                }
+                if (this._onbuttonup && newValue === 0) {
+                    this._onbuttonup(buttonIndex);
+                }
+            }
+            return newValue;
+        }
+
+        public update() {
+            super.update();
+            for (var index = 0; index < this._buttons.length; index++) {
+                this._buttons[index] = this._setButtonValue(this.browserGamepad.buttons[index].value, this._buttons[index], index);
+            }
+        }
+    }
+}

+ 3 - 8
src/Tools/Gamepad/babylon.gamepadManager.ts

@@ -39,6 +39,8 @@
                         this._babylonGamepads[i] = null;
                         
                         this.onGamepadDisconnectedObservable.notifyObservers(gamepadToRemove);
+
+                        gamepadToRemove.dispose();
                         break;
                     }
                 }            
@@ -93,7 +95,6 @@
             if (xboxOne || (<string>gamepad.id).search("Xbox 360") !== -1 || (<string>gamepad.id).search("xinput") !== -1) {
                 newGamepad = new Xbox360Pad(gamepad.id, gamepad.index, gamepad, xboxOne);
             }
-            // (<string>gamepad.id).search("Open VR") !== -1 || (<string>gamepad.id).search("Oculus Touch") !== -1
             // if pose is supported, use the (WebVR) pose enabled controller
             else if (gamepad.pose) {
                 newGamepad = PoseEnabledControllerHelper.InitiateController(gamepad);
@@ -129,13 +130,7 @@
             }
 
             if (this._isMonitoring) {
-                if (window.requestAnimationFrame) {
-                    window.requestAnimationFrame(() => { this._checkGamepadsStatus(); });
-                } else if (window.mozRequestAnimationFrame) {
-                    window.mozRequestAnimationFrame(() => { this._checkGamepadsStatus(); });
-                } else if (window.webkitRequestAnimationFrame) {
-                    window.webkitRequestAnimationFrame(() => { this._checkGamepadsStatus(); });
-                }
+                Tools.QueueNewFrame(() => { this._checkGamepadsStatus(); });
             }
         }
 

+ 0 - 112
src/Tools/Gamepad/babylon.gamepads.ts

@@ -1,116 +1,4 @@
 module BABYLON {
-    export class StickValues {
-        constructor(public x, public y) {
-        }
-    }
-    export class Gamepad {
-
-        public type: number;
-
-        private _leftStick: StickValues;
-        private _rightStick: StickValues;
-
-        private _leftStickAxisX: number;
-        private _leftStickAxisY: number;
-        private _rightStickAxisX: number;
-        private _rightStickAxisY: number;
-
-        private _onleftstickchanged: (values: StickValues) => void;
-        private _onrightstickchanged: (values: StickValues) => void;
-
-        public static GAMEPAD = 0;
-        public static GENERIC = 1;
-        public static XBOX = 2;
-        public static POSE_ENABLED = 3;
-
-        constructor(public id: string, public index: number, public browserGamepad, leftStickX: number = 0, leftStickY: number = 1, rightStickX: number = 2, rightStickY: number = 3) {
-            this.type = Gamepad.GAMEPAD;
-            this._leftStickAxisX = leftStickX;
-            this._leftStickAxisY = leftStickY;
-            this._rightStickAxisX = rightStickX;
-            this._rightStickAxisY = rightStickY;
-            if (this.browserGamepad.axes.length >= 2) {
-                this._leftStick = { x: this.browserGamepad.axes[this._leftStickAxisX], y: this.browserGamepad.axes[this._leftStickAxisY] };
-            }
-            if (this.browserGamepad.axes.length >= 4) {
-                this._rightStick = { x: this.browserGamepad.axes[this._rightStickAxisX], y: this.browserGamepad.axes[this._rightStickAxisY] };
-            }
-        }
-
-        public onleftstickchanged(callback: (values: StickValues) => void) {
-            this._onleftstickchanged = callback;
-        }
-
-        public onrightstickchanged(callback: (values: StickValues) => void) {
-            this._onrightstickchanged = callback;
-        }
-
-        public get leftStick(): StickValues {
-            return this._leftStick;
-        }
-        public set leftStick(newValues: StickValues) {
-            if (this._onleftstickchanged && (this._leftStick.x !== newValues.x || this._leftStick.y !== newValues.y)) {
-                this._onleftstickchanged(newValues);
-            }
-            this._leftStick = newValues;
-        }
-        public get rightStick(): StickValues {
-            return this._rightStick;
-        }
-        public set rightStick(newValues: StickValues) {
-            if (this._onrightstickchanged && (this._rightStick.x !== newValues.x || this._rightStick.y !== newValues.y)) {
-                this._onrightstickchanged(newValues);
-            }
-            this._rightStick = newValues;
-        }
-
-        public update() {
-            if (this._leftStick) {
-                this.leftStick = { x: this.browserGamepad.axes[this._leftStickAxisX], y: this.browserGamepad.axes[this._leftStickAxisY] };
-            }
-            if (this._rightStick) {
-                this.rightStick = { x: this.browserGamepad.axes[this._rightStickAxisX], y: this.browserGamepad.axes[this._rightStickAxisY] };
-            }
-        }
-    }
-
-    export class GenericPad extends Gamepad {
-        private _buttons: Array<number>;
-        private _onbuttondown: (buttonPressed: number) => void;
-        private _onbuttonup: (buttonReleased: number) => void;
-
-        public onbuttondown(callback: (buttonPressed: number) => void) {
-            this._onbuttondown = callback;
-        }
-        public onbuttonup(callback: (buttonReleased: number) => void) {
-            this._onbuttonup = callback;
-        }
-
-        constructor(id: string, index: number, browserGamepad) {
-            super(id, index, browserGamepad);
-            this.type = Gamepad.GENERIC;
-            this._buttons = new Array(browserGamepad.buttons.length);
-        }
-
-        private _setButtonValue(newValue: number, currentValue: number, buttonIndex: number): number {
-            if (newValue !== currentValue) {
-                if (this._onbuttondown && newValue === 1) {
-                    this._onbuttondown(buttonIndex);
-                }
-                if (this._onbuttonup && newValue === 0) {
-                    this._onbuttonup(buttonIndex);
-                }
-            }
-            return newValue;
-        }
-
-        public update() {
-            super.update();
-            for (var index = 0; index < this._buttons.length; index++) {
-                this._buttons[index] = this._setButtonValue(this.browserGamepad.buttons[index].value, this._buttons[index], index);
-            }
-        }
-    }
 
     export enum Xbox360Button {
         A,

+ 0 - 492
src/Tools/Gamepad/babylon.extendedGamepad.ts

@@ -1,492 +0,0 @@
-module BABYLON {
-
-    export enum PoseEnabledControllerType {
-        VIVE,
-        OCULUS,
-        WINDOWS,
-        GENERIC
-    }
-
-    export interface MutableGamepadButton {
-        value: number;
-        touched: boolean;
-        pressed: boolean;
-    }
-
-    export class PoseEnabledControllerHelper {
-        public static InitiateController(vrGamepad: any) {
-            // Oculus Touch
-            if (vrGamepad.id.indexOf('Oculus Touch') !== -1) {
-                return new OculusTouchController(vrGamepad);
-            }
-            // Windows Mixed Reality controllers 
-            // else if (vrGamepad.id.indexOf('Spatial Control') === 0) {
-            //     //return new WindowsMixedRealityController(vrGamepad);
-            // }
-            // HTC Vive
-            else if (vrGamepad.id.toLowerCase().indexOf('openvr') !== -1) {
-                return new ViveController(vrGamepad);
-            }
-            // Generic 
-            else {
-                return new GenericController(vrGamepad);
-            }
-        }
-    }
-
-    export class PoseEnabledController extends Gamepad implements PoseControlled {
-        devicePosition: Vector3;
-        deviceRotationQuaternion: Quaternion;
-        deviceScaleFactor: number = 1;
-
-        public position: Vector3;
-        public rotationQuaternion: Quaternion;
-        public controllerType: PoseEnabledControllerType;
-
-        private _calculatedPosition: Vector3;
-        private _calculatedRotation: Quaternion;
-
-        public rawPose: DevicePose; //GamepadPose;
-
-        public _mesh: AbstractMesh; // a node that will be attached to this Gamepad
-        private _poseControlledCamera: TargetCamera;
-
-        private _leftHandSystemQuaternion: Quaternion = new Quaternion();
-
-        constructor(public vrGamepad) {
-            super(vrGamepad.id, vrGamepad.index, vrGamepad);
-            this.type = Gamepad.POSE_ENABLED;
-            this.controllerType = PoseEnabledControllerType.GENERIC;
-            this.position = Vector3.Zero();
-            this.rotationQuaternion = new Quaternion();
-            this.devicePosition = Vector3.Zero();
-            this.deviceRotationQuaternion = new Quaternion();
-
-            this._calculatedPosition = Vector3.Zero();
-            this._calculatedRotation = new Quaternion();
-            Quaternion.RotationYawPitchRollToRef(Math.PI, 0, 0, this._leftHandSystemQuaternion);
-        }
-
-        public update() {
-            super.update();
-            var pose: GamepadPose = this.vrGamepad.pose;
-            this.updateFromDevice(pose);
-
-            if (this._mesh) {
-                this._mesh.position.copyFrom(this._calculatedPosition);
-                this._mesh.rotationQuaternion.copyFrom(this._calculatedRotation);
-            }
-        }
-
-        updateFromDevice(poseData: DevicePose) {
-            if (poseData) {
-                this.rawPose = poseData;
-                if (poseData.position) {
-                    this.devicePosition.copyFromFloats(poseData.position[0], poseData.position[1], -poseData.position[2]);
-                    if (this._mesh && this._mesh.getScene().useRightHandedSystem) {
-                        this.devicePosition.z *= -1;
-                    }
-
-                    this.devicePosition.scaleToRef(this.deviceScaleFactor, this._calculatedPosition);
-                    this._calculatedPosition.addInPlace(this.position);
-                }
-                if (poseData.orientation) {
-                    this.deviceRotationQuaternion.copyFromFloats(this.rawPose.orientation[0], this.rawPose.orientation[1], -this.rawPose.orientation[2], -this.rawPose.orientation[3]);
-                    if (this._mesh) {
-                        if (this._mesh.getScene().useRightHandedSystem) {
-                            this.deviceRotationQuaternion.z *= -1;
-                            this.deviceRotationQuaternion.w *= -1;
-                        } else {
-                            this.deviceRotationQuaternion.multiplyToRef(this._leftHandSystemQuaternion, this.deviceRotationQuaternion);
-                        }
-                    }
-
-                    // if the camera is set, rotate to the camera's rotation
-                    this.deviceRotationQuaternion.multiplyToRef(this.rotationQuaternion, this._calculatedRotation);
-                }
-            }
-        }
-
-
-        public attachToMesh(mesh: AbstractMesh) {
-            if (this._mesh) {
-                this._mesh.parent = undefined;
-            }
-            this._mesh = mesh;
-            if (this._poseControlledCamera) {
-                this._mesh.parent = this._poseControlledCamera;
-            }
-            if (!this._mesh.rotationQuaternion) {
-                this._mesh.rotationQuaternion = new Quaternion();
-            }
-        }
-
-        public attachToPoseControlledCamera(camera: TargetCamera) {
-            this._poseControlledCamera = camera;
-            if (this._mesh) {
-                this._mesh.parent = this._poseControlledCamera;
-            }
-        }
-
-        public dispose() {
-            if (this._mesh) {
-                this._mesh.dispose();
-            }
-            this._mesh = undefined;
-        }
-
-        public get mesh(): AbstractMesh {
-            return this._mesh;
-        }
-
-        public getForwardRay(length = 100): Ray {
-            if (!this.mesh) {
-                return new Ray(Vector3.Zero(), new BABYLON.Vector3(0, 0, 1), length);
-            }
-
-            var m = this.mesh.getWorldMatrix();
-            var origin = m.getTranslation();
-
-            var forward = new BABYLON.Vector3(0, 0, -1);
-            var forwardWorld = BABYLON.Vector3.TransformNormal(forward, m);
-
-            var direction = BABYLON.Vector3.Normalize(forwardWorld);            
-
-            return new Ray(origin, direction, length);
-        } 
-    }
-
-    export interface GamepadButtonChanges {
-        changed: boolean;
-        pressChanged: boolean;
-        touchChanged: boolean;
-        valueChanged: boolean;
-    }
-
-    export abstract class WebVRController extends PoseEnabledController {
-
-        //public onTriggerStateChangedObservable = new Observable<{ state: ExtendedGamepadButton, changes: GamepadButtonChanges }>();
-
-        public onTriggerStateChangedObservable = new Observable<ExtendedGamepadButton>();
-
-        public onMainButtonStateChangedObservable = new Observable<ExtendedGamepadButton>();
-
-        public onSecondaryButtonStateChangedObservable = new Observable<ExtendedGamepadButton>();
-
-        public onPadStateChangedObservable = new Observable<ExtendedGamepadButton>();
-        public onPadValuesChangedObservable = new Observable<StickValues>();
-
-        protected _buttons: Array<MutableGamepadButton>;
-
-        private _onButtonStateChange: (controlledIndex: number, buttonIndex: number, state: ExtendedGamepadButton) => void;
-
-        public onButtonStateChange(callback: (controlledIndex: number, buttonIndex: number, state: ExtendedGamepadButton) => void) {
-            this._onButtonStateChange = callback;
-        }
-
-        public pad: StickValues = { x: 0, y: 0 };
-
-        public hand: string; // 'left' or 'right', see https://w3c.github.io/gamepad/extensions.html#gamepadhand-enum
-
-        constructor(vrGamepad) {
-            super(vrGamepad);
-            this._buttons = new Array<ExtendedGamepadButton>(vrGamepad.buttons.length);
-            this.hand = vrGamepad.hand;
-        }
-
-        public update() {
-            super.update();
-            for (var index = 0; index < this._buttons.length; index++) {
-                this._setButtonValue(this.vrGamepad.buttons[index], this._buttons[index], index);
-            };
-            if (this.leftStick.x !== this.pad.x || this.leftStick.y !== this.pad.y) {
-                this.pad.x = this.leftStick.x;
-                this.pad.y = this.leftStick.y;
-                this.onPadValuesChangedObservable.notifyObservers(this.pad);
-            }
-        }
-
-        protected abstract handleButtonChange(buttonIdx: number, value: ExtendedGamepadButton, changes: GamepadButtonChanges);
-
-        public abstract initControllerMesh(scene: Scene, meshLoaded?: (mesh: AbstractMesh) => void);
-
-        private _setButtonValue(newState: ExtendedGamepadButton, currentState: ExtendedGamepadButton, buttonIndex: number) {
-            if (!newState) {
-                newState = {
-                    pressed: false,
-                    touched: false,
-                    value: 0
-                };
-            }  
-            if (!currentState) {
-                this._buttons[buttonIndex] = {
-                    pressed: newState.pressed,
-                    touched: newState.touched,
-                    value: newState.value
-                }
-                return;
-            }
-            this._checkChanges(newState, currentState);
-            if (this._changes.changed) {
-                this._onButtonStateChange && this._onButtonStateChange(this.index, buttonIndex, newState);
-
-                this.handleButtonChange(buttonIndex, newState, this._changes);
-            }
-            this._buttons[buttonIndex].pressed = newState.pressed;
-            this._buttons[buttonIndex].touched = newState.touched;
-            // oculus triggers are never 0, thou not touched.
-            this._buttons[buttonIndex].value = newState.value < 0.00000001 ? 0 : newState.value;
-        }
-
-        // avoid GC, store state in a tmp object
-        private _changes: GamepadButtonChanges = {
-            pressChanged: false,
-            touchChanged: false,
-            valueChanged: false,
-            changed: false
-        };
-
-        private _checkChanges(newState: ExtendedGamepadButton, currentState: ExtendedGamepadButton) {
-            this._changes.pressChanged = newState.pressed !== currentState.pressed;
-            this._changes.touchChanged = newState.touched !== currentState.touched;
-            this._changes.valueChanged = newState.value !== currentState.value;
-            this._changes.changed = this._changes.pressChanged || this._changes.touchChanged || this._changes.valueChanged;
-            return this._changes;
-        }
-    }
-
-    export class OculusTouchController extends WebVRController {
-        private _defaultModel: BABYLON.AbstractMesh;
-
-        public onSecondaryTriggerStateChangedObservable = new Observable<ExtendedGamepadButton>();
-
-        public onThumbRestChangedObservable = new Observable<ExtendedGamepadButton>();
-
-        constructor(vrGamepad) {
-            super(vrGamepad);
-            this.controllerType = PoseEnabledControllerType.OCULUS;
-        }
-
-        public initControllerMesh(scene: Scene, meshLoaded?: (mesh: AbstractMesh) => void) {
-            let meshName = this.hand === 'right' ? 'RightTouch.babylon' : 'LeftTouch.babylon';
-            SceneLoader.ImportMesh("", "http://yoda.blob.core.windows.net/models/", meshName, scene, (newMeshes) => {
-                /*
-                Parent Mesh name: oculus_touch_left
-                - body
-                - trigger
-                - thumbstick
-                - grip
-                - button_y 
-                - button_x
-                - button_enter
-                */
-
-                this._defaultModel = newMeshes[1];
-                if (meshLoaded) {
-                    meshLoaded(this._defaultModel);
-                }
-                this.attachToMesh(this._defaultModel);
-            });
-        }
-
-
-        // helper getters for left and right hand.
-        public get onAButtonStateChangedObservable() {
-            if (this.hand === 'right') {
-                return this.onMainButtonStateChangedObservable;
-            } else {
-                throw new Error('No A button on left hand');
-            }
-        }
-
-        public get onBButtonStateChangedObservable() {
-            if (this.hand === 'right') {
-                return this.onSecondaryButtonStateChangedObservable;
-            } else {
-                throw new Error('No B button on left hand');
-            }
-        }
-
-        public get onXButtonStateChangedObservable() {
-            if (this.hand === 'left') {
-                return this.onMainButtonStateChangedObservable;
-            } else {
-                throw new Error('No X button on right hand');
-            }
-        }
-
-        public get onYButtonStateChangedObservable() {
-            if (this.hand === 'left') {
-                return this.onSecondaryButtonStateChangedObservable;
-            } else {
-                throw new Error('No Y button on right hand');
-            }
-        }
-
-        /*
-         0) thumb stick (touch, press, value = pressed (0,1)). value is in this.leftStick
-         1) index trigger (touch (?), press (only when value > 0.1), value 0 to 1)
-         2) secondary trigger (same)
-         3) A (right) X (left), touch, pressed = value
-         4) B / Y 
-         5) thumb rest
-        */
-        protected handleButtonChange(buttonIdx: number, state: ExtendedGamepadButton, changes: GamepadButtonChanges) {
-            let notifyObject = state; //{ state: state, changes: changes };
-            let triggerDirection = this.hand === 'right' ? -1 : 1;
-            switch (buttonIdx) {
-                case 0:
-                    this.onPadStateChangedObservable.notifyObservers(notifyObject);
-                    return;
-                case 1: // index trigger
-                    if (this._defaultModel) {
-                        (<AbstractMesh>(this._defaultModel.getChildren()[3])).rotation.x = -notifyObject.value * 0.20;
-                        (<AbstractMesh>(this._defaultModel.getChildren()[3])).position.y = -notifyObject.value * 0.005;
-                        (<AbstractMesh>(this._defaultModel.getChildren()[3])).position.z = -notifyObject.value * 0.005;
-                    }
-                    this.onTriggerStateChangedObservable.notifyObservers(notifyObject);
-                    return;
-                case 2:  // secondary trigger
-                    if (this._defaultModel) {
-                        (<AbstractMesh>(this._defaultModel.getChildren()[4])).position.x = triggerDirection * notifyObject.value * 0.0035;
-                    }
-                    this.onSecondaryTriggerStateChangedObservable.notifyObservers(notifyObject);
-                    return;
-                case 3:
-                    if (this._defaultModel) {
-                        if (notifyObject.pressed) {
-                            (<AbstractMesh>(this._defaultModel.getChildren()[1])).position.y = -0.001;
-                        }
-                        else {
-                            (<AbstractMesh>(this._defaultModel.getChildren()[1])).position.y = 0;
-                        }
-                    }
-                    this.onMainButtonStateChangedObservable.notifyObservers(notifyObject);
-                    return;
-                case 4:
-                    if (this._defaultModel) {
-                        if (notifyObject.pressed) {
-                            (<AbstractMesh>(this._defaultModel.getChildren()[2])).position.y = -0.001;
-                        }
-                        else {
-                            (<AbstractMesh>(this._defaultModel.getChildren()[2])).position.y = 0;
-                        }
-                    }
-                    this.onSecondaryButtonStateChangedObservable.notifyObservers(notifyObject);
-                    return;
-                case 5:
-                    this.onThumbRestChangedObservable.notifyObservers(notifyObject);
-                    return;
-            }
-        }
-
-    }
-
-    export class ViveController extends WebVRController {
-        private _defaultModel: BABYLON.AbstractMesh;
-
-        constructor(vrGamepad) {
-            super(vrGamepad);
-            this.controllerType = PoseEnabledControllerType.VIVE;
-        }
-
-        public initControllerMesh(scene: Scene, meshLoaded?: (mesh: AbstractMesh) => void) {
-            SceneLoader.ImportMesh("", "http://yoda.blob.core.windows.net/models/", "ViveWand.babylon", scene, (newMeshes) => {
-                /*
-                Parent Mesh name: ViveWand
-                - body
-                - r_gripper
-                - l_gripper
-                - menu_button
-                - system_button
-                - trackpad
-                - trigger
-                - LED
-                */
-                this._defaultModel = newMeshes[1];
-                if (meshLoaded) {
-                    meshLoaded(this._defaultModel);
-                }
-                this.attachToMesh(this._defaultModel);
-            });
-        }
-
-
-        public get onLeftButtonStateChangedObservable() {
-            return this.onMainButtonStateChangedObservable;
-        }
-
-        public get onRightButtonStateChangedObservable() {
-            return this.onMainButtonStateChangedObservable;
-        }
-
-        public get onMenuButtonStateChangedObservable() {
-            return this.onSecondaryButtonStateChangedObservable;
-        }
-
-        /**
-         * Vive mapping:
-         * 0: touchpad
-         * 1: trigger
-         * 2: left AND right buttons
-         * 3: menu button
-         */
-        protected handleButtonChange(buttonIdx: number, state: ExtendedGamepadButton, changes: GamepadButtonChanges) {
-            let notifyObject = state; //{ state: state, changes: changes };
-            switch (buttonIdx) {
-                case 0:
-                    this.onPadStateChangedObservable.notifyObservers(notifyObject);
-                    return;
-                case 1: // index trigger
-                    if (this._defaultModel) {
-                        (<AbstractMesh>(this._defaultModel.getChildren()[6])).rotation.x = -notifyObject.value * 0.15;
-                    }
-                    this.onTriggerStateChangedObservable.notifyObservers(notifyObject);
-                    return;
-                case 2:  // left AND right button
-                    this.onMainButtonStateChangedObservable.notifyObservers(notifyObject);
-                    return;
-                case 3:
-                    if (this._defaultModel) {
-                        if (notifyObject.pressed) {
-                            (<AbstractMesh>(this._defaultModel.getChildren()[2])).position.y = -0.001;
-                        }
-                        else {
-                            (<AbstractMesh>(this._defaultModel.getChildren()[2])).position.y = 0;
-                        }
-                    }
-                    this.onSecondaryButtonStateChangedObservable.notifyObservers(notifyObject);
-                    return;
-            }
-        }
-    }
-
-    export class GenericController extends WebVRController {
-        private _defaultModel: BABYLON.AbstractMesh;
-
-        constructor(vrGamepad) {
-            super(vrGamepad);
-        }
-
-        public initControllerMesh(scene: Scene, meshLoaded?: (mesh: AbstractMesh) => void) {
-            SceneLoader.ImportMesh("", "http://yoda.blob.core.windows.net/models/", "genericvrcontroller.babylon", scene, (newMeshes) => {
-                this._defaultModel = newMeshes[1];
-                if (meshLoaded) {
-                    meshLoaded(this._defaultModel);
-                }
-                this.attachToMesh(this._defaultModel);
-            });
-        }
-
-        protected handleButtonChange(buttonIdx: number, state: ExtendedGamepadButton, changes: GamepadButtonChanges) {
-            console.log("Button id: " + buttonIdx + "state: ");
-            console.dir(state);
-        }
-    }
-}
-
-interface ExtendedGamepadButton extends GamepadButton {
-    readonly pressed: boolean;
-    readonly touched: boolean;
-    readonly value: number;
-}

+ 5 - 7
src/babylon.mixins.ts

@@ -112,13 +112,6 @@ interface CanvasRenderingContext2D {
     msImageSmoothingEnabled: boolean;
 }
 
-interface Navigator {
-    getGamepads(func?: any): any;
-    webkitGetGamepads(func?: any): any
-    msGetGamepads(func?: any): any;
-    webkitGamepads(func?: any): any;
-}
-
 interface WebGLTexture {
     isReady: boolean;
     isCube: boolean;
@@ -184,6 +177,11 @@ interface Navigator {
     webkitGetUserMedia: any;
     mozGetUserMedia: any;
     msGetUserMedia: any;
+
+    getGamepads(func?: any): any;
+    webkitGetGamepads(func?: any): any
+    msGetGamepads(func?: any): any;
+    webkitGamepads(func?: any): any;    
 }
 
 interface HTMLVideoElement {