Skip to main content

goud_engine/core/math/
vec3.rs

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