1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use nalgebra::{Point2, RealField};
use simba::scalar::SubsetOf;

/// Fixed quantity wrt field of view.
///
///   * Implements [`Default`] and can be created with `Fixed::default()` returning
///     `Fixed::Ver(N::frac_pi_4())`.
///   * Implements `From<N>` and can be created with `N::into()` returning `Fixed::Ver()`.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Fixed<N: Copy + RealField> {
	/// Fixed horizontal field of view aka Vert- scaling.
	Hor(N),
	/// Fixed vertical field of view aka Hor+ scaling.
	Ver(N),
	/// Fixed unit per pixel on focus plane at distance from eye of one aka Pixel-based scaling.
	Upp(N),
}

impl<N: Copy + RealField> Default for Fixed<N> {
	fn default() -> Self {
		N::frac_pi_4().into()
	}
}

impl<N: Copy + RealField> From<N> for Fixed<N> {
	fn from(fov: N) -> Self {
		Self::Ver(fov)
	}
}

impl<N: Copy + RealField> Fixed<N> {
	/// Converts to fixed horizontal field of view wrt maximum position in screen space.
	#[must_use]
	pub fn to_hor(self, max: &Point2<N>) -> Self {
		let two = N::one() + N::one();
		Self::Hor(match self {
			Self::Hor(fov) => fov,
			Self::Ver(fov) => (max.x / max.y * (fov / two).tan()).atan() * two,
			Self::Upp(upp) => (max.x / two * upp).atan() * two,
		})
	}
	/// Converts to fixed vertical field of view wrt maximum position in screen space.
	#[must_use]
	pub fn to_ver(self, max: &Point2<N>) -> Self {
		let two = N::one() + N::one();
		Self::Ver(match self {
			Self::Hor(fov) => (max.y / max.x * (fov / two).tan()).atan() * two,
			Self::Ver(fov) => fov,
			Self::Upp(upp) => (max.y / two * upp).atan() * two,
		})
	}
	/// Converts to fixed unit per pixel on focus plane at distance from eye of one wrt maximum
	/// position in screen space.
	#[must_use]
	pub fn to_upp(self, max: &Point2<N>) -> Self {
		let two = N::one() + N::one();
		Self::Upp(match self {
			Self::Hor(fov) => (fov / two).tan() * two / max.x,
			Self::Ver(fov) => (fov / two).tan() * two / max.y,
			Self::Upp(upp) => upp,
		})
	}
	/// Maximum position in camera space and unit per pixel on focus plane wrt distance between
	/// eye and target and maximum position in screen space.
	#[must_use]
	pub fn max_and_upp(&self, zat: N, max: &Point2<N>) -> (Point2<N>, N) {
		let two = N::one() + N::one();
		match *self {
			Self::Hor(fov) => {
				let x = zat * (fov / two).tan();
				let y = max.y / max.x * x;
				(Point2::new(x, y), x * two / max.x)
			}
			Self::Ver(fov) => {
				let y = zat * (fov / two).tan();
				let x = max.x / max.y * y;
				(Point2::new(x, y), y * two / max.y)
			}
			Self::Upp(upp) => {
				let upp = upp * zat;
				(max / two * upp, upp)
			}
		}
	}
	/// Underlying quantity.
	#[must_use]
	pub const fn into_inner(self) -> N {
		match self {
			Self::Hor(fov) | Self::Ver(fov) => fov,
			Self::Upp(upp) => upp,
		}
	}
	/// Casts components to another type, e.g., between [`f32`] and [`f64`].
	#[must_use]
	pub fn cast<M: Copy + RealField>(self) -> Fixed<M>
	where
		N: SubsetOf<M>,
	{
		match self {
			Self::Hor(fov) => Fixed::Hor(fov.to_superset()),
			Self::Ver(fov) => Fixed::Ver(fov.to_superset()),
			Self::Upp(fov) => Fixed::Upp(fov.to_superset()),
		}
	}
}

#[cfg(feature = "rkyv")]
impl<N: Copy + RealField> rkyv::Archive for Fixed<N> {
	type Archived = Self;
	type Resolver = ();

	#[inline]
	#[allow(unsafe_code)]
	unsafe fn resolve(&self, _: usize, (): Self::Resolver, out: *mut Self::Archived) {
		out.write(rkyv::to_archived!(*self as Self));
	}
}

#[cfg(feature = "rkyv")]
impl<Ser: rkyv::Fallible + ?Sized, N: Copy + RealField> rkyv::Serialize<Ser> for Fixed<N> {
	#[inline]
	fn serialize(&self, _: &mut Ser) -> Result<Self::Resolver, Ser::Error> {
		Ok(())
	}
}

#[cfg(feature = "rkyv")]
impl<De: rkyv::Fallible + ?Sized, N: Copy + RealField> rkyv::Deserialize<Self, De> for Fixed<N> {
	#[inline]
	fn deserialize(&self, _: &mut De) -> Result<Self, De::Error> {
		Ok(rkyv::from_archived!(*self))
	}
}