1use std::io::{self, Cursor, Write};
2
3pub use azalea_buf::AzBuf;
4use azalea_buf::{AzBufVar, BufReadError};
5
6use crate::{math, position::Vec3};
7
8pub trait PositionDeltaTrait {
9 fn x(&self) -> f64;
10 fn y(&self) -> f64;
11 fn z(&self) -> f64;
12}
13
14#[derive(AzBuf, Clone, Debug, Default, PartialEq)]
16pub struct PositionDelta8 {
17 pub xa: i16,
18 pub ya: i16,
19 pub za: i16,
20}
21
22impl PositionDeltaTrait for PositionDelta8 {
23 fn x(&self) -> f64 {
24 (self.xa as f64) / 4096.0
25 }
26 fn y(&self) -> f64 {
27 (self.ya as f64) / 4096.0
28 }
29 fn z(&self) -> f64 {
30 (self.za as f64) / 4096.0
31 }
32}
33impl<T: PositionDeltaTrait> From<T> for Vec3 {
34 fn from(value: T) -> Self {
35 Vec3::new(value.x(), value.y(), value.z())
36 }
37}
38
39impl Vec3 {
40 #[must_use]
41 pub fn with_delta(&self, delta: &impl PositionDeltaTrait) -> Vec3 {
42 Vec3 {
43 x: self.x + delta.x(),
44 y: self.y + delta.y(),
45 z: self.z + delta.z(),
46 }
47 }
48
49 pub fn normalize(&self) -> Vec3 {
50 let length = f64::sqrt(self.x * self.x + self.y * self.y + self.z * self.z);
51 if length < 1e-5 {
52 return Vec3::ZERO;
53 }
54 Vec3 {
55 x: self.x / length,
56 y: self.y / length,
57 z: self.z / length,
58 }
59 }
60
61 pub fn multiply(&self, x: f64, y: f64, z: f64) -> Vec3 {
62 Vec3 {
63 x: self.x * x,
64 y: self.y * y,
65 z: self.z * z,
66 }
67 }
68 pub fn scale(&self, amount: f64) -> Vec3 {
69 self.multiply(amount, amount, amount)
70 }
71}
72
73#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
78pub enum LpVec3 {
79 #[default]
80 Zero,
81 Normal {
82 a: u8,
83 b: u8,
84 c: u32,
85 },
86 Extended {
87 a: u8,
88 b: u8,
89 c: u32,
90 d: u32,
91 },
92}
93
94impl AzBuf for LpVec3 {
95 fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
96 let a = u8::azalea_read(buf)?;
97 if a == 0 {
98 return Ok(LpVec3::Zero);
99 }
100 let b = u8::azalea_read(buf)?;
101 let c = u32::azalea_read(buf)?;
102 if a & 4 == 4 {
103 let d = u32::azalea_read_var(buf)?;
104 Ok(LpVec3::Extended { a, b, c, d })
105 } else {
106 Ok(LpVec3::Normal { a, b, c })
107 }
108 }
109 fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
110 match self {
111 LpVec3::Zero => {
112 0u8.azalea_write(buf)?;
113 }
114 LpVec3::Normal { a, b, c } => {
115 a.azalea_write(buf)?;
116 b.azalea_write(buf)?;
117 c.azalea_write(buf)?;
118 }
119 LpVec3::Extended { a, b, c, d } => {
120 a.azalea_write(buf)?;
121 b.azalea_write(buf)?;
122 c.azalea_write(buf)?;
123 d.azalea_write_var(buf)?;
124 }
125 }
126 Ok(())
127 }
128}
129impl LpVec3 {
130 pub fn from_vec3(vec3: Vec3) -> Self {
131 let x = Self::sanitize(vec3.x);
132 let y = Self::sanitize(vec3.y);
133 let z = Self::sanitize(vec3.z);
134 let max = x.abs().max(y.abs()).max(z.abs());
135 if max < 3.051944088384301E-5 {
136 return LpVec3::Zero;
137 }
138
139 let divisor = math::ceil_long(max);
140 let is_extended = divisor & 3 != divisor;
141 let packed_divisor = if is_extended {
142 (divisor as u64 & 3) | 4
143 } else {
144 divisor as u64
145 };
146 let packed_x = Self::pack(x / (divisor as f64)) << 3;
147 let packed_y = Self::pack(y / (divisor as f64)) << 18;
148 let packed_z = Self::pack(z / (divisor as f64)) << 33;
149 let packed = packed_divisor | packed_x | packed_y | packed_z;
150
151 let a = packed as u8;
152 let b = (packed >> 8) as u8;
153 let c = (packed >> 16) as u32;
154
155 if is_extended {
156 let d = ((divisor as u64) >> 2) as u32;
157 Self::Extended { a, b, c, d }
158 } else {
159 Self::Normal { a, b, c }
160 }
161 }
162
163 pub fn to_vec3(self) -> Vec3 {
164 match self {
165 LpVec3::Zero => Vec3::ZERO,
166 LpVec3::Normal { a, b, c } => {
167 let packed: u64 = (c as u64) << 16 | (b as u64) << 8 | (a as u64);
168 let multiplier = (a & 3) as u64 as f64;
169
170 Vec3 {
171 x: Self::unpack(packed >> 3) * multiplier,
172 y: Self::unpack(packed >> 18) * multiplier,
173 z: Self::unpack(packed >> 33) * multiplier,
174 }
175 }
176 LpVec3::Extended { a, b, c, d } => {
177 let packed: u64 = (c as u64) << 16 | (b as u64) << 8 | (a as u64);
178 let multiplier = (a & 3) as u64;
179 let multiplier = multiplier | ((d as u64) << 2);
180 let multiplier = multiplier as f64;
181
182 Vec3 {
183 x: Self::unpack(packed >> 3) * multiplier,
184 y: Self::unpack(packed >> 18) * multiplier,
185 z: Self::unpack(packed >> 33) * multiplier,
186 }
187 }
188 }
189 }
190
191 fn unpack(value: u64) -> f64 {
192 f64::min((value & 32767) as f64, 32766.) * 2. / 32766. - 1.
193 }
194
195 fn pack(value: f64) -> u64 {
196 f64::round((value * 0.5 + 0.5) * 32766.) as u64
197 }
198
199 fn sanitize(value: f64) -> f64 {
200 if value.is_nan() {
201 0.
202 } else {
203 f64::clamp(value, -1.7179869183E10, 1.7179869183E10)
204 }
205 }
206}
207impl From<LpVec3> for Vec3 {
208 fn from(value: LpVec3) -> Self {
209 value.to_vec3()
210 }
211}
212impl From<Vec3> for LpVec3 {
213 fn from(value: Vec3) -> Self {
214 LpVec3::from_vec3(value)
215 }
216}
217#[cfg(test)]
218mod tests {
219 use super::*;
220
221 static TEST_VALUES: [Vec3; 3] = [
222 Vec3::ZERO,
223 Vec3 {
224 x: 1.234,
225 y: -5.678,
226 z: 9.876,
227 },
228 Vec3 {
229 x: 10000000.,
230 y: -5000000.,
231 z: 9876543.,
232 },
233 ];
234
235 #[test]
236 fn test_lpvec3_roundtrip() {
237 fn close_enough(a: f64, b: f64) -> bool {
238 a == b || (a / b - 1.).abs() < 0.01
239 }
240
241 for v in TEST_VALUES {
242 let lp = LpVec3::from_vec3(v);
243 let v2 = lp.to_vec3();
244 assert!(
245 close_enough(v.x, v2.x) && close_enough(v.y, v2.y) && close_enough(v.z, v2.z),
246 "Original: {:?}, Roundtrip: {:?}",
247 v,
248 v2
249 );
250 }
251 }
252
253 #[test]
254 fn test_encode_decode_lpvec3() {
255 for v in TEST_VALUES {
256 let v: LpVec3 = LpVec3::from(v);
257 let mut first_buf = Vec::new();
258 v.azalea_write(&mut first_buf).unwrap();
259 let decoded = LpVec3::azalea_read(&mut Cursor::new(&first_buf)).unwrap();
260 assert_eq!(v, decoded);
261
262 let mut second_buf = Vec::new();
263 LpVec3::from(Vec3::from(decoded))
264 .azalea_write(&mut second_buf)
265 .unwrap();
266
267 assert_eq!(first_buf, second_buf);
268 }
269 }
270}