Skip to main content

goud_engine/core/math/
vec2.rs

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