Skip to main content

fey_math/
vec4.rs

1use crate::{Num, Vec2, Vec3, impl_vec, vec2, vec3};
2use std::fmt::{Display, Formatter};
3
4pub type Vec4F = Vec4<f32>;
5pub type Vec4I = Vec4<i32>;
6pub type Vec4U = Vec4<u32>;
7
8/// A 4-dimensional vector.
9#[repr(C)]
10#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
11pub struct Vec4<T> {
12    pub x: T,
13    pub y: T,
14    pub z: T,
15    pub w: T,
16}
17
18/// Create a [`Vec4`].
19#[inline]
20pub const fn vec4<T>(x: T, y: T, z: T, w: T) -> Vec4<T> {
21    Vec4 { x, y, z, w }
22}
23
24impl_vec!(
25    NAME = Vec4
26    SHORT = vec4
27    LEN = 4
28    FIELDS = (x, y, z, w)
29    TUPLE = (T, T, T, T)
30);
31
32impl<T> Vec4<T> {
33    /// Return the vector with the x-value replaced.
34    #[inline]
35    pub fn with_x(self, x: T) -> Self {
36        Self { x, ..self }
37    }
38
39    /// Return the vector with the y-value replaced.
40    #[inline]
41    pub fn with_y(self, y: T) -> Self {
42        Self { y, ..self }
43    }
44
45    /// Return the vector with the z-value replaced.
46    #[inline]
47    pub fn with_z(self, z: T) -> Self {
48        Self { z, ..self }
49    }
50
51    /// Return the vector with the w-value replaced.
52    #[inline]
53    pub fn with_w(self, w: T) -> Self {
54        Self { w, ..self }
55    }
56}
57
58impl<T: Copy> Vec4<T> {
59    /// Reduce to a 2D vector by dropping `z` and `w`.
60    #[inline]
61    pub const fn xy(self) -> Vec2<T> {
62        vec2(self.x, self.y)
63    }
64
65    /// Reduce to a 3D vector by dropping `w`.
66    #[inline]
67    pub const fn xyz(self) -> Vec3<T> {
68        vec3(self.x, self.y, self.z)
69    }
70
71    /// Swizzle components.
72    #[inline]
73    pub fn yxzw(self) -> Self {
74        vec4(self.y, self.x, self.z, self.w)
75    }
76
77    /// Swizzle components.
78    #[inline]
79    pub fn zxyw(self) -> Self {
80        vec4(self.z, self.x, self.y, self.w)
81    }
82
83    /// Swizzle components.
84    #[inline]
85    pub fn wxzy(self) -> Self {
86        vec4(self.w, self.x, self.z, self.y)
87    }
88
89    /// Swizzle components.
90    #[inline]
91    pub fn yxwz(self) -> Self {
92        vec4(self.y, self.x, self.w, self.z)
93    }
94
95    /// Swizzle components.
96    #[inline]
97    pub fn yzxw(self) -> Self {
98        vec4(self.y, self.z, self.x, self.w)
99    }
100
101    /// Swizzle components.
102    #[inline]
103    pub fn zyxw(self) -> Self {
104        vec4(self.z, self.y, self.x, self.w)
105    }
106
107    /// Swizzle components.
108    #[inline]
109    pub fn wzxy(self) -> Self {
110        vec4(self.w, self.z, self.x, self.y)
111    }
112
113    /// Swizzle components.
114    #[inline]
115    pub fn yzwx(self) -> Self {
116        vec4(self.y, self.z, self.w, self.x)
117    }
118
119    /// Swizzle components.
120    #[inline]
121    pub fn zywx(self) -> Self {
122        vec4(self.z, self.y, self.w, self.x)
123    }
124
125    /// Swizzle components.
126    #[inline]
127    pub fn wzyx(self) -> Self {
128        vec4(self.w, self.z, self.y, self.x)
129    }
130
131    /// Swizzle components.
132    #[inline]
133    pub fn ywzx(self) -> Self {
134        vec4(self.y, self.w, self.z, self.x)
135    }
136}
137
138impl<T: Num> Vec4<T> {
139    /// A unit vector representing the x-axis, equal to `(1, 0, 0, 0)`.
140    pub const X_AXIS: Self = vec4(T::ONE, T::ZERO, T::ZERO, T::ZERO);
141
142    /// A unit vector representing the y-axis, equal to `(0, 1, 0, 0)`.
143    pub const Y_AXIS: Self = vec4(T::ZERO, T::ONE, T::ZERO, T::ZERO);
144
145    /// A unit vector representing the z-axis, equal to `(0, 0, 1, 0)`.
146    pub const Z_AXIS: Self = vec4(T::ZERO, T::ZERO, T::ONE, T::ZERO);
147
148    /// A unit vector representing the w-axis, equal to `(0, 0, 0, 1)`.
149    pub const W_AXIS: Self = vec4(T::ZERO, T::ZERO, T::ZERO, T::ONE);
150}
151
152impl<T: Display> Display for Vec4<T> {
153    #[inline]
154    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
155        self.x.fmt(f)?;
156        f.write_str(", ")?;
157        self.y.fmt(f)?;
158        f.write_str(", ")?;
159        self.z.fmt(f)?;
160        f.write_str(", ")?;
161        self.w.fmt(f)
162    }
163}
164
165impl<T: Num> From<Vec2<T>> for Vec4<T> {
166    #[inline]
167    fn from(Vec2 { x, y }: Vec2<T>) -> Self {
168        vec4(x, y, T::ZERO, T::ZERO)
169    }
170}
171
172impl<T: Num> From<Vec3<T>> for Vec4<T> {
173    #[inline]
174    fn from(Vec3 { x, y, z }: Vec3<T>) -> Self {
175        vec4(x, y, z, T::ZERO)
176    }
177}
178
179#[cfg(test)]
180mod tests {
181    use super::*;
182
183    #[test]
184    fn vec4_math() {
185        assert_eq!(
186            vec4(1.0, 2.0, 3.0, 4.0) + vec4(2.0, 3.0, 4.0, 5.0),
187            vec4(3.0, 5.0, 7.0, 9.0)
188        );
189        assert_eq!(vec4(1.0, 2.0, 2.0, 4.0).len(), 5.0); // one that happens to be all integers. neat
190        assert_eq!(vec4(1.0, 2.0, 3.0, 4.0) * 2.0, vec4(2.0, 4.0, 6.0, 8.0));
191        assert_eq!(
192            vec4(1.0, 2.0, 3.0, 4.0).min(vec4(4.0, 3.0, 2.0, 1.0)),
193            vec4(1.0, 2.0, 2.0, 1.0)
194        );
195        assert_eq!(
196            vec4(1.0, 2.0, 3.0, 4.0).max(vec4(4.0, 3.0, 2.0, 1.0)),
197            vec4(4.0, 3.0, 3.0, 4.0)
198        );
199        assert_eq!(
200            vec4(1.0, 2.0, 3.0, 4.0).clamp(vec4(2.0, 2.0, 2.0, 2.0), vec4(3.0, 3.0, 3.0, 3.0)),
201            vec4(2.0, 2.0, 3.0, 3.0)
202        );
203    }
204}