use rand::Rng;
use std::ops::SubAssign;
#[allow(dead_code)]
use std::ops::{Add, AddAssign, Div, Index, IndexMut, Mul, Neg, Sub};
#[derive(Debug, Copy, Clone)]
pub struct Vec3 {
pub x: f64,
pub y: f64,
pub z: f64,
}
pub type Point3 = Vec3;
impl Vec3 {
pub fn new<T>(x: T, y: T, z: T) -> Self
where
T: Into<f64> + Copy,
{
Self {
x: x.into(),
y: y.into(),
z: z.into(),
}
}
pub fn random(min: f64, max: f64) -> Vec3 {
let mut rng = rand::thread_rng();
Vec3 {
x: rng.gen_range(min..max),
y: rng.gen_range(min..max),
z: rng.gen_range(min..max),
}
}
pub fn length(&self) -> f64 {
self.length_squared().sqrt()
}
pub fn length_squared(&self) -> f64 {
self.x * self.x + self.y * self.y + self.z * self.z
}
pub fn near_zero(&self) -> bool {
let s = 1e-8;
return self.x.abs() < s && self.y.abs() < s && self.z.abs() < s;
}
pub fn normalized(self) -> Self {
return self / self.length();
}
fn random_in_unit_sphere() -> Vec3 {
loop {
let p = Vec3::random(-1., 1.);
if p.length_squared() < 1. {
return p;
}
}
}
pub fn random_in_unit_disk() -> Vec3 {
loop {
let p = Vec3::random(-1., 1.) * Vec3::new(1., 1., 0.);
if p.length_squared() < 1. {
return p;
}
}
}
pub fn reflect(self, n: &Vec3) -> Self {
return self - *n * dot(&self, &n) * 2.;
}
pub fn random_normalized() -> Vec3 {
Self::random_in_unit_sphere().normalized()
}
pub fn random_on_hemisphere(normal: Vec3) -> Vec3 {
let on_sphere = Self::random_normalized();
if dot(&on_sphere, &normal) > 0.0 {
return on_sphere;
} else {
return -on_sphere;
}
}
}
#[macro_export]
macro_rules! vec3 {
($x:expr, $y:expr, $z:expr) => {
Vec3 {
x: $x as f64,
y: $y as f64,
z: $z as f64,
}
};
}
pub fn dot(u: &Vec3, v: &Vec3) -> f64 {
return (u[0] * v[0]) + (u[1] * v[1]) + (u[2] * v[2]);
}
pub fn refract(uv: Vec3, n: &Vec3, etai_over_etat: f64) -> Vec3 {
let cos_theta = f64::min(dot(&-uv, n), 1.0); let r_out_perp = etai_over_etat * (uv + cos_theta * *n);
let r_out_parallel = -*n * (1.0 - r_out_perp.length_squared()).abs().sqrt();
r_out_perp + r_out_parallel
}
pub fn cross(a: &Vec3, b: &Vec3) -> Vec3 {
Vec3 {
x: a.y * b.z - a.z * b.y,
y: a.z * b.x - a.x * b.z,
z: a.x * b.y - a.y * b.x,
}
}
impl From<f64> for Vec3 {
fn from(n: f64) -> Self {
Vec3 { x: n, y: n, z: n }
}
}
impl Index<usize> for Vec3 {
type Output = f64;
fn index(&self, index: usize) -> &Self::Output {
match index {
0 => &self.x,
1 => &self.y,
2 => &self.z,
_ => panic!("Index out of bounds"),
}
}
}
impl IndexMut<usize> for Vec3 {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
match index {
0 => &mut self.x,
1 => &mut self.y,
2 => &mut self.z,
_ => panic!("Index out of bounds"),
}
}
}
impl Neg for Vec3 {
type Output = Vec3;
fn neg(self) -> Vec3 {
Vec3 {
x: -self.x,
y: -self.y,
z: -self.z,
}
}
}
impl Add for Vec3 {
type Output = Vec3;
fn add(self, other: Vec3) -> Vec3 {
Vec3 {
x: self.x + other.x,
y: self.y + other.y,
z: self.z + other.z,
}
}
}
impl<T> Add<T> for Vec3
where
T: Into<f64> + Copy,
{
type Output = Vec3;
fn add(self, other: T) -> Vec3 {
let other = other.into() as f64;
Vec3 {
x: self.x + other,
y: self.y + other,
z: self.z + other,
}
}
}
impl Sub for Vec3 {
type Output = Vec3;
fn sub(self, other: Vec3) -> Vec3 {
Vec3 {
x: self.x - other.x,
y: self.y - other.y,
z: self.z - other.z,
}
}
}
impl<T> Sub<T> for Vec3
where
T: Into<f64> + Copy,
{
type Output = Vec3;
fn sub(self, other: T) -> Vec3 {
let other = other.into() as f64;
Vec3 {
x: self.x - other,
y: self.y - other,
z: self.z - other,
}
}
}
impl Mul for Vec3 {
type Output = Vec3;
fn mul(self, other: Vec3) -> Vec3 {
Vec3 {
x: self.x * other.x,
y: self.y * other.y,
z: self.z * other.z,
}
}
}
impl<T> Mul<T> for Vec3
where
T: Into<f64> + Copy,
{
type Output = Vec3;
fn mul(self, other: T) -> Vec3 {
let other = other.into() as f64;
Vec3 {
x: self.x * other,
y: self.y * other,
z: self.z * other,
}
}
}
impl Mul<Vec3> for f64 {
type Output = Vec3;
fn mul(self, other: Vec3) -> Self::Output {
Vec3 {
x: self * other.x,
y: self * other.y,
z: self * other.z,
}
}
}
impl<T> Div<T> for Vec3
where
T: Into<f64> + Copy,
{
type Output = Vec3;
fn div(self, other: T) -> Vec3 {
let other = other.into();
Vec3 {
x: self.x / other,
y: self.y / other,
z: self.z / other,
}
}
}
impl Div<Vec3> for f64 {
type Output = Vec3;
fn div(self, other: Vec3) -> Self::Output {
Vec3 {
x: self / other.x,
y: self / other.y,
z: self / other.z,
}
}
}
impl Div<Vec3> for Vec3 {
type Output = Vec3;
fn div(self, other: Vec3) -> Vec3 {
Vec3 {
x: self.x / other.x,
y: self.y / other.y,
z: self.z / other.z,
}
}
}
impl AddAssign for Vec3 {
fn add_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, rhs: Self) {
*self = Self {
x: self.x - rhs.x,
y: self.y - rhs.y,
z: self.z - rhs.z,
}
}
}
impl Default for Vec3 {
fn default() -> Self {
Self {
x: 0.,
y: 0.,
z: 0.,
}
}
}