gloss_renderer/components/
cam_comps.rs1pub const CLICK_DURATION_MS: u128 = 250;
5
6use std::collections::HashMap;
7use wasm_timer::Instant;
8use winit::event::Touch;
9
10extern crate nalgebra as na;
11extern crate nalgebra_glm as glm;
12
13#[derive(Eq, PartialEq, Debug, Default)]
14pub enum TargetResolutionUpdate {
15 Fixed,
16 #[default]
17 WindowSize,
18}
19
20#[derive(Default)]
21pub struct TargetResolution {
22 pub width: u32,
23 pub height: u32,
24 pub update_mode: TargetResolutionUpdate,
25}
26
27#[derive(Eq, PartialEq, Debug)]
28pub enum CamMode {
29 Rotation,
30 Translation,
31}
32
33#[derive(Clone)]
36pub struct PosLookat {
37 pub position: na::Point3<f32>, pub lookat: na::Point3<f32>,
39 pub up: na::Vector3<f32>,
40}
41
42pub enum Projection {
44 WithFov(ProjectionWithFov),
46 WithIntrinsics(ProjectionWithIntrinsics),
47}
48
49#[derive(Clone)]
51pub struct ProjectionWithFov {
52 pub aspect_ratio: f32,
53 pub fovy: f32, pub near: f32,
55 pub far: f32,
56}
57
58#[derive(Clone)]
59pub struct ProjectionWithIntrinsics {
60 pub fx: f32,
61 pub fy: f32, pub cx: f32,
63 pub cy: f32,
64 pub near: f32,
67 pub far: f32,
68}
69
70#[allow(clippy::struct_excessive_bools)]
73pub struct CamController {
74 pub mouse_mode: CamMode,
75 pub mouse_pressed: bool,
76 pub prev_mouse_pos_valid: bool,
77 pub prev_mouse: na::Vector2<f32>,
78 pub limit_max_dist: Option<f32>,
79 pub limit_max_vertical_angle: Option<f32>,
80 pub limit_min_vertical_angle: Option<f32>,
81 pub id2active_touches: HashMap<u64, Touch>, pub cursor_position: Option<winit::dpi::PhysicalPosition<f64>>,
85 pub last_press: Option<Instant>,
86 pub is_last_press_click: bool,
87 pub mouse_moved_while_pressed: bool,
88}
89
90impl Default for PosLookat {
93 fn default() -> Self {
94 Self {
95 position: na::Point3::<f32>::new(0.0, 1.0, 3.0),
96 lookat: na::Point3::<f32>::new(0.0, 0.0, 0.0),
97 up: na::Vector3::<f32>::new(0.0, 1.0, 0.0),
98 }
99 }
100}
101impl PosLookat {
102 pub fn new(position: na::Point3<f32>, lookat: na::Point3<f32>) -> Self {
103 Self {
104 position,
105 lookat,
106 ..Default::default()
107 }
108 }
109
110 pub fn new_from_model_matrix(model_matrix: na::SimilarityMatrix3<f32>, dist_lookat: f32) -> Self {
113 let position = model_matrix.isometry.translation.vector;
114 let mat = model_matrix.isometry.to_matrix();
115 let rot: na::Matrix3<f32> = mat.fixed_view::<3, 3>(0, 0).into();
116 let axis_lookat = rot.column(1); let lookat = position + axis_lookat * dist_lookat;
118
119 let position = na::Point3::<f32>::from(position);
120 let lookat = na::Point3::<f32>::from(lookat);
121
122 Self {
123 position,
124 lookat,
125 up: na::Vector3::<f32>::new(0.0, 1.0, 0.0),
126 }
127 }
128
129 pub fn view_matrix(&self) -> na::Matrix4<f32> {
132 self.view_matrix_isometry().to_matrix()
133 }
134
135 pub fn view_matrix_isometry(&self) -> na::IsometryMatrix3<f32> {
139 na::IsometryMatrix3::<f32>::look_at_rh(&self.position, &self.lookat, &self.up)
140 }
141
142 pub fn direction(&self) -> na::Vector3<f32> {
144 (self.lookat - self.position).normalize()
145 }
146
147 pub fn model_matrix_isometry(&self) -> na::IsometryMatrix3<f32> {
151 self.view_matrix_isometry().inverse()
152 }
153
154 pub fn model_matrix(&self) -> na::Matrix4<f32> {
157 self.model_matrix_isometry().to_matrix()
158 }
159
160 pub fn cam_axes(&self) -> na::Matrix3<f32> {
164 let model_matrix = self.model_matrix();
165 let rot = model_matrix.fixed_view::<3, 3>(0, 0);
166 rot.into()
167 }
168
169 pub fn dolly(&mut self, s: f32) {
171 let eye_look_vec = self.lookat - self.position; let movement = eye_look_vec * s;
173 self.position += movement;
174 }
175
176 pub fn orbit(&mut self, rot: na::Rotation3<f32>) {
178 let model_matrix = self.model_matrix_isometry();
181
182 let trans_to_look_at = na::Translation3::from(-self.lookat);
183 let trans_back = na::Translation3::from(self.lookat);
184
185 let model_matrix_rotated = trans_back * rot * trans_to_look_at * model_matrix;
186
187 self.position = model_matrix_rotated.translation.vector.into();
189
190 let model_matrix_rotated_mat = model_matrix_rotated.to_matrix();
197 let cam_axes_after = model_matrix_rotated_mat.fixed_view::<3, 3>(0, 0);
198 let up_cam_axis = cam_axes_after.column(1);
199 let dot_up = self.up.dot(&up_cam_axis);
200 if dot_up < 0.0 {
201 self.up = -self.up;
202 }
203 }
204
205 pub fn orbit_y(&mut self, degrees: f32) {
207 let axis = na::Vector3::y_axis();
208 let rot = na::Rotation3::from_axis_angle(&axis, degrees.to_radians());
209
210 self.orbit(rot);
211 }
212
213 pub fn shift_cam(&mut self, pos: na::Point3<f32>) {
216 let displacement = pos - self.position;
217 self.position += displacement;
218 self.lookat += displacement;
219 }
220
221 pub fn shift_lookat(&mut self, pos: na::Point3<f32>) {
224 let displacement = pos - self.lookat;
225 self.position += displacement;
226 self.lookat += displacement;
227 }
228
229 pub fn dist_lookat(&self) -> f32 {
231 (self.position - self.lookat).norm()
232 }
233}
234
235impl Default for Projection {
236 fn default() -> Self {
237 Self::WithFov(ProjectionWithFov::default())
238 }
239}
240impl Projection {
241 pub fn proj_matrix(&self, width: u32, height: u32) -> na::Matrix4<f32> {
245 match self {
246 Projection::WithFov(proj) => proj.proj_matrix(),
247 Projection::WithIntrinsics(proj) => proj.proj_matrix(width, height),
248 }
249 }
250 pub fn proj_matrix_reverse_z(&self, width: u32, height: u32) -> na::Matrix4<f32> {
254 match self {
255 Projection::WithFov(proj) => proj.proj_matrix_reverse_z(),
256 Projection::WithIntrinsics(proj) => proj.proj_matrix_reverse_z(width, height),
257 }
258 }
259 pub fn near_far(&self) -> (f32, f32) {
260 match self {
261 Projection::WithFov(proj) => (proj.near, proj.far),
262 Projection::WithIntrinsics(proj) => (proj.near, proj.far),
263 }
264 }
265 pub fn set_near(&mut self, val: f32) {
266 match self {
267 Projection::WithFov(ref mut proj) => proj.near = val,
268 Projection::WithIntrinsics(ref mut proj) => proj.near = val,
269 }
270 }
271 pub fn set_far(&mut self, val: f32) {
272 match self {
273 Projection::WithFov(ref mut proj) => proj.far = val,
274 Projection::WithIntrinsics(ref mut proj) => proj.far = val,
275 }
276 }
277}
278
279impl Default for ProjectionWithFov {
281 fn default() -> Self {
282 Self {
283 aspect_ratio: 1.6,
284 fovy: 0.7, near: 0.01,
286 far: 100.0,
287 }
288 }
289}
290impl ProjectionWithFov {
291 pub fn proj_matrix(&self) -> na::Matrix4<f32> {
294 glm::perspective_rh_zo(self.aspect_ratio, self.fovy, self.near, self.far)
295 }
296 pub fn proj_matrix_reverse_z(&self) -> na::Matrix4<f32> {
301 let mat = self.proj_matrix();
311
312 let mut depth_remap = glm::TMat4::identity();
320 depth_remap[(2, 2)] = -1.0;
321 depth_remap[(2, 3)] = 1.0;
322
323 depth_remap * mat
324 }
328}
329
330impl ProjectionWithIntrinsics {
331 #[allow(clippy::cast_precision_loss)]
332 pub fn proj_matrix(&self, width: u32, height: u32) -> na::Matrix4<f32> {
333 let mut projection_matrix = na::Matrix4::<f32>::zeros();
334
335 projection_matrix[(0, 0)] = 2.0 * self.fx / width as f32;
337 projection_matrix[(1, 1)] = 2.0 * self.fy / height as f32;
338 projection_matrix[(0, 2)] = 1.0 - (2.0 * self.cx / width as f32);
339 projection_matrix[(1, 2)] = (2.0 * self.cy / height as f32) - 1.0;
340 projection_matrix[(2, 2)] = -self.far / (self.far - self.near);
344 projection_matrix[(2, 3)] = -self.far * self.near / (self.far - self.near);
345 projection_matrix[(3, 2)] = -1.0;
346 projection_matrix
347 }
348
349 pub fn proj_matrix_reverse_z(&self, width: u32, height: u32) -> na::Matrix4<f32> {
350 let mat = self.proj_matrix(width, height);
351
352 let mut depth_remap = glm::TMat4::identity();
353 depth_remap[(2, 2)] = -1.0;
354 depth_remap[(2, 3)] = 1.0;
355
356 depth_remap * mat
357 }
361}
362impl Default for CamController {
364 fn default() -> Self {
365 Self {
366 mouse_mode: CamMode::Rotation,
367 mouse_pressed: false,
368 prev_mouse_pos_valid: false,
369 prev_mouse: na::Vector2::<f32>::zeros(),
370 limit_max_dist: None,
371 limit_max_vertical_angle: None,
372 limit_min_vertical_angle: None,
373 id2active_touches: HashMap::new(),
374 cursor_position: None,
375 last_press: None,
376 is_last_press_click: false,
377 mouse_moved_while_pressed: false,
378 }
379 }
380}
381impl CamController {
382 pub fn new(limit_max_dist: Option<f32>, limit_max_vertical_angle: Option<f32>, limit_min_vertical_angle: Option<f32>) -> Self {
383 Self {
384 limit_max_dist,
385 limit_max_vertical_angle,
386 limit_min_vertical_angle,
387 ..Default::default()
388 }
389 }
390 pub fn decide_if_click(&mut self) {
391 if let Some(last_press) = self.last_press {
392 if last_press.elapsed().as_millis() < CLICK_DURATION_MS {
393 self.is_last_press_click = true;
395 }
396 }
397 }
398}