Skip to main content

rusteal_core/
ue_math.rs

1use glam::{DQuat, DVec2, DVec3, Vec4};
2
3#[derive(Clone, Copy, Debug, PartialEq)]
4pub struct Rotator {
5    pub pitch: f64,
6    pub yaw: f64,
7    pub roll: f64,
8}
9
10impl Rotator {
11    pub const ZERO: Rotator = Rotator {
12        pitch: 0.0,
13        yaw: 0.0,
14        roll: 0.0,
15    };
16
17    pub fn new(pitch: f64, yaw: f64, roll: f64) -> Self {
18        Rotator { pitch, yaw, roll }
19    }
20}
21
22impl From<Rotator> for DQuat {
23    fn from(r: Rotator) -> DQuat {
24        let deg2rad = std::f64::consts::PI / 180.0;
25        let (sp, cp) = (r.pitch * 0.5 * deg2rad).sin_cos();
26        let (sy, cy) = (r.yaw * 0.5 * deg2rad).sin_cos();
27        let (sr, cr) = (r.roll * 0.5 * deg2rad).sin_cos();
28
29        DQuat::from_xyzw(
30            cy * cp * sr - sy * sp * cr,
31            cy * sp * cr + sy * cp * sr,
32            sy * cp * cr - cy * sp * sr,
33            cy * cp * cr + sy * sp * sr,
34        )
35    }
36}
37
38impl From<DQuat> for Rotator {
39    fn from(q: DQuat) -> Rotator {
40        let rad2deg = 180.0 / std::f64::consts::PI;
41
42        let sinr_cosp = 2.0 * (q.w * q.x + q.y * q.z);
43        let cosr_cosp = 1.0 - 2.0 * (q.x * q.x + q.y * q.y);
44        let roll = sinr_cosp.atan2(cosr_cosp);
45
46        let sinp = 2.0 * (q.w * q.y - q.z * q.x);
47
48        let pitch = if sinp.abs() >= 1.0 {
49            std::f64::consts::FRAC_PI_2.copysign(sinp)
50        } else {
51            sinp.asin()
52        };
53
54        let siny_cosp = 2.0 * (q.w * q.z + q.x * q.y);
55        let cosy_cosp = 1.0 - 2.0 * (q.y * q.y + q.z * q.z);
56        let yaw = siny_cosp.atan2(cosy_cosp);
57
58        Rotator {
59            pitch: pitch * rad2deg,
60            yaw: yaw * rad2deg,
61            roll: roll * rad2deg,
62        }
63    }
64}
65
66#[derive(Clone, Copy, Debug, PartialEq)]
67pub struct Transform {
68    pub rotation: DQuat,
69    pub translation: DVec3,
70    pub scale: DVec3,
71}
72
73impl Transform {
74    pub const IDENTITY: Transform = Transform {
75        rotation: DQuat::IDENTITY,
76        translation: DVec3::ZERO,
77        scale: DVec3::ONE,
78    };
79
80    pub fn new(rotation: DQuat, translation: DVec3, scale: DVec3) -> Self {
81        Transform {
82            rotation,
83            translation,
84            scale,
85        }
86    }
87
88    pub fn from_translation(translation: DVec3) -> Self {
89        Transform {
90            translation,
91            ..Self::IDENTITY
92        }
93    }
94
95    pub fn from_rotation(rotation: DQuat) -> Self {
96        Transform {
97            rotation,
98            ..Self::IDENTITY
99        }
100    }
101}
102
103#[derive(Clone, Copy, Debug, PartialEq)]
104pub struct LinearColor {
105    pub r: f32,
106    pub g: f32,
107    pub b: f32,
108    pub a: f32,
109}
110
111impl LinearColor {
112    pub const BLACK: LinearColor = LinearColor {
113        r: 0.0,
114        g: 0.0,
115        b: 0.0,
116        a: 1.0,
117    };
118    pub const WHITE: LinearColor = LinearColor {
119        r: 1.0,
120        g: 1.0,
121        b: 1.0,
122        a: 1.0,
123    };
124    pub const RED: LinearColor = LinearColor {
125        r: 1.0,
126        g: 0.0,
127        b: 0.0,
128        a: 1.0,
129    };
130    pub const GREEN: LinearColor = LinearColor {
131        r: 0.0,
132        g: 1.0,
133        b: 0.0,
134        a: 1.0,
135    };
136    pub const BLUE: LinearColor = LinearColor {
137        r: 0.0,
138        g: 0.0,
139        b: 1.0,
140        a: 1.0,
141    };
142
143    pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
144        LinearColor { r, g, b, a }
145    }
146}
147
148impl From<LinearColor> for Vec4 {
149    fn from(c: LinearColor) -> Vec4 {
150        Vec4::new(c.r, c.g, c.b, c.a)
151    }
152}
153
154impl From<Vec4> for LinearColor {
155    fn from(v: Vec4) -> LinearColor {
156        LinearColor {
157            r: v.x,
158            g: v.y,
159            b: v.z,
160            a: v.w,
161        }
162    }
163}
164
165#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
166pub struct Color {
167    pub r: u8,
168    pub g: u8,
169    pub b: u8,
170    pub a: u8,
171}
172
173impl Color {
174    pub const BLACK: Color = Color {
175        r: 0,
176        g: 0,
177        b: 0,
178        a: 255,
179    };
180    pub const WHITE: Color = Color {
181        r: 255,
182        g: 255,
183        b: 255,
184        a: 255,
185    };
186    pub const RED: Color = Color {
187        r: 255,
188        g: 0,
189        b: 0,
190        a: 255,
191    };
192    pub const GREEN: Color = Color {
193        r: 0,
194        g: 255,
195        b: 0,
196        a: 255,
197    };
198    pub const BLUE: Color = Color {
199        r: 0,
200        g: 0,
201        b: 255,
202        a: 255,
203    };
204
205    pub fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
206        Color { r, g, b, a }
207    }
208}
209
210#[derive(Clone, Copy, Debug, PartialEq)]
211pub struct Plane {
212    pub normal: DVec3,
213    pub d: f64,
214}
215
216impl Plane {
217    pub fn new(normal: DVec3, d: f64) -> Self {
218        Plane { normal, d }
219    }
220}
221
222#[derive(Clone, Copy, Debug, PartialEq)]
223pub struct Ray {
224    pub origin: DVec3,
225    pub direction: DVec3,
226}
227
228impl Ray {
229    pub fn new(origin: DVec3, direction: DVec3) -> Self {
230        Ray { origin, direction }
231    }
232}
233
234#[derive(Clone, Copy, Debug, PartialEq)]
235pub struct Sphere {
236    pub center: DVec3,
237    pub radius: f64,
238}
239
240impl Sphere {
241    pub fn new(center: DVec3, radius: f64) -> Self {
242        Sphere { center, radius }
243    }
244}
245
246#[derive(Clone, Copy, Debug, PartialEq)]
247pub struct UeBox {
248    pub min: DVec3,
249    pub max: DVec3,
250}
251
252impl UeBox {
253    pub fn new(min: DVec3, max: DVec3) -> Self {
254        UeBox { min, max }
255    }
256}
257
258#[derive(Clone, Copy, Debug, PartialEq)]
259pub struct UeBox2d {
260    pub min: DVec2,
261    pub max: DVec2,
262}
263
264impl UeBox2d {
265    pub fn new(min: DVec2, max: DVec2) -> Self {
266        UeBox2d { min, max }
267    }
268}
269
270#[derive(Clone, Copy, Debug, PartialEq)]
271pub struct BoxSphereBounds {
272    pub origin: DVec3,
273    pub box_extent: DVec3,
274    pub sphere_radius: f64,
275}
276
277impl BoxSphereBounds {
278    pub fn new(origin: DVec3, box_extent: DVec3, sphere_radius: f64) -> Self {
279        BoxSphereBounds {
280            origin,
281            box_extent,
282            sphere_radius,
283        }
284    }
285}
286
287#[cfg(test)]
288mod tests {
289    use super::*;
290
291    #[test]
292    fn rotator_zero_to_quat_is_identity() {
293        let q: DQuat = Rotator::ZERO.into();
294        let diff = (q - DQuat::IDENTITY).length();
295        assert!(diff < 1e-10, "Expected identity quat, got {q:?}");
296    }
297
298    #[test]
299    fn rotator_roundtrip() {
300        let r = Rotator::new(30.0, 45.0, 60.0);
301        let q: DQuat = r.into();
302        let r2: Rotator = q.into();
303        assert!((r.pitch - r2.pitch).abs() < 1e-10);
304        assert!((r.yaw - r2.yaw).abs() < 1e-10);
305        assert!((r.roll - r2.roll).abs() < 1e-10);
306    }
307
308    #[test]
309    fn linear_color_vec4_roundtrip() {
310        let c = LinearColor::new(0.5, 0.3, 0.8, 1.0);
311        let v: Vec4 = c.into();
312        let c2: LinearColor = v.into();
313        assert_eq!(c, c2);
314    }
315}