use nalgebra::{Point2, RealField};
use simba::scalar::SubsetOf;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Fixed<N: Copy + RealField> {
Hor(N),
Ver(N),
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> {
#[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,
})
}
#[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,
})
}
#[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,
})
}
#[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)
}
}
}
#[must_use]
pub const fn into_inner(self) -> N {
match self {
Self::Hor(fov) | Self::Ver(fov) => fov,
Self::Upp(upp) => upp,
}
}
#[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))
}
}