import { Vector3, FxaaPostProcess, Axis } from '../loader/babylonjs-import';
import { PivotTargetCamera } from './PivotTargetCamera';
import './CameraExtensions';
import '../loader/SceneExtensions';
/** Camera projection modes */
export var Projection;
(function (Projection) {
    Projection[Projection["Perspective"] = 0] = "Perspective";
    Projection[Projection["Orthographic"] = 1] = "Orthographic";
})(Projection || (Projection = {}));
export var PivotMode;
(function (PivotMode) {
    PivotMode[PivotMode["Auto"] = 0] = "Auto";
    PivotMode[PivotMode["Fixed"] = 1] = "Fixed";
})(PivotMode || (PivotMode = {}));
export class ViewerCamera {
    viewer;
    activeCamera;
    _projection;
    static cameraMinZ = 0.01;
    _pivotCameraPostProcess;
    constructor(viewer) {
        this.viewer = viewer;
        this._projection = Projection.Perspective;
        this.activeCamera = new PivotTargetCamera('camera', new Vector3(-1, 1, -1), viewer.scene);
        this.activeCamera.mode = this._projection;
        this.activeCamera.minZ = ViewerCamera.cameraMinZ; // 10 cm is enough
        this.activeCamera.maxZ = 10000; // TODO Should be adjusted so we only see world bounding box
        this.activeCamera.inertia = 0.6;
        this.activeCamera.attachControl();
        this.disposeAndReEnableFXAA();
    }
    /**
     * This method is to make sure that the FXAA filter is always the last postprocess to be applied. ATM Babylon has no real way of rearranging post processes
     */
    disposeAndReEnableFXAA() {
        if (this._pivotCameraPostProcess) {
            this._pivotCameraPostProcess.dispose();
        }
        this._pivotCameraPostProcess = new FxaaPostProcess('fxaaPivotCamera', 1.0, this.activeCamera);
        this._pivotCameraPostProcess.samples = 4;
    }
    get maxZ() {
        return this.activeCamera.maxZ;
    }
    set maxZ(n) {
        this.activeCamera.maxZ = n;
    }
    get minZ() {
        return this.activeCamera.minZ;
    }
    set minZ(n) {
        this.activeCamera.minZ = n;
    }
    /**
     * Attaches a behavior to the camera.
     * @param behavior The behavior to be attached to the camera.
     * @returns true if the behavior was successfully attached to the camera, otherwise false.
     */
    attachBehavior(behavior) {
        const attachment = behavior.attach(this.activeCamera);
        if (attachment) {
            this.disposeAndReEnableFXAA();
        }
        return attachment;
    }
    /**
     * Detaches a behavior from the camera.
     * @param behavior The behavior to be detached from the camera.
     * @returns true if the behavior was successfully detached to the camera, otherwise false.
     */
    detachBehavior(behavior) {
        return behavior.detach(this.activeCamera);
    }
    setPivot(mode, pivot) {
        if (mode === PivotMode.Auto || !pivot) {
            this.activeCamera.twinfinity.pivot.isFrozen = false;
            this.activeCamera.twinfinity.pivot.update();
        }
        else {
            this.activeCamera.twinfinity.pivot.update({ target: pivot });
            this.activeCamera.twinfinity.pivot.isFrozen = true;
        }
    }
    clearPivot() {
        this.setPivot(PivotMode.Auto);
    }
    get position() {
        return this.activeCamera.position;
    }
    set position(position) {
        this.activeCamera.position.copyFrom(position);
        this.viewer.scene.render(true);
    }
    get target() {
        return this.activeCamera.getTarget();
    }
    set target(target) {
        this.activeCamera.setTarget(target);
    }
    get forwardVector() {
        return this.activeCamera.getDirection(Axis.Z);
    }
    zoomToExtent(aabb, direction) {
        this.activeCamera.twinfinity.pivot.zoomToExtent(aabb, direction);
    }
    pick(o) {
        return this.activeCamera.twinfinity.pick(o);
    }
    get projection() {
        return this.activeCamera.mode;
    }
    set projection(projection) {
        this.activeCamera.mode = projection;
        // force camera to render with new camera projection
        this.viewer.scene.render(true);
    }
    get mode() {
        return this.options.mode;
    }
    set mode(v) {
        this.options.mode = v;
    }
    get topDownMode() {
        return this.activeCamera.topDownMode;
    }
    set topDownMode(topDownMode) {
        this.activeCamera.topDownMode = topDownMode;
        this.viewer.scene.render(true);
    }
    get options() {
        return this.activeCamera.inputs;
    }
}
//# sourceMappingURL=ViewerCamera.js.map