Skip to main content

goud_engine/core/math/
vec4.rs

1//! 4D vector type with FFI-safe memory layout.
2
3use std::ops::{Add, Div, Mul, Neg, Sub};
4
5use super::vec3::Vec3;
6
7/// A 4D vector with FFI-safe memory layout.
8///
9/// This type is commonly used for homogeneous coordinates in graphics
10/// or RGBA colors. It is guaranteed to have the same memory layout as
11/// a C struct with four consecutive f32 fields.
12#[repr(C)]
13#[derive(Clone, Copy, Debug, PartialEq, Default, serde::Serialize, serde::Deserialize)]
14pub struct Vec4 {
15    /// The x-component of the vector.
16    pub x: f32,
17    /// The y-component of the vector.
18    pub y: f32,
19    /// The z-component of the vector.
20    pub z: f32,
21    /// The w-component of the vector.
22    pub w: f32,
23}
24
25impl Vec4 {
26    /// Creates a new Vec4 from x, y, z, w components.
27    #[inline]
28    pub const fn new(x: f32, y: f32, z: f32, w: f32) -> Self {
29        Self { x, y, z, w }
30    }
31
32    /// Returns the zero vector (0, 0, 0, 0).
33    #[inline]
34    pub const fn zero() -> Self {
35        Self {
36            x: 0.0,
37            y: 0.0,
38            z: 0.0,
39            w: 0.0,
40        }
41    }
42
43    /// Returns the one vector (1, 1, 1, 1).
44    #[inline]
45    pub const fn one() -> Self {
46        Self {
47            x: 1.0,
48            y: 1.0,
49            z: 1.0,
50            w: 1.0,
51        }
52    }
53
54    /// Creates a Vec4 from a Vec3 and w component.
55    #[inline]
56    pub const fn from_vec3(v: Vec3, w: f32) -> Self {
57        Self {
58            x: v.x,
59            y: v.y,
60            z: v.z,
61            w,
62        }
63    }
64
65    /// Returns the xyz components as a Vec3.
66    #[inline]
67    pub const fn xyz(self) -> Vec3 {
68        Vec3 {
69            x: self.x,
70            y: self.y,
71            z: self.z,
72        }
73    }
74
75    /// Computes the dot product of two vectors.
76    #[inline]
77    pub fn dot(self, other: Self) -> f32 {
78        self.x * other.x + self.y * other.y + self.z * other.z + self.w * other.w
79    }
80
81    /// Returns the squared length of the vector.
82    #[inline]
83    pub fn length_squared(self) -> f32 {
84        self.dot(self)
85    }
86
87    /// Returns the length (magnitude) of the vector.
88    #[inline]
89    pub fn length(self) -> f32 {
90        self.length_squared().sqrt()
91    }
92
93    /// Returns a normalized (unit length) version of this vector.
94    #[inline]
95    pub fn normalize(self) -> Self {
96        let len = self.length();
97        if len == 0.0 {
98            Self::zero()
99        } else {
100            self / len
101        }
102    }
103
104    /// Linearly interpolates between two vectors.
105    #[inline]
106    pub fn lerp(self, other: Self, t: f32) -> Self {
107        Self {
108            x: self.x + (other.x - self.x) * t,
109            y: self.y + (other.y - self.y) * t,
110            z: self.z + (other.z - self.z) * t,
111            w: self.w + (other.w - self.w) * t,
112        }
113    }
114}
115
116impl Add for Vec4 {
117    type Output = Self;
118    #[inline]
119    fn add(self, other: Self) -> Self {
120        Self {
121            x: self.x + other.x,
122            y: self.y + other.y,
123            z: self.z + other.z,
124            w: self.w + other.w,
125        }
126    }
127}
128
129impl Sub for Vec4 {
130    type Output = Self;
131    #[inline]
132    fn sub(self, other: Self) -> Self {
133        Self {
134            x: self.x - other.x,
135            y: self.y - other.y,
136            z: self.z - other.z,
137            w: self.w - other.w,
138        }
139    }
140}
141
142impl Mul<f32> for Vec4 {
143    type Output = Self;
144    #[inline]
145    fn mul(self, scalar: f32) -> Self {
146        Self {
147            x: self.x * scalar,
148            y: self.y * scalar,
149            z: self.z * scalar,
150            w: self.w * scalar,
151        }
152    }
153}
154
155impl Mul<Vec4> for f32 {
156    type Output = Vec4;
157    #[inline]
158    fn mul(self, vec: Vec4) -> Vec4 {
159        vec * self
160    }
161}
162
163impl Div<f32> for Vec4 {
164    type Output = Self;
165    #[inline]
166    fn div(self, scalar: f32) -> Self {
167        Self {
168            x: self.x / scalar,
169            y: self.y / scalar,
170            z: self.z / scalar,
171            w: self.w / scalar,
172        }
173    }
174}
175
176impl Neg for Vec4 {
177    type Output = Self;
178    #[inline]
179    fn neg(self) -> Self {
180        Self {
181            x: -self.x,
182            y: -self.y,
183            z: -self.z,
184            w: -self.w,
185        }
186    }
187}
188
189impl From<cgmath::Vector4<f32>> for Vec4 {
190    #[inline]
191    fn from(v: cgmath::Vector4<f32>) -> Self {
192        Self {
193            x: v.x,
194            y: v.y,
195            z: v.z,
196            w: v.w,
197        }
198    }
199}
200
201impl From<Vec4> for cgmath::Vector4<f32> {
202    #[inline]
203    fn from(v: Vec4) -> Self {
204        cgmath::Vector4::new(v.x, v.y, v.z, v.w)
205    }
206}