import { boundingClientRectCache } from '../BoundingClientRectCache';
import { Vector3, Matrix } from '../loader/babylonjs-import';
export class TwinfinityDefaultCameraStateSnapshot {
    camera;
    _position = Vector3.Zero();
    _minZ = 0;
    _maxZ = 0;
    _mode = 0;
    _fov = 0;
    _orthoBottom = null;
    _orthoTop = null;
    _orthoLeft = null;
    _orthoRight = null;
    _canvasClientRect = {
        bottom: 0,
        height: 0,
        left: 0,
        right: 0,
        top: 0,
        width: 0
    };
    _viewMatrix = new Matrix();
    _projectionMatrix = new Matrix();
    _engineHardwareScaling;
    _lastChangeTimestamp = -1;
    _lastCheckTimestamp = -1;
    constructor(camera) {
        this.camera = camera;
    }
    /**
     * Checks if the camera has changed since the last time _copyCameraStateToSelf(this.camera) was called. If checkOnlyDimensions is true,
     * only the camera dimensions are checked for differences. If checkOnlyDimensions is false, camera dimensions, scale, rotation and translation is checked.
     * @param checkOnlyDimensions Specifies whether to only check camera dimensions (width, height, stuff like that) or to check camera dimensions in addition to everything else
     * @returns A boolean which is true if the current camera state is different from when _copyCameraStateToSelf(this.camera) was last called
     */
    checkIsChanged(checkOnlyDimensions = false) {
        const engine = this.camera.getEngine();
        const clientRect = boundingClientRectCache.getOrAdd(engine.getRenderingCanvas());
        const clientHardwareScaling = engine.getHardwareScalingLevel();
        const isDimensionsChanged = this._canvasClientRect.bottom !== clientRect.bottom ||
            this._canvasClientRect.height !== clientRect.height ||
            this._canvasClientRect.left !== clientRect.left ||
            this._canvasClientRect.right !== clientRect.right ||
            this._canvasClientRect.top !== clientRect.top ||
            this._canvasClientRect.width !== clientRect.width ||
            this.camera.mode !== this._mode ||
            this._engineHardwareScaling !== clientHardwareScaling;
        return ((isDimensionsChanged && checkOnlyDimensions) ||
            isDimensionsChanged ||
            !this._viewMatrix.equals(this.camera.getViewMatrix()) ||
            !this._projectionMatrix.equals(this.camera.getProjectionMatrix()) ||
            this.camera.minZ !== this._minZ ||
            this.camera.maxZ !== this._maxZ ||
            this.camera.fov !== this._fov ||
            this.camera.orthoBottom !== this._orthoBottom ||
            this.camera.orthoTop !== this._orthoTop ||
            this.camera.orthoLeft !== this._orthoLeft ||
            this.camera.orthoRight !== this._orthoRight ||
            !this.camera.position.equalsWithEpsilon(this._position));
    }
    get isChanged() {
        return this.checkIsChanged(false);
    }
    /**
     * @returns timestamp in miliseconds of when the last refresh that returned true was done.
     */
    get lastChangeTimestamp() {
        return this._lastChangeTimestamp;
    }
    /**
     * @returns timestamp in miliseconds of when the last refresh was done.
     */
    get lastCheckTimestamp() {
        return this._lastCheckTimestamp;
    }
    refresh() {
        const ret = this.isChanged;
        this._lastCheckTimestamp = performance.now();
        if (ret) {
            this._lastChangeTimestamp = this._lastCheckTimestamp;
        }
        this._copyCameraStateToSelf(this.camera);
        return ret;
    }
    _copyCameraStateToSelf(camera) {
        this._viewMatrix.copyFrom(camera.getViewMatrix());
        this._projectionMatrix.copyFrom(camera.getProjectionMatrix());
        const engine = this.camera.getEngine();
        const clientRect = boundingClientRectCache.getOrAdd(engine.getRenderingCanvas());
        if (clientRect) {
            this._canvasClientRect.bottom = clientRect.bottom;
            this._canvasClientRect.height = clientRect.height;
            this._canvasClientRect.left = clientRect.left;
            this._canvasClientRect.right = clientRect.right;
            this._canvasClientRect.top = clientRect.top;
            this._canvasClientRect.width = clientRect.width;
        }
        else {
            for (const p of Object.keys(this._canvasClientRect)) {
                this._canvasClientRect[p] = 0;
            }
        }
        this._position.copyFrom(camera.position);
        this._minZ = camera.minZ;
        this._maxZ = camera.maxZ;
        this._mode = camera.mode;
        this._fov = camera.fov;
        this._orthoBottom = camera.orthoBottom;
        this._orthoTop = camera.orthoTop;
        this._orthoLeft = camera.orthoLeft;
        this._orthoRight = camera.orthoRight;
        this._engineHardwareScaling = camera.getEngine().getHardwareScalingLevel();
    }
}
export class TwinfinityTargetCameraStateSnapshot extends TwinfinityDefaultCameraStateSnapshot {
    _targetCamera;
    _rotation = Vector3.Zero();
    _target = Vector3.Zero();
    constructor(_targetCamera) {
        super(_targetCamera);
        this._targetCamera = _targetCamera;
    }
    get isChanged() {
        return (super.isChanged ||
            !this._rotation.equalsWithEpsilon(this._targetCamera.rotation) ||
            !this._target.equalsWithEpsilon(this._targetCamera.target));
    }
    _copyCameraStateToSelf(state) {
        super._copyCameraStateToSelf(state);
        this._rotation.copyFrom(state.rotation);
        this._target.copyFrom(state.target);
    }
}
//# sourceMappingURL=TwinfinityCameraStateSnapshot.js.map