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