use crate::{ Float, Image, Point, perlin::Perlin };
use crate::tracer::{Color, hit::Hit};
const MARBLE_SCALE: Float = 4.0;
const MARBLE_FREQ: Float = 60.0;
const MARBLE_AMP: Float = 20.0;
const MARBLE_OCTAVES: i32 = 6;
const MARBLE_GAIN: Float = 0.5;
pub enum Texture {
Solid(Color),
Checkerboard(Box<Texture>, Box<Texture>, Float),
Marble(Perlin, Color),
Image(Image),
}
impl Texture {
pub fn albedo_at(&self, h: &Hit) -> Color {
match self {
Texture::Solid(c) => *c,
Texture::Marble(pn, c) => {
let xo = h.p;
let turb = Self::turbulence(pn, 0.0, MARBLE_SCALE * xo.abs(), 0);
let scaled = 1.0 -
(0.5 + 0.5 * (MARBLE_FREQ * xo.x + MARBLE_AMP * turb).sin())
.powi(6);
*c * scaled
}
Texture::Checkerboard(t1, t2, s) => {
let uv = h.uv * (*s);
if (uv.x.floor() + uv.y.floor()) as i32 % 2 == 0 {
t1.albedo_at(h)
} else {
t2.albedo_at(h)
}
}
Texture::Image(img) => {
let uv = h.uv;
let x = uv.x * img.width as Float;
let x = x.floor() as usize;
let y = uv.y * img.height as Float;
let y = img.height - y.floor() as u32 - 1;
img.buffer[x + (y*img.width) as usize]
}
}
}
fn turbulence(pn: &Perlin, acc: Float, p: Point, depth: i32) -> Float {
if depth >= MARBLE_OCTAVES {
return acc;
}
let w = MARBLE_GAIN.powi(depth);
Self::turbulence(pn, acc + w * pn.noise_at(p).abs(), 2.0 * p, depth + 1)
}
}