fj_viewer/
viewer.rs

1use fj_interop::Model;
2use tracing::warn;
3
4use crate::{
5    camera::{Camera, FocusPoint},
6    graphics::{DrawConfig, Renderer},
7    input::InputHandler,
8    InputEvent, NormalizedScreenPosition, RendererInitError, Screen,
9    ScreenSize,
10};
11
12/// The Fornjot model viewer
13pub struct Viewer {
14    camera: Camera,
15    cursor: Option<NormalizedScreenPosition>,
16    draw_config: DrawConfig,
17    focus_point: Option<FocusPoint>,
18    renderer: Renderer,
19    model: Option<Model>,
20}
21
22impl Viewer {
23    /// Construct a new instance of `Viewer`
24    pub async fn new(screen: &impl Screen) -> Result<Self, RendererInitError> {
25        let renderer = Renderer::new(screen).await?;
26
27        Ok(Self {
28            camera: Camera::default(),
29            cursor: None,
30            draw_config: DrawConfig::default(),
31            focus_point: None,
32            renderer,
33            model: None,
34        })
35    }
36
37    /// Access the cursor
38    pub fn cursor(&mut self) -> &mut Option<NormalizedScreenPosition> {
39        &mut self.cursor
40    }
41
42    /// Toggle the "draw model" setting
43    pub fn toggle_draw_model(&mut self) {
44        self.draw_config.draw_model = !self.draw_config.draw_model;
45    }
46
47    /// Toggle the "draw mesh" setting
48    pub fn toggle_draw_mesh(&mut self) {
49        self.draw_config.draw_mesh = !self.draw_config.draw_mesh;
50    }
51
52    /// Handle the model being updated
53    pub fn handle_model_update(&mut self, model: Model) {
54        self.renderer.update_geometry((&model.mesh).into());
55
56        let aabb = model.aabb;
57        if self.model.replace(model).is_none() {
58            self.camera.init_planes(&aabb);
59        }
60    }
61
62    /// Handle an input event
63    pub fn handle_input_event(&mut self, event: InputEvent) {
64        if let Some(focus_point) = self.focus_point {
65            InputHandler::handle_event(event, focus_point, &mut self.camera);
66        }
67    }
68
69    /// Handle the screen being resized
70    pub fn handle_screen_resize(&mut self, screen_size: ScreenSize) {
71        self.renderer.handle_resize(screen_size);
72    }
73
74    /// Compute and store a focus point, unless one is already stored
75    pub fn add_focus_point(&mut self) {
76        if let Some(model) = &self.model {
77            if self.focus_point.is_none() {
78                self.focus_point =
79                    Some(self.camera.focus_point(self.cursor, model));
80            }
81        }
82    }
83
84    /// Remove the stored focus point
85    pub fn remove_focus_point(&mut self) {
86        self.focus_point = None;
87    }
88
89    /// Draw the graphics
90    pub fn draw(&mut self) {
91        let aabb = self
92            .model
93            .as_ref()
94            .map(|shape| shape.aabb)
95            .unwrap_or_default();
96
97        self.camera.update_planes(&aabb);
98
99        if let Err(err) = self.renderer.draw(&self.camera, &self.draw_config) {
100            warn!("Draw error: {}", err);
101        }
102    }
103}