UNPKG

@babylonjs/viewer

Version:

The Babylon Viewer aims to simplify a specific but common Babylon.js use case: loading, viewing, and interacting with a 3D model.

2,796 lines 139 kB
import { l as __runInitializers, aY as Tools, cd as KeyboardEventTypes, V as Vector3, q as __esDecorate, s as serialize, ce as CameraInputTypes, O as Observable, by as PointerEventTypes, cf as EventConstants, M as Matrix, T as TmpVectors, cg as CameraInputsManager, aE as _MissingSideEffect, A as AbstractEngine, b3 as Vector2, ch as TargetCamera, r as serializeAsVector3, a as EngineStore, o as SerializationHelper, G as GetClass, a7 as VertexBuffer, m as Texture, C as Constants, Q as SmartArray, y as Logger } from './index-HyNDfLMI.esm.js';

/**
 * Manage the keyboard inputs to control the movement of a free camera.
 * @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/customizingCameraInputs
 */
let FreeCameraKeyboardMoveInput = (() => {
    var _a;
    let _keysUp_decorators;
    let _keysUp_initializers = [];
    let _keysUp_extraInitializers = [];
    let _keysUpward_decorators;
    let _keysUpward_initializers = [];
    let _keysUpward_extraInitializers = [];
    let _keysDown_decorators;
    let _keysDown_initializers = [];
    let _keysDown_extraInitializers = [];
    let _keysDownward_decorators;
    let _keysDownward_initializers = [];
    let _keysDownward_extraInitializers = [];
    let _keysLeft_decorators;
    let _keysLeft_initializers = [];
    let _keysLeft_extraInitializers = [];
    let _keysRight_decorators;
    let _keysRight_initializers = [];
    let _keysRight_extraInitializers = [];
    let _rotationSpeed_decorators;
    let _rotationSpeed_initializers = [];
    let _rotationSpeed_extraInitializers = [];
    let _keysRotateLeft_decorators;
    let _keysRotateLeft_initializers = [];
    let _keysRotateLeft_extraInitializers = [];
    let _keysRotateRight_decorators;
    let _keysRotateRight_initializers = [];
    let _keysRotateRight_extraInitializers = [];
    let _keysRotateUp_decorators;
    let _keysRotateUp_initializers = [];
    let _keysRotateUp_extraInitializers = [];
    let _keysRotateDown_decorators;
    let _keysRotateDown_initializers = [];
    let _keysRotateDown_extraInitializers = [];
    return _a = class FreeCameraKeyboardMoveInput {
            constructor() {
                /**
                 * Gets or Set the list of keyboard keys used to control the forward move of the camera.
                 */
                this.keysUp = __runInitializers(this, _keysUp_initializers, [38]);
                /**
                 * Gets or Set the list of keyboard keys used to control the upward move of the camera.
                 */
                this.keysUpward = (__runInitializers(this, _keysUp_extraInitializers), __runInitializers(this, _keysUpward_initializers, [33]));
                /**
                 * Gets or Set the list of keyboard keys used to control the backward move of the camera.
                 */
                this.keysDown = (__runInitializers(this, _keysUpward_extraInitializers), __runInitializers(this, _keysDown_initializers, [40]));
                /**
                 * Gets or Set the list of keyboard keys used to control the downward move of the camera.
                 */
                this.keysDownward = (__runInitializers(this, _keysDown_extraInitializers), __runInitializers(this, _keysDownward_initializers, [34]));
                /**
                 * Gets or Set the list of keyboard keys used to control the left strafe move of the camera.
                 */
                this.keysLeft = (__runInitializers(this, _keysDownward_extraInitializers), __runInitializers(this, _keysLeft_initializers, [37]));
                /**
                 * Gets or Set the list of keyboard keys used to control the right strafe move of the camera.
                 */
                this.keysRight = (__runInitializers(this, _keysLeft_extraInitializers), __runInitializers(this, _keysRight_initializers, [39]));
                /**
                 * Defines the pointer angular sensibility  along the X and Y axis or how fast is the camera rotating.
                 */
                this.rotationSpeed = (__runInitializers(this, _keysRight_extraInitializers), __runInitializers(this, _rotationSpeed_initializers, 0.5));
                /**
                 * Gets or Set the list of keyboard keys used to control the left rotation move of the camera.
                 */
                this.keysRotateLeft = (__runInitializers(this, _rotationSpeed_extraInitializers), __runInitializers(this, _keysRotateLeft_initializers, []));
                /**
                 * Gets or Set the list of keyboard keys used to control the right rotation move of the camera.
                 */
                this.keysRotateRight = (__runInitializers(this, _keysRotateLeft_extraInitializers), __runInitializers(this, _keysRotateRight_initializers, []));
                /**
                 * Gets or Set the list of keyboard keys used to control the up rotation move of the camera.
                 */
                this.keysRotateUp = (__runInitializers(this, _keysRotateRight_extraInitializers), __runInitializers(this, _keysRotateUp_initializers, []));
                /**
                 * Gets or Set the list of keyboard keys used to control the down rotation move of the camera.
                 */
                this.keysRotateDown = (__runInitializers(this, _keysRotateUp_extraInitializers), __runInitializers(this, _keysRotateDown_initializers, []));
                this._keys = (__runInitializers(this, _keysRotateDown_extraInitializers), new Array());
            }
            /**
             * 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);
                if (this._onCanvasBlurObserver) {
                    return;
                }
                this._scene = this.camera.getScene();
                this._engine = this._scene.getEngine();
                this._onCanvasBlurObserver = this._engine.onCanvasBlurObservable.add(() => {
                    this._keys.length = 0;
                });
                this._onKeyboardObserver = this._scene.onKeyboardObservable.add((info) => {
                    const evt = info.event;
                    if (!evt.metaKey) {
                        if (info.type === KeyboardEventTypes.KEYDOWN) {
                            if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
                                this.keysDown.indexOf(evt.keyCode) !== -1 ||
                                this.keysLeft.indexOf(evt.keyCode) !== -1 ||
                                this.keysRight.indexOf(evt.keyCode) !== -1 ||
                                this.keysUpward.indexOf(evt.keyCode) !== -1 ||
                                this.keysDownward.indexOf(evt.keyCode) !== -1 ||
                                this.keysRotateLeft.indexOf(evt.keyCode) !== -1 ||
                                this.keysRotateRight.indexOf(evt.keyCode) !== -1 ||
                                this.keysRotateUp.indexOf(evt.keyCode) !== -1 ||
                                this.keysRotateDown.indexOf(evt.keyCode) !== -1) {
                                const index = this._keys.indexOf(evt.keyCode);
                                if (index === -1) {
                                    this._keys.push(evt.keyCode);
                                }
                                if (!noPreventDefault) {
                                    evt.preventDefault();
                                }
                            }
                        }
                        else {
                            if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
                                this.keysDown.indexOf(evt.keyCode) !== -1 ||
                                this.keysLeft.indexOf(evt.keyCode) !== -1 ||
                                this.keysRight.indexOf(evt.keyCode) !== -1 ||
                                this.keysUpward.indexOf(evt.keyCode) !== -1 ||
                                this.keysDownward.indexOf(evt.keyCode) !== -1 ||
                                this.keysRotateLeft.indexOf(evt.keyCode) !== -1 ||
                                this.keysRotateRight.indexOf(evt.keyCode) !== -1 ||
                                this.keysRotateUp.indexOf(evt.keyCode) !== -1 ||
                                this.keysRotateDown.indexOf(evt.keyCode) !== -1) {
                                const index = this._keys.indexOf(evt.keyCode);
                                if (index >= 0) {
                                    this._keys.splice(index, 1);
                                }
                                if (!noPreventDefault) {
                                    evt.preventDefault();
                                }
                            }
                        }
                    }
                });
            }
            /**
             * Detach the current controls from the specified dom element.
             */
            detachControl() {
                if (this._scene) {
                    if (this._onKeyboardObserver) {
                        this._scene.onKeyboardObservable.remove(this._onKeyboardObserver);
                    }
                    if (this._onCanvasBlurObserver) {
                        this._engine.onCanvasBlurObservable.remove(this._onCanvasBlurObserver);
                    }
                    this._onKeyboardObserver = null;
                    this._onCanvasBlurObserver = null;
                }
                this._keys.length = 0;
            }
            /**
             * Update the current camera state depending on the inputs that have been used this frame.
             * This is a dynamically created lambda to avoid the performance penalty of looping for inputs in the render loop.
             */
            checkInputs() {
                if (this._onKeyboardObserver) {
                    const camera = this.camera;
                    // Movement keys are gated on the keyboard→translate mapping and rotation keys on
                    // keyboard→rotate. Removing the corresponding entry disables that family of keys.
                    // An entry's optional `sensitivity` acts as a gain (default 1) over the legacy scaling.
                    const input = camera.movement.input;
                    const translateEntry = input.getEntry("keyboard", "translate");
                    const rotateEntry = input.getEntry("keyboard", "rotate");
                    const rotateGain = rotateEntry?.sensitivity ?? 1;
                    // Movement keys are accumulated into a single local direction and applied once below, so that
                    // holding two directions at once (e.g. forward + left) moves along a normalized diagonal at the
                    // same speed as a single direction, instead of the ~1.41x boost (sqrt(2)) that results from
                    // applying each movement key independently. Rotation keys act on separate angular axes and are
                    // applied directly as before.
                    const localDirection = camera._localDirection.copyFromFloats(0, 0, 0);
                    // Keyboard
                    for (let index = 0; index < this._keys.length; index++) {
                        const keyCode = this._keys[index];
                        if (this.keysLeft.indexOf(keyCode) !== -1) {
                            localDirection.x -= 1;
                        }
                        else if (this.keysUp.indexOf(keyCode) !== -1) {
                            localDirection.z += 1;
                        }
                        else if (this.keysRight.indexOf(keyCode) !== -1) {
                            localDirection.x += 1;
                        }
                        else if (this.keysDown.indexOf(keyCode) !== -1) {
                            localDirection.z -= 1;
                        }
                        else if (this.keysUpward.indexOf(keyCode) !== -1) {
                            localDirection.y += 1;
                        }
                        else if (this.keysDownward.indexOf(keyCode) !== -1) {
                            localDirection.y -= 1;
                        }
                        else if (this.keysRotateLeft.indexOf(keyCode) !== -1) {
                            if (rotateEntry) {
                                camera.cameraRotation.y -= this._getLocalRotation() * rotateGain;
                            }
                        }
                        else if (this.keysRotateRight.indexOf(keyCode) !== -1) {
                            if (rotateEntry) {
                                camera.cameraRotation.y += this._getLocalRotation() * rotateGain;
                            }
                        }
                        else if (this.keysRotateUp.indexOf(keyCode) !== -1) {
                            if (rotateEntry) {
                                camera.cameraRotation.x -= this._getLocalRotation() * rotateGain;
                            }
                        }
                        else if (this.keysRotateDown.indexOf(keyCode) !== -1) {
                            if (rotateEntry) {
                                camera.cameraRotation.x += this._getLocalRotation() * rotateGain;
                            }
                        }
                    }
                    // Apply a single, normalized movement once all keys for this frame have been accumulated.
                    // Translation is suppressed when the keyboard→translate mapping is removed.
                    if (translateEntry && (localDirection.x !== 0 || localDirection.y !== 0 || localDirection.z !== 0)) {
                        const speed = camera._computeLocalCameraSpeed() * (translateEntry.sensitivity ?? 1);
                        // Normalize so a diagonal isn't faster than an axis-aligned move, then scale to the per-frame speed.
                        localDirection.normalize().scaleInPlace(speed);
                        if (camera.getScene().useRightHandedSystem) {
                            localDirection.z *= -1;
                        }
                        camera.getViewMatrix().invertToRef(camera._cameraTransformMatrix);
                        Vector3.TransformNormalToRef(localDirection, camera._cameraTransformMatrix, camera._transformedDirection);
                        camera.cameraDirection.addInPlace(camera._transformedDirection);
                    }
                }
            }
            /**
             * Gets the class name of the current input.
             * @returns the class name
             */
            getClassName() {
                return "FreeCameraKeyboardMoveInput";
            }
            /** @internal */
            _onLostFocus() {
                this._keys.length = 0;
            }
            /**
             * Get the friendly name associated with the input class.
             * @returns the input friendly name
             */
            getSimpleName() {
                return "keyboard";
            }
            _getLocalRotation() {
                const handednessMultiplier = this.camera._calculateHandednessMultiplier();
                const rotation = ((this.rotationSpeed * this._engine.getDeltaTime()) / 1000) * handednessMultiplier;
                return rotation;
            }
        },
        (() => {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
            _keysUp_decorators = [serialize()];
            _keysUpward_decorators = [serialize()];
            _keysDown_decorators = [serialize()];
            _keysDownward_decorators = [serialize()];
            _keysLeft_decorators = [serialize()];
            _keysRight_decorators = [serialize()];
            _rotationSpeed_decorators = [serialize()];
            _keysRotateLeft_decorators = [serialize()];
            _keysRotateRight_decorators = [serialize()];
            _keysRotateUp_decorators = [serialize()];
            _keysRotateDown_decorators = [serialize()];
            __esDecorate(null, null, _keysUp_decorators, { kind: "field", name: "keysUp", static: false, private: false, access: { has: obj => "keysUp" in obj, get: obj => obj.keysUp, set: (obj, value) => { obj.keysUp = value; } }, metadata: _metadata }, _keysUp_initializers, _keysUp_extraInitializers);
            __esDecorate(null, null, _keysUpward_decorators, { kind: "field", name: "keysUpward", static: false, private: false, access: { has: obj => "keysUpward" in obj, get: obj => obj.keysUpward, set: (obj, value) => { obj.keysUpward = value; } }, metadata: _metadata }, _keysUpward_initializers, _keysUpward_extraInitializers);
            __esDecorate(null, null, _keysDown_decorators, { kind: "field", name: "keysDown", static: false, private: false, access: { has: obj => "keysDown" in obj, get: obj => obj.keysDown, set: (obj, value) => { obj.keysDown = value; } }, metadata: _metadata }, _keysDown_initializers, _keysDown_extraInitializers);
            __esDecorate(null, null, _keysDownward_decorators, { kind: "field", name: "keysDownward", static: false, private: false, access: { has: obj => "keysDownward" in obj, get: obj => obj.keysDownward, set: (obj, value) => { obj.keysDownward = value; } }, metadata: _metadata }, _keysDownward_initializers, _keysDownward_extraInitializers);
            __esDecorate(null, null, _keysLeft_decorators, { kind: "field", name: "keysLeft", static: false, private: false, access: { has: obj => "keysLeft" in obj, get: obj => obj.keysLeft, set: (obj, value) => { obj.keysLeft = value; } }, metadata: _metadata }, _keysLeft_initializers, _keysLeft_extraInitializers);
            __esDecorate(null, null, _keysRight_decorators, { kind: "field", name: "keysRight", static: false, private: false, access: { has: obj => "keysRight" in obj, get: obj => obj.keysRight, set: (obj, value) => { obj.keysRight = value; } }, metadata: _metadata }, _keysRight_initializers, _keysRight_extraInitializers);
            __esDecorate(null, null, _rotationSpeed_decorators, { kind: "field", name: "rotationSpeed", static: false, private: false, access: { has: obj => "rotationSpeed" in obj, get: obj => obj.rotationSpeed, set: (obj, value) => { obj.rotationSpeed = value; } }, metadata: _metadata }, _rotationSpeed_initializers, _rotationSpeed_extraInitializers);
            __esDecorate(null, null, _keysRotateLeft_decorators, { kind: "field", name: "keysRotateLeft", static: false, private: false, access: { has: obj => "keysRotateLeft" in obj, get: obj => obj.keysRotateLeft, set: (obj, value) => { obj.keysRotateLeft = value; } }, metadata: _metadata }, _keysRotateLeft_initializers, _keysRotateLeft_extraInitializers);
            __esDecorate(null, null, _keysRotateRight_decorators, { kind: "field", name: "keysRotateRight", static: false, private: false, access: { has: obj => "keysRotateRight" in obj, get: obj => obj.keysRotateRight, set: (obj, value) => { obj.keysRotateRight = value; } }, metadata: _metadata }, _keysRotateRight_initializers, _keysRotateRight_extraInitializers);
            __esDecorate(null, null, _keysRotateUp_decorators, { kind: "field", name: "keysRotateUp", static: false, private: false, access: { has: obj => "keysRotateUp" in obj, get: obj => obj.keysRotateUp, set: (obj, value) => { obj.keysRotateUp = value; } }, metadata: _metadata }, _keysRotateUp_initializers, _keysRotateUp_extraInitializers);
            __esDecorate(null, null, _keysRotateDown_decorators, { kind: "field", name: "keysRotateDown", static: false, private: false, access: { has: obj => "keysRotateDown" in obj, get: obj => obj.keysRotateDown, set: (obj, value) => { obj.keysRotateDown = value; } }, metadata: _metadata }, _keysRotateDown_initializers, _keysRotateDown_extraInitializers);
            if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        })(),
        _a;
})();
CameraInputTypes["FreeCameraKeyboardMoveInput"] = FreeCameraKeyboardMoveInput;

