use crate::aabb::BoundingSphere;
use crate::{Mat4, Vec3};
use serde::{Deserialize, Serialize};
#[cfg(test)]
#[path = "projection_tests.rs"]
mod tests;
const MIN_NEAR: f32 = 0.01;
#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)]
pub enum Projection {
Perspective {
fov_y: f32,
aspect: f32,
near: f32,
far: f32,
},
Orthographic {
height: f32,
aspect: f32,
near: f32,
far: f32,
},
}
impl Projection {
#[must_use]
pub fn matrix(&self) -> Mat4 {
match *self {
Self::Perspective {
fov_y,
aspect,
near,
far,
} => {
glam::camera::rh::proj::directx::perspective(fov_y, aspect, far, near).into()
}
Self::Orthographic {
height,
aspect,
near,
far,
} => {
let half_h = height * 0.5;
let half_w = half_h * aspect;
glam::camera::rh::proj::directx::orthographic(
-half_w, half_w, -half_h, half_h, far, near,
)
.into()
}
}
}
pub fn fit_near_far(&mut self, eye: Vec3, bound: &BoundingSphere) {
let distance = eye.distance(bound.center);
let pad = bound.radius.max(1.0) * 0.01;
let new_far = distance + bound.radius + pad;
let new_near = (distance - bound.radius - pad).max(MIN_NEAR);
match self {
Self::Perspective { near, far, .. } | Self::Orthographic { near, far, .. } => {
*near = new_near;
*far = new_far;
}
}
}
#[must_use]
pub fn aspect(&self) -> f32 {
match *self {
Self::Perspective { aspect, .. } | Self::Orthographic { aspect, .. } => aspect,
}
}
pub fn set_aspect(&mut self, new_aspect: f32) {
match self {
Self::Perspective { aspect, .. } | Self::Orthographic { aspect, .. } => {
*aspect = new_aspect;
}
}
}
}