use fj_interop::model::Model;
use tracing::warn;
use crate::{
camera::{Camera, FocusPoint},
graphics::{DrawConfig, Renderer},
input::InputHandler,
InputEvent, NormalizedScreenPosition, RendererInitError, Screen,
ScreenSize,
};
pub struct Viewer {
camera: Camera,
cursor: Option<NormalizedScreenPosition>,
draw_config: DrawConfig,
focus_point: Option<FocusPoint>,
renderer: Renderer,
model: Option<Model>,
}
impl Viewer {
pub async fn new(screen: &impl Screen) -> Result<Self, RendererInitError> {
let renderer = Renderer::new(screen).await?;
Ok(Self {
camera: Camera::default(),
cursor: None,
draw_config: DrawConfig::default(),
focus_point: None,
renderer,
model: None,
})
}
pub fn cursor(&mut self) -> &mut Option<NormalizedScreenPosition> {
&mut self.cursor
}
pub fn toggle_draw_model(&mut self) {
self.draw_config.draw_model = !self.draw_config.draw_model;
}
pub fn toggle_draw_mesh(&mut self) {
self.draw_config.draw_mesh = !self.draw_config.draw_mesh;
}
pub fn handle_model_update(&mut self, model: Model) {
self.renderer.update_geometry((&model.mesh).into());
let aabb = model.aabb;
if self.model.replace(model).is_none() {
self.camera.init_planes(&aabb);
}
}
pub fn handle_input_event(&mut self, event: InputEvent) {
if let Some(focus_point) = self.focus_point {
InputHandler::handle_event(event, focus_point, &mut self.camera);
}
}
pub fn handle_screen_resize(&mut self, screen_size: ScreenSize) {
self.renderer.handle_resize(screen_size);
}
pub fn add_focus_point(&mut self) {
if let Some(model) = &self.model {
if self.focus_point.is_none() {
self.focus_point =
Some(self.camera.focus_point(self.cursor, model));
}
}
}
pub fn remove_focus_point(&mut self) {
self.focus_point = None;
}
pub fn draw(&mut self) {
let aabb = self
.model
.as_ref()
.map(|shape| shape.aabb)
.unwrap_or_default();
self.camera.update_planes(&aabb);
if let Err(err) = self.renderer.draw(&self.camera, &self.draw_config) {
warn!("Draw error: {}", err);
}
}
}