package org.sunflow.raytracer;

import org.sunflow.math.Point2;
import org.sunflow.math.Point3;

/**
 * Represents a mapping from the 3D scene onto the final image. A camera is responsible for determining what ray to cast
 * through each pixel.
 */
public abstract class Camera {
    private int imageWidth;
    private int imageHeight;

    /**
     * Default constructor, sets the resolution of the image plane the camera will project to.
     * @param imageWidth
     * @param imageHeight
     */
    protected Camera(int imageWidth, int imageHeight) {
        this.imageWidth = imageWidth;
        this.imageHeight = imageHeight;
    }

    /**
     * Create a new {@link Ray ray} to be cast through pixel (x,y) on the image plane. Two sampling parameters are
     * provided for lens sampling. They are guarenteed to be in the interval [0,1). They can be used to perturb the
     * position of the source of the ray on the lens of the camera for DOF effects.
     * @param x x coordinate of the pixel
     * @param y y coordinate of the pixel
     * @param lensX x lens sampling parameter
     * @param lensY y lens sampling parameter
     * @return a new ray passing through the given pixel
     */
    public abstract Ray getRay(double x, double y, double lensX, double lensY);

    /**
     * Project the specified 3D point onto the image plane. Returns <code>null</code> if the point is outside the
     * viewing volume.
     * @param p point to transform
     * @return screen point or <code>null</code> if the point is not visible
     */
    public abstract Point2 getPoint(Point3 p);

    /**
     * Gets the width of the image plane associated to this camera.
     * @return the width of the image plane
     */
    public int getImageWidth() {
        return imageWidth;
    }

    /**
     * Gets the height of the image plane associated to this camera.
     * @return the height of the image plane
     */
    public int getImageHeight() {
        return imageHeight;
    }
}