grafix_toolbox/kit/opengl/geom/
camera.rs1use super::{GL::Frame, lazy::*, *};
2use crate::math::{la::*, *};
3
4#[derive(Debug, Clone)]
5pub struct FocusCam {
6 pub target: V3,
7 proj: Memoized<M4, (uVec2, Vec2)>,
8 view: Memoized<M4, (Q, V3)>,
9 orient: Memoized<(Q, V3), (Vec3, V3)>,
10 view_proj: Cell<Option<M4>>,
11 inv_view: Cell<Option<M4>>,
12}
13impl FocusCam {
14 pub fn pos(&self) -> Vec3 {
15 (*self.orient).pipe(|(_, p)| p).pipe(Vec3)
16 }
17 pub fn fov(&self) -> f32 {
18 self.proj.get_args().pipe(|&(_, (f, _))| f)
19 }
20 pub fn new(target: V3, polar_zoom: Vec3) -> Self {
21 let (proj, view, orient, (view_proj, inv_view)) = (Memoized::zero(proj_f), Memoized::zero(view_f), Memoized::zero(orient_f), Def());
22
23 FocusCam { target, proj, orient, view, view_proj, inv_view }.tap(|c| c.set_polar(polar_zoom))
24 }
25 pub fn track(&mut self, tgt: V3) {
26 let Self { target, orient, view_proj, .. } = self;
27 if &tgt != target {
28 *target = tgt;
29 orient.reset();
30 view_proj.set(None);
31 }
32 }
33 pub fn set_proj(&mut self, f: &impl Frame, (fov, far): Vec2) {
34 if self.proj.apply((f.size(), (fov, far))).changed {
35 self.view_proj.set(None);
36 }
37 }
38 pub fn set_polar(&mut self, polar_zoom: Vec3) {
39 let Self { target, orient, view, view_proj, inv_view, .. } = self;
40
41 let MemRes { changed, val } = orient.apply((&polar_zoom, &*target));
42 if changed && view.apply(val).changed {
43 view_proj.set(None);
44 inv_view.set(None);
45 }
46 }
47 pub fn V(&self) -> &M4 {
48 &self.view
49 }
50 pub fn iV(&self) -> &M4 {
51 let Self { inv_view, .. } = self;
52 if inv_view.bind().is_none() {
53 inv_view.set(inverse4(*self.view).pipe(Some));
54 }
55
56 unsafe { &*inv_view.as_ptr() }.as_valid()
57 }
58 pub fn VP(&self) -> &M4 {
59 let Self { view_proj, .. } = self;
60 if view_proj.bind().is_none() {
61 view_proj.set((self.P() * self.V()).pipe(Some));
62 }
63
64 unsafe { &*view_proj.as_ptr() }.as_valid()
65 }
66 pub fn P(&self) -> &M4 {
67 &self.proj
68 }
69 pub fn MV(&self, model: &M4) -> M4 {
70 self.V() * model
71 }
72 pub fn MVP(&self, model: &M4) -> M4 {
73 self.VP() * model
74 }
75 pub fn iL(&self) -> Vec3 {
76 (*self.orient).pipe(|(_, p)| Vec3(-p))
77 }
78 pub fn N(&self, model: &M4) -> M3 {
79 crop_3x3(model).pipe(inverse3).transpose()
80 }
81 pub fn NV(&self, model: &M4) -> M3 {
82 let m = self.V() * model;
83 crop_3x3(&m).transpose().pipe(inverse3)
84 }
85}
86impl Default for FocusCam {
87 fn default() -> Self {
88 Self::new(Def(), Vec3((0, -90, 1)))
89 }
90}
91#[cfg(feature = "adv_fs")]
92mod serde {
93 use {super::*, crate::ser::*};
94
95 impl Serialize for FocusCam {
96 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
97 let Self { target, proj, view, orient, .. } = self;
98 (target, proj, view, orient).serialize(s)
99 }
100 }
101 impl<'de> Deserialize<'de> for FocusCam {
102 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
103 let (target, proj, view, orient) = <(V3, Memoized<M4, (uVec2, Vec2)>, Memoized<M4, (Q, V3)>, Memoized<(Q, V3), (Vec3, V3)>)>::deserialize(d)?;
104 let proj = proj.finalize_deserialization(proj_f);
105 let view = view.finalize_deserialization(view_f);
106 let orient = orient.finalize_deserialization(orient_f);
107 Self { target, proj, view, orient, ..Def() }.pipe(Ok)
108 }
109 }
110}
111
112fn proj_f(&(size, (fov, far)): &(uVec2, Vec2)) -> M4 {
113 let (w, h) = size;
114 let aspect = f32(w) / f32(h);
115 let fov = fov.to_radians();
116 let fov = fov.or_val(w >= h, || 2. * ((fov * 0.5).tan() / aspect).atan());
117 perspective(aspect, fov, 0.01, far)
118}
119fn view_f((orient, pos): &(Q, V3)) -> M4 {
120 let rot = orient.inverse().to_rotation_matrix().to_homogeneous();
121 let trans = M4::new_translation(&-pos);
122 rot * trans
123}
124fn orient_f(&((a, e, dist), target): &(Vec3, V3)) -> (Q, V3) {
125 let (a, e) = (a, e).map(|c| c.to_radians());
126
127 let mut orient = Q::identity();
128 let yaw = Q::from_axis_angle(&V3::y_axis(), a);
129 orient = yaw * orient;
130
131 let pitch = Q::from_axis_angle(&V3::x_axis(), e);
132 orient *= pitch;
133
134 let dir = orient * -V3::z_axis();
135 let pos = target - *dir * dist;
136 (orient, pos)
137}