use ray_tracing_core::prelude::*;

#[derive(Debug)]
pub struct OrenNayar {
    rho: Float,
    color: Color,
}

impl OrenNayar {
    pub fn new(rho: Float, color: Color) -> Self {
        Self { rho, color }
    }
}

impl<R: Rng> Material<R> for OrenNayar {
    fn eval(&self, w_in: Dir3, w_out: Dir3, _rng: &mut R) -> Color {
        if w_out.y() > 0.0 {
            let cos_alpha = Float::min(w_in.y(), w_out.y());
            let cos_beta = Float::max(w_in.y(), w_out.y());

            let a = 1.0 - (self.rho * self.rho) / (2.0 * self.rho * self.rho + 0.33);
            let b = 0.45 * self.rho * self.rho / (self.rho * self.rho + 0.09);

            let sin_alpha = Float::sqrt(1.0 - cos_alpha * cos_alpha);
            let tan_beta = Float::sqrt(1.0 - cos_beta * cos_beta) / cos_beta;

            let w_in_tick = w_in - Dir3::up() * w_in.y();
            let w_out_tick = w_out - Dir3::up() * w_out.y();

            let cos_phi = Dir3::dot(w_in_tick, w_out_tick);

            self.color
                * FloatConsts::FRAC_1_PI
                * (a + b * Float::max(0.0, cos_phi) * sin_alpha * tan_beta)
        } else {
            Color::black()
        }
    }
}
