freeCameraTouchInput.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. import { __decorate } from "../../tslib.es6.js";
  2. import { serialize } from "../../Misc/decorators.js";
  3. import { CameraInputTypes } from "../../Cameras/cameraInputsManager.js";
  4. import { PointerEventTypes } from "../../Events/pointerEvents.js";
  5. import { Matrix, Vector3 } from "../../Maths/math.vector.js";
  6. import { Tools } from "../../Misc/tools.js";
  7. /**
  8. * Manage the touch inputs to control the movement of a free camera.
  9. * @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/customizingCameraInputs
  10. */
  11. export class FreeCameraTouchInput {
  12. /**
  13. * Manage the touch inputs to control the movement of a free camera.
  14. * @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/customizingCameraInputs
  15. * @param allowMouse Defines if mouse events can be treated as touch events
  16. */
  17. constructor(
  18. /**
  19. * Define if mouse events can be treated as touch events
  20. */
  21. allowMouse = false) {
  22. this.allowMouse = allowMouse;
  23. /**
  24. * Defines the touch sensibility for rotation.
  25. * The lower the faster.
  26. */
  27. this.touchAngularSensibility = 200000.0;
  28. /**
  29. * Defines the touch sensibility for move.
  30. * The lower the faster.
  31. */
  32. this.touchMoveSensibility = 250.0;
  33. /**
  34. * Swap touch actions so that one touch is used for rotation and multiple for movement
  35. */
  36. this.singleFingerRotate = false;
  37. this._offsetX = null;
  38. this._offsetY = null;
  39. this._pointerPressed = new Array();
  40. this._isSafari = Tools.IsSafari();
  41. }
  42. /**
  43. * Attach the input controls to a specific dom element to get the input from.
  44. * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
  45. */
  46. attachControl(noPreventDefault) {
  47. // eslint-disable-next-line prefer-rest-params
  48. noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments);
  49. let previousPosition = null;
  50. if (this._pointerInput === undefined) {
  51. this._onLostFocus = () => {
  52. this._offsetX = null;
  53. this._offsetY = null;
  54. };
  55. this._pointerInput = (p) => {
  56. const evt = p.event;
  57. const isMouseEvent = evt.pointerType === "mouse" || (this._isSafari && typeof evt.pointerType === "undefined");
  58. if (!this.allowMouse && isMouseEvent) {
  59. return;
  60. }
  61. if (p.type === PointerEventTypes.POINTERDOWN) {
  62. if (!noPreventDefault) {
  63. evt.preventDefault();
  64. }
  65. this._pointerPressed.push(evt.pointerId);
  66. if (this._pointerPressed.length !== 1) {
  67. return;
  68. }
  69. previousPosition = {
  70. x: evt.clientX,
  71. y: evt.clientY,
  72. };
  73. }
  74. else if (p.type === PointerEventTypes.POINTERUP) {
  75. if (!noPreventDefault) {
  76. evt.preventDefault();
  77. }
  78. const index = this._pointerPressed.indexOf(evt.pointerId);
  79. if (index === -1) {
  80. return;
  81. }
  82. this._pointerPressed.splice(index, 1);
  83. if (index != 0) {
  84. return;
  85. }
  86. previousPosition = null;
  87. this._offsetX = null;
  88. this._offsetY = null;
  89. }
  90. else if (p.type === PointerEventTypes.POINTERMOVE) {
  91. if (!noPreventDefault) {
  92. evt.preventDefault();
  93. }
  94. if (!previousPosition) {
  95. return;
  96. }
  97. const index = this._pointerPressed.indexOf(evt.pointerId);
  98. if (index != 0) {
  99. return;
  100. }
  101. this._offsetX = evt.clientX - previousPosition.x;
  102. this._offsetY = -(evt.clientY - previousPosition.y);
  103. }
  104. };
  105. }
  106. this._observer = this.camera
  107. .getScene()
  108. ._inputManager._addCameraPointerObserver(this._pointerInput, PointerEventTypes.POINTERDOWN | PointerEventTypes.POINTERUP | PointerEventTypes.POINTERMOVE);
  109. if (this._onLostFocus) {
  110. const engine = this.camera.getEngine();
  111. const element = engine.getInputElement();
  112. element && element.addEventListener("blur", this._onLostFocus);
  113. }
  114. }
  115. /**
  116. * Detach the current controls from the specified dom element.
  117. */
  118. detachControl() {
  119. if (this._pointerInput) {
  120. if (this._observer) {
  121. this.camera.getScene()._inputManager._removeCameraPointerObserver(this._observer);
  122. this._observer = null;
  123. }
  124. if (this._onLostFocus) {
  125. const engine = this.camera.getEngine();
  126. const element = engine.getInputElement();
  127. element && element.removeEventListener("blur", this._onLostFocus);
  128. this._onLostFocus = null;
  129. }
  130. this._pointerPressed.length = 0;
  131. this._offsetX = null;
  132. this._offsetY = null;
  133. }
  134. }
  135. /**
  136. * Update the current camera state depending on the inputs that have been used this frame.
  137. * This is a dynamically created lambda to avoid the performance penalty of looping for inputs in the render loop.
  138. */
  139. checkInputs() {
  140. if (this._offsetX === null || this._offsetY === null) {
  141. return;
  142. }
  143. if (this._offsetX === 0 && this._offsetY === 0) {
  144. return;
  145. }
  146. const camera = this.camera;
  147. const handednessMultiplier = camera._calculateHandednessMultiplier();
  148. camera.cameraRotation.y = (handednessMultiplier * this._offsetX) / this.touchAngularSensibility;
  149. const rotateCamera = (this.singleFingerRotate && this._pointerPressed.length === 1) || (!this.singleFingerRotate && this._pointerPressed.length > 1);
  150. if (rotateCamera) {
  151. camera.cameraRotation.x = -this._offsetY / this.touchAngularSensibility;
  152. }
  153. else {
  154. const speed = camera._computeLocalCameraSpeed();
  155. const direction = new Vector3(0, 0, this.touchMoveSensibility !== 0 ? (speed * this._offsetY) / this.touchMoveSensibility : 0);
  156. Matrix.RotationYawPitchRollToRef(camera.rotation.y, camera.rotation.x, 0, camera._cameraRotationMatrix);
  157. camera.cameraDirection.addInPlace(Vector3.TransformCoordinates(direction, camera._cameraRotationMatrix));
  158. }
  159. }
  160. /**
  161. * Gets the class name of the current input.
  162. * @returns the class name
  163. */
  164. getClassName() {
  165. return "FreeCameraTouchInput";
  166. }
  167. /**
  168. * Get the friendly name associated with the input class.
  169. * @returns the input friendly name
  170. */
  171. getSimpleName() {
  172. return "touch";
  173. }
  174. }
  175. __decorate([
  176. serialize()
  177. ], FreeCameraTouchInput.prototype, "touchAngularSensibility", void 0);
  178. __decorate([
  179. serialize()
  180. ], FreeCameraTouchInput.prototype, "touchMoveSensibility", void 0);
  181. CameraInputTypes["FreeCameraTouchInput"] = FreeCameraTouchInput;
  182. //# sourceMappingURL=freeCameraTouchInput.js.map