1use crate::comp::{self, Ori};
2
3use super::{Plane, Projection};
4use rand::Rng;
5use serde::{Deserialize, Serialize};
6use tracing::warn;
7use vek::*;
8
9#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
13#[serde(into = "SerdeDir")]
14#[serde(from = "SerdeDir")]
15pub struct Dir(Vec3<f32>);
16impl Default for Dir {
17 fn default() -> Self { Self::forward() }
18}
19
20#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
22struct SerdeDir(Vec3<f32>);
23impl From<SerdeDir> for Dir {
24 fn from(dir: SerdeDir) -> Self {
25 let dir = dir.0;
26 if dir.map(f32::is_nan).reduce_or() {
27 warn!(
28 ?dir,
29 "Deserialized dir containing NaNs, replacing with default"
30 );
31 Default::default()
32 } else if !dir.is_normalized() {
33 warn!(
34 ?dir,
35 "Deserialized unnormalized dir, replacing with default"
36 );
37 Default::default()
38 } else {
39 Self(dir)
40 }
41 }
42}
43
44impl From<Dir> for SerdeDir {
45 fn from(other: Dir) -> SerdeDir { SerdeDir(*other) }
46}
47impl Dir {
67 pub fn new(dir: Vec3<f32>) -> Self {
68 debug_assert!(!dir.map(f32::is_nan).reduce_or());
69 debug_assert!(dir.is_normalized());
70 Self(dir)
71 }
72
73 pub fn from_unnormalized(dirs: Vec3<f32>) -> Option<Self> {
74 dirs.try_normalized().map(|dir| {
75 #[cfg(debug_assertions)]
76 {
77 if dir.map(f32::is_nan).reduce_or() {
78 panic!("{} => {}", dirs, dir);
79 }
80 }
81 Self(dir)
82 })
83 }
84
85 pub fn random_2d(rng: &mut impl Rng) -> Self {
87 let a = rng.random_range(0.0..std::f32::consts::TAU);
88 Self::new(Vec3::new(a.cos(), a.sin(), 0.0))
90 }
91
92 pub fn slerp(from: Self, to: Self, factor: f32) -> Self {
93 Self(slerp_normalized(from.0, to.0, factor))
94 }
95
96 #[must_use]
97 pub fn slerped_to(self, to: Self, factor: f32) -> Self {
98 Self(slerp_normalized(self.0, to.0, factor))
99 }
100
101 pub fn slerp_to_vec3(from: Self, to: Vec3<f32>, factor: f32) -> Self {
103 Self(slerp_to_unnormalized(from.0, to, factor).unwrap_or_else(|e| e))
104 }
105
106 pub fn rotation_between(&self, to: Self) -> Quaternion<f32> {
107 Quaternion::<f32>::rotation_from_to_3d(self.0, to.0)
108 }
109
110 pub fn rotation(&self) -> Quaternion<f32> { Self::default().rotation_between(*self) }
111
112 pub fn is_valid(&self) -> bool { !self.0.map(f32::is_nan).reduce_or() && self.is_normalized() }
113
114 pub fn up() -> Self { Dir::new(Vec3::<f32>::unit_z()) }
115
116 pub fn down() -> Self { -Dir::new(Vec3::<f32>::unit_z()) }
117
118 pub fn left() -> Self { -Dir::new(Vec3::<f32>::unit_x()) }
119
120 pub fn right() -> Self { Dir::new(Vec3::<f32>::unit_x()) }
121
122 pub fn forward() -> Self { Dir::new(Vec3::<f32>::unit_y()) }
123
124 pub fn back() -> Self { -Dir::new(Vec3::<f32>::unit_y()) }
125
126 pub fn to_horizontal(self) -> Option<Self> { Self::from_unnormalized(self.xy().into()) }
127
128 pub fn vec(&self) -> &Vec3<f32> { &self.0 }
129
130 pub fn to_vec(self) -> Vec3<f32> { self.0 }
131
132 pub fn merge_z(self, look_dir: Self) -> Self {
133 let xy_dir = Dir::from_unnormalized(Vec3::new(self.x, self.y, 0.0)).unwrap_or_default();
143 let pitch = xy_dir.rotation_between(self);
144
145 Ori::from(Vec3::new(look_dir.x, look_dir.y, 0.0))
146 .prerotated(pitch)
147 .look_dir()
148 }
149
150 pub fn look_toward(
153 this_pos: &comp::Pos,
154 this_body: Option<&comp::Body>,
155 this_scale: Option<&comp::Scale>,
156 tgt_pos: &comp::Pos,
157 tgt_body: Option<&comp::Body>,
158 tgt_scale: Option<&comp::Scale>,
159 ) -> Option<Self> {
160 let eye_offset = this_body.map_or(0.0, |b| b.eye_height(this_scale.map_or(1.0, |s| s.0)));
161 let tgt_eye_offset = tgt_body.map_or(0.0, |b| b.eye_height(tgt_scale.map_or(1.0, |s| s.0)));
162 Dir::from_unnormalized(
163 Vec3::new(tgt_pos.0.x, tgt_pos.0.y, tgt_pos.0.z + tgt_eye_offset)
164 - Vec3::new(this_pos.0.x, this_pos.0.y, this_pos.0.z + eye_offset),
165 )
166 }
167}
168
169impl std::ops::Deref for Dir {
170 type Target = Vec3<f32>;
171
172 fn deref(&self) -> &Vec3<f32> { &self.0 }
173}
174
175impl From<Dir> for Vec3<f32> {
176 fn from(dir: Dir) -> Self { *dir }
177}
178
179impl Projection<Plane> for Dir {
180 type Output = Option<Self>;
181
182 fn projected(self, plane: &Plane) -> Self::Output {
183 Dir::from_unnormalized(plane.projection(*self))
184 }
185}
186
187impl Projection<Dir> for Vec3<f32> {
188 type Output = Vec3<f32>;
189
190 fn projected(self, dir: &Dir) -> Self::Output {
191 let dir = **dir;
192 self.dot(dir) * dir
193 }
194}
195
196impl std::ops::Mul<Dir> for Quaternion<f32> {
197 type Output = Dir;
198
199 fn mul(self, dir: Dir) -> Self::Output { Dir((self * *dir).normalized()) }
200}
201
202impl std::ops::Neg for Dir {
203 type Output = Dir;
204
205 fn neg(self) -> Dir { Dir::new(-self.0) }
206}
207
208#[inline(always)]
214fn slerp_normalized(from: Vec3<f32>, to: Vec3<f32>, factor: f32) -> Vec3<f32> {
215 debug_assert!(!to.map(f32::is_nan).reduce_or());
216 debug_assert!(!from.map(f32::is_nan).reduce_or());
217 #[cfg(debug_assertions)]
219 {
220 let unnormalized = {
221 let len_sq = from.magnitude_squared();
222 !(0.999..=1.001).contains(&len_sq)
223 };
224
225 if unnormalized {
226 panic!("Called slerp_normalized with unnormalized `from`: {}", from);
227 }
228 }
229
230 #[cfg(debug_assertions)]
232 {
233 let unnormalized = {
234 let len_sq = from.magnitude_squared();
235 !(0.999..=1.001).contains(&len_sq)
236 };
237
238 if unnormalized {
239 panic!("Called slerp_normalized with unnormalized `to`: {}", to);
240 }
241 }
242
243 let dot = from.dot(to);
244 if dot >= 1.0 - 1E-6 {
245 return to;
247 }
248
249 let (from, to, factor) = if dot < -0.999 {
250 let mid_dir = if from.z.abs() > 0.999 {
254 Vec3::unit_x()
256 } else {
257 Vec3::new(from.y, -from.x, 0.0).normalized()
259 };
260
261 if factor > 0.5 {
262 (mid_dir, to, factor * 2.0 - 1.0)
263 } else {
264 (from, mid_dir, factor * 2.0)
265 }
266 } else {
267 (from, to, factor)
268 };
269
270 let slerped = Vec3::slerp(from, to, factor);
271 let slerped_normalized = slerped.normalized();
272 #[cfg(debug_assertions)]
276 {
277 if !slerped_normalized.is_normalized() || slerped_normalized.map(f32::is_nan).reduce_or() {
278 panic!(
279 "Failed to normalize {:?} produced from:\nslerp(\n {:?},\n {:?},\n \
280 {:?},\n)\nWith result: {:?})",
281 slerped, from, to, factor, slerped_normalized
282 );
283 }
284 }
285
286 slerped_normalized
287}
288
289fn slerp_to_unnormalized(
299 from: Vec3<f32>,
300 to: Vec3<f32>,
301 factor: f32,
302) -> Result<Vec3<f32>, Vec3<f32>> {
303 to.try_normalized()
304 .map(|to| slerp_normalized(from, to, factor))
305 .ok_or(from)
306}