package org.sunflow.raytracer;

import org.sunflow.image.Bitmap;
import org.sunflow.image.Color;

/**
 * Represents a 2D texture, typically used by {@link Shader shaders}.
 */
public class Texture {
    private Bitmap textureData;

    /**
     * Creates a new texture from the specfied file.
     *
     * @param filename image file to load
     */
    Texture(String filename) {
        textureData = new Bitmap(filename);
    }

    /**
     * Gets the color at location (x,y) in the texture. The lookup is performed using the fractional component of the
     * coordinates, treating the texture as a unit square tiled in both directions. Bicubic filtering is performed on
     * the four nearest pixels to the lookup point.
     *
     * @param x x coordinate into the texture
     * @param y y coordinate into the texture
     * @return filtered color at location (x,y)
     */
    public Color getPixel(double x, double y) {
        x = x - (int) x;
        y = y - (int) y;
        if (x < 0.0)
            x += 1.0;
        if (y < 0.0)
            y += 1.0;
        float dx = (float) x * (textureData.getWidth() - 1);
        float dy = (float) y * (textureData.getHeight() - 1);
        int ix0 = (int) dx;
        int iy0 = (int) dy;
        int ix1 = (ix0 + 1) % textureData.getWidth();
        int iy1 = (iy0 + 1) % textureData.getHeight();
        float u = dx - ix0;
        float v = dy - iy0;
        u = u * u * (3.0f - (2.0f * u));
        v = v * v * (3.0f - (2.0f * v));
        float k00 = (1.0f - u) * (1.0f - v);
        Color c00 = textureData.getPixel(ix0, iy0);
        float k01 = (1.0f - u) * v;
        Color c01 = textureData.getPixel(ix0, iy1);
        float k10 = u * (1.0f - v);
        Color c10 = textureData.getPixel(ix1, iy0);
        float k11 = u * v;
        Color c11 = textureData.getPixel(ix1, iy1);
        Color c = new Color(c00).mul(k00);
        c.madd(k01, c01);
        c.madd(k10, c10);
        c.madd(k11, c11);
        return c;
    }
}