use crate::glam::*;
#[derive(Default, Debug, Clone, Copy)]
pub struct Camera3d {
pub transform: Camera3dTransform,
pub projection: Projection,
}
impl Camera3d {
pub fn to_matrix(self) -> mint::ColumnMatrix4<f32> {
(self.projection.to_matrix() * self.transform.to_matrix()).into()
}
}
#[derive(Debug, Clone, Copy)]
pub struct Camera3dTransform {
pub position: mint::Point3<f32>,
pub yaw: f32,
pub pitch: f32,
}
impl Default for Camera3dTransform {
fn default() -> Self {
Self {
position: Vec3::ZERO.into(),
yaw: 0.0,
pitch: 0.0,
}
}
}
impl Camera3dTransform {
pub fn new<V: Into<mint::Point3<f32>>>(position: V, yaw: f32, pitch: f32) -> Self {
Self {
position: position.into(),
yaw,
pitch,
}
}
#[must_use]
pub fn position<P>(mut self, position_: P) -> Self
where
P: Into<mint::Point3<f32>>,
{
let p: mint::Point3<f32> = position_.into();
self.position = p;
self
}
#[must_use]
pub fn translate<T>(self, translate_: T) -> Self
where
T: Into<mint::Vector3<f32>>,
{
let t: mint::Vector3<f32> = translate_.into();
self.position(glam::Vec3::from(self.position) + glam::Vec3::from(t))
}
pub(crate) fn to_matrix(self) -> Mat4 {
let (sin_pitch, cos_pitch) = self.pitch.sin_cos();
let (sin_yaw, cos_yaw) = self.yaw.sin_cos();
glam::Mat4::look_to_rh(
self.position.into(),
Vec3::new(cos_pitch * cos_yaw, sin_pitch, cos_pitch * sin_yaw).normalize(),
Vec3::Y,
)
}
}
#[derive(Clone, Copy, Debug)]
pub struct Projection {
pub aspect: f32,
pub fovy: f32,
pub znear: f32,
pub zfar: f32,
}
impl Default for Projection {
fn default() -> Self {
Self::new(1920, 1080, 70.0_f32.to_radians(), 0.1, 1000.0)
}
}
impl Projection {
pub fn new(width: u32, height: u32, fovy: f32, znear: f32, zfar: f32) -> Self {
Self {
aspect: width as f32 / height as f32,
fovy,
znear,
zfar,
}
}
pub fn resize(&mut self, width: u32, height: u32) {
self.aspect = width as f32 / height as f32;
}
pub(crate) fn to_matrix(self) -> Mat4 {
Mat4::perspective_rh(self.fovy, self.aspect, self.znear, self.zfar)
}
}