diff --git a/src/linalg.rs b/src/linalg.rs new file mode 100644 index 0000000..ace4f18 --- /dev/null +++ b/src/linalg.rs @@ -0,0 +1,320 @@ +use std::ops::{Add, Deref, Mul}; + +use crate::point::Point3f; + +pub type Float = f32; + +//-************************************************************************ +// Vectors +//-************************************************************************ + +#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] +#[repr(transparent)] +pub struct Vek { + pub vec: [Float; N], +} + +pub type Vec3 = Vek<3>; +pub type Vec4 = Vek<4>; + +//-************************************************************************ +// Matrices +//-************************************************************************ + +#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] +#[repr(transparent)] +pub struct Mat { + pub rows: [Vek; N], +} + +pub type Mat3 = Mat<3>; +pub type Mat4 = Mat<4>; + +//-************************************************************************ +// inherent impls +//-************************************************************************ + +// Vec3 +impl Vec3 { + pub fn new(x: Float, y: Float, z: Float) -> Self { + Self { vec: [x, y, z] } + } + + pub fn x(&self) -> Float { + self.vec[0] + } + + pub fn y(&self) -> Float { + self.vec[1] + } + + pub fn z(&self) -> Float { + self.vec[2] + } + + pub fn dot(&self, rhs: &Self) -> Float { + self.x() * rhs.x() + self.y() * rhs.y() + self.z() * rhs.z() + } + + pub fn len(&self) -> Float { + self.len_squared().sqrt() + } + + pub fn len_squared(&self) -> Float { + self.x().powi(2) + self.y().powi(2) + self.z().powi(2) + } + + pub fn scale(self, factor: Float) -> Self { + self * factor + } +} + +// Vec4 +impl Vec4 { + pub fn new(x: Float, y: Float, z: Float, w: Float) -> Self { + Self { vec: [x, y, z, w] } + } + + pub fn x(&self) -> Float { + self.vec[0] + } + + pub fn y(&self) -> Float { + self.vec[1] + } + + pub fn z(&self) -> Float { + self.vec[2] + } + + pub fn w(&self) -> Float { + self.vec[3] + } + pub fn dot(&self, rhs: &Self) -> Float { + self.x() * rhs.x() + self.y() * rhs.y() + self.z() * rhs.z() + self.w() * rhs.w() + } + + pub fn len(&self) -> Float { + self.len_squared().sqrt() + } + + pub fn len_squared(&self) -> Float { + self.x().powi(2) + self.y().powi(2) + self.z().powi(2) + self.w().powi(2) + } + + pub fn scale(self, factor: Float) -> Self { + self * factor + } +} + +// Mat3 +impl Mat3 { + pub fn new(rows: [Vec3; 3]) -> Self { + Self { rows } + } + + pub fn identity() -> Self { + Self::default() + } + + /// panics if `row` is > 2 + pub fn row(&self, row: usize) -> Vec3 { + self[row] + } + + pub fn a(&self) -> Vec3 { + self[0] + } + + pub fn b(&self) -> Vec3 { + self[1] + } + + pub fn c(&self) -> Vec3 { + self[2] + } + + pub fn transpose(&self) -> Self { + let a = [self[0][0], self[1][0], self[2][0]].into(); + let b = [self[0][1], self[1][1], self[2][1]].into(); + let c = [self[0][2], self[1][2], self[2][2]].into(); + Self { rows: [a, b, c] } + } + + pub fn invert(&self) -> Self { + todo!() + } +} + +//-************************************************************************ +// trait impls +//-************************************************************************ + +// Vec3 +impl Default for Vec3 { + fn default() -> Self { + Self { + vec: Default::default(), + } + } +} + +impl From<[Float; 3]> for Vec3 { + fn from(vec: [Float; 3]) -> Self { + Self { vec } + } +} + +impl Deref for Vec3 { + type Target = [Float; 3]; + + fn deref(&self) -> &Self::Target { + &self.vec + } +} + +impl Mul for Vec3 { + type Output = Self; + + fn mul(self, rhs: Float) -> Self::Output { + let [x, y, z] = self.vec; + Self { + vec: [x * rhs, y * rhs, z * rhs], + } + } +} + +impl Mul for Float { + type Output = Vec3; + + fn mul(self, rhs: Vec3) -> Self::Output { + rhs * self + } +} + +/// Adding a vector to a point like "point + vec" +#[allow(clippy::unnecessary_cast)] +impl Add for Point3f { + type Output = Point3f; + + fn add(self, v: Vec3) -> Self::Output { + Point3f::new( + (self.x() as Float + v.x()) as f32, + (self.y() as Float + v.y()) as f32, + (self.z() as Float + v.z()) as f32, + ) + } +} + +// Vec4 +impl Default for Vec4 { + fn default() -> Self { + Self { + vec: [0., 0., 0., 1.], + } + } +} + +impl From<[Float; 4]> for Vec4 { + fn from(vec: [Float; 4]) -> Self { + Self { vec } + } +} + +impl Deref for Vec4 { + type Target = [Float; 4]; + + fn deref(&self) -> &Self::Target { + &self.vec + } +} + +impl Mul for Vec4 { + type Output = Self; + + fn mul(self, rhs: Float) -> Self::Output { + let [x, y, z, w] = self.vec; + Self { + vec: [x * rhs, y * rhs, z * rhs, w * rhs], + } + } +} + +impl Mul for Float { + type Output = Vec4; + + fn mul(self, rhs: Vec4) -> Self::Output { + rhs * self + } +} + +// Mat3 +impl Default for Mat3 { + fn default() -> Self { + Self { + rows: [ + [1., 0., 0.].into(), + [0., 1., 0.].into(), + [0., 0., 1.].into(), + ], + } + } +} + +impl Deref for Mat3 { + type Target = [Vec3; 3]; + + fn deref(&self) -> &Self::Target { + &self.rows + } +} + +impl Mul for Mat3 { + type Output = Vec3; + + fn mul(self, rhs: Vec3) -> Self::Output { + todo!() + } +} + +impl Default for Mat4 { + fn default() -> Self { + Self { + rows: [ + [1., 0., 0., 0.].into(), + [0., 1., 0., 0.].into(), + [0., 0., 1., 0.].into(), + [0., 0., 0., 1.].into(), + ], + } + } +} + +impl Deref for Mat4 { + type Target = [Vec4; 4]; + + fn deref(&self) -> &Self::Target { + &self.rows + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn mat3_transpose() { + // identity doesn't change under transpose + let m = Mat3::default(); + assert_eq!(1.0, m[0][0]); + assert_eq!(0.0, m[0][1]); + assert_eq!(m, m.transpose()); + + let m = Mat3::new([[1.; 3].into(), [2.; 3].into(), [3.; 3].into()]); + assert_eq!(m.a(), [1., 1., 1.].into()); + + let mt = m.transpose(); + assert_ne!(m, mt); + assert_eq!(mt.a(), [1., 2., 3.].into()); + } +} diff --git a/src/main.rs b/src/main.rs index 91fae05..0be6b71 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,6 +12,8 @@ mod model; mod triangle; use triangle::*; +mod linalg; + use crate::model::Model; const BLACK: TGAColor = TGAColor { bgra: [0u8; 4] };