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