1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
use crate::{Matrix, Point, Vector};

impl std::ops::Mul for Matrix {
    type Output = Self;

    fn mul(self, rhs: Self) -> Self {
        let mut result = Self::zero();

        for i in 0..4 {
            for j in 0..4 {
                for k in 0..4 {
                    result.0[i][j] += self.0[i][k] * rhs.0[k][j];
                }
            }
        }

        result
    }
}

impl std::ops::Mul<Point> for Matrix {
    type Output = Point;

    fn mul(self, rhs: Point) -> Point {
        Point::new(
            self.0[0][0] * rhs.x + self.0[1][0] * rhs.y + self.0[2][0] * rhs.z + self.0[3][0],
            self.0[0][1] * rhs.x + self.0[1][1] * rhs.y + self.0[2][1] * rhs.z + self.0[3][1],
            self.0[0][2] * rhs.x + self.0[1][2] * rhs.y + self.0[2][2] * rhs.z + self.0[3][2],
        )
    }
}

impl std::ops::Mul<Vector> for Matrix {
    type Output = Vector;

    fn mul(self, rhs: Vector) -> Vector {
        Vector::new(
            self.0[0][0] * rhs.x + self.0[1][0] * rhs.y + self.0[2][0] * rhs.z,
            self.0[0][1] * rhs.x + self.0[1][1] * rhs.y + self.0[2][1] * rhs.z,
            self.0[0][2] * rhs.x + self.0[1][2] * rhs.y + self.0[2][2] * rhs.z,
        )
    }
}

macro_rules! scalar_op {
    ($trait: ident, $op_fn: ident, $type: ty, $other_type: ty, $result_type: ty, $op: tt) => {
        impl std::ops::$trait<($other_type)> for $type {
            type Output = $result_type;

            fn $op_fn(self, rhs: $other_type) -> $result_type {
                <$result_type>::new(self.x $op rhs, self.y $op rhs, self.z $op rhs)
            }
        }
    };
}

macro_rules! vector_op {
    ($trait: ident, $op_fn: ident, $type: ty, $other_type: ty, $result_type: ty, $op: tt) => {
        impl std::ops::$trait<($other_type)> for $type {
            type Output = $result_type;

            fn $op_fn(self, rhs: $other_type) -> $result_type {
                <$result_type>::new(self.x $op rhs.x, self.y $op rhs.y, self.z $op rhs.z)
            }
        }
    };
}

scalar_op!(Add, add, Point, f32, Point, +);
scalar_op!(Sub, sub, Point, f32, Point, -);
scalar_op!(Mul, mul, Point, f32, Point, *);

scalar_op!(Add, add, Vector, f32, Vector, +);
scalar_op!(Sub, sub, Vector, f32, Vector, -);
scalar_op!(Mul, mul, Vector, f32, Vector, *);

vector_op!(Add, add, Vector, Vector, Vector, +);
vector_op!(Sub, sub, Vector, Vector, Vector, -);

vector_op!(Add, add, Point, Vector, Point, +);
vector_op!(Sub, sub, Point, Vector, Point, -);
vector_op!(Sub, sub, Point, Point, Vector, -);