veloren_common/util/
dir.rs1use super::{Plane, Projection};
2use rand::Rng;
3use serde::{Deserialize, Serialize};
4use tracing::warn;
5use vek::*;
6
7#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
11#[serde(into = "SerdeDir")]
12#[serde(from = "SerdeDir")]
13pub struct Dir(Vec3<f32>);
14impl Default for Dir {
15 fn default() -> Self { Self::forward() }
16}
17
18#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
20struct SerdeDir(Vec3<f32>);
21impl From<SerdeDir> for Dir {
22 fn from(dir: SerdeDir) -> Self {
23 let dir = dir.0;
24 if dir.map(f32::is_nan).reduce_or() {
25 warn!(
26 ?dir,
27 "Deserialized dir containing NaNs, replacing with default"
28 );
29 Default::default()
30 } else if !dir.is_normalized() {
31 warn!(
32 ?dir,
33 "Deserialized unnormalized dir, replacing with default"
34 );
35 Default::default()
36 } else {
37 Self(dir)
38 }
39 }
40}
41
42impl From<Dir> for SerdeDir {
43 fn from(other: Dir) -> SerdeDir { SerdeDir(*other) }
44}
45impl Dir {
65 pub fn new(dir: Vec3<f32>) -> Self {
66 debug_assert!(!dir.map(f32::is_nan).reduce_or());
67 debug_assert!(dir.is_normalized());
68 Self(dir)
69 }
70
71 pub fn from_unnormalized(dirs: Vec3<f32>) -> Option<Self> {
72 dirs.try_normalized().map(|dir| {
73 #[cfg(debug_assertions)]
74 {
75 if dir.map(f32::is_nan).reduce_or() {
76 panic!("{} => {}", dirs, dir);
77 }
78 }
79 Self(dir)
80 })
81 }
82
83 pub fn random_2d(rng: &mut impl Rng) -> Self {
85 let a = rng.gen_range(0.0..std::f32::consts::TAU);
86 Self::new(Vec3::new(a.cos(), a.sin(), 0.0))
88 }
89
90 pub fn slerp(from: Self, to: Self, factor: f32) -> Self {
91 Self(slerp_normalized(from.0, to.0, factor))
92 }
93
94 #[must_use]
95 pub fn slerped_to(self, to: Self, factor: f32) -> Self {
96 Self(slerp_normalized(self.0, to.0, factor))
97 }
98
99 pub fn slerp_to_vec3(from: Self, to: Vec3<f32>, factor: f32) -> Self {
101 Self(slerp_to_unnormalized(from.0, to, factor).unwrap_or_else(|e| e))
102 }
103
104 pub fn rotation_between(&self, to: Self) -> Quaternion<f32> {
105 Quaternion::<f32>::rotation_from_to_3d(self.0, to.0)
106 }
107
108 pub fn rotation(&self) -> Quaternion<f32> { Self::default().rotation_between(*self) }
109
110 pub fn is_valid(&self) -> bool { !self.0.map(f32::is_nan).reduce_or() && self.is_normalized() }
111
112 pub fn up() -> Self { Dir::new(Vec3::<f32>::unit_z()) }
113
114 pub fn down() -> Self { -Dir::new(Vec3::<f32>::unit_z()) }
115
116 pub fn left() -> Self { -Dir::new(Vec3::<f32>::unit_x()) }
117
118 pub fn right() -> Self { Dir::new(Vec3::<f32>::unit_x()) }
119
120 pub fn forward() -> Self { Dir::new(Vec3::<f32>::unit_y()) }
121
122 pub fn back() -> Self { -Dir::new(Vec3::<f32>::unit_y()) }
123
124 pub fn to_horizontal(self) -> Option<Self> { Self::from_unnormalized(self.xy().into()) }
125
126 pub fn vec(&self) -> &Vec3<f32> { &self.0 }
127
128 pub fn to_vec(self) -> Vec3<f32> { self.0 }
129}
130
131impl std::ops::Deref for Dir {
132 type Target = Vec3<f32>;
133
134 fn deref(&self) -> &Vec3<f32> { &self.0 }
135}
136
137impl From<Dir> for Vec3<f32> {
138 fn from(dir: Dir) -> Self { *dir }
139}
140
141impl Projection<Plane> for Dir {
142 type Output = Option<Self>;
143
144 fn projected(self, plane: &Plane) -> Self::Output {
145 Dir::from_unnormalized(plane.projection(*self))
146 }
147}
148
149impl Projection<Dir> for Vec3<f32> {
150 type Output = Vec3<f32>;
151
152 fn projected(self, dir: &Dir) -> Self::Output {
153 let dir = **dir;
154 self.dot(dir) * dir
155 }
156}
157
158impl std::ops::Mul<Dir> for Quaternion<f32> {
159 type Output = Dir;
160
161 fn mul(self, dir: Dir) -> Self::Output { Dir((self * *dir).normalized()) }
162}
163
164impl std::ops::Neg for Dir {
165 type Output = Dir;
166
167 fn neg(self) -> Dir { Dir::new(-self.0) }
168}
169
170#[inline(always)]
176fn slerp_normalized(from: Vec3<f32>, to: Vec3<f32>, factor: f32) -> Vec3<f32> {
177 debug_assert!(!to.map(f32::is_nan).reduce_or());
178 debug_assert!(!from.map(f32::is_nan).reduce_or());
179 #[cfg(debug_assertions)]
181 {
182 let unnormalized = {
183 let len_sq = from.magnitude_squared();
184 !(0.999..=1.001).contains(&len_sq)
185 };
186
187 if unnormalized {
188 panic!("Called slerp_normalized with unnormalized `from`: {}", from);
189 }
190 }
191
192 #[cfg(debug_assertions)]
194 {
195 let unnormalized = {
196 let len_sq = from.magnitude_squared();
197 !(0.999..=1.001).contains(&len_sq)
198 };
199
200 if unnormalized {
201 panic!("Called slerp_normalized with unnormalized `to`: {}", to);
202 }
203 }
204
205 let dot = from.dot(to);
206 if dot >= 1.0 - 1E-6 {
207 return to;
209 }
210
211 let (from, to, factor) = if dot < -0.999 {
212 let mid_dir = if from.z.abs() > 0.999 {
216 Vec3::unit_x()
218 } else {
219 Vec3::new(from.y, -from.x, 0.0).normalized()
221 };
222
223 if factor > 0.5 {
224 (mid_dir, to, factor * 2.0 - 1.0)
225 } else {
226 (from, mid_dir, factor * 2.0)
227 }
228 } else {
229 (from, to, factor)
230 };
231
232 let slerped = Vec3::slerp(from, to, factor);
233 let slerped_normalized = slerped.normalized();
234 #[cfg(debug_assertions)]
238 {
239 if !slerped_normalized.is_normalized() || slerped_normalized.map(f32::is_nan).reduce_or() {
240 panic!(
241 "Failed to normalize {:?} produced from:\nslerp(\n {:?},\n {:?},\n \
242 {:?},\n)\nWith result: {:?})",
243 slerped, from, to, factor, slerped_normalized
244 );
245 }
246 }
247
248 slerped_normalized
249}
250
251fn slerp_to_unnormalized(
261 from: Vec3<f32>,
262 to: Vec3<f32>,
263 factor: f32,
264) -> Result<Vec3<f32>, Vec3<f32>> {
265 to.try_normalized()
266 .map(|to| slerp_normalized(from, to, factor))
267 .ok_or(from)
268}