package org.sunflow.raytracer.camera;

import org.sunflow.math.OrthoNormalBasis;
import org.sunflow.math.Point2;
import org.sunflow.math.Point3;
import org.sunflow.math.Vector3;
import org.sunflow.raytracer.Camera;
import org.sunflow.raytracer.Ray;

public class PinholeCamera extends Camera {
    private Point3 eye;
    private OrthoNormalBasis basis;
    private double au;
    private double av;

    public PinholeCamera(Point3 eye, Point3 target, Vector3 up, double fov, int width, int height) {
        super(width, height);
        this.eye = new Point3(eye);
        basis = OrthoNormalBasis.makeFromWV(Point3.sub(eye, target, new Vector3()), up);
        au = Math.tan(((fov * Math.PI) / 180.0) / 2.0);
        av = (height * au) / width;
    }

    public Ray getRay(double x, double y, double lensX, double lensY) {
        double du = -au + ((2.0 * au * x) / (getImageWidth() - 1.0));
        double dv = -av + ((2.0 * av * y) / (getImageHeight() - 1.0));
        return new Ray(eye, basis.transform(new Vector3(du, dv, -1), new Vector3()));
    }

    public Point2 getPoint(Point3 p) {
        Vector3 v = new Vector3();
        basis.untransform(Point3.sub(p, eye, new Vector3()), v);
        if (v.z > 0.0)
            return null;
        Point2 sp = new Point2();
        sp.x = (((v.x / (-v.z)) + au) * (getImageWidth() - 1.0)) / (2.0 * au);
        sp.y = (((v.y / (-v.z)) + av) * (getImageHeight() - 1.0)) / (2.0 * av);
        return sp;
    }
}