Skip to main content

grafix_toolbox/kit/opengl/geom/
camera.rs

1use 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}