UNPKG

@babylonjs/core

Version:

Getting started? Play directly with the Babylon.js API using our [playground](https://playground.babylonjs.com/). It also contains a lot of samples to learn how to use it.

244 lines 13.8 kB
import { __esDecorate, __runInitializers } from "../../tslib.es6.js"; import { Observable } from "../../Misc/observable.js"; import { serialize } from "../../Misc/decorators.js"; import { CameraInputTypes } from "../../Cameras/cameraInputsManager.js"; import { PointerEventTypes } from "../../Events/pointerEvents.js"; import { Tools } from "../../Misc/tools.pure.js"; /** * Manage the mouse inputs to control the movement of a free camera. * @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/customizingCameraInputs */ let FreeCameraMouseInput = (() => { var _a; let _buttons_decorators; let _buttons_initializers = []; let _buttons_extraInitializers = []; let _angularSensibility_decorators; let _angularSensibility_initializers = []; let _angularSensibility_extraInitializers = []; return _a = class FreeCameraMouseInput { /** * Applies a pointer-drag delta as camera rotation, but only if the camera's configurable * input map resolves the current pointer interaction to "rotate". The map is consulted with * the currently active mouse button so consumers can remap or disable pointer-driven rotation. * The applied scale comes from the resolved entry's `sensitivity`/`sensitivityX`/`sensitivityY`, * falling back to the legacy `angularSensibility` for backward compatibility. The rotation is * still written to `camera.cameraRotation` (not the movement accumulators) so existing code that * reads `cameraRotation` immediately after a pointer event keeps working. * @param offsetX Horizontal pointer delta (already handedness-adjusted). * @param offsetY Vertical pointer delta (already handedness-adjusted). */ _applyPointerRotation(offsetX, offsetY) { this._pointerConditions.button = this._currentActiveButton; const entry = this.camera.movement.input.resolveInteraction("pointer", this._pointerConditions); if (!entry || entry.interaction !== "rotate") { return; } const sensitivityX = entry.sensitivityX ?? entry.sensitivity ?? 1 / this.angularSensibility; const sensitivityY = entry.sensitivityY ?? entry.sensitivity ?? 1 / this.angularSensibility; this.camera.cameraRotation.y += offsetX * sensitivityX; this.camera.cameraRotation.x += offsetY * sensitivityY; } /** * Manage the mouse inputs to control the movement of a free camera. * @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/customizingCameraInputs * @param touchEnabled Defines if touch is enabled or not */ constructor( /** * [true] Define if touch is enabled in the mouse input */ touchEnabled = true) { this.touchEnabled = touchEnabled; /** * Defines the buttons associated with the input to handle camera move. */ this.buttons = __runInitializers(this, _buttons_initializers, [0, 1, 2]); /** * Defines the pointer angular sensibility along the X and Y axis or how fast is the camera rotating. */ this.angularSensibility = (__runInitializers(this, _buttons_extraInitializers), __runInitializers(this, _angularSensibility_initializers, 2000.0)); this._pointerInput = __runInitializers(this, _angularSensibility_extraInitializers); this._previousPosition = null; /** * Observable for when a pointer move event occurs containing the move offset */ this.onPointerMovedObservable = new Observable(); /** * @internal * If the camera should be rotated automatically based on pointer movement */ this._allowCameraRotation = true; this._currentActiveButton = -1; this._activePointerId = -1; /** Reused conditions object for `resolveInteraction` to avoid per-move allocations. */ this._pointerConditions = {}; } /** * Attach the input controls to a specific dom element to get the input from. * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault) */ attachControl(noPreventDefault) { noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments); const engine = this.camera.getEngine(); const element = engine.getInputElement(); if (!this._pointerInput) { this._pointerInput = (p) => { const evt = p.event; const isTouch = evt.pointerType === "touch"; if (!this.touchEnabled && isTouch) { return; } if (p.type !== PointerEventTypes.POINTERMOVE && this.buttons.indexOf(evt.button) === -1) { return; } const srcElement = evt.target; if (p.type === PointerEventTypes.POINTERDOWN) { // If the input is touch with more than one touch OR if the input is mouse and there is already an active button, return if ((isTouch && this._activePointerId !== -1) || (!isTouch && this._currentActiveButton !== -1)) { return; } this._activePointerId = evt.pointerId; try { srcElement?.setPointerCapture(evt.pointerId); } catch (e) { //Nothing to do with the error. Execution will continue. } if (this._currentActiveButton === -1) { this._currentActiveButton = evt.button; } this._previousPosition = { x: evt.clientX, y: evt.clientY, }; if (!noPreventDefault) { evt.preventDefault(); if (element) { element.focus(); } } // This is required to move while pointer button is down if (engine.isPointerLock && this._onMouseMove) { this._onMouseMove(p.event); } } else if (p.type === PointerEventTypes.POINTERUP) { // If input is touch with a different touch id OR if input is mouse with a different button, return if ((isTouch && this._activePointerId !== evt.pointerId) || (!isTouch && this._currentActiveButton !== evt.button)) { return; } try { srcElement?.releasePointerCapture(evt.pointerId); } catch (e) { //Nothing to do with the error. } this._currentActiveButton = -1; this._previousPosition = null; if (!noPreventDefault) { evt.preventDefault(); } this._activePointerId = -1; } else if (p.type === PointerEventTypes.POINTERMOVE && (this._activePointerId === evt.pointerId || !isTouch)) { if (engine.isPointerLock && this._onMouseMove) { this._onMouseMove(p.event); } else if (this._previousPosition) { const handednessMultiplier = this.camera._calculateHandednessMultiplier(); const offsetX = (evt.clientX - this._previousPosition.x) * handednessMultiplier; const offsetY = (evt.clientY - this._previousPosition.y) * handednessMultiplier; if (this._allowCameraRotation) { this._applyPointerRotation(offsetX, offsetY); } this.onPointerMovedObservable.notifyObservers({ offsetX: offsetX, offsetY: offsetY }); this._previousPosition = { x: evt.clientX, y: evt.clientY, }; if (!noPreventDefault) { evt.preventDefault(); } } } }; } this._onMouseMove = (evt) => { if (!engine.isPointerLock) { return; } const handednessMultiplier = this.camera._calculateHandednessMultiplier(); this._applyPointerRotation(evt.movementX * handednessMultiplier, evt.movementY * handednessMultiplier); this._previousPosition = null; if (!noPreventDefault) { evt.preventDefault(); } }; this._observer = this.camera .getScene() ._inputManager._addCameraPointerObserver(this._pointerInput, PointerEventTypes.POINTERDOWN | PointerEventTypes.POINTERUP | PointerEventTypes.POINTERMOVE); if (element) { this._contextMenuBind = (evt) => this.onContextMenu(evt); element.addEventListener("contextmenu", this._contextMenuBind, false); // TODO: We need to figure out how to handle this for Native } } /** * Called on JS contextmenu event. * Override this method to provide functionality. * @param evt the context menu event */ onContextMenu(evt) { evt.preventDefault(); } /** * Detach the current controls from the specified dom element. */ detachControl() { if (this._observer) { this.camera.getScene()._inputManager._removeCameraPointerObserver(this._observer); if (this._contextMenuBind) { const engine = this.camera.getEngine(); const element = engine.getInputElement(); if (element) { element.removeEventListener("contextmenu", this._contextMenuBind); } } if (this.onPointerMovedObservable) { this.onPointerMovedObservable.clear(); } this._observer = null; this._onMouseMove = null; this._previousPosition = null; } this._activePointerId = -1; this._currentActiveButton = -1; } /** * Gets the class name of the current input. * @returns the class name */ getClassName() { return "FreeCameraMouseInput"; } /** * Get the friendly name associated with the input class. * @returns the input friendly name */ getSimpleName() { return "mouse"; } }, (() => { const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0; _buttons_decorators = [serialize()]; _angularSensibility_decorators = [serialize()]; __esDecorate(null, null, _buttons_decorators, { kind: "field", name: "buttons", static: false, private: false, access: { has: obj => "buttons" in obj, get: obj => obj.buttons, set: (obj, value) => { obj.buttons = value; } }, metadata: _metadata }, _buttons_initializers, _buttons_extraInitializers); __esDecorate(null, null, _angularSensibility_decorators, { kind: "field", name: "angularSensibility", static: false, private: false, access: { has: obj => "angularSensibility" in obj, get: obj => obj.angularSensibility, set: (obj, value) => { obj.angularSensibility = value; } }, metadata: _metadata }, _angularSensibility_initializers, _angularSensibility_extraInitializers); if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); })(), _a; })(); export { FreeCameraMouseInput }; CameraInputTypes["FreeCameraMouseInput"] = FreeCameraMouseInput; //# sourceMappingURL=freeCameraMouseInput.js.map