use super::{GL::Frame, *}; use crate::math::{la::*, *}; #[derive(Debug, Clone)] pub struct FocusCam { pub target: V3, proj: Memoized, view: Memoized, orient: Memoized<(Q, V3), (Vec3, V3)>, view_proj: Cell>, inv_view: Cell>, } impl FocusCam { pub fn pos(&self) -> Vec3 { Vec3(self.orient.get().1) } pub fn fov(&self) -> f32 { self.proj.get_args().1 .0 } pub fn new(target: V3, polar_zoom: Vec3) -> Self { let proj = Memoized::zero(proj_f); let view = Memoized::zero(view_f); let orient = Memoized::zero(orient_f); let (view_proj, inv_view) = Def(); let mut c = FocusCam { target, proj, orient, view, view_proj, inv_view }; c.set_polar(polar_zoom); c } pub fn track(&mut self, tgt: V3) { let Self { target, orient, view_proj, .. } = self; if &tgt != target { *target = tgt; orient.reset(); view_proj.replace(None); } } pub fn set_proj(&mut self, f: &impl Frame, (fov, far): Vec2) { if self.proj.apply((f.size(), (fov, far))).changed { self.view_proj.replace(None); } } pub fn set_polar(&mut self, polar_zoom: Vec3) { let Self { target, orient, view, view_proj, inv_view, .. } = self; let MemRes { changed, val } = orient.apply((&polar_zoom, &*target)); if changed && view.apply(val).changed { view_proj.replace(None); inv_view.replace(None); } } pub fn V(&self) -> &M4 { &self.view } pub fn iV(&self) -> &M4 { let Self { inv_view, .. } = self; if inv_view.inspect(|s| s.is_none()) { inv_view.replace(Some(inverse4(*self.view))); } unsafe { &*inv_view.as_ptr() }.as_ref().valid() } pub fn VP(&self) -> &M4 { let Self { view_proj, .. } = self; if view_proj.inspect(|s| s.is_none()) { view_proj.replace(Some(self.P() * self.V())); } unsafe { &*view_proj.as_ptr() }.as_ref().valid() } pub fn P(&self) -> &M4 { &self.proj } pub fn MV(&self, model: &M4) -> M4 { self.V() * model } pub fn MVP(&self, model: &M4) -> M4 { self.VP() * model } pub fn iL(&self) -> Vec3 { Vec3(-self.orient.1) } pub fn N(&self, model: &M4) -> M3 { inverse3(crop_3x3(model)).transpose() } pub fn NV(&self, model: &M4) -> M3 { let m = self.V() * model; inverse3(crop_3x3(&m).transpose()) } } impl Default for FocusCam { fn default() -> Self { Self::new(V3::new(0., 0., 0.), Vec3((0, -90, 1))) } } #[cfg(feature = "adv_fs")] mod serde { use {super::*, crate::ser::*}; impl Serialize for FocusCam { fn serialize(&self, s: S) -> Result { let Self { target, proj, view, orient, .. } = self; (target, proj, view, orient).serialize(s) } } impl<'de> Deserialize<'de> for FocusCam { fn deserialize>(d: D) -> Result { let (target, proj, view, orient) = <(V3, Memoized, Memoized, Memoized<(Q, V3), (Vec3, V3)>)>::deserialize(d)?; let proj = proj.finalize_deserialization(proj_f); let view = view.finalize_deserialization(view_f); let orient = orient.finalize_deserialization(orient_f); Ok(Self { target, proj, view, orient, ..Def() }) } } } fn proj_f(&(size, (fov, far)): &(uVec2, Vec2)) -> M4 { let (w, h) = size; let aspect = f32(w) / f32(h); let fov = fov.to_radians(); let fov = if w < h { 2. * ((fov * 0.5).tan() / aspect).atan() } else { fov }; perspective(aspect, fov, 0.01, far) } fn view_f((orient, pos): &(Q, V3)) -> M4 { let rot = orient.inverse().to_rotation_matrix().to_homogeneous(); let trans = M4::new_translation(&-pos); rot * trans } fn orient_f(&((a, e, dist), target): &(Vec3, V3)) -> (Q, V3) { let (a, e) = (a, e).map(|c| c.to_radians()); let mut orient = Q::identity(); let yaw = Q::from_axis_angle(&V3::y_axis(), a); orient = yaw * orient; let pitch = Q::from_axis_angle(&V3::x_axis(), e); orient *= pitch; let dir = orient * -V3::z_axis(); let pos = target - *dir * dist; (orient, pos) }