havok_types/math/
vector4.rs

1use parse_display::Display;
2
3/// # Vector4
4///
5/// # C++ Info
6/// - name: `hkVector4`
7/// - type_size: ` 16`(x86)/` 16`(x86_64)
8///
9/// # Examples
10/// ```
11/// use havok_types::Vector4;
12///
13/// assert_eq!(Vector4::new(1.0, 1.0, 1.0, 0.0).to_string(), "(1.000000 1.000000 1.000000 0.000000)");
14/// assert_eq!(Vector4::new(-0.0, 0.0, -0.0, 1.0).to_string(), "(-0.000000 0.000000 -0.000000 1.000000)");
15/// ```
16///
17/// # XML representation
18/// ```xml
19/// <hkparam name="">
20///   <!-- x         y        z         w -->
21///   (-0.000000 0.000000 -0.000000 1.000000)
22/// </hkparam>
23/// ```
24#[cfg_attr(feature = "json_schema", derive(schemars::JsonSchema))]
25#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
26#[repr(C, align(16))]
27#[derive(Debug, Clone, Default, PartialEq, PartialOrd, Display)]
28#[display("({x:.06} {y:.06} {z:.06} {w:.06})")]
29pub struct Vector4 {
30    /// # C++ Info
31    /// - name: `x`(ctype: `hkReal`)
32    /// - offset: `  0`(x86)/`  0`(x86_64)
33    /// - type_size: ` 4`(x86)/` 4`(x86_64)
34    pub x: f32,
35    /// # C++ Info
36    /// - name: `y`(ctype: `hkReal`)
37    /// - offset: `  4`(x86)/`  4`(x86_64)
38    /// - type_size: ` 4`(x86)/` 4`(x86_64)
39    pub y: f32,
40    /// # C++ Info
41    /// - name: `z`(ctype: `hkReal`)
42    /// - offset: `  8`(x86)/`  8`(x86_64)
43    /// - type_size: ` 4`(x86)/` 4`(x86_64)
44    pub z: f32,
45    /// # C++ Info
46    /// - name: `w`(ctype: `hkReal`)
47    /// - offset: ` 12`(x86)/` 12`(x86_64)
48    /// - type_size: ` 4`(x86)/` 4`(x86_64)
49    pub w: f32,
50}
51
52static_assertions::assert_eq_size!(Vector4, [u8; 16]);
53
54impl Vector4 {
55    /// Creates a new `Vector4`
56    pub const fn new(x: f32, y: f32, z: f32, w: f32) -> Self {
57        Self { x, y, z, w }
58    }
59
60    /// As a byte array in little endian.
61    #[inline]
62    pub fn to_le_bytes(&self) -> [u8; 16] {
63        let mut bytes = [0_u8; 16];
64        bytes[0..4].copy_from_slice(&self.x.to_le_bytes());
65        bytes[4..8].copy_from_slice(&self.y.to_le_bytes());
66        bytes[8..12].copy_from_slice(&self.z.to_le_bytes());
67        bytes[12..16].copy_from_slice(&self.w.to_le_bytes());
68        bytes
69    }
70
71    /// As a byte array in big endian.
72    #[inline]
73    pub fn to_be_bytes(&self) -> [u8; 16] {
74        let mut bytes = [0_u8; 16];
75        bytes[0..4].copy_from_slice(&self.x.to_be_bytes());
76        bytes[4..8].copy_from_slice(&self.y.to_be_bytes());
77        bytes[8..12].copy_from_slice(&self.z.to_be_bytes());
78        bytes[12..16].copy_from_slice(&self.w.to_be_bytes());
79        bytes
80    }
81
82    /// Create a [`Vector4`] value from its representation as a byte array in little endian.
83    #[inline]
84    pub const fn from_le_bytes(bytes: &[u8; 16]) -> Self {
85        Self {
86            x: f32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]),
87            y: f32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]),
88            z: f32::from_le_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]),
89            w: f32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]),
90        }
91    }
92
93    /// Create a [`Vector4`] value from its representation as a byte array in big endian.
94    #[inline]
95    pub const fn from_be_bytes(bytes: &[u8; 16]) -> Self {
96        Self {
97            x: f32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]),
98            y: f32::from_be_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]),
99            z: f32::from_be_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]),
100            w: f32::from_be_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]),
101        }
102    }
103}
104
105static_assertions::assert_eq_size!(Vector4, [u8; 16]); // Vector4 must be 16bytes size.
106static_assertions::assert_eq_align!(Vector4, u128); // Vector4 must be 16bytes(16 * 8 = 128bit) align.
107
108#[cfg(test)]
109mod tests {
110    use super::*;
111
112    #[test]
113    fn test() {
114        #[rustfmt::skip]
115        let expected_bytes: &[u8; 16] = &[
116            0, 0, 128, 63, // 1.0 in bytes (little-endian): 0x3F800000 → [0x00, 0x00, 0x80, 0x3F]
117            0, 0, 128, 63, // 1.0 in bytes (little-endian): 0x3F800000 → [0x00, 0x00, 0x80, 0x3F]
118            0, 0, 128, 63, // 1.0 in bytes (little-endian): 0x3F800000 → [0x00, 0x00, 0x80, 0x3F]
119            0, 0, 0, 0,    // 0.0 in bytes (little-endian): 0x00000000 → [0x00, 0x00, 0x00, 0x00]
120        ];
121
122        assert_eq!(
123            &Vector4::new(1.0, 1.0, 1.0, 0.0).to_le_bytes(),
124            expected_bytes,
125        );
126    }
127}