webVRController.ts 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. import { Observable } from "Tools/observable";
  2. import { Scene } from "scene";
  3. import { AbstractMesh } from "Mesh/abstractMesh";
  4. import { _TimeToken } from "Instrumentation/timeToken";
  5. import { _DepthCullingState, _StencilState, _AlphaState } from "States";
  6. import { PoseEnabledController, ExtendedGamepadButton, MutableGamepadButton } from "./poseEnabledController";
  7. import { StickValues, GamepadButtonChanges } from "Gamepad/gamepad";
  8. /**
  9. * Defines the WebVRController object that represents controllers tracked in 3D space
  10. */
  11. export abstract class WebVRController extends PoseEnabledController {
  12. /**
  13. * Internal, the default controller model for the controller
  14. */
  15. protected _defaultModel: AbstractMesh;
  16. // Observables
  17. /**
  18. * Fired when the trigger state has changed
  19. */
  20. public onTriggerStateChangedObservable = new Observable<ExtendedGamepadButton>();
  21. /**
  22. * Fired when the main button state has changed
  23. */
  24. public onMainButtonStateChangedObservable = new Observable<ExtendedGamepadButton>();
  25. /**
  26. * Fired when the secondary button state has changed
  27. */
  28. public onSecondaryButtonStateChangedObservable = new Observable<ExtendedGamepadButton>();
  29. /**
  30. * Fired when the pad state has changed
  31. */
  32. public onPadStateChangedObservable = new Observable<ExtendedGamepadButton>();
  33. /**
  34. * Fired when controllers stick values have changed
  35. */
  36. public onPadValuesChangedObservable = new Observable<StickValues>();
  37. /**
  38. * Array of button availible on the controller
  39. */
  40. protected _buttons: Array<MutableGamepadButton>;
  41. private _onButtonStateChange: (controlledIndex: number, buttonIndex: number, state: ExtendedGamepadButton) => void;
  42. /**
  43. * Fired when a controller button's state has changed
  44. * @param callback the callback containing the button that was modified
  45. */
  46. public onButtonStateChange(callback: (controlledIndex: number, buttonIndex: number, state: ExtendedGamepadButton) => void) {
  47. this._onButtonStateChange = callback;
  48. }
  49. /**
  50. * X and Y axis corrisponding to the controllers joystick
  51. */
  52. public pad: StickValues = { x: 0, y: 0 };
  53. /**
  54. * 'left' or 'right', see https://w3c.github.io/gamepad/extensions.html#gamepadhand-enum
  55. */
  56. public hand: string;
  57. /**
  58. * The default controller model for the controller
  59. */
  60. public get defaultModel(): AbstractMesh {
  61. return this._defaultModel;
  62. }
  63. /**
  64. * Creates a new WebVRController from a gamepad
  65. * @param vrGamepad the gamepad that the WebVRController should be created from
  66. */
  67. constructor(vrGamepad: any) {
  68. super(vrGamepad);
  69. this._buttons = new Array<ExtendedGamepadButton>(vrGamepad.buttons.length);
  70. this.hand = vrGamepad.hand;
  71. }
  72. /**
  73. * Updates the state of the controller and mesh based on the current position and rotation of the controller
  74. */
  75. public update() {
  76. super.update();
  77. for (var index = 0; index < this._buttons.length; index++) {
  78. this._setButtonValue(this.browserGamepad.buttons[index], this._buttons[index], index);
  79. }
  80. if (this.leftStick.x !== this.pad.x || this.leftStick.y !== this.pad.y) {
  81. this.pad.x = this.leftStick.x;
  82. this.pad.y = this.leftStick.y;
  83. this.onPadValuesChangedObservable.notifyObservers(this.pad);
  84. }
  85. }
  86. /**
  87. * Function to be called when a button is modified
  88. */
  89. protected abstract _handleButtonChange(buttonIdx: number, value: ExtendedGamepadButton, changes: GamepadButtonChanges): void;
  90. /**
  91. * Loads a mesh and attaches it to the controller
  92. * @param scene the scene the mesh should be added to
  93. * @param meshLoaded callback for when the mesh has been loaded
  94. */
  95. public abstract initControllerMesh(scene: Scene, meshLoaded?: (mesh: AbstractMesh) => void): void;
  96. private _setButtonValue(newState: ExtendedGamepadButton, currentState: ExtendedGamepadButton, buttonIndex: number) {
  97. if (!newState) {
  98. newState = {
  99. pressed: false,
  100. touched: false,
  101. value: 0
  102. };
  103. }
  104. if (!currentState) {
  105. this._buttons[buttonIndex] = {
  106. pressed: newState.pressed,
  107. touched: newState.touched,
  108. value: newState.value
  109. };
  110. return;
  111. }
  112. this._checkChanges(newState, currentState);
  113. if (this._changes.changed) {
  114. this._onButtonStateChange && this._onButtonStateChange(this.index, buttonIndex, newState);
  115. this._handleButtonChange(buttonIndex, newState, this._changes);
  116. }
  117. this._buttons[buttonIndex].pressed = newState.pressed;
  118. this._buttons[buttonIndex].touched = newState.touched;
  119. // oculus triggers are never 0, thou not touched.
  120. this._buttons[buttonIndex].value = newState.value < 0.00000001 ? 0 : newState.value;
  121. }
  122. // avoid GC, store state in a tmp object
  123. private _changes: GamepadButtonChanges = {
  124. pressChanged: false,
  125. touchChanged: false,
  126. valueChanged: false,
  127. changed: false
  128. };
  129. private _checkChanges(newState: ExtendedGamepadButton, currentState: ExtendedGamepadButton) {
  130. this._changes.pressChanged = newState.pressed !== currentState.pressed;
  131. this._changes.touchChanged = newState.touched !== currentState.touched;
  132. this._changes.valueChanged = newState.value !== currentState.value;
  133. this._changes.changed = this._changes.pressChanged || this._changes.touchChanged || this._changes.valueChanged;
  134. return this._changes;
  135. }
  136. /**
  137. * Disposes of th webVRCOntroller
  138. */
  139. public dispose(): void {
  140. super.dispose();
  141. this.onTriggerStateChangedObservable.clear();
  142. this.onMainButtonStateChangedObservable.clear();
  143. this.onSecondaryButtonStateChangedObservable.clear();
  144. this.onPadStateChangedObservable.clear();
  145. this.onPadValuesChangedObservable.clear();
  146. }
  147. }