use core::f32::math::sqrt; use std::{ fmt::Display, ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}, }; use rand::RngExt; #[derive(Copy, Clone)] pub struct Vec3 { r: f32, g: f32, b: f32, } pub type Colour = Vec3; impl Vec3 { pub fn new(r: f32, g: f32, b: f32) -> Vec3 { Self { r: r, g: g, b: b } } pub fn nil() -> Vec3 { Self { r: 0., g: 0., b: 0., } } pub fn random() -> Vec3 { let mut rng = rand::rng(); Vec3 { r: rng.random_range(-1.0..1.), g: rng.random_range(-1.0..1.), b: rng.random_range(-1.0..1.), } } pub fn random_unit() -> Vec3 { loop { let v = Vec3::random(); if v.length_squared() <= 1. { return v / v.length(); } } } pub fn random_unit_hemisphere(n: &Vec3) -> Vec3 { let v = Vec3::random_unit(); if n.dot(&v) > 0.0 { v } else { -v } } pub fn x(&self) -> &f32 { &self.r } pub fn y(&self) -> &f32 { &self.g } pub fn z(&self) -> &f32 { &self.b } pub fn length(&self) -> f32 { sqrt(self.length_squared()) } pub fn length_squared(&self) -> f32 { (self.r * self.r + self.g * self.g + self.b * self.b) as f32 } pub fn dot(&self, other: &Vec3) -> f32 { self.r * other.r + self.g * other.g + self.b * other.b } pub fn cross(&self, other: &Vec3) -> Vec3 { Vec3 { r: self.g * other.b - self.b * other.g, g: self.b * other.r - self.r * other.b, b: self.r * other.g - self.g * other.r, } } pub fn make_unit(mut self) { self /= self.length(); } pub fn get_unit(self) -> Vec3 { self / self.length() } pub fn output(self) -> image::Rgb { // gamma correction let r = if self.r > 0. { sqrt(self.r).clamp(0., 1.) } else { 0. }; let g = if self.g > 0. { sqrt(self.g).clamp(0., 1.) } else { 0. }; let b = if self.b > 0. { sqrt(self.b).clamp(0.1, 1.) } else { 0. }; let ir = (255.599 * r) as u8; let ig = (255.599 * g) as u8; let ib = (255.599 * b) as u8; image::Rgb([ir, ig, ib]) } pub fn clone(&self) -> Vec3 { Vec3 { r: self.r, g: self.g, b: self.b, } } } impl Neg for Vec3 { type Output = Self; fn neg(self) -> Self::Output { Self { r: -self.r, g: -self.g, b: -self.b, } } } impl Add for Vec3 { type Output = Self; fn add(self, _rhs: Self) -> Self { Self { r: self.r + _rhs.r, g: self.g + _rhs.g, b: self.b + _rhs.b, } } } impl Add for Vec3 { type Output = Self; fn add(self, f: f32) -> Self { Self { r: self.r + f, g: self.g + f, b: self.b + f, } } } impl AddAssign for Vec3 { fn add_assign(&mut self, other: Self) { *self = Self { r: self.r + other.r, g: self.g + other.g, b: self.b + other.b, }; } } impl AddAssign for Vec3 { fn add_assign(&mut self, f: f32) { *self = Self { r: self.r + f, g: self.g + f, b: self.b + f, }; } } impl Sub<&Vec3> for Vec3 { type Output = Self; fn sub(self, rhs: &Self) -> Self { Self { r: self.r - rhs.r, g: self.g - rhs.g, b: self.b - rhs.b, } } } impl Sub for Vec3 { type Output = Self; fn sub(self, rhs: Self) -> Self { Self { r: self.r - rhs.r, g: self.g - rhs.g, b: self.b - rhs.b, } } } impl Sub for Vec3 { type Output = Self; fn sub(self, f: f32) -> Self { Self { r: self.r - f, g: self.g - f, b: self.b - f, } } } impl SubAssign for Vec3 { fn sub_assign(&mut self, rhs: Self) { *self = Self { r: self.r - rhs.r, g: self.g - rhs.g, b: self.b - rhs.b, }; } } impl SubAssign for Vec3 { fn sub_assign(&mut self, f: f32) { *self = Self { r: self.r - f, g: self.g - f, b: self.b - f, }; } } impl Mul for Vec3 { type Output = Vec3; fn mul(self, rhs: Self) -> Self::Output { Self { r: self.r * rhs.r, g: self.g * rhs.g, b: self.b * rhs.b, } } } impl Mul for u32 { type Output = Vec3; fn mul(self, rhs: Vec3) -> Self::Output { let f = self as f32; Vec3 { r: rhs.r * f, g: rhs.g * f, b: rhs.b * f, } } } impl Mul for Vec3 { type Output = Self; fn mul(self, f: f32) -> Self::Output { Self { r: self.r * f, g: self.g * f, b: self.b * f, } } } impl Mul for f32 { type Output = Vec3; fn mul(self, rhs: Vec3) -> Self::Output { Vec3 { r: rhs.r * self, g: rhs.g * self, b: rhs.b * self, } } } impl MulAssign for Vec3 { fn mul_assign(&mut self, rhs: Self) { *self = Self { r: self.r * rhs.r, g: self.g * rhs.g, b: self.b * rhs.b, }; } } impl MulAssign for Vec3 { fn mul_assign(&mut self, f: f32) { *self = Self { r: self.r * f, g: self.g * f, b: self.b * f, }; } } impl Div for Vec3 { type Output = Self; fn div(self, rhs: Self) -> Self::Output { Self { r: self.r / rhs.r, g: self.g / rhs.g, b: self.b / rhs.b, } } } impl Div for Vec3 { type Output = Self; fn div(self, i: i32) -> Self::Output { let f: f32 = i as f32; Self { r: self.r / f, g: self.g / f, b: self.b / f, } } } impl Div for Vec3 { type Output = Self; fn div(self, f: f32) -> Self::Output { Self { r: self.r / f, g: self.g / f, b: self.b / f, } } } impl DivAssign for Vec3 { fn div_assign(&mut self, rhs: Self) { *self = Self { r: self.r / rhs.r, g: self.g / rhs.g, b: self.b / rhs.b, }; } } impl DivAssign for Vec3 { fn div_assign(&mut self, f: f32) { *self = Self { r: self.r / f, g: self.g / f, b: self.b / f, }; } } impl PartialEq for Vec3 { fn eq(&self, other: &Self) -> bool { self.r == other.r && self.g == other.g && self.b == other.b } } impl Display for Vec3 { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "({}, {}, {})", self.r, self.g, self.b) } }