use crate::calculus::calculus::{Point3, Vec3}; use crate::interval::Interval; // "Ideal" aspect ratio, allowing fraction pub const ASPECT_RATIO: f32 = 16.0 / 9.0; pub const IMG_WIDTH: usize = 400; pub const IMG_HEIGHT: usize = get_image_height(IMG_WIDTH, ASPECT_RATIO); pub const SAMPLES_PER_PIXEL: usize = 100; pub const MAX_DEPTH: usize = 50; pub const VFOV: f32 = 30.0; pub const LOOK_FROM: Point3 = Point3 { x: -2.0, y: 2.0, z: 1.0 }; pub const LOOK_AT: Point3 = Point3 { x: 0.0, y: 0.0, z: -1.0 }; pub const VUP: Vec3 = Vec3 { x: 0.0, y: 1.0, z: 0.0 }; pub const DEFOCUS_ANGLE: f32 = 0.0; pub const FOCUS_DIST: f32 = 4.0; pub const fn get_image_height(image_width: usize, aspect_ratio: f32) -> usize { let image_height = (image_width as f32 / aspect_ratio) as usize; if image_width < 1 { 1 } else { image_height } } #[derive(Debug, Clone)] pub struct Color { pub r: f32, pub g: f32, pub b: f32, } #[allow(unused)] pub enum ColorName { Black, White, Red, Lime, Blue, Yellow, Cyan, Magenta, Silver, Gray, Maroon, Olive, Green, Purple, Teal, Navy, } impl Color { pub fn new(r: f32, g: f32, b: f32) -> Self { Self { r, g, b } } pub fn from_name(name: ColorName) -> Self { match name { ColorName::Black => { Self::new(0.0, 0.0, 0.0) } ColorName::White => { Self::new(1.0, 1.0, 1.0) } ColorName::Red => { Self::new(1.0, 0.0, 0.0) } ColorName::Lime => { Self::new(0.0, 1.0, 0.0) } ColorName::Blue => { Self::new(0.0, 0.0, 1.0) } ColorName::Yellow => { Self::new(1.0, 1.0, 0.0) } ColorName::Cyan => { Self::new(0.0, 1.0, 1.0) } ColorName::Magenta => { Self::new(1.0, 0.0, 1.0) } ColorName::Silver => { Self::new(0.75, 0.75, 0.75) } ColorName::Gray => { Self::new(0.5, 0.5, 0.5) } ColorName::Maroon => { Self::new(0.5, 0.0, 0.0) } ColorName::Olive => { Self::new(0.5, 0.5, 0.0)} ColorName::Green => { Self::new(0.0, 0.5, 0.0) } ColorName::Purple => { Self::new(0.5, 0.0, 0.5) } ColorName::Teal => { Self::new(0.0, 0.5, 0.5) } ColorName::Navy => { Self::new(0.0, 0.0, 0.5) } } } pub fn mul_scalar(&self, scalar: f32) -> Color { Self { r: self.r * scalar, g: self.g * scalar, b: self.b * scalar, } } pub fn add(&self, other: &Self) -> Color { Self { r: self.r + other.r, g: self.g + other.g, b: self.b + other.b } } pub fn elem_prod(&self, other: &Self) -> Self { Self { r: self.r * other.r, g: self.g * other.g, b: self.b * other.b, } } fn _linear_to_gamma(linear_comp: f32) -> f32 { if linear_comp > 0.0 { linear_comp.sqrt() } else { 0.0 } } pub fn linear_to_gamma(&mut self) { self.r = Self::_linear_to_gamma(self.r); self.g = Self::_linear_to_gamma(self.g); self.b = Self::_linear_to_gamma(self.b); } } #[derive(Debug, Copy, Clone)] pub struct Pixel { pub r: u8, pub g: u8, pub b: u8, } impl Pixel { pub fn from_frac(r: f32, g: f32, b: f32) -> Self { let intensity = Interval::new(0.0, 0.999); Self { r: (256.0 * intensity.clamp(r)) as u8, g: (256.0 * intensity.clamp(g)) as u8, b: (256.0 * intensity.clamp(b)) as u8, } } pub fn from_color(color: &Color) -> Self { let mut clone = color.clone(); clone.linear_to_gamma(); let (r, g, b) = (color.r, color.g, color.b); Self::from_frac(r, g, b) } } impl Default for Pixel { fn default() -> Self { Pixel { r:0, g:0, b:0 } } } pub type DisplayBuffer = [[Pixel; IMG_WIDTH]; IMG_HEIGHT];