/**
 * 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;
})();
CameraInputTypes["FreeCameraMouseInput"] = FreeCameraMouseInput;

/**
 * Base class for mouse wheel input..
 * See FollowCameraMouseWheelInput in src/Cameras/Inputs/freeCameraMouseWheelInput.ts
 * for example usage.
 */
let BaseCameraMouseWheelInput = (() => {
    var _a;
    let _wheelPrecisionX_decorators;
    let _wheelPrecisionX_initializers = [];
    let _wheelPrecisionX_extraInitializers = [];
    let _wheelPrecisionY_decorators;
    let _wheelPrecisionY_initializers = [];
    let _wheelPrecisionY_extraInitializers = [];
    let _wheelPrecisionZ_decorators;
    let _wheelPrecisionZ_initializers = [];
    let _wheelPrecisionZ_extraInitializers = [];
    return _a = class BaseCameraMouseWheelInput {
            constructor() {
                /**
                 * How fast is the camera moves in relation to X axis mouseWheel events.
                 * Use negative value to reverse direction.
                 */
                this.wheelPrecisionX = __runInitializers(this, _wheelPrecisionX_initializers, 3.0);
                /**
                 * How fast is the camera moves in relation to Y axis mouseWheel events.
                 * Use negative value to reverse direction.
                 */
                this.wheelPrecisionY = (__runInitializers(this, _wheelPrecisionX_extraInitializers), __runInitializers(this, _wheelPrecisionY_initializers, 3.0));
                /**
                 * How fast is the camera moves in relation to Z axis mouseWheel events.
                 * Use negative value to reverse direction.
                 */
                this.wheelPrecisionZ = (__runInitializers(this, _wheelPrecisionY_extraInitializers), __runInitializers(this, _wheelPrecisionZ_initializers, 3.0));
                /**
                 * Observable for when a mouse wheel move event occurs.
                 */
                this.onChangedObservable = (__runInitializers(this, _wheelPrecisionZ_extraInitializers), new Observable());
                /**
                 * Incremental value of multiple mouse wheel movements of the X axis.
                 * Should be zero-ed when read.
                 */
                this._wheelDeltaX = 0;
                /**
                 * Incremental value of multiple mouse wheel movements of the Y axis.
                 * Should be zero-ed when read.
                 */
                this._wheelDeltaY = 0;
                /**
                 * Incremental value of multiple mouse wheel movements of the Z axis.
                 * Should be zero-ed when read.
                 */
                this._wheelDeltaZ = 0;
                /**
                 * Firefox uses a different scheme to report scroll distances to other
                 * browsers. Rather than use complicated methods to calculate the exact
                 * multiple we need to apply, let's just cheat and use a constant.
                 * https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent/deltaMode
                 * https://stackoverflow.com/questions/20110224/what-is-the-height-of-a-line-in-a-wheel-event-deltamode-dom-delta-line
                 */
                this._ffMultiplier = 12;
                /**
                 * Different event attributes for wheel data fall into a few set ranges.
                 * Some relevant but dated date here:
                 * https://stackoverflow.com/questions/5527601/normalizing-mousewheel-speed-across-browsers
                 */
                this._normalize = 120;
            }
            /**
             * 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);
                this._wheel = (pointer) => {
                    // sanity check - this should be a PointerWheel event.
                    if (pointer.type !== PointerEventTypes.POINTERWHEEL) {
                        return;
                    }
                    const event = pointer.event;
                    const platformScale = event.deltaMode === EventConstants.DOM_DELTA_LINE ? this._ffMultiplier : 1; // If this happens to be set to DOM_DELTA_LINE, adjust accordingly
                    this._wheelDeltaX += (this.wheelPrecisionX * platformScale * event.deltaX) / this._normalize;
                    this._wheelDeltaY -= (this.wheelPrecisionY * platformScale * event.deltaY) / this._normalize;
                    this._wheelDeltaZ += (this.wheelPrecisionZ * platformScale * event.deltaZ) / this._normalize;
                    if (event.preventDefault) {
                        if (!noPreventDefault) {
                            event.preventDefault();
                        }
                    }
                };
                this._observer = this.camera.getScene()._inputManager._addCameraPointerObserver(this._wheel, PointerEventTypes.POINTERWHEEL);
            }
            /**
             * Detach the current controls from the specified dom element.
             */
            detachControl() {
                if (this._observer) {
                    this.camera.getScene()._inputManager._removeCameraPointerObserver(this._observer);
                    this._observer = null;
                    this._wheel = null;
                }
                if (this.onChangedObservable) {
                    this.onChangedObservable.clear();
                }
            }
            /**
             * Called for each rendered frame.
             */
            checkInputs() {
                this.onChangedObservable.notifyObservers({
                    wheelDeltaX: this._wheelDeltaX,
                    wheelDeltaY: this._wheelDeltaY,
                    wheelDeltaZ: this._wheelDeltaZ,
                });
                // Clear deltas.
                this._wheelDeltaX = 0;
                this._wheelDeltaY = 0;
                this._wheelDeltaZ = 0;
            }
            /**
             * Gets the class name of the current input.
             * @returns the class name
             */
            getClassName() {
                return "BaseCameraMouseWheelInput";
            }
            /**
             * Get the friendly name associated with the input class.
             * @returns the input friendly name
             */
            getSimpleName() {
                return "mousewheel";
            }
        },
        (() => {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
            _wheelPrecisionX_decorators = [serialize()];
            _wheelPrecisionY_decorators = [serialize()];
            _wheelPrecisionZ_decorators = [serialize()];
            __esDecorate(null, null, _wheelPrecisionX_decorators, { kind: "field", name: "wheelPrecisionX", static: false, private: false, access: { has: obj => "wheelPrecisionX" in obj, get: obj => obj.wheelPrecisionX, set: (obj, value) => { obj.wheelPrecisionX = value; } }, metadata: _metadata }, _wheelPrecisionX_initializers, _wheelPrecisionX_extraInitializers);
            __esDecorate(null, null, _wheelPrecisionY_decorators, { kind: "field", name: "wheelPrecisionY", static: false, private: false, access: { has: obj => "wheelPrecisionY" in obj, get: obj => obj.wheelPrecisionY, set: (obj, value) => { obj.wheelPrecisionY = value; } }, metadata: _metadata }, _wheelPrecisionY_initializers, _wheelPrecisionY_extraInitializers);
            __esDecorate(null, null, _wheelPrecisionZ_decorators, { kind: "field", name: "wheelPrecisionZ", static: false, private: false, access: { has: obj => "wheelPrecisionZ" in obj, get: obj => obj.wheelPrecisionZ, set: (obj, value) => { obj.wheelPrecisionZ = value; } }, metadata: _metadata }, _wheelPrecisionZ_initializers, _wheelPrecisionZ_extraInitializers);
            if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        })(),
        _a;
})();

// eslint-disable-next-line @typescript-eslint/naming-convention
var _CameraProperty;
(function (_CameraProperty) {
    _CameraProperty[_CameraProperty["MoveRelative"] = 0] = "MoveRelative";
    _CameraProperty[_CameraProperty["RotateRelative"] = 1] = "RotateRelative";
    _CameraProperty[_CameraProperty["MoveScene"] = 2] = "MoveScene";
})(_CameraProperty || (_CameraProperty = {}));
/**
 * Manage the mouse wheel inputs to control a free camera.
 * @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/customizingCameraInputs
 */
let FreeCameraMouseWheelInput = (() => {
    var _a;
    let _classSuper = BaseCameraMouseWheelInput;
    let _instanceExtraInitializers = [];
    let _set_wheelXMoveRelative_decorators;
    let _set_wheelYMoveRelative_decorators;
    let _set_wheelZMoveRelative_decorators;
    let _set_wheelXRotateRelative_decorators;
    let _set_wheelYRotateRelative_decorators;
    let _set_wheelZRotateRelative_decorators;
    let _set_wheelXMoveScene_decorators;
    let _set_wheelYMoveScene_decorators;
    let _set_wheelZMoveScene_decorators;
    return _a = class FreeCameraMouseWheelInput extends _classSuper {
            constructor() {
                super(...arguments);
                /**
                 * Defines the camera the input is attached to.
                 */
                this.camera = __runInitializers(this, _instanceExtraInitializers);
                this._moveRelative = Vector3.Zero();
                this._rotateRelative = Vector3.Zero();
                this._moveScene = Vector3.Zero();
                /**
                 * These are set to the desired default behaviour.
                 */
                this._wheelXAction = _CameraProperty.MoveRelative;
                this._wheelXActionCoordinate = 0 /* Coordinate.X */;
                this._wheelYAction = _CameraProperty.MoveRelative;
                this._wheelYActionCoordinate = 2 /* Coordinate.Z */;
                this._wheelZAction = null;
                this._wheelZActionCoordinate = null;
            }
            /**
             * Gets the class name of the current input.
             * @returns the class name
             */
            getClassName() {
                return "FreeCameraMouseWheelInput";
            }
            /**
             * Set which movement axis (relative to camera's orientation) the mouse
             * wheel's X axis controls.
             * @param axis The axis to be moved. Set null to clear.
             */
            set wheelXMoveRelative(axis) {
                if (axis === null && this._wheelXAction !== _CameraProperty.MoveRelative) {
                    // Attempting to clear different _wheelXAction.
                    return;
                }
                this._wheelXAction = _CameraProperty.MoveRelative;
                this._wheelXActionCoordinate = axis;
            }
            /**
             * Get the configured movement axis (relative to camera's orientation) the
             * mouse wheel's X axis controls.
             * @returns The configured axis or null if none.
             */
            get wheelXMoveRelative() {
                if (this._wheelXAction !== _CameraProperty.MoveRelative) {
                    return null;
                }
                return this._wheelXActionCoordinate;
            }
            /**
             * Set which movement axis (relative to camera's orientation) the mouse
             * wheel's Y axis controls.
             * @param axis The axis to be moved. Set null to clear.
             */
            set wheelYMoveRelative(axis) {
                if (axis === null && this._wheelYAction !== _CameraProperty.MoveRelative) {
                    // Attempting to clear different _wheelYAction.
                    return;
                }
                this._wheelYAction = _CameraProperty.MoveRelative;
                this._wheelYActionCoordinate = axis;
            }
            /**
             * Get the configured movement axis (relative to camera's orientation) the
             * mouse wheel's Y axis controls.
             * @returns The configured axis or null if none.
             */
            get wheelYMoveRelative() {
                if (this._wheelYAction !== _CameraProperty.MoveRelative) {
                    return null;
                }
                return this._wheelYActionCoordinate;
            }
            /**
             * Set which movement axis (relative to camera's orientation) the mouse
             * wheel's Z axis controls.
             * @param axis The axis to be moved. Set null to clear.
             */
            set wheelZMoveRelative(axis) {
                if (axis === null && this._wheelZAction !== _CameraProperty.MoveRelative) {
                    // Attempting to clear different _wheelZAction.
                    return;
                }
                this._wheelZAction = _CameraProperty.MoveRelative;
                this._wheelZActionCoordinate = axis;
            }
            /**
             * Get the configured movement axis (relative to camera's orientation) the
             * mouse wheel's Z axis controls.
             * @returns The configured axis or null if none.
             */
            get wheelZMoveRelative() {
                if (this._wheelZAction !== _CameraProperty.MoveRelative) {
                    return null;
                }
                return this._wheelZActionCoordinate;
            }
            /**
             * Set which rotation axis (relative to camera's orientation) the mouse
             * wheel's X axis controls.
             * @param axis The axis to be moved. Set null to clear.
             */
            set wheelXRotateRelative(axis) {
                if (axis === null && this._wheelXAction !== _CameraProperty.RotateRelative) {
                    // Attempting to clear different _wheelXAction.
                    return;
                }
                this._wheelXAction = _CameraProperty.RotateRelative;
                this._wheelXActionCoordinate = axis;
            }
            /**
             * Get the configured rotation axis (relative to camera's orientation) the
             * mouse wheel's X axis controls.
             * @returns The configured axis or null if none.
             */
            get wheelXRotateRelative() {
                if (this._wheelXAction !== _CameraProperty.RotateRelative) {
                    return null;
                }
                return this._wheelXActionCoordinate;
            }
            /**
             * Set which rotation axis (relative to camera's orientation) the mouse
             * wheel's Y axis controls.
             * @param axis The axis to be moved. Set null to clear.
             */
            set wheelYRotateRelative(axis) {
                if (axis === null && this._wheelYAction !== _CameraProperty.RotateRelative) {
                    // Attempting to clear different _wheelYAction.
                    return;
                }
                this._wheelYAction = _CameraProperty.RotateRelative;
                this._wheelYActionCoordinate = axis;
            }
            /**
             * Get the configured rotation axis (relative to camera's orientation) the
             * mouse wheel's Y axis controls.
             * @returns The configured axis or null if none.
             */
            get wheelYRotateRelative() {
                if (this._wheelYAction !== _CameraProperty.RotateRelative) {
                    return null;
                }
                return this._wheelYActionCoordinate;
            }
            /**
             * Set which rotation axis (relative to camera's orientation) the mouse
             * wheel's Z axis controls.
             * @param axis The axis to be moved. Set null to clear.
             */
            set wheelZRotateRelative(axis) {
                if (axis === null && this._wheelZAction !== _CameraProperty.RotateRelative) {
                    // Attempting to clear different _wheelZAction.
                    return;
                }
                this._wheelZAction = _CameraProperty.RotateRelative;
                this._wheelZActionCoordinate = axis;
            }
            /**
             * Get the configured rotation axis (relative to camera's orientation) the
             * mouse wheel's Z axis controls.
             * @returns The configured axis or null if none.
             */
            get wheelZRotateRelative() {
                if (this._wheelZAction !== _CameraProperty.RotateRelative) {
                    return null;
                }
                return this._wheelZActionCoordinate;
            }
            /**
             * Set which movement axis (relative to the scene) the mouse wheel's X axis
             * controls.
             * @param axis The axis to be moved. Set null to clear.
             */
            set wheelXMoveScene(axis) {
                if (axis === null && this._wheelXAction !== _CameraProperty.MoveScene) {
                    // Attempting to clear different _wheelXAction.
                    return;
                }
                this._wheelXAction = _CameraProperty.MoveScene;
                this._wheelXActionCoordinate = axis;
            }
            /**
             * Get the configured movement axis (relative to the scene) the mouse wheel's
             * X axis controls.
             * @returns The configured axis or null if none.
             */
            get wheelXMoveScene() {
                if (this._wheelXAction !== _CameraProperty.MoveScene) {
                    return null;
                }
                return this._wheelXActionCoordinate;
            }
            /**
             * Set which movement axis (relative to the scene) the mouse wheel's Y axis
             * controls.
             * @param axis The axis to be moved. Set null to clear.
             */
            set wheelYMoveScene(axis) {
                if (axis === null && this._wheelYAction !== _CameraProperty.MoveScene) {
                    // Attempting to clear different _wheelYAction.
                    return;
                }
                this._wheelYAction = _CameraProperty.MoveScene;
                this._wheelYActionCoordinate = axis;
            }
            /**
             * Get the configured movement axis (relative to the scene) the mouse wheel's
             * Y axis controls.
             * @returns The configured axis or null if none.
             */
            get wheelYMoveScene() {
                if (this._wheelYAction !== _CameraProperty.MoveScene) {
                    return null;
                }
                return this._wheelYActionCoordinate;
            }
            /**
             * Set which movement axis (relative to the scene) the mouse wheel's Z axis
             * controls.
             * @param axis The axis to be moved. Set null to clear.
             */
            set wheelZMoveScene(axis) {
                if (axis === null && this._wheelZAction !== _CameraProperty.MoveScene) {
                    // Attempting to clear different _wheelZAction.
                    return;
                }
                this._wheelZAction = _CameraProperty.MoveScene;
                this._wheelZActionCoordinate = axis;
            }
            /**
             * Get the configured movement axis (relative to the scene) the mouse wheel's
             * Z axis controls.
             * @returns The configured axis or null if none.
             */
            get wheelZMoveScene() {
                if (this._wheelZAction !== _CameraProperty.MoveScene) {
                    return null;
                }
                return this._wheelZActionCoordinate;
            }
            /**
             * Called for each rendered frame.
             */
            checkInputs() {
                if (this._wheelDeltaX === 0 && this._wheelDeltaY === 0 && this._wheelDeltaZ == 0) {
                    return;
                }
                // Clear the camera properties that we might be updating.
                this._moveRelative.setAll(0);
                this._rotateRelative.setAll(0);
                this._moveScene.setAll(0);
                // Set the camera properties that are to be updated.
                this._updateCamera();
                if (this.camera.getScene().useRightHandedSystem) {
                    // TODO: Does this need done for worldUpdate too?
                    this._moveRelative.z *= -1;
                }
                // Convert updates relative to camera to world position update.
                const cameraTransformMatrix = Matrix.Zero();
                this.camera.getViewMatrix().invertToRef(cameraTransformMatrix);
                const transformedDirection = Vector3.Zero();
                Vector3.TransformNormalToRef(this._moveRelative, cameraTransformMatrix, transformedDirection);
                // Apply updates to camera position.
                this.camera.cameraRotation.x += this._rotateRelative.x / 200;
                this.camera.cameraRotation.y += this._rotateRelative.y / 200;
                this.camera.cameraDirection.addInPlace(transformedDirection);
                this.camera.cameraDirection.addInPlace(this._moveScene);
                // Call the base class implementation to handle observers and do cleanup.
                super.checkInputs();
            }
            /**
             * Update the camera according to any configured properties for the 3
             * mouse-wheel axis.
             */
            _updateCamera() {
                // Do the camera updates for each of the 3 touch-wheel axis.
                this._updateCameraProperty(this._wheelDeltaX, this._wheelXAction, this._wheelXActionCoordinate);
                this._updateCameraProperty(this._wheelDeltaY, this._wheelYAction, this._wheelYActionCoordinate);
                this._updateCameraProperty(this._wheelDeltaZ, this._wheelZAction, this._wheelZActionCoordinate);
            }
            /**
             * Update one property of the camera.
             * @param value
             * @param cameraProperty
             * @param coordinate
             */
            _updateCameraProperty(
            /* Mouse-wheel delta. */
            value, 
            /* Camera property to be changed. */
            cameraProperty, 
            /* Axis of Camera property to be changed. */
            coordinate) {
                if (value === 0) {
                    // Mouse wheel has not moved.
                    return;
                }
                if (cameraProperty === null || coordinate === null) {
                    // Mouse wheel axis not configured.
                    return;
                }
                let action = null;
                switch (cameraProperty) {
                    case _CameraProperty.MoveRelative:
                        action = this._moveRelative;
                        break;
                    case _CameraProperty.RotateRelative:
                        action = this._rotateRelative;
                        break;
                    case _CameraProperty.MoveScene:
                        action = this._moveScene;
                        break;
                }
                switch (coordinate) {
                    case 0 /* Coordinate.X */:
                        action.set(value, 0, 0);
                        break;
                    case 1 /* Coordinate.Y */:
                        action.set(0, value, 0);
                        break;
                    case 2 /* Coordinate.Z */:
                        action.set(0, 0, value);
                        break;
                }
            }
        },
        (() => {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
            _set_wheelXMoveRelative_decorators = [serialize()];
            _set_wheelYMoveRelative_decorators = [serialize()];
            _set_wheelZMoveRelative_decorators = [serialize()];
            _set_wheelXRotateRelative_decorators = [serialize()];
            _set_wheelYRotateRelative_decorators = [serialize()];
            _set_wheelZRotateRelative_decorators = [serialize()];
            _set_wheelXMoveScene_decorators = [serialize()];
            _set_wheelYMoveScene_decorators = [serialize()];
            _set_wheelZMoveScene_decorators = [serialize()];
            __esDecorate(_a, null, _set_wheelXMoveRelative_decorators, { kind: "setter", name: "wheelXMoveRelative", static: false, private: false, access: { has: obj => "wheelXMoveRelative" in obj, set: (obj, value) => { obj.wheelXMoveRelative = value; } }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(_a, null, _set_wheelYMoveRelative_decorators, { kind: "setter", name: "wheelYMoveRelative", static: false, private: false, access: { has: obj => "wheelYMoveRelative" in obj, set: (obj, value) => { obj.wheelYMoveRelative = value; } }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(_a, null, _set_wheelZMoveRelative_decorators, { kind: "setter", name: "wheelZMoveRelative", static: false, private: false, access: { has: obj => "wheelZMoveRelative" in obj, set: (obj, value) => { obj.wheelZMoveRelative = value; } }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(_a, null, _set_wheelXRotateRelative_decorators, { kind: "setter", name: "wheelXRotateRelative", static: false, private: false, access: { has: obj => "wheelXRotateRelative" in obj, set: (obj, value) => { obj.wheelXRotateRelative = value; } }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(_a, null, _set_wheelYRotateRelative_decorators, { kind: "setter", name: "wheelYRotateRelative", static: false, private: false, access: { has: obj => "wheelYRotateRelative" in obj, set: (obj, value) => { obj.wheelYRotateRelative = value; } }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(_a, null, _set_wheelZRotateRelative_decorators, { kind: "setter", name: "wheelZRotateRelative", static: false, private: false, access: { has: obj => "wheelZRotateRelative" in obj, set: (obj, value) => { obj.wheelZRotateRelative = value; } }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(_a, null, _set_wheelXMoveScene_decorators, { kind: "setter", name: "wheelXMoveScene", static: false, private: false, access: { has: obj => "wheelXMoveScene" in obj, set: (obj, value) => { obj.wheelXMoveScene = value; } }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(_a, null, _set_wheelYMoveScene_decorators, { kind: "setter", name: "wheelYMoveScene", static: false, private: false, access: { has: obj => "wheelYMoveScene" in obj, set: (obj, value) => { obj.wheelYMoveScene = value; } }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(_a, null, _set_wheelZMoveScene_decorators, { kind: "setter", name: "wheelZMoveScene", static: false, private: false, access: { has: obj => "wheelZMoveScene" in obj, set: (obj, value) => { obj.wheelZMoveScene = value; } }, metadata: _metadata }, null, _instanceExtraInitializers);
            if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        })(),
        _a;
})();
CameraInputTypes["FreeCameraMouseWheelInput"] = FreeCameraMouseWheelInput;

/**
 * Manage the touch inputs to control the movement of a free camera.
 * @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/customizingCameraInputs
 */
let FreeCameraTouchInput = (() => {
    var _a;
    let _touchAngularSensibility_decorators;
    let _touchAngularSensibility_initializers = [];
    let _touchAngularSensibility_extraInitializers = [];
    let _touchMoveSensibility_decorators;
    let _touchMoveSensibility_initializers = [];
    let _touchMoveSensibility_extraInitializers = [];
    return _a = class FreeCameraTouchInput {
            /**
             * Manage the touch inputs to control the movement of a free camera.
             * @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/customizingCameraInputs
             * @param allowMouse Defines if mouse events can be treated as touch events
             */
            constructor(
            /**
             * [false] Define if mouse events can be treated as touch events
             */
            allowMouse = false) {
                this.allowMouse = allowMouse;
                /**
                 * Defines the touch sensibility for rotation.
                 * The lower the faster.
                 */
                this.touchAngularSensibility = __runInitializers(this, _touchAngularSensibility_initializers, 200000.0);
                /**
                 * Defines the touch sensibility for move.
                 * The lower the faster.
                 */
                this.touchMoveSensibility = (__runInitializers(this, _touchAngularSensibility_extraInitializers), __runInitializers(this, _touchMoveSensibility_initializers, 250.0));
                /**
                 * Swap touch actions so that one touch is used for rotation and multiple for movement
                 */
                this.singleFingerRotate = (__runInitializers(this, _touchMoveSensibility_extraInitializers), false);
                this._offsetX = null;
                this._offsetY = null;
                this._pointerPressed = new Array();
                this._isSafari = Tools.IsSafari();
            }
            /**
             * 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);
                let previousPosition = null;
                if (this._pointerInput === undefined) {
                    this._onLostFocus = () => {
                        this._offsetX = null;
                        this._offsetY = null;
                    };
                    this._pointerInput = (p) => {
                        const evt = p.event;
                        const isMouseEvent = evt.pointerType === "mouse" || (this._isSafari && typeof evt.pointerType === "undefined");
                        if (!this.allowMouse && isMouseEvent) {
                            return;
                        }
                        if (p.type === PointerEventTypes.POINTERDOWN) {
                            if (!noPreventDefault) {
                                evt.preventDefault();
                            }
                            this._pointerPressed.push(evt.pointerId);
                            if (this._pointerPressed.length !== 1) {
                                return;
                            }
                            previousPosition = {
                                x: evt.clientX,
                                y: evt.clientY,
                            };
                        }
                        else if (p.type === PointerEventTypes.POINTERUP) {
                            if (!noPreventDefault) {
                                evt.preventDefault();
                            }
                            const index = this._pointerPressed.indexOf(evt.pointerId);
                            if (index === -1) {
                                return;
                            }
                            this._pointerPressed.splice(index, 1);
                            if (index != 0) {
                                return;
                            }
                            previousPosition = null;
                            this._offsetX = null;
                            this._offsetY = null;
                        }
                        else if (p.type === PointerEventTypes.POINTERMOVE) {
                            if (!noPreventDefault) {
                                evt.preventDefault();
                            }
                            if (!previousPosition) {
                                return;
                            }
                            const index = this._pointerPressed.indexOf(evt.pointerId);
                            if (index != 0) {
                                return;
                            }
                            this._offsetX = evt.clientX - previousPosition.x;
                            this._offsetY = -(evt.clientY - previousPosition.y);
                        }
                    };
                }
                this._observer = this.camera
                    .getScene()
                    ._inputManager._addCameraPointerObserver(this._pointerInput, PointerEventTypes.POINTERDOWN | PointerEventTypes.POINTERUP | PointerEventTypes.POINTERMOVE);
                if (this._onLostFocus) {
                    const engine = this.camera.getEngine();
                    const element = engine.getInputElement();
                    if (element) {
                        element.addEventListener("blur", this._onLostFocus);
                    }
                }
            }
            /**
             * Detach the current controls from the specified dom element.
             */
            detachControl() {
                if (this._pointerInput) {
                    if (this._observer) {
                        this.camera.getScene()._inputManager._removeCameraPointerObserver(this._observer);
                        this._observer = null;
                    }
                    if (this._onLostFocus) {
                        const engine = this.camera.getEngine();
                        const element = engine.getInputElement();
                        if (element) {
                            element.removeEventListener("blur", this._onLostFocus);
                        }
                        this._onLostFocus = null;
                    }
                    this._pointerPressed.length = 0;
                    this._offsetX = null;
                    this._offsetY = null;
                }
            }
            /**
             * Update the current camera state depending on the inputs that have been used this frame.
             * This is a dynamically created lambda to avoid the performance penalty of looping for inputs in the render loop.
             */
            checkInputs() {
                if (this._offsetX === null || this._offsetY === null) {
                    return;
                }
                if (this._offsetX === 0 && this._offsetY === 0) {
                    return;
                }
                const camera = this.camera;
                // Touch look (yaw/pitch) is gated on touch→rotate and the forward drag-move on
                // touch→translate. Removing an entry disables that touch behavior. An entry's optional
                // `sensitivity` replaces the legacy 1/touchAngularSensibility (rotate) or
                // 1/touchMoveSensibility (translate) scale factor.
                const input = camera.movement.input;
                const rotateEntry = input.getEntry("touch", "rotate");
                const translateEntry = input.getEntry("touch", "translate");
                const handednessMultiplier = camera._calculateHandednessMultiplier();
                const rotateCamera = (this.singleFingerRotate && this._pointerPressed.length === 1) || (!this.singleFingerRotate && this._pointerPressed.length > 1);
                if (rotateEntry) {
                    const rotateSensitivity = rotateEntry.sensitivity ?? 1 / this.touchAngularSensibility;
                    camera.cameraRotation.y = this._offsetX * handednessMultiplier * rotateSensitivity;
                    if (rotateCamera) {
                        camera.cameraRotation.x = -(this._offsetY * handednessMultiplier) * rotateSensitivity;
                    }
                }
                if (!rotateCamera && translateEntry) {
                    const speed = camera._computeLocalCameraSpeed();
                    const moveSensitivity = translateEntry.sensitivity ?? (this.touchMoveSensibility !== 0 ? 1 / this.touchMoveSensibility : 0);
                    const direction = TmpVectors.Vector3[0];
                    direction.copyFromFloats(0, 0, speed * this._offsetY * moveSensitivity);
                    Matrix.RotationYawPitchRollToRef(camera.rotation.y, camera.rotation.x, 0, camera._cameraRotationMatrix);
                    Vector3.TransformCoordinatesToRef(direction, camera._cameraRotationMatrix, direction);
                    camera.cameraDirection.addInPlace(direction);
                }
            }
            /**
             * Gets the class name of the current input.
             * @returns the class name
             */
            getClassName() {
                return "FreeCameraTouchInput";
            }
            /**
             * Get the friendly name associated with the input class.
             * @returns the input friendly name
             */
            getSimpleName() {
                return "touch";
            }
        },
        (() => {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
            _touchAngularSensibility_decorators = [serialize()];
            _touchMoveSensibility_decorators = [serialize()];
            __esDecorate(null, null, _touchAngularSensibility_decorators, { kind: "field", name: "touchAngularSensibility", static: false, private: false, access: { has: obj => "touchAngularSensibility" in obj, get: obj => obj.touchAngularSensibility, set: (obj, value) => { obj.touchAngularSensibility = value; } }, metadata: _metadata }, _touchAngularSensibility_initializers, _touchAngularSensibility_extraInitializers);
            __esDecorate(null, null, _touchMoveSensibility_decorators, { kind: "field", name: "touchMoveSensibility", static: false, private: false, access: { has: obj => "touchMoveSensibility" in obj, get: obj => obj.touchMoveSensibility, set: (obj, value) => { obj.touchMoveSensibility = value; } }, metadata: _metadata }, _touchMoveSensibility_initializers, _touchMoveSensibility_extraInitializers);
            if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        })(),
        _a;
})();
CameraInputTypes["FreeCameraTouchInput"] = FreeCameraTouchInput;

/** This file must only contain pure code and pure imports */
/**
 * Default Inputs manager for the FreeCamera.
 * It groups all the default supported inputs for ease of use.
 * @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/customizingCameraInputs
 */
class FreeCameraInputsManager extends CameraInputsManager {
    /**
     * Instantiates a new FreeCameraInputsManager.
     * @param camera Defines the camera the inputs belong to
     */
    constructor(camera) {
        super(camera);
        /**
         * @internal
         */
        this._mouseInput = null;
        /**
         * @internal
         */
        this._mouseWheelInput = null;
    }
    /**
     * Add keyboard input support to the input manager.
     * @returns the current input manager
     */
    addKeyboard() {
        this.add(new FreeCameraKeyboardMoveInput());
        return this;
    }
    /**
     * Add mouse input support to the input manager.
     * @param touchEnabled if the FreeCameraMouseInput should support touch (default: true)
     * @returns the current input manager
     */
    addMouse(touchEnabled = true) {
        if (!this._mouseInput) {
            this._mouseInput = new FreeCameraMouseInput(touchEnabled);
            this.add(this._mouseInput);
        }
        return this;
    }
    /**
     * Removes the mouse input support from the manager
     * @returns the current input manager
     */
    removeMouse() {
        if (this._mouseInput) {
            this.remove(this._mouseInput);
        }
        return this;
    }
    /**
     * Add mouse wheel input support to the input manager.
     * @returns the current input manager
     */
    addMouseWheel() {
        if (!this._mouseWheelInput) {
            this._mouseWheelInput = new FreeCameraMouseWheelInput();
            this.add(this._mouseWheelInput);
        }
        return this;
    }
    /**
     * Removes the mouse wheel input support from the manager
     * @returns the current input manager
     */
    removeMouseWheel() {
        if (this._mouseWheelInput) {
            this.remove(this._mouseWheelInput);
        }
        return this;
    }
    /**
     * Add touch input support to the input manager.
     * @returns the current input manager
     */
    addTouch() {
        this.add(new FreeCameraTouchInput());
        return this;
    }
    /**
     * Remove all attached input methods from a camera
     */
    clear() {
        super.clear();
        this._mouseInput = null;
    }
}
FreeCameraInputsManager.prototype.addDeviceOrientation ??= _MissingSideEffect("FreeCameraInputsManager", "addDeviceOrientation");
FreeCameraInputsManager.prototype.addVirtualJoystick ??= _MissingSideEffect("FreeCameraInputsManager", "addVirtualJoystick");
FreeCameraInputsManager.prototype.addGamepad ??= _MissingSideEffect("FreeCameraInputsManager", "addGamepad");
// #endregion GENERATED_SIDE_EFFECT_STUBS

/** This file must only contain pure code and pure imports */
/**
 * This represents a free type of camera. It can be useful in First Person Shooter game for instance.
 * Please consider using the new UniversalCamera instead as it adds more functionality like the gamepad.
 * @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/camera_introduction#universal-camera
 */
let FreeCamera = (() => {
    var _a;
    let _classSuper = TargetCamera;
    let _ellipsoid_decorators;
    let _ellipsoid_initializers = [];
    let _ellipsoid_extraInitializers = [];
    let _ellipsoidOffset_decorators;
    let _ellipsoidOffset_initializers = [];
    let _ellipsoidOffset_extraInitializers = [];
    let _checkCollisions_decorators;
    let _checkCollisions_initializers = [];
    let _checkCollisions_extraInitializers = [];
    let _applyGravity_decorators;
    let _applyGravity_initializers = [];
    let _applyGravity_extraInitializers = [];
    return _a = class FreeCamera extends _classSuper {
            /**
             * Gets the input sensibility for a mouse input. (default is 2000.0)
             * Higher values reduce sensitivity.
             */
            get angularSensibility() {
                const mouse = this.inputs.attached["mouse"];
                if (mouse) {
                    return mouse.angularSensibility;
                }
                return 0;
            }
            /**
             * Sets the input sensibility for a mouse input. (default is 2000.0)
             * Higher values reduce sensitivity.
             */
            set angularSensibility(value) {
                const mouse = this.inputs.attached["mouse"];
                if (mouse) {
                    mouse.angularSensibility = value;
                }
            }
            /**
             * Gets or Set the list of keyboard keys used to control the forward move of the camera.
             */
            get keysUp() {
                const keyboard = this.inputs.attached["keyboard"];
                if (keyboard) {
                    return keyboard.keysUp;
                }
                return [];
            }
            set keysUp(value) {
                const keyboard = this.inputs.attached["keyboard"];
                if (keyboard) {
                    keyboard.keysUp = value;
                }
            }
            /**
             * Gets or Set the list of keyboard keys used to control the upward move of the camera.
             */
            get keysUpward() {
                const keyboard = this.inputs.attached["keyboard"];
                if (keyboard) {
                    return keyboard.keysUpward;
                }
                return [];
            }
            set keysUpward(value) {
                const keyboard = this.inputs.attached["keyboard"];
                if (keyboard) {
                    keyboard.keysUpward = value;
                }
            }
            /**
             * Gets or Set the list of keyboard keys used to control the backward move of the camera.
             */
            get keysDown() {
                const keyboard = this.inputs.attached["keyboard"];
                if (keyboard) {
                    return keyboard.keysDown;
                }
                return [];
            }
            set keysDown(value) {
                const keyboard = this.inputs.attached["keyboard"];
                if (keyboard) {
                    keyboard.keysDown = value;
                }
            }
            /**
             * Gets or Set the list of keyboard keys used to control the downward move of the camera.
             */
            get keysDownward() {
                const keyboard = this.inputs.attached["keyboard"];
                if (keyboard) {
                    return keyboard.keysDownward;
                }
                return [];
            }
            set keysDownward(value) {
                const keyboard = this.inputs.attached["keyboard"];
                if (keyboard) {
                    keyboard.keysDownward = value;
                }
            }
            /**
             * Gets or Set the list of keyboard keys used to control the left strafe move of the camera.
             */
            get keysLeft() {
                const keyboard = this.inputs.attached["keyboard"];
                if (keyboard) {
                    return keyboard.keysLeft;
                }
                return [];
            }
            set keysLeft(value) {
                const keyboard = this.inputs.attached["keyboard"];
                if (keyboard) {
                    keyboard.keysLeft = value;
                }
            }
            /**
             * Gets or Set the list of keyboard keys used to control the right strafe move of the camera.
             */
            get keysRight() {
                const keyboard = this.inputs.attached["keyboard"];
                if (keyboard) {
                    return keyboard.keysRight;
                }
                return [];
            }
            set keysRight(value) {
                const keyboard = this.inputs.attached["keyboard"];
                if (keyboard) {
                    keyboard.keysRight = value;
                }
            }
            /**
             * Gets or Set the list of keyboard keys used to control the left rotation move of the camera.
             */
            get keysRotateLeft() {
                const keyboard = this.inputs.attached["keyboard"];
                if (keyboard) {
                    return keyboard.keysRotateLeft;
                }
                return [];
            }
            set keysRotateLeft(value) {
                const keyboard = this.inputs.attached["keyboard"];
                if (keyboard) {
                    keyboard.keysRotateLeft = value;
                }
            }
            /**
             * Gets or Set the list of keyboard keys used to control the right rotation move of the camera.
             */
            get keysRotateRight() {
                const keyboard = this.inputs.attached["keyboard"];
                if (keyboard) {
                    return keyboard.keysRotateRight;
                }
                return [];
            }
            set keysRotateRight(value) {
                const keyboard = this.inputs.attached["keyboard"];
                if (keyboard) {
                    keyboard.keysRotateRight = value;
                }
            }
            /**
             * Gets or Set the list of keyboard keys used to control the up rotation move of the camera.
             */
            get keysRotateUp() {
                const keyboard = this.inputs.attached["keyboard"];
                if (keyboard) {
                    return keyboard.keysRotateUp;
                }
                return [];
            }
            set keysRotateUp(value) {
                const keyboard = this.inputs.attached["keyboard"];
                if (keyboard) {
                    keyboard.keysRotateUp = value;
                }
            }
            /**
             * Gets or Set the list of keyboard keys used to control the down rotation move of the camera.
             */
            get keysRotateDown() {
                const keyboard = this.inputs.attached["keyboard"];
                if (keyboard) {
                    return keyboard.keysRotateDown;
                }
                return [];
            }
            set keysRotateDown(value) {
                const keyboard = this.inputs.attached["keyboard"];
                if (keyboard) {
                    keyboard.keysRotateDown = value;
                }
            }
            /**
             * Instantiates a Free Camera.
             * This represents a free type of camera. It can be useful in First Person Shooter game for instance.
             * Please consider using the new UniversalCamera instead as it adds more functionality like touch to this camera.
             * @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/camera_introduction#universal-camera
             * @param name Define the name of the camera in the scene
             * @param position Define the start position of the camera in the scene
             * @param scene Define the scene the camera belongs to
             * @param setActiveOnSceneIfNoneActive Defines whether the camera should be marked as active if not other active cameras have been defined
             */
            constructor(name, position, scene, setActiveOnSceneIfNoneActive = true) {
                super(name, position, scene, setActiveOnSceneIfNoneActive);
                /**
                 * Define the collision ellipsoid of the camera.
                 * This is helpful to simulate a camera body like the player body around the camera
                 * @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/camera_collisions#arcrotatecamera
                 */
                this.ellipsoid = __runInitializers(this, _ellipsoid_initializers, new Vector3(0.5, 1, 0.5));
                /**
                 * Define an offset for the position of the ellipsoid around the camera.
                 * This can be helpful to determine the center of the body near the gravity center of the body
                 * instead of its head.
                 */
                this.ellipsoidOffset = (__runInitializers(this, _ellipsoid_extraInitializers), __runInitializers(this, _ellipsoidOffset_initializers, new Vector3(0, 0, 0)));
                /**
                 * Enable or disable collisions of the camera with the rest of the scene objects.
                 */
                this.checkCollisions = (__runInitializers(this, _ellipsoidOffset_extraInitializers), __runInitializers(this, _checkCollisions_initializers, false));
                /**
                 * Enable or disable gravity on the camera.
                 */
                this.applyGravity = (__runInitializers(this, _checkCollisions_extraInitializers), __runInitializers(this, _applyGravity_initializers, false));
                /**
                 * Define the input manager associated to the camera.
                 */
                this.inputs = __runInitializers(this, _applyGravity_extraInitializers);
                this._needMoveForGravity = false;
                this._oldPosition = Vector3.Zero();
                this._diffPosition = Vector3.Zero();
                this._newPosition = Vector3.Zero();
                // Collisions
                this._collisionMask = -1;
                this._onCollisionPositionChange = (collisionId, newPosition, collidedMesh = null) => {
                    this._newPosition.copyFrom(newPosition);
                    this._newPosition.subtractToRef(this._oldPosition, this._diffPosition);
                    if (this._diffPosition.length() > AbstractEngine.CollisionsEpsilon) {
                        this.position.addToRef(this._diffPosition, this._deferredPositionUpdate);
                        if (!this._deferOnly) {
                            this.position.copyFrom(this._deferredPositionUpdate);
                        }
                        else {
                            this._deferredUpdated = true;
                        }
                        // call onCollide, if defined. Note that in case of deferred update, the actual position change might happen in the next frame.
                        if (this.onCollide && collidedMesh) {
                            this.onCollide(collidedMesh);
                        }
                    }
                };
                this.inputs = new FreeCameraInputsManager(this);
                this.inputs.addKeyboard().addMouse();
            }
            /**
             * Attached controls to the current camera.
             * @param ignored defines an ignored parameter kept for backward compatibility.
             * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
             */
            attachControl(ignored, noPreventDefault) {
                noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments);
                this.inputs.attachElement(noPreventDefault);
            }
            /**
             * Detach the current controls from the specified dom element.
             */
            detachControl() {
                this.inputs.detachElement();
                this.cameraDirection = new Vector3(0, 0, 0);
                this.cameraRotation = new Vector2(0, 0);
            }
            /**
             * Define a collision mask to limit the list of object the camera can collide with
             */
            get collisionMask() {
                return this._collisionMask;
            }
            set collisionMask(mask) {
                this._collisionMask = !isNaN(mask) ? mask : -1;
            }
            /**
             * @internal
             */
            _collideWithWorld(displacement) {
                let globalPosition;
                if (this.parent) {
                    globalPosition = Vector3.TransformCoordinates(this.position, this.parent.getWorldMatrix());
                }
                else {
                    globalPosition = this.position;
                }
                globalPosition.subtractFromFloatsToRef(0, this.ellipsoid.y, 0, this._oldPosition);
                this._oldPosition.addInPlace(this.ellipsoidOffset);
                const coordinator = this.getScene().collisionCoordinator;
                if (!this._collider) {
                    this._collider = coordinator.createCollider();
                }
                this._collider._radius = this.ellipsoid;
                this._collider.collisionMask = this._collisionMask;
                //no need for clone, as long as gravity is not on.
                let actualDisplacement = displacement;
                //add gravity to the direction to prevent the dual-collision checking
                if (this.applyGravity) {
                    //this prevents mending with cameraDirection, a global variable of the free camera class.
                    actualDisplacement = displacement.add(this.getScene().gravity);
                }
                coordinator.getNewPosition(this._oldPosition, actualDisplacement, this._collider, 3, null, this._onCollisionPositionChange, this.uniqueId);
            }
            /** @internal */
            _checkInputs() {
                if (!this._localDirection) {
                    this._localDirection = Vector3.Zero();
                    this._transformedDirection = Vector3.Zero();
                }
                this.inputs.checkInputs();
                super._checkInputs();
            }
            /**
             * Enable movement without a user input. This allows gravity to always be applied.
             */
            set needMoveForGravity(value) {
                this._needMoveForGravity = value;
            }
            /**
             * When true, gravity is applied whether there is user input or not.
             */
            get needMoveForGravity() {
                return this._needMoveForGravity;
            }
            /** @internal */
            _decideIfNeedsToMove() {
                return this._needMoveForGravity || Math.abs(this.cameraDirection.x) > 0 || Math.abs(this.cameraDirection.y) > 0 || Math.abs(this.cameraDirection.z) > 0;
            }
            /** @internal */
            _updatePosition() {
                if (this.checkCollisions && this.getScene().collisionsEnabled) {
                    this._collideWithWorld(this.cameraDirection);
                }
                else {
                    super._updatePosition();
                }
            }
            /**
             * Destroy the camera and release the current resources hold by it.
             */
            dispose() {
                this.inputs.clear();
                super.dispose();
            }
            /**
             * Gets the current object class name.
             * @returns the class name
             */
            getClassName() {
                return "FreeCamera";
            }
        },
        (() => {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
            _ellipsoid_decorators = [serializeAsVector3()];
            _ellipsoidOffset_decorators = [serializeAsVector3()];
            _checkCollisions_decorators = [serialize()];
            _applyGravity_decorators = [serialize()];
            __esDecorate(null, null, _ellipsoid_decorators, { kind: "field", name: "ellipsoid", static: false, private: false, access: { has: obj => "ellipsoid" in obj, get: obj => obj.ellipsoid, set: (obj, value) => { obj.ellipsoid = value; } }, metadata: _metadata }, _ellipsoid_initializers, _ellipsoid_extraInitializers);
            __esDecorate(null, null, _ellipsoidOffset_decorators, { kind: "field", name: "ellipsoidOffset", static: false, private: false, access: { has: obj => "ellipsoidOffset" in obj, get: obj => obj.ellipsoidOffset, set: (obj, value) => { obj.ellipsoidOffset = value; } }, metadata: _metadata }, _ellipsoidOffset_initializers, _ellipsoidOffset_extraInitializers);
            __esDecorate(null, null, _checkCollisions_decorators, { kind: "field", name: "checkCollisions", static: false, private: false, access: { has: obj => "checkCollisions" in obj, get: obj => obj.checkCollisions, set: (obj, value) => { obj.checkCollisions = value; } }, metadata: _metadata }, _checkCollisions_initializers, _checkCollisions_extraInitializers);
            __esDecorate(null, null, _applyGravity_decorators, { kind: "field", name: "applyGravity", static: false, private: false, access: { has: obj => "applyGravity" in obj, get: obj => obj.applyGravity, set: (obj, value) => { obj.applyGravity = value; } }, metadata: _metadata }, _applyGravity_initializers, _applyGravity_extraInitializers);
            if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        })(),
        _a;
})();

/**
 * Defines a target to use with MorphTargetManager
 * @see https://doc.babylonjs.com/features/featuresDeepDive/mesh/morphTargets
 */
let MorphTarget = (() => {
    var _a;
    let _id_decorators;
    let _id_initializers = [];
    let _id_extraInitializers = [];
    let _morphTargetManager_decorators;
    let _morphTargetManager_initializers = [];
    let _morphTargetManager_extraInitializers = [];
    return _a = class MorphTarget {
            /**
             * Gets or sets the influence of this target (ie. its weight in the overall morphing)
             */
            get influence() {
                return this._influence;
            }
            set influence(influence) {
                if (this._influence === influence) {
                    return;
                }
                const previous = this._influence;
                this._influence = influence;
                if (this.onInfluenceChanged.hasObservers()) {
                    this.onInfluenceChanged.notifyObservers(previous === 0 || influence === 0);
                }
            }
            /**
             * Gets or sets the animation properties override
             */
            get animationPropertiesOverride() {
                if (!this._animationPropertiesOverride && this._scene) {
                    return this._scene.animationPropertiesOverride;
                }
                return this._animationPropertiesOverride;
            }
            set animationPropertiesOverride(value) {
                this._animationPropertiesOverride = value;
            }
            /**
             * Creates a new MorphTarget
             * @param name defines the name of the target
             * @param influence defines the influence to use
             * @param scene defines the scene the morphtarget belongs to
             * @param morphTargetManager morph target manager this morph target is associated with
             */
            constructor(name, influence = 0, scene = null, morphTargetManager = null) {
                this.name = name;
                /**
                 * Gets or sets the list of animations
                 */
                this.animations = [];
                this._positions = null;
                this._normals = null;
                this._tangents = null;
                this._uvs = null;
                this._uv2s = null;
                this._colors = null;
                this._uniqueId = 0;
                /**
                 * Observable raised when the influence changes
                 */
                this.onInfluenceChanged = new Observable();
                /** @internal */
                this._onDataLayoutChanged = new Observable();
                /**
                 * Gets or sets the id of the morph Target
                 */
                this.id = __runInitializers(this, _id_initializers, void 0);
                /**
                 * Gets or sets the morph target manager this morph target is associated with
                 */
                this.morphTargetManager = (__runInitializers(this, _id_extraInitializers), __runInitializers(this, _morphTargetManager_initializers, null));
                this._animationPropertiesOverride = (__runInitializers(this, _morphTargetManager_extraInitializers), null);
                this.id = name;
                this.morphTargetManager = morphTargetManager;
                this._scene = scene || EngineStore.LastCreatedScene;
                this.influence = influence;
                if (this._scene) {
                    this._uniqueId = this._scene.getUniqueId();
                }
            }
            /**
             * Gets the unique ID of this manager
             */
            get uniqueId() {
                return this._uniqueId;
            }
            /**
             * Gets a boolean defining if the target contains position data
             */
            get hasPositions() {
                return !!this._positions;
            }
            /**
             * Gets a boolean defining if the target contains normal data
             */
            get hasNormals() {
                return !!this._normals;
            }
            /**
             * Gets a boolean defining if the target contains tangent data
             */
            get hasTangents() {
                return !!this._tangents;
            }
            /**
             * Gets a boolean defining if the target contains texture coordinates data
             */
            get hasUVs() {
                return !!this._uvs;
            }
            /**
             * Gets a boolean defining if the target contains texture coordinates 2 data
             */
            get hasUV2s() {
                return !!this._uv2s;
            }
            get hasColors() {
                return !!this._colors;
            }
            /**
             * Gets the number of vertices stored in this target
             */
            get vertexCount() {
                return this._positions
                    ? this._positions.length / 3
                    : this._normals
                        ? this._normals.length / 3
                        : this._tangents
                            ? this._tangents.length / 3
                            : this._uvs
                                ? this._uvs.length / 2
                                : this._uv2s
                                    ? this._uv2s.length / 2
                                    : this._colors
                                        ? this._colors.length / 4
                                        : 0;
            }
            /**
             * Affects position data to this target
             * @param data defines the position data to use
             */
            setPositions(data) {
                const hadPositions = this.hasPositions;
                this._positions = data;
                if (hadPositions !== this.hasPositions) {
                    this._onDataLayoutChanged.notifyObservers(undefined);
                }
            }
            /**
             * Gets the position data stored in this target
             * @returns a FloatArray containing the position data (or null if not present)
             */
            getPositions() {
                return this._positions;
            }
            /**
             * Affects normal data to this target
             * @param data defines the normal data to use
             */
            setNormals(data) {
                const hadNormals = this.hasNormals;
                this._normals = data;
                if (hadNormals !== this.hasNormals) {
                    this._onDataLayoutChanged.notifyObservers(undefined);
                }
            }
            /**
             * Gets the normal data stored in this target
             * @returns a FloatArray containing the normal data (or null if not present)
             */
            getNormals() {
                return this._normals;
            }
            /**
             * Affects tangent data to this target
             * @param data defines the tangent data to use
             */
            setTangents(data) {
                const hadTangents = this.hasTangents;
                this._tangents = data;
                if (hadTangents !== this.hasTangents) {
                    this._onDataLayoutChanged.notifyObservers(undefined);
                }
            }
            /**
             * Gets the tangent data stored in this target
             * @returns a FloatArray containing the tangent data (or null if not present)
             */
            getTangents() {
                return this._tangents;
            }
            /**
             * Affects texture coordinates data to this target
             * @param data defines the texture coordinates data to use
             */
            setUVs(data) {
                const hadUVs = this.hasUVs;
                this._uvs = data;
                if (hadUVs !== this.hasUVs) {
                    this._onDataLayoutChanged.notifyObservers(undefined);
                }
            }
            /**
             * Gets the texture coordinates data stored in this target
             * @returns a FloatArray containing the texture coordinates data (or null if not present)
             */
            getUVs() {
                return this._uvs;
            }
            /**
             * Affects texture coordinates 2 data to this target
             * @param data defines the texture coordinates 2 data to use
             */
            setUV2s(data) {
                const hadUV2s = this.hasUV2s;
                this._uv2s = data;
                if (hadUV2s !== this.hasUV2s) {
                    this._onDataLayoutChanged.notifyObservers(undefined);
                }
            }
            /**
             * Gets the texture coordinates 2 data stored in this target
             * @returns a FloatArray containing the texture coordinates 2 data (or null if not present)
             */
            getUV2s() {
                return this._uv2s;
            }
            /**
             * Affects color data to this target
             * @param data defines the color data to use
             */
            setColors(data) {
                const hadColors = this.hasColors;
                this._colors = data;
                if (hadColors !== this.hasColors) {
                    this._onDataLayoutChanged.notifyObservers(undefined);
                }
            }
            /**
             * Gets the color data stored in this target
             * @returns a FloatArray containing the color data (or null if not present)
             */
            getColors() {
                return this._colors;
            }
            /**
             * Clone the current target
             * @returns a new MorphTarget
             */
            clone() {
                const newOne = SerializationHelper.Clone(() => new _a(this.name, this.influence, this._scene, this.morphTargetManager), this);
                newOne._positions = this._positions;
                newOne._normals = this._normals;
                newOne._tangents = this._tangents;
                newOne._uvs = this._uvs;
                newOne._uv2s = this._uv2s;
                newOne._colors = this._colors;
                return newOne;
            }
            /**
             * Serializes the current target into a Serialization object
             * @returns the serialized object
             */
            serialize() {
                const serializationObject = {};
                serializationObject.name = this.name;
                serializationObject.influence = this.influence;
                if (this.id != null) {
                    serializationObject.id = this.id;
                }
                serializationObject.uniqueId = this.uniqueId;
                serializationObject.positions = Array.prototype.slice.call(this.getPositions());
                if (this.hasNormals) {
                    serializationObject.normals = Array.prototype.slice.call(this.getNormals());
                }
                if (this.hasTangents) {
                    serializationObject.tangents = Array.prototype.slice.call(this.getTangents());
                }
                if (this.hasUVs) {
                    serializationObject.uvs = Array.prototype.slice.call(this.getUVs());
                }
                if (this.hasUV2s) {
                    serializationObject.uv2s = Array.prototype.slice.call(this.getUV2s());
                }
                if (this.hasColors) {
                    serializationObject.colors = Array.prototype.slice.call(this.getColors());
                }
                // Animations
                SerializationHelper.AppendSerializedAnimations(this, serializationObject);
                return serializationObject;
            }
            /**
             * Returns the string "MorphTarget"
             * @returns "MorphTarget"
             */
            getClassName() {
                return "MorphTarget";
            }
            // Statics
            /**
             * Creates a new target from serialized data
             * @param serializationObject defines the serialized data to use
             * @param scene defines the hosting scene
             * @param morphTargetManager morph target manager this morph target is associated with
             * @returns a new MorphTarget
             */
            static Parse(serializationObject, scene, morphTargetManager = null) {
                const result = new _a(serializationObject.name, serializationObject.influence, scene, morphTargetManager);
                result.setPositions(serializationObject.positions);
                if (serializationObject.id != null) {
                    result.id = serializationObject.id;
                }
                if (serializationObject.normals) {
                    result.setNormals(serializationObject.normals);
                }
                if (serializationObject.tangents) {
                    result.setTangents(serializationObject.tangents);
                }
                if (serializationObject.uvs) {
                    result.setUVs(serializationObject.uvs);
                }
                if (serializationObject.uv2s) {
                    result.setUV2s(serializationObject.uv2s);
                }
                if (serializationObject.colors) {
                    result.setColors(serializationObject.colors);
                }
                // Animations
                if (serializationObject.animations) {
                    for (let animationIndex = 0; animationIndex < serializationObject.animations.length; animationIndex++) {
                        const parsedAnimation = serializationObject.animations[animationIndex];
                        const internalClass = GetClass("BABYLON.Animation");
                        if (internalClass) {
                            result.animations.push(internalClass.Parse(parsedAnimation));
                        }
                    }
                    if (serializationObject.autoAnimate && scene) {
                        scene.beginAnimation(result, serializationObject.autoAnimateFrom, serializationObject.autoAnimateTo, serializationObject.autoAnimateLoop, serializationObject.autoAnimateSpeed || 1.0);
                    }
                }
                return result;
            }
            /**
             * Creates a MorphTarget from mesh data
             * @param mesh defines the source mesh
             * @param name defines the name to use for the new target
             * @param influence defines the influence to attach to the target
             * @returns a new MorphTarget
             */
            static FromMesh(mesh, name, influence) {
                if (!name) {
                    name = mesh.name;
                }
                const result = new _a(name, influence, mesh.getScene(), mesh.morphTargetManager);
                result.setPositions(mesh.getVerticesData(VertexBuffer.PositionKind));
                if (mesh.isVerticesDataPresent(VertexBuffer.NormalKind)) {
                    result.setNormals(mesh.getVerticesData(VertexBuffer.NormalKind));
                }
                if (mesh.isVerticesDataPresent(VertexBuffer.TangentKind)) {
                    result.setTangents(mesh.getVerticesData(VertexBuffer.TangentKind));
                }
                if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
                    result.setUVs(mesh.getVerticesData(VertexBuffer.UVKind));
                }
                if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind)) {
                    result.setUV2s(mesh.getVerticesData(VertexBuffer.UV2Kind));
                }
                if (mesh.isVerticesDataPresent(VertexBuffer.ColorKind)) {
                    result.setColors(mesh.getVerticesData(VertexBuffer.ColorKind));
                }
                return result;
            }
        },
        (() => {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
            _id_decorators = [serialize()];
            _morphTargetManager_decorators = [serialize()];
            __esDecorate(null, null, _id_decorators, { kind: "field", name: "id", static: false, private: false, access: { has: obj => "id" in obj, get: obj => obj.id, set: (obj, value) => { obj.id = value; } }, metadata: _metadata }, _id_initializers, _id_extraInitializers);
            __esDecorate(null, null, _morphTargetManager_decorators, { kind: "field", name: "morphTargetManager", static: false, private: false, access: { has: obj => "morphTargetManager" in obj, get: obj => obj.morphTargetManager, set: (obj, value) => { obj.morphTargetManager = value; } }, metadata: _metadata }, _morphTargetManager_initializers, _morphTargetManager_extraInitializers);
            if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        })(),
        _a;
})();

/**
 * Class used to store 2D array textures containing user data
 */
class RawTexture2DArray extends Texture {
    /**
     * Gets the number of layers of the texture
     */
    get depth() {
        return this._depth;
    }
    /**
     * Create a new RawTexture2DArray
     * @param data defines the data of the texture
     * @param width defines the width of the texture
     * @param height defines the height of the texture
     * @param depth defines the number of layers of the texture
     * @param format defines the texture format to use
     * @param scene defines the hosting scene
     * @param generateMipMaps defines a boolean indicating if mip levels should be generated (true by default)
     * @param invertY defines if texture must be stored with Y axis inverted
     * @param samplingMode defines the sampling mode to use (Texture.TRILINEAR_SAMPLINGMODE by default)
     * @param textureType defines the texture Type (Engine.TEXTURETYPE_UNSIGNED_BYTE, Engine.TEXTURETYPE_FLOAT...)
     * @param creationFlags specific flags to use when creating the texture (Constants.TEXTURE_CREATIONFLAG_STORAGE for storage textures, for eg)
     * @param mipLevelCount defines the number of mip levels to allocate for the texture
     */
    constructor(data, width, height, depth, 
    /** Gets or sets the texture format to use */
    format, scene, generateMipMaps = true, invertY = false, samplingMode = Texture.TRILINEAR_SAMPLINGMODE, textureType = Constants.TEXTURETYPE_UNSIGNED_BYTE, creationFlags, mipLevelCount) {
        super(null, scene, !generateMipMaps, invertY);
        this.format = format;
        this._texture = scene
            .getEngine()
            .createRawTexture2DArray(data, width, height, depth, format, generateMipMaps, invertY, samplingMode, null, textureType, creationFlags ?? 0, mipLevelCount);
        this._depth = depth;
        this.is2DArray = true;
    }
    /**
     * Update the texture with new data
     * @param data defines the data to store in the texture
     */
    update(data) {
        this.updateMipLevel(data, 0);
    }
    /**
     * Updates a specific mip level of the texture.
     * @param data The new data for the mip level
     * @param mipLevel The mip level to update (0 is the base level)
     */
    updateMipLevel(data, mipLevel) {
        if (!this._texture) {
            return;
        }
        this._getEngine().updateRawTexture2DArray(this._texture, data, this._texture.format, this._texture.invertY, null, this._texture.type, mipLevel);
    }
    /**
     * Creates a RGBA texture from some data.
     * @param data Define the texture data
     * @param width Define the width of the texture
     * @param height Define the height of the texture
     * @param depth defines the number of layers of the texture
     * @param scene defines the scene the texture will belong to
     * @param generateMipMaps Define whether or not to create mip maps for the texture
     * @param invertY define if the data should be flipped on Y when uploaded to the GPU
     * @param samplingMode define the texture sampling mode (Texture.xxx_SAMPLINGMODE)
     * @param type define the format of the data (int, float... Engine.TEXTURETYPE_xxx)
     * @returns the RGBA texture
     */
    static CreateRGBATexture(data, width, height, depth, scene, generateMipMaps = true, invertY = false, samplingMode = Constants.TEXTURE_TRILINEAR_SAMPLINGMODE, type = Constants.TEXTURETYPE_UNSIGNED_BYTE) {
        return new RawTexture2DArray(data, width, height, depth, Constants.TEXTUREFORMAT_RGBA, scene, generateMipMaps, invertY, samplingMode, type);
    }
}

/**
 * This class is used to deform meshes using morphing between different targets
 * @see https://doc.babylonjs.com/features/featuresDeepDive/mesh/morphTargets
 */
class MorphTargetManager {
    /**
     * Sets a boolean indicating that adding new target or updating an existing target will not update the underlying data buffers
     */
    set areUpdatesFrozen(block) {
        if (block) {
            this._blockCounter++;
        }
        else {
            this._blockCounter--;
            if (this._blockCounter <= 0) {
                this._blockCounter = 0;
                this._syncActiveTargets(this._forceUpdateWhenUnfrozen);
                this._forceUpdateWhenUnfrozen = false;
            }
        }
    }
    get areUpdatesFrozen() {
        return this._blockCounter > 0;
    }
    /**
     * Creates a new MorphTargetManager
     * @param scene defines the current scene
     * @param meshName name of the mesh this morph target manager is associated with
     */
    constructor(scene = null, meshName) {
        this.meshName = meshName;
        this._targets = new Array();
        this._targetInfluenceChangedObservers = new Array();
        this._targetDataLayoutChangedObservers = new Array();
        this._activeTargets = new SmartArray(16);
        this._supportsPositions = false;
        this._supportsNormals = false;
        this._supportsTangents = false;
        this._supportsUVs = false;
        this._supportsUV2s = false;
        this._supportsColors = false;
        this._vertexCount = 0;
        this._uniqueId = 0;
        this._tempInfluences = new Array();
        this._canUseTextureForTargets = false;
        this._blockCounter = 0;
        this._mustSynchronize = true;
        this._forceUpdateWhenUnfrozen = false;
        /** @internal */
        this._textureVertexStride = 0;
        /** @internal */
        this._textureWidth = 0;
        /** @internal */
        this._textureHeight = 1;
        /** @internal */
        this._parentContainer = null;
        /**
         * Gets or sets a boolean indicating if influencers must be optimized (eg. recompiling the shader if less influencers are used)
         */
        this.optimizeInfluencers = true;
        /**
         * Gets or sets a boolean indicating if positions must be morphed
         */
        this.enablePositionMorphing = true;
        /**
         * Gets or sets a boolean indicating if normals must be morphed
         */
        this.enableNormalMorphing = true;
        /**
         * Gets or sets a boolean indicating if tangents must be morphed
         */
        this.enableTangentMorphing = true;
        /**
         * Gets or sets a boolean indicating if UV must be morphed
         */
        this.enableUVMorphing = true;
        /**
         * Gets or sets a boolean indicating if UV2 must be morphed
         */
        this.enableUV2Morphing = true;
        /**
         * Gets or sets a boolean indicating if colors must be morphed
         */
        this.enableColorMorphing = true;
        this._numMaxInfluencers = 0;
        this._useTextureToStoreTargets = true;
        /**
         * Gets or sets an object used to store user defined information for the MorphTargetManager
         */
        this.metadata = null;
        this._influencesAreDirty = false;
        this._needUpdateInfluences = false;
        if (!scene) {
            scene = EngineStore.LastCreatedScene;
        }
        this._scene = scene;
        if (this._scene) {
            this._scene.addMorphTargetManager(this);
            this._uniqueId = this._scene.getUniqueId();
            const engineCaps = this._scene.getEngine().getCaps();
            this._canUseTextureForTargets =
                engineCaps.canUseGLVertexID && engineCaps.textureFloat && engineCaps.maxVertexTextureImageUnits > 0 && engineCaps.texture2DArrayMaxLayerCount > 1;
        }
    }
    /**
     * Gets or sets the maximum number of influencers (targets) (default value: 0).
     * Setting a value for this property can lead to a smoother experience, as only one shader will be compiled, which will use this value as the maximum number of influencers.
     * If you leave the value at 0 (default), a new shader will be compiled every time the number of active influencers changes. This can cause problems, as compiling a shader takes time.
     * If you assign a non-zero value to this property, you need to ensure that this value is greater than the maximum number of (active) influencers you'll need for this morph manager.
     * Otherwise, the number of active influencers will be truncated at the value you set for this property, which can lead to unexpected results.
     * Note that this property has no effect if "useTextureToStoreTargets" is false.
     * Note as well that if MorphTargetManager.ConstantTargetCountForTextureMode is greater than 0, this property will be ignored and the constant value will be used instead.
     */
    get numMaxInfluencers() {
        if (MorphTargetManager.ConstantTargetCountForTextureMode > 0 && this.isUsingTextureForTargets) {
            return MorphTargetManager.ConstantTargetCountForTextureMode;
        }
        return this._numMaxInfluencers;
    }
    set numMaxInfluencers(value) {
        if (this._numMaxInfluencers === value) {
            return;
        }
        this._numMaxInfluencers = value;
        this._mustSynchronize = true;
        this._syncActiveTargets();
    }
    /**
     * Gets the unique ID of this manager
     */
    get uniqueId() {
        return this._uniqueId;
    }
    /**
     * Gets the number of vertices handled by this manager
     */
    get vertexCount() {
        return this._vertexCount;
    }
    /**
     * Gets a boolean indicating if this manager supports morphing of positions
     */
    get supportsPositions() {
        return this._supportsPositions && this.enablePositionMorphing;
    }
    /**
     * Gets a boolean indicating if this manager supports morphing of normals
     */
    get supportsNormals() {
        return this._supportsNormals && this.enableNormalMorphing;
    }
    /**
     * Gets a boolean indicating if this manager supports morphing of tangents
     */
    get supportsTangents() {
        return this._supportsTangents && this.enableTangentMorphing;
    }
    /**
     * Gets a boolean indicating if this manager supports morphing of texture coordinates
     */
    get supportsUVs() {
        return this._supportsUVs && this.enableUVMorphing;
    }
    /**
     * Gets a boolean indicating if this manager supports morphing of texture coordinates 2
     */
    get supportsUV2s() {
        return this._supportsUV2s && this.enableUV2Morphing;
    }
    /**
     * Gets a boolean indicating if this manager supports morphing of colors
     */
    get supportsColors() {
        return this._supportsColors && this.enableColorMorphing;
    }
    /**
     * Gets a boolean indicating if this manager has data for morphing positions
     */
    get hasPositions() {
        return this._supportsPositions;
    }
    /**
     * Gets a boolean indicating if this manager has data for morphing normals
     */
    get hasNormals() {
        return this._supportsNormals;
    }
    /**
     * Gets a boolean indicating if this manager has data for morphing tangents
     */
    get hasTangents() {
        return this._supportsTangents;
    }
    /**
     * Gets a boolean indicating if this manager has data for morphing texture coordinates
     */
    get hasUVs() {
        return this._supportsUVs;
    }
    /**
     * Gets a boolean indicating if this manager has data for morphing texture coordinates 2
     */
    get hasUV2s() {
        return this._supportsUV2s;
    }
    /**
     * Gets a boolean indicating if this manager has data for morphing colors
     */
    get hasColors() {
        return this._supportsColors;
    }
    /**
     * Gets the number of targets stored in this manager
     */
    get numTargets() {
        return this._targets.length;
    }
    /**
     * Gets the number of influencers (ie. the number of targets with influences > 0)
     */
    get numInfluencers() {
        if (this._influencesAreDirty) {
            this._syncActiveTargets();
        }
        return this._activeTargets.length;
    }
    /**
     * Gets the list of influences (one per target)
     */
    get influences() {
        if (this._influencesAreDirty) {
            this._syncActiveTargets();
        }
        return this._influences;
    }
    /**
     * Gets or sets a boolean indicating that targets should be stored as a texture instead of using vertex attributes (default is true).
     * Please note that this option is not available if the hardware does not support it
     */
    get useTextureToStoreTargets() {
        return this._useTextureToStoreTargets;
    }
    set useTextureToStoreTargets(value) {
        if (this._useTextureToStoreTargets === value) {
            return;
        }
        this._useTextureToStoreTargets = value;
        this._mustSynchronize = true;
        this._syncActiveTargets();
    }
    /**
     * Gets a boolean indicating that the targets are stored into a texture (instead of as attributes)
     */
    get isUsingTextureForTargets() {
        return (MorphTargetManager.EnableTextureStorage &&
            this.useTextureToStoreTargets &&
            this._canUseTextureForTargets &&
            !this._scene?.getEngine().getCaps().disableMorphTargetTexture);
    }
    /**
     * Gets the active target at specified index. An active target is a target with an influence > 0
     * @param index defines the index to check
     * @returns the requested target
     */
    getActiveTarget(index) {
        if (this._influencesAreDirty) {
            this._syncActiveTargets();
        }
        return this._activeTargets.data[index];
    }
    /**
     * Gets the target at specified index
     * @param index defines the index to check
     * @returns the requested target
     */
    getTarget(index) {
        return this._targets[index];
    }
    /**
     * Gets the first target with the specified name
     * @param name defines the name to check
     * @returns the requested target
     */
    getTargetByName(name) {
        for (const target of this._targets) {
            if (target.name === name) {
                return target;
            }
        }
        return null;
    }
    /**
     * Add a new target to this manager
     * @param target defines the target to add
     */
    addTarget(target) {
        this._targets.push(target);
        this._targetInfluenceChangedObservers.push(target.onInfluenceChanged.add((needUpdate) => {
            if (this.areUpdatesFrozen && needUpdate) {
                this._forceUpdateWhenUnfrozen = true;
            }
            this._influencesAreDirty = true;
            this._needUpdateInfluences = this._needUpdateInfluences || needUpdate;
        }));
        this._targetDataLayoutChangedObservers.push(target._onDataLayoutChanged.add(() => {
            this._mustSynchronize = true;
            this._syncActiveTargets();
        }));
        this._mustSynchronize = true;
        this._syncActiveTargets();
    }
    /**
     * Removes a target from the manager
     * @param target defines the target to remove
     */
    removeTarget(target) {
        const index = this._targets.indexOf(target);
        if (index >= 0) {
            this._targets.splice(index, 1);
            target.onInfluenceChanged.remove(this._targetInfluenceChangedObservers.splice(index, 1)[0]);
            target._onDataLayoutChanged.remove(this._targetDataLayoutChangedObservers.splice(index, 1)[0]);
            this._mustSynchronize = true;
            this._syncActiveTargets();
        }
        if (this._scene) {
            this._scene.stopAnimation(target);
        }
    }
    /**
     * @internal
     */
    _bind(effect) {
        if (this._influencesAreDirty) {
            this._syncActiveTargets();
        }
        effect.setFloat3("morphTargetTextureInfo", this._textureVertexStride, this._textureWidth, this._textureHeight);
        effect.setFloatArray("morphTargetTextureIndices", this._morphTargetTextureIndices);
        effect.setTexture("morphTargets", this._targetStoreTexture);
        effect.setFloat("morphTargetCount", this.numInfluencers);
    }
    /**
     * Clone the current manager
     * @returns a new MorphTargetManager
     */
    clone() {
        const copy = new MorphTargetManager(this._scene);
        copy.areUpdatesFrozen = true;
        for (const target of this._targets) {
            copy.addTarget(target.clone());
        }
        copy.areUpdatesFrozen = false;
        copy.enablePositionMorphing = this.enablePositionMorphing;
        copy.enableNormalMorphing = this.enableNormalMorphing;
        copy.enableTangentMorphing = this.enableTangentMorphing;
        copy.enableUVMorphing = this.enableUVMorphing;
        copy.enableUV2Morphing = this.enableUV2Morphing;
        copy.enableColorMorphing = this.enableColorMorphing;
        copy.metadata = this.metadata;
        return copy;
    }
    /**
     * Serializes the current manager into a Serialization object
     * @returns the serialized object
     */
    serialize() {
        const serializationObject = {};
        serializationObject.id = this.uniqueId;
        serializationObject.meshName = this.meshName;
        serializationObject.targets = [];
        for (const target of this._targets) {
            serializationObject.targets.push(target.serialize());
        }
        if (this.metadata) {
            serializationObject.metadata = this.metadata;
        }
        return serializationObject;
    }
    _syncActiveTargets(needUpdate = false) {
        if (this.areUpdatesFrozen) {
            return;
        }
        needUpdate = needUpdate || this._needUpdateInfluences;
        this._needUpdateInfluences = false;
        this._influencesAreDirty = false;
        const wasUsingTextureForTargets = !!this._targetStoreTexture;
        const isUsingTextureForTargets = this.isUsingTextureForTargets;
        if (this._mustSynchronize || wasUsingTextureForTargets !== isUsingTextureForTargets) {
            this._mustSynchronize = false;
            this.synchronize();
        }
        let influenceCount = 0;
        this._activeTargets.reset();
        if (!this._morphTargetTextureIndices || this._morphTargetTextureIndices.length !== this._targets.length) {
            this._morphTargetTextureIndices = new Float32Array(this._targets.length);
        }
        let targetIndex = -1;
        for (const target of this._targets) {
            targetIndex++;
            if (target.influence === 0 && this.optimizeInfluencers) {
                continue;
            }
            if (this._activeTargets.length >= MorphTargetManager.MaxActiveMorphTargetsInVertexAttributeMode && !this.isUsingTextureForTargets) {
                break;
            }
            this._activeTargets.push(target);
            this._morphTargetTextureIndices[influenceCount] = targetIndex;
            this._tempInfluences[influenceCount++] = target.influence;
        }
        if (this._morphTargetTextureIndices.length !== influenceCount) {
            this._morphTargetTextureIndices = this._morphTargetTextureIndices.slice(0, influenceCount);
        }
        if (!this._influences || this._influences.length !== influenceCount) {
            this._influences = new Float32Array(influenceCount);
        }
        for (let index = 0; index < influenceCount; index++) {
            this._influences[index] = this._tempInfluences[index];
        }
        if (needUpdate && this._scene) {
            for (const mesh of this._scene.meshes) {
                if (mesh.morphTargetManager === this) {
                    if (isUsingTextureForTargets) {
                        mesh._markSubMeshesAsAttributesDirty();
                    }
                    else {
                        mesh._syncGeometryWithMorphTargetManager();
                    }
                }
            }
        }
    }
    /**
     * Synchronize the targets with all the meshes using this morph target manager
     */
    synchronize() {
        if (!this._scene || this.areUpdatesFrozen) {
            return;
        }
        const engine = this._scene.getEngine();
        this._supportsPositions = true;
        this._supportsNormals = true;
        this._supportsTangents = true;
        this._supportsUVs = true;
        this._supportsUV2s = true;
        this._supportsColors = true;
        this._vertexCount = 0;
        this._targetStoreTexture?.dispose();
        this._targetStoreTexture = null;
        if (this.isUsingTextureForTargets && this._targets.length > engine.getCaps().texture2DArrayMaxLayerCount) {
            this.useTextureToStoreTargets = false;
        }
        for (const target of this._targets) {
            this._supportsPositions = this._supportsPositions && target.hasPositions;
            this._supportsNormals = this._supportsNormals && target.hasNormals;
            this._supportsTangents = this._supportsTangents && target.hasTangents;
            this._supportsUVs = this._supportsUVs && target.hasUVs;
            this._supportsUV2s = this._supportsUV2s && target.hasUV2s;
            this._supportsColors = this._supportsColors && target.hasColors;
            const vertexCount = target.vertexCount;
            if (this._vertexCount === 0) {
                this._vertexCount = vertexCount;
            }
            else if (this._vertexCount !== vertexCount) {
                Logger.Error(`Incompatible target. Targets must all have the same vertices count. Current vertex count: ${this._vertexCount}, vertex count for target "${target.name}": ${vertexCount}`);
                return;
            }
        }
        if (this.isUsingTextureForTargets) {
            this._textureVertexStride = 0;
            this._supportsPositions && this._textureVertexStride++;
            this._supportsNormals && this._textureVertexStride++;
            this._supportsTangents && this._textureVertexStride++;
            this._supportsUVs && this._textureVertexStride++;
            this._supportsUV2s && this._textureVertexStride++;
            this._supportsColors && this._textureVertexStride++;
            this._textureWidth = this._vertexCount * this._textureVertexStride || 1;
            this._textureHeight = 1;
            const maxTextureSize = engine.getCaps().maxTextureSize;
            if (this._textureWidth > maxTextureSize) {
                this._textureHeight = Math.ceil(this._textureWidth / maxTextureSize);
                this._textureWidth = maxTextureSize;
            }
            const targetCount = this._targets.length;
            const data = new Float32Array(targetCount * this._textureWidth * this._textureHeight * 4);
            let offset;
            for (let index = 0; index < targetCount; index++) {
                const target = this._targets[index];
                const positions = target.getPositions();
                const normals = target.getNormals();
                const uvs = target.getUVs();
                const tangents = target.getTangents();
                const uv2s = target.getUV2s();
                const colors = target.getColors();
                offset = index * this._textureWidth * this._textureHeight * 4;
                for (let vertex = 0; vertex < this._vertexCount; vertex++) {
                    if (this._supportsPositions && positions) {
                        data[offset] = positions[vertex * 3];
                        data[offset + 1] = positions[vertex * 3 + 1];
                        data[offset + 2] = positions[vertex * 3 + 2];
                        offset += 4;
                    }
                    if (this._supportsNormals && normals) {
                        data[offset] = normals[vertex * 3];
                        data[offset + 1] = normals[vertex * 3 + 1];
                        data[offset + 2] = normals[vertex * 3 + 2];
                        offset += 4;
                    }
                    if (this._supportsUVs && uvs) {
                        data[offset] = uvs[vertex * 2];
                        data[offset + 1] = uvs[vertex * 2 + 1];
                        offset += 4;
                    }
                    if (this._supportsTangents && tangents) {
                        data[offset] = tangents[vertex * 3];
                        data[offset + 1] = tangents[vertex * 3 + 1];
                        data[offset + 2] = tangents[vertex * 3 + 2];
                        offset += 4;
                    }
                    if (this._supportsUV2s && uv2s) {
                        data[offset] = uv2s[vertex * 2];
                        data[offset + 1] = uv2s[vertex * 2 + 1];
                        offset += 4;
                    }
                    if (this._supportsColors && colors) {
                        data[offset] = colors[vertex * 4];
                        data[offset + 1] = colors[vertex * 4 + 1];
                        data[offset + 2] = colors[vertex * 4 + 2];
                        data[offset + 3] = colors[vertex * 4 + 3];
                        offset += 4;
                    }
                }
            }
            this._targetStoreTexture = RawTexture2DArray.CreateRGBATexture(data, this._textureWidth, this._textureHeight, targetCount, this._scene, false, false, Constants.TEXTURE_NEAREST_SAMPLINGMODE, Constants.TEXTURETYPE_FLOAT);
            this._targetStoreTexture.name = `Morph texture_${this.uniqueId}`;
        }
        // Flag meshes as dirty to resync with the active targets
        for (const mesh of this._scene.meshes) {
            if (mesh.morphTargetManager === this) {
                mesh._syncGeometryWithMorphTargetManager();
            }
        }
    }
    /**
     * Release all resources
     */
    dispose() {
        if (this._targetStoreTexture) {
            this._targetStoreTexture.dispose();
        }
        this._targetStoreTexture = null;
        this.metadata = null;
        // Remove from scene
        if (this._scene) {
            this._scene.removeMorphTargetManager(this);
            if (this._parentContainer) {
                const index = this._parentContainer.morphTargetManagers.indexOf(this);
                if (index > -1) {
                    this._parentContainer.morphTargetManagers.splice(index, 1);
                }
                this._parentContainer = null;
            }
            for (const morph of this._targets) {
                this._scene.stopAnimation(morph);
            }
        }
    }
    // Statics
    /**
     * Creates a new MorphTargetManager from serialized data
     * @param serializationObject defines the serialized data
     * @param scene defines the hosting scene
     * @returns the new MorphTargetManager
     */
    static Parse(serializationObject, scene) {
        const result = new MorphTargetManager(scene);
        for (const targetData of serializationObject.targets) {
            result.addTarget(MorphTarget.Parse(targetData, scene, result));
        }
        if (serializationObject.metadata) {
            result.metadata = serializationObject.metadata;
        }
        return result;
    }
}
/** Enable storing morph target data into textures when set to true (true by default) */
MorphTargetManager.EnableTextureStorage = true;
/** Maximum number of active morph targets supported in the "vertex attribute" mode (i.e., not the "texture" mode) */
MorphTargetManager.MaxActiveMorphTargetsInVertexAttributeMode = 8;
/**
 * When used in texture mode, if greather than 0, this will override the the morph manager numMaxInfluencers value.
 */
MorphTargetManager.ConstantTargetCountForTextureMode = 0;

export { FreeCamera as F, MorphTargetManager as M, MorphTarget as a };
//# sourceMappingURL=morphTargetManager-BcCzrruC.esm.js.map