use std::ops::{
Neg,
Add, Sub,
Mul, Div,
AddAssign, SubAssign,
MulAssign, DivAssign
};
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Vec3 {
pub x: f32,
pub y: f32,
pub z: f32
}
impl Vec3 {
pub fn new(x: f32, y: f32, z: f32) -> Vec3 {
Vec3 {x, y, z}
}
pub fn dot(self, other: Vec3) -> f32 {
self.x * other.x + self.y * other.y + self.z * other.z
}
pub fn cross(self, other: Vec3) -> Vec3 {
Vec3::new(
self.y * other.z - self.z * other.y,
self.z * other.x - self.x * other.z,
self.x * other.y - self.y * other.x
)
}
pub fn len(self) -> f32 {
(self.x * self.x + self.y * self.y + self.z * self.z).sqrt()
}
pub fn len_sqr(self) -> f32 {
self.x * self.x + self.y * self.y + self.z * self.z
}
pub fn normalize(self) -> Vec3 {
let k = self.len().recip();
Vec3::new(self.x * k, self.y * k, self.z * k)
}
pub fn reflect(self, normal: Vec3) -> Vec3 {
self - 2f32 * self.dot(normal) * normal
}
pub fn refract(self, normal: Vec3, eta: f32) -> Option<Vec3> {
let unit = self.normalize();
let dt = unit.dot(normal);
let discriminant = 1f32 - eta * eta * (1f32 - dt * dt);
match discriminant > 0f32 {
true => Some(eta * (unit - normal * dt) - normal * discriminant.sqrt()),
false => None
}
}
}
impl Neg for Vec3 {
type Output = Vec3;
fn neg(self) -> Self::Output {
Vec3 {
x: -self.x,
y: -self.y,
z: -self.z
}
}
}
impl Add<Vec3> for Vec3 {
type Output = Vec3;
fn add(self, other: Vec3) -> Self::Output {
Vec3 {
x: self.x + other.x,
y: self.y + other.y,
z: self.z + other.z
}
}
}
impl Sub<Vec3> for Vec3 {
type Output = Vec3;
fn sub(self, other: Vec3) -> Self::Output {
Vec3 {
x: self.x - other.x,
y: self.y - other.y,
z: self.z - other.z
}
}
}
impl Mul<Vec3> for Vec3 {
type Output = Vec3;
fn mul(self, other: Vec3) -> Self::Output {
Vec3 {
x: self.x * other.x,
y: self.y * other.y,
z: self.z * other.z
}
}
}
impl Mul<f32> for Vec3 {
type Output = Vec3;
fn mul(self, other: f32) -> Self::Output {
Vec3 {
x: self.x * other,
y: self.y * other,
z: self.z * other
}
}
}
impl Mul<Vec3> for f32 {
type Output = Vec3;
fn mul(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) -> Self::Output {
Vec3 {
x: self.x / other.x,
y: self.y / other.y,
z: self.z / other.z
}
}
}
impl Div<f32> for Vec3 {
type Output = Vec3;
fn div(self, other: f32) -> Self::Output {
Vec3 {
x: self.x / other,
y: self.y / other,
z: self.z / other
}
}
}
impl AddAssign for Vec3 {
fn add_assign(&mut self, other: Vec3) {
*self = Vec3 {
x: self.x + other.x,
y: self.y + other.y,
z: self.z + other.z
};
}
}
impl SubAssign for Vec3 {
fn sub_assign(&mut self, other: Vec3) {
*self = Vec3 {
x: self.x - other.x,
y: self.y - other.y,
z: self.z - other.z
};
}
}
impl MulAssign<Vec3> for Vec3 {
fn mul_assign(&mut self, other: Vec3) {
*self = Vec3 {
x: self.x * other.x,
y: self.y * other.y,
z: self.z * other.z
};
}
}
impl MulAssign<f32> for Vec3 {
fn mul_assign(&mut self, other: f32) {
*self = Vec3 {
x: self.x * other,
y: self.y * other,
z: self.z * other
}
}
}
impl DivAssign<Vec3> for Vec3 {
fn div_assign(&mut self, other: Vec3) {
*self = Vec3 {
x: self.x / other.x,
y: self.y / other.y,
z: self.z / other.z
}
}
}
impl DivAssign<f32> for Vec3 {
fn div_assign(&mut self, other: f32) {
*self = Vec3 {
x: self.x / other,
y: self.y / other,
z: self.z / other
}
}
}
#[macro_export]
macro_rules! vec3 {
($value:expr) => { $crate::Vec3::new($value, $value, $value) };
($x:expr, $y:expr, $z:expr) => { $crate::Vec3::new($x, $y, $z) };
}
#[macro_export]
macro_rules! dot {
($a:expr, $b:expr) => { $a.dot($b) }
}
#[macro_export]
macro_rules! cross {
($a:expr, $b:expr) => { $a.cross($b) }
}
#[macro_export]
macro_rules! len {
($v:expr) => { $v.len() }
}
#[macro_export]
macro_rules! len_sqr {
($v:expr) => { $v.len_sqr() }
}
#[macro_export]
macro_rules! normalize {
($v:expr) => { $v.normalize() }
}
#[macro_export]
macro_rules! reflect {
($v:expr, $n:expr) => { $v.reflect($n) }
}
#[macro_export]
macro_rules! refract {
($v:expr, $normal:expr, $n:expr) => { $v.refract($normal, $n) }
}
#[cfg(test)]
mod tests {
use crate::{vec3, dot, cross, len, len_sqr, normalize, reflect};
use super::*;
#[test]
fn macro_vec3() {
let value: f32 = 2.78;
let va1 = vec3!(value);
let vb1 = Vec3::new(value, value, value);
assert_eq!(va1, vb1);
let (x, y, z): (f32, f32, f32) = (2.98, 5.45, 6.45);
let va3 = vec3!(x, y, z);
let vb3 = Vec3::new(x, y, z);
assert_eq!(va3, vb3);
}
#[test]
fn macro_dot() {
let a = vec3!(1.0, 2.0, 3.0);
let b = vec3!(1.0, 5.0, 7.0);
assert_eq!(dot!(a, b), 32.0);
assert_eq!(dot!(a, b), dot!(b, a));
}
#[test]
fn macro_cross() {
let i = vec3!(1.0, 0.0, 0.0);
let j = vec3!(0.0, 1.0, 0.0);
let k = vec3!(0.0, 0.0, 1.0);
assert_eq!(cross!(i, j), k);
assert_eq!(cross!(j, k), i);
assert_eq!(cross!(k, i), j);
assert_eq!(cross!(j, i), -k);
assert_eq!(cross!(k, j), -i);
assert_eq!(cross!(i, k), -j);
}
#[test]
fn macro_len() {
let v = vec3!(3.0, 4.0, 0.0);
assert_eq!(len!(v), 5.0);
}
#[test]
fn macro_len_sqr() {
let v = vec3!(3.0, 4.0, 0.0);
assert_eq!(len_sqr!(v), 25.0);
}
#[test]
fn macro_normalize() {
let a = vec3!(5.0, 0.0, 0.0);
let b = vec3!(10.0, 0.0, 0.0);
assert_eq!(normalize!(a), normalize!(b));
}
#[test]
fn macro_reflect() {
let normal = vec3!(0.0, 1.0, 0.0);
let incident = vec3!(0.0, -1.0, 0.0);
assert_eq!(reflect!(incident, normal), vec3!(0.0, 1.0, 0.0));
let incident = vec3!(-1.0, -1.0, 0.0);
assert_eq!(reflect!(incident, normal), vec3!(-1.0, 1.0, 0.0));
}
#[test]
fn macro_refract() {
let n = 1.5; let normal = vec3!(0.0, 1.0, 0.0);
let incident = vec3!(0.0, -1.0, 0.0);
assert_eq!(refract!(incident, normal, n), Some(incident));
let incident = vec3!(-0.7, -1.0, 0.0);
assert_eq!(refract!(incident, normal, n), Some(vec3!(-0.86019355, -0.5099678, 0.0)));
let incident = vec3!(-1.0, -0.05, 0.0);
assert_eq!(refract!(incident, normal, n), None);
let incident = vec3!(1.0, 0.05, 0.0);
assert_eq!(refract!(incident, normal, n), None); }
#[test]
fn vec3_new() {
let v = Vec3::new(1.0, 2.0, 3.0);
assert_eq!(v.x, 1.0);
assert_eq!(v.y, 2.0);
assert_eq!(v.z, 3.0);
}
#[test]
fn vec3_dot() {
let a = vec3!(1.0, 2.0, 3.0);
let b = vec3!(1.0, 5.0, 7.0);
assert_eq!(a.dot(b), 32.0);
assert_eq!(a.dot(b), b.dot(a));
}
#[test]
fn vec3_cross() {
let i = vec3!(1.0, 0.0, 0.0);
let j = vec3!(0.0, 1.0, 0.0);
let k = vec3!(0.0, 0.0, 1.0);
assert_eq!(i.cross(j), k);
assert_eq!(j.cross(k), i);
assert_eq!(k.cross(i), j);
assert_eq!(j.cross(i), -k);
assert_eq!(k.cross(j), -i);
assert_eq!(i.cross(k), -j);
}
#[test]
fn vec3_len() {
let v = vec3!(3.0, 4.0, 0.0);
assert_eq!(v.len(), 5.0);
}
#[test]
fn vec3_len_sqr() {
let v = vec3!(3.0, 4.0, 0.0);
assert_eq!(v.len_sqr(), 25.0);
}
#[test]
fn vec3_normalize() {
let a = vec3!(5.0, 0.0, 0.0);
let b = vec3!(10.0, 0.0, 0.0);
assert_eq!(a.normalize(), b.normalize());
}
#[test]
fn vec3_reflect() {
let normal = vec3!(0.0, 1.0, 0.0);
let incident = vec3!(0.0, -1.0, 0.0);
assert_eq!(incident.reflect(normal), vec3!(0.0, 1.0, 0.0));
let incident = vec3!(-1.0, -1.0, 0.0);
assert_eq!(incident.reflect(normal), vec3!(-1.0, 1.0, 0.0));
}
#[test]
fn vec3_refract() {
let n = 1.5; let normal = vec3!(0.0, 1.0, 0.0);
let incident = vec3!(0.0, -1.0, 0.0);
assert_eq!(incident.refract(normal, n), Some(incident));
let incident = vec3!(-0.7, -1.0, 0.0);
assert_eq!(incident.refract(normal, n), Some(vec3!(-0.86019355, -0.5099678, 0.0)));
let incident = vec3!(-1.0, -0.05, 0.0);
assert_eq!(incident.refract(normal, n), None);
let incident = vec3!(1.0, 0.05, 0.0);
assert_eq!(incident.refract(normal, n), None); }
#[test]
fn vec3_neg() {
let a = vec3!(2.0, 5.0, 7.0);
assert_eq!(-a, vec3!(-2.0, -5.0, -7.0));
}
#[test]
fn vec3_add() {
let a = vec3!(2.0, 3.0, 4.0);
let b = vec3!(1.0, 0.0, -1.0);
assert_eq!(a + b, vec3!(3.0));
}
#[test]
fn vec3_sub() {
let a = vec3!(5.0, 6.0, 7.0);
let b = vec3!(2.0, 3.0, 4.0);
assert_eq!(a - b, vec3!(3.0));
assert_eq!(b - a, vec3!(-3.0));
}
#[test]
fn vec3_mul() {
let a = vec3!(2.0, 3.0, 4.0);
let b = vec3!(2.0);
assert_eq!(a * b, vec3!(4.0, 6.0, 8.0));
let v = vec3!(2.5, 3.5, 1.0);
let s = 2.0;
let vs = vec3!(5.0, 7.0, 2.0);
assert_eq!(v * s, vs);
assert_eq!(s * v, vs);
}
#[test]
fn vec3_div() {
let a = vec3!(4.0, 6.0, 8.0);
let b = vec3!(2.0);
assert_eq!(a / b, vec3!(2.0, 3.0, 4.0));
assert_eq!(b / a, vec3!(0.5, 1.0 / 3.0, 0.25));
let v = vec3!(3.0, 2.0, 4.0);
let s = 2.0;
assert_eq!(v / s, vec3!(1.5, 1.0, 2.0));
}
#[test]
fn vec3_add_assign() {
let mut v = vec3!(2.0, 3.0, 5.0);
v += vec3!(2.0, 1.0, -1.0);
assert_eq!(v, vec3!(4.0));
}
#[test]
fn vec3_sub_assign() {
let mut v = vec3!(2.0, 3.0, 5.0);
v -= vec3!(2.0, 1.0, -1.0);
assert_eq!(v, vec3!(0.0, 2.0, 6.0));
}
#[test]
fn vec3_mul_assign() {
let mut v = vec3!(2.0, 4.0, 5.0);
v *= vec3!(2.0);
assert_eq!(v, vec3!(4.0, 8.0, 10.0));
v *= 3.0;
assert_eq!(v, vec3!(12.0, 24.0, 30.0));
}
#[test]
fn vec3_div_assign() {
let mut v = vec3!(2.0, 4.0, 6.0);
v /= vec3!(2.0);
assert_eq!(v, vec3!(1.0, 2.0, 3.0));
v /= 2.0;
assert_eq!(v, vec3!(0.5, 1.0, 1.5));
}
}