grafix_toolbox/kit/opengl/geom/
camera.rs

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