package optics.view;

import basics.math.algebra.Matrix;
import basics.math.algebra.Ray;
import basics.math.algebra.Vector;

public class PinholeCamera implements Camera {

    private Vector center;
    private Vector up;
    private Vector front;
    private Vector left;

    private double nearPlane;
    private double farPlane;
    private double fov;

    public PinholeCamera(Vector from, Vector lookat, double fov, double nearPlane, double farPlane) {
        this.center = from;
        this.nearPlane = nearPlane;
        this.farPlane = farPlane;

        this.fov = 1.0 / Math.tan(Math.toRadians(fov * 0.5));

        this.front = lookat.sub(from).normalize();
        this.up = front.shuffle(Vector.SwizzleMask.YZX).negate().normalize();
        this.left = this.front.cross(this.up).normalize();
    }

    @Override
    public Ray generateViewRay(double u, double v) {
        return new Ray(center, front.scale(this.fov).add(left.scale(u)).add(up.scale(v)).normalize(), this.nearPlane, this.farPlane);
    }

    @Override
    public void transform(Vector translation, Matrix rotation) {
        this.front = rotation.mul(this.front);
        this.left = rotation.mul(this.left);
        this.up = rotation.mul(this.up);

        this.center = this.center.add(this.front.scale(translation.z));
        this.center = this.center.add(this.left.scale(-translation.x));
        this.center = this.center.add(this.up.scale(translation.y));
    }

    @Override
    public String toString() {
        return "Pinhole-Camera { from: " + center.toString() + " front: " + front.toString() + " up: " + up.toString() + " left: " + left.toString() + " }";
    }
}
