From d475bd262076a73adda916301d05381d01a384e4 Mon Sep 17 00:00:00 2001 From: Sam Jeeves Date: Tue, 12 Jul 2022 10:31:05 +0200 Subject: [PATCH 1/8] High-level fj-viewer events --- crates/fj-viewer/src/camera.rs | 27 ++++-- crates/fj-viewer/src/input/event.rs | 37 ++++++-- crates/fj-viewer/src/input/handler.rs | 108 ++++++---------------- crates/fj-viewer/src/input/movement.rs | 64 +++++-------- crates/fj-viewer/src/input/rotation.rs | 88 ++++++++---------- crates/fj-viewer/src/input/zoom.rs | 41 +-------- crates/fj-viewer/src/screen.rs | 11 +++ crates/fj-window/src/run.rs | 121 +++++++++++++------------ 8 files changed, 211 insertions(+), 286 deletions(-) diff --git a/crates/fj-viewer/src/camera.rs b/crates/fj-viewer/src/camera.rs index 0a3d5f8a3..13a86d3ff 100644 --- a/crates/fj-viewer/src/camera.rs +++ b/crates/fj-viewer/src/camera.rs @@ -4,7 +4,7 @@ use std::f64::consts::FRAC_PI_2; use fj_interop::mesh::Mesh; use fj_math::{Aabb, Point, Scalar, Transform, Triangle, Vector}; -use crate::screen::{Position, Size}; +use crate::screen::{NormalizedPosition, Position, Size}; /// The camera abstraction /// @@ -104,6 +104,19 @@ impl Camera { .inverse_transform_point(&Point::<3>::origin()) } + /// Transform a normalized cursor position on the near plane to model space. + pub fn normalized_cursor_to_model_space( + &self, + cursor: NormalizedPosition, + ) -> Point<3> { + // Cursor position in camera space. + let f = (self.field_of_view_in_x() / 2.).tan() * self.near_plane(); + let cursor = Point::origin() + + Vector::from([cursor.x * f, cursor.y * f, -self.near_plane()]); + + self.camera_to_model().inverse_transform_point(&cursor) + } + /// Transform the position of the cursor on the near plane to model space. pub fn cursor_to_model_space( &self, @@ -118,19 +131,13 @@ impl Camera { let x = cursor.x / width * 2. - 1.; let y = -(cursor.y / height * 2. - 1.) / aspect_ratio; - // Cursor position in camera space. - let f = (self.field_of_view_in_x() / 2.).tan() * self.near_plane(); - let cursor = - Point::origin() + Vector::from([x * f, y * f, -self.near_plane()]); - - self.camera_to_model().inverse_transform_point(&cursor) + self.normalized_cursor_to_model_space(NormalizedPosition { x, y }) } /// Compute the point on the model, that the cursor currently points to. pub fn focus_point( &self, - size: Size, - cursor: Option, + cursor: Option, mesh: &Mesh>, ) -> FocusPoint { let cursor = match cursor { @@ -140,7 +147,7 @@ impl Camera { // Transform camera and cursor positions to model space. let origin = self.position(); - let cursor = self.cursor_to_model_space(cursor, size); + let cursor = self.normalized_cursor_to_model_space(cursor); let dir = (cursor - origin).normalize(); let mut min_t = None; diff --git a/crates/fj-viewer/src/input/event.rs b/crates/fj-viewer/src/input/event.rs index 0160e578e..1b142b154 100644 --- a/crates/fj-viewer/src/input/event.rs +++ b/crates/fj-viewer/src/input/event.rs @@ -1,15 +1,38 @@ -use crate::screen::Position; +use crate::{camera::FocusPoint, screen::NormalizedPosition}; /// An input event pub enum Event { - /// The cursor has moved to another position - CursorMoved(Position), + /// A new focus point was selected. + FocusPoint(FocusPoint), - /// A key has been pressed or released - Key(Key, KeyState), + /// Move the view up, down, left or right + Pan { + /// The normalized position of the cursor before input + previous: NormalizedPosition, + /// The normalized position of the cursor after input + current: NormalizedPosition, + }, - /// The user scrolled - Scroll(MouseScrollDelta), + /// Rotate the view around the focus point + Orbit { + /// The normalized position of the cursor before input + previous: NormalizedPosition, + /// The normalized position of the cursor after input + current: NormalizedPosition, + }, + + /// Move the view forwards and backwards + Zoom(f64), + + /// Application should exit + Exit, + + /// Toggle the shaded display of the model. + ToggleModel, + /// Toggle the model's wireframe. + ToggleMesh, + /// Toggle debug information. + ToggleDebug, } /// Describes a difference in the vertical mouse scroll wheel state. diff --git a/crates/fj-viewer/src/input/handler.rs b/crates/fj-viewer/src/input/handler.rs index 7bc24446c..e9fa6194f 100644 --- a/crates/fj-viewer/src/input/handler.rs +++ b/crates/fj-viewer/src/input/handler.rs @@ -1,20 +1,11 @@ -use fj_interop::mesh::Mesh; -use fj_math::Point; - -use super::{ - event::KeyState, movement::Movement, rotation::Rotation, zoom::Zoom, Event, - Key, -}; -use crate::{ - camera::Camera, - screen::{Position, Size}, -}; +use super::{movement::Movement, rotation::Rotation, zoom::Zoom, Event}; +use crate::camera::{Camera, FocusPoint}; /// Input handling abstraction /// /// Takes user input and applies them to application state. pub struct Handler { - cursor: Option, + focus_point: FocusPoint, movement: Movement, rotation: Rotation, @@ -22,92 +13,47 @@ pub struct Handler { } impl Handler { - /// Returns the state of the cursor position. - pub fn cursor(&self) -> Option { - self.cursor - } - /// Handle an input event pub fn handle_event( &mut self, event: Event, - screen_size: Size, - mesh: &Mesh>, camera: &mut Camera, actions: &mut Actions, ) { match event { - Event::CursorMoved(position) => { - if let Some(previous) = self.cursor { - let diff_x = position.x - previous.x; - let diff_y = position.y - previous.y; - - self.movement.apply(self.cursor, camera, screen_size); - self.rotation.apply(diff_x, diff_y, camera); - } - - self.cursor = Some(position); - } - Event::Key(Key::Escape, KeyState::Pressed) => actions.exit = true, - - Event::Key(Key::Key1, KeyState::Pressed) => { - actions.toggle_model = true - } - Event::Key(Key::Key2, KeyState::Pressed) => { - actions.toggle_mesh = true - } - Event::Key(Key::Key3, KeyState::Pressed) => { - actions.toggle_debug = true - } - - Event::Key(Key::MouseLeft, KeyState::Pressed) => { - let focus_point = - camera.focus_point(screen_size, self.cursor(), mesh); - - self.rotation.start(focus_point); + Event::FocusPoint(focus_point) => self.focus_point = focus_point, + Event::Pan { previous, current } => self.movement.apply( + previous, + current, + &self.focus_point, + camera, + ), + Event::Orbit { previous, current } => self.rotation.apply( + previous, + current, + &self.focus_point, + camera, + ), + Event::Zoom(zoom_delta) => { + self.zoom + .apply_to_camera(zoom_delta, &self.focus_point, camera) } - Event::Key(Key::MouseLeft, KeyState::Released) => { - self.rotation.stop(); - } - Event::Key(Key::MouseRight, KeyState::Pressed) => { - let focus_point = - camera.focus_point(screen_size, self.cursor(), mesh); - - self.movement.start(focus_point, self.cursor); - } - Event::Key(Key::MouseRight, KeyState::Released) => { - self.movement.stop(); - } - - Event::Scroll(delta) => { - self.zoom.push(delta); - } - - _ => {} + Event::Exit => actions.exit = true, + Event::ToggleModel => actions.toggle_model = true, + Event::ToggleMesh => actions.toggle_mesh = true, + Event::ToggleDebug => actions.toggle_debug = true, } } - - /// Update application state from user input. - pub fn update( - &mut self, - delta_t: f64, - camera: &mut Camera, - screen_size: Size, - mesh: &Mesh>, - ) { - let focus_point = camera.focus_point(screen_size, self.cursor(), mesh); - self.zoom.apply_to_camera(delta_t, focus_point, camera); - } } impl Default for Handler { fn default() -> Self { Self { - cursor: None, + focus_point: FocusPoint::none(), - movement: Movement::new(), - rotation: Rotation::new(), - zoom: Zoom::new(), + movement: Movement, + rotation: Rotation, + zoom: Zoom, } } } diff --git a/crates/fj-viewer/src/input/movement.rs b/crates/fj-viewer/src/input/movement.rs index b1e4aeba8..cc1c75b1b 100644 --- a/crates/fj-viewer/src/input/movement.rs +++ b/crates/fj-viewer/src/input/movement.rs @@ -2,57 +2,35 @@ use fj_math::{Point, Scalar, Transform, Vector}; use crate::{ camera::{Camera, FocusPoint}, - screen::{Position, Size}, + screen::NormalizedPosition, }; -pub struct Movement { - focus_point: FocusPoint, - cursor: Option, -} +pub struct Movement; impl Movement { - pub fn new() -> Self { - Self { - focus_point: FocusPoint::none(), - cursor: None, - } - } - - pub fn start(&mut self, focus_point: FocusPoint, cursor: Option) { - self.focus_point = focus_point; - self.cursor = cursor; - } - - pub fn stop(&mut self) { - self.focus_point = FocusPoint::none(); - } - pub fn apply( &mut self, - cursor: Option, + previous: NormalizedPosition, + current: NormalizedPosition, + focus_point: &FocusPoint, camera: &mut Camera, - size: Size, ) { - if let (Some(previous), Some(cursor)) = (self.cursor, cursor) { - let previous = camera.cursor_to_model_space(previous, size); - let cursor = camera.cursor_to_model_space(cursor, size); - - if let Some(focus_point) = self.focus_point.0 { - let d1 = Point::distance(&camera.position(), &cursor); - let d2 = Point::distance(&camera.position(), &focus_point); - - let diff = (cursor - previous) * d2 / d1; - let offset = camera.camera_to_model().transform_vector(&diff); - - camera.translation = camera.translation - * Transform::translation(Vector::from([ - offset.x, - offset.y, - Scalar::ZERO, - ])); - } + let previous = camera.normalized_cursor_to_model_space(previous); + let cursor = camera.normalized_cursor_to_model_space(current); + + if let Some(focus_point) = focus_point.0 { + let d1 = Point::distance(&camera.position(), &cursor); + let d2 = Point::distance(&camera.position(), &focus_point); + + let diff = (cursor - previous) * d2 / d1; + let offset = camera.camera_to_model().transform_vector(&diff); + + camera.translation = camera.translation + * Transform::translation(Vector::from([ + offset.x, + offset.y, + Scalar::ZERO, + ])); } - - self.cursor = cursor; } } diff --git a/crates/fj-viewer/src/input/rotation.rs b/crates/fj-viewer/src/input/rotation.rs index 84f627a31..71f58118c 100644 --- a/crates/fj-viewer/src/input/rotation.rs +++ b/crates/fj-viewer/src/input/rotation.rs @@ -1,57 +1,47 @@ use fj_math::{Point, Transform, Vector}; -use crate::camera::{Camera, FocusPoint}; +use crate::{ + camera::{Camera, FocusPoint}, + screen::NormalizedPosition, +}; -pub struct Rotation { - active: bool, - focus_point: FocusPoint, -} +pub struct Rotation; impl Rotation { - pub fn new() -> Self { - Self { - active: false, - focus_point: FocusPoint::none(), - } - } - - pub fn start(&mut self, focus_point: FocusPoint) { - self.active = true; - self.focus_point = focus_point; - } - - pub fn stop(&mut self) { - self.active = false; - } - - pub fn apply(&self, diff_x: f64, diff_y: f64, camera: &mut Camera) { - if self.active { - let rotate_around: Vector<3> = - self.focus_point.0.unwrap_or_else(Point::origin).coords; - - let f = 0.005; - - let angle_x = diff_y * f; - let angle_y = diff_x * f; - - let rotate_around = Transform::translation(rotate_around); - - // the model rotates not the camera, so invert the transform - let camera_rotation = camera.rotation.inverse(); - let right_vector = right_vector(&camera_rotation); - let up_vector = up_vector(&camera_rotation); - - let rotation = Transform::rotation(right_vector * angle_x) - * Transform::rotation(up_vector * angle_y); - - let transform = camera.camera_to_model() - * rotate_around - * rotation - * rotate_around.inverse(); - - camera.rotation = transform.extract_rotation(); - camera.translation = transform.extract_translation(); - } + pub fn apply( + &self, + previous: NormalizedPosition, + current: NormalizedPosition, + focus_point: &FocusPoint, + camera: &mut Camera, + ) { + let rotate_around: Vector<3> = + focus_point.0.unwrap_or_else(Point::origin).coords; + + let f = -5.; + + let diff_x = current.x - previous.x; + let diff_y = current.y - previous.y; + let angle_x = diff_y * f; + let angle_y = -diff_x * f; + + let rotate_around = Transform::translation(rotate_around); + + // the model rotates not the camera, so invert the transform + let camera_rotation = camera.rotation.inverse(); + let right_vector = right_vector(&camera_rotation); + let up_vector = up_vector(&camera_rotation); + + let rotation = Transform::rotation(right_vector * angle_x) + * Transform::rotation(up_vector * angle_y); + + let transform = camera.camera_to_model() + * rotate_around + * rotation + * rotate_around.inverse(); + + camera.rotation = transform.extract_rotation(); + camera.translation = transform.extract_translation(); } } diff --git a/crates/fj-viewer/src/input/zoom.rs b/crates/fj-viewer/src/input/zoom.rs index b95765281..14984408f 100644 --- a/crates/fj-viewer/src/input/zoom.rs +++ b/crates/fj-viewer/src/input/zoom.rs @@ -2,54 +2,21 @@ use fj_math::{Transform, Vector}; use crate::camera::{Camera, FocusPoint}; -use super::event::MouseScrollDelta; - -pub struct Zoom { - accumulated_delta: f64, -} +pub struct Zoom; impl Zoom { - pub fn new() -> Self { - Self { - accumulated_delta: 0.0, - } - } - - pub fn push(&mut self, delta: MouseScrollDelta) { - // Accumulate all zoom inputs - self.accumulated_delta += match delta { - MouseScrollDelta::Line(delta) => ZOOM_FACTOR_LINE * delta, - MouseScrollDelta::Pixel(delta) => ZOOM_FACTOR_PIXEL * delta, - }; - } - pub fn apply_to_camera( &mut self, - delta_t: f64, - focus_point: FocusPoint, + zoom_delta: f64, + focus_point: &FocusPoint, camera: &mut Camera, ) { let distance = match focus_point.0 { Some(fp) => (fp - camera.position()).magnitude(), None => camera.position().coords.magnitude(), }; - let displacement = - self.accumulated_delta * delta_t * distance.into_f64(); + let displacement = zoom_delta * distance.into_f64(); camera.translation = camera.translation * Transform::translation(Vector::from([0.0, 0.0, -displacement])); - - self.accumulated_delta = 0.; } } - -/// Affects the speed of zoom movement given a scroll wheel input in lines. -/// -/// Smaller values will move the camera less with the same input. -/// Larger values will move the camera more with the same input. -const ZOOM_FACTOR_LINE: f64 = 15.0; - -/// Affects the speed of zoom movement given a scroll wheel input in pixels. -/// -/// Smaller values will move the camera less with the same input. -/// Larger values will move the camera more with the same input. -const ZOOM_FACTOR_PIXEL: f64 = 1.0; diff --git a/crates/fj-viewer/src/screen.rs b/crates/fj-viewer/src/screen.rs index 5b3e8678e..d857383bb 100644 --- a/crates/fj-viewer/src/screen.rs +++ b/crates/fj-viewer/src/screen.rs @@ -24,6 +24,17 @@ pub struct Position { pub y: f64, } +/// Cursor position in normalized coordinates (-1 to +1) with aspect ratio taken into account. +/// i.e. the center of the screen is at (0, 0) +#[derive(Clone, Copy, Debug)] +pub struct NormalizedPosition { + /// The x coordinate of the position + pub x: f64, + + /// The y coordinate of the position + pub y: f64, +} + /// The size of the screen #[derive(Clone, Copy, Debug)] pub struct Size { diff --git a/crates/fj-window/src/run.rs b/crates/fj-window/src/run.rs index a732d6026..6122e798a 100644 --- a/crates/fj-window/src/run.rs +++ b/crates/fj-window/src/run.rs @@ -3,15 +3,15 @@ //! Provides the functionality to create a window and perform basic viewing //! with programmed models. -use std::{error, time::Instant}; +use std::error; use fj_host::Watcher; use fj_operations::shape_processor::ShapeProcessor; use fj_viewer::{ camera::Camera, graphics::{self, DrawConfig, Renderer}, - input::{self, KeyState}, - screen::{Position, Screen as _, Size}, + input, + screen::{NormalizedPosition, Screen as _, Size}, }; use futures::executor::block_on; use tracing::{trace, warn}; @@ -34,7 +34,8 @@ pub fn run( let event_loop = EventLoop::new(); let window = Window::new(&event_loop)?; - let mut previous_time = Instant::now(); + let mut previous_cursor = None; + let mut held_mouse_button = None; let mut input_handler = input::Handler::default(); let mut renderer = block_on(Renderer::new(&window))?; @@ -49,8 +50,6 @@ pub fn run( let mut actions = input::Actions::new(); - let now = Instant::now(); - if let Some(new_shape) = watcher.receive() { match shape_processor.process(&new_shape) { Ok(new_shape) => { @@ -148,19 +147,10 @@ pub fn run( }, .. } => match virtual_key_code { - VirtualKeyCode::Escape => Some(input::Event::Key( - input::Key::Escape, - KeyState::Pressed, - )), - VirtualKeyCode::Key1 => { - Some(input::Event::Key(input::Key::Key1, KeyState::Pressed)) - } - VirtualKeyCode::Key2 => { - Some(input::Event::Key(input::Key::Key2, KeyState::Pressed)) - } - VirtualKeyCode::Key3 => { - Some(input::Event::Key(input::Key::Key3, KeyState::Pressed)) - } + VirtualKeyCode::Escape => Some(input::Event::Exit), + VirtualKeyCode::Key1 => Some(input::Event::ToggleModel), + VirtualKeyCode::Key2 => Some(input::Event::ToggleMesh), + VirtualKeyCode::Key3 => Some(input::Event::ToggleDebug), _ => None, }, @@ -168,55 +158,64 @@ pub fn run( event: WindowEvent::CursorMoved { position, .. }, .. } => { - let position = Position { - x: position.x, - y: position.y, + let [width, height] = window.size().as_f64(); + let aspect_ratio = width / height; + + // Cursor position in normalized coordinates (-1 to +1) with + // aspect ratio taken into account. + let current = NormalizedPosition { + x: position.x / width * 2. - 1., + y: -(position.y / height * 2. - 1.) / aspect_ratio, }; - Some(input::Event::CursorMoved(position)) + let event = match (previous_cursor, held_mouse_button) { + (Some(previous), Some(button)) => match button { + MouseButton::Left => { + Some(input::Event::Orbit { previous, current }) + } + MouseButton::Right => { + Some(input::Event::Pan { previous, current }) + } + _ => None, + }, + _ => None, + }; + previous_cursor = Some(current); + event } Event::WindowEvent { event: WindowEvent::MouseInput { state, button, .. }, .. } => { - let state = match state { - ElementState::Pressed => input::KeyState::Pressed, - ElementState::Released => input::KeyState::Released, + match state { + ElementState::Pressed => held_mouse_button = Some(button), + ElementState::Released => held_mouse_button = None, }; - - match button { - MouseButton::Left => { - Some(input::Event::Key(input::Key::MouseLeft, state)) - } - MouseButton::Right => { - Some(input::Event::Key(input::Key::MouseRight, state)) + if let (Some(shape), Some(camera)) = (&shape, &camera) { + match button { + MouseButton::Left | MouseButton::Right => { + Some(input::Event::FocusPoint( + camera + .focus_point(previous_cursor, &shape.mesh), + )) + } + _ => None, } - _ => None, + } else { + None } } Event::WindowEvent { event: WindowEvent::MouseWheel { delta, .. }, .. - } => Some(input::Event::Scroll(match delta { + } => Some(input::Event::Zoom(match delta { MouseScrollDelta::LineDelta(_, y) => { - input::MouseScrollDelta::Line(y as f64) + (y as f64) * ZOOM_FACTOR_LINE } MouseScrollDelta::PixelDelta(PhysicalPosition { y, .. - }) => input::MouseScrollDelta::Pixel(y), + }) => y * ZOOM_FACTOR_PIXEL, })), Event::MainEventsCleared => { - let delta_t = now.duration_since(previous_time); - previous_time = now; - - if let (Some(shape), Some(camera)) = (&shape, &mut camera) { - input_handler.update( - delta_t.as_secs_f64(), - camera, - window.size(), - &shape.mesh, - ); - } - window.window().request_redraw(); None @@ -237,16 +236,8 @@ pub fn run( _ => None, }; - if let (Some(event), Some(shape), Some(camera)) = - (event, &shape, &mut camera) - { - input_handler.handle_event( - event, - window.size(), - &shape.mesh, - camera, - &mut actions, - ); + if let (Some(event), Some(camera)) = (event, &mut camera) { + input_handler.handle_event(event, camera, &mut actions); } if actions.exit { @@ -275,3 +266,15 @@ pub enum Error { #[error("Error initializing graphics")] GraphicsInit(#[from] graphics::InitError), } + +/// Affects the speed of zoom movement given a scroll wheel input in lines. +/// +/// Smaller values will move the camera less with the same input. +/// Larger values will move the camera more with the same input. +const ZOOM_FACTOR_LINE: f64 = 0.075; + +/// Affects the speed of zoom movement given a scroll wheel input in pixels. +/// +/// Smaller values will move the camera less with the same input. +/// Larger values will move the camera more with the same input. +const ZOOM_FACTOR_PIXEL: f64 = 0.005; From 4ff534c0ac618c76fd9d14a7a58ac6b15f8f6812 Mon Sep 17 00:00:00 2001 From: Sam Jeeves Date: Tue, 12 Jul 2022 10:56:18 +0200 Subject: [PATCH 2/8] Remove unneeded code --- crates/fj-viewer/src/camera.rs | 23 +++-------------------- crates/fj-viewer/src/input/handler.rs | 3 +-- crates/fj-viewer/src/input/movement.rs | 4 ++-- crates/fj-viewer/src/input/zoom.rs | 2 +- crates/fj-viewer/src/screen.rs | 14 ++------------ 5 files changed, 9 insertions(+), 37 deletions(-) diff --git a/crates/fj-viewer/src/camera.rs b/crates/fj-viewer/src/camera.rs index 13a86d3ff..5698aca0d 100644 --- a/crates/fj-viewer/src/camera.rs +++ b/crates/fj-viewer/src/camera.rs @@ -4,7 +4,7 @@ use std::f64::consts::FRAC_PI_2; use fj_interop::mesh::Mesh; use fj_math::{Aabb, Point, Scalar, Transform, Triangle, Vector}; -use crate::screen::{NormalizedPosition, Position, Size}; +use crate::screen::NormalizedPosition; /// The camera abstraction /// @@ -105,7 +105,7 @@ impl Camera { } /// Transform a normalized cursor position on the near plane to model space. - pub fn normalized_cursor_to_model_space( + pub fn cursor_to_model_space( &self, cursor: NormalizedPosition, ) -> Point<3> { @@ -117,23 +117,6 @@ impl Camera { self.camera_to_model().inverse_transform_point(&cursor) } - /// Transform the position of the cursor on the near plane to model space. - pub fn cursor_to_model_space( - &self, - cursor: Position, - size: Size, - ) -> Point<3> { - let [width, height] = size.as_f64(); - let aspect_ratio = width / height; - - // Cursor position in normalized coordinates (-1 to +1) with - // aspect ratio taken into account. - let x = cursor.x / width * 2. - 1.; - let y = -(cursor.y / height * 2. - 1.) / aspect_ratio; - - self.normalized_cursor_to_model_space(NormalizedPosition { x, y }) - } - /// Compute the point on the model, that the cursor currently points to. pub fn focus_point( &self, @@ -147,7 +130,7 @@ impl Camera { // Transform camera and cursor positions to model space. let origin = self.position(); - let cursor = self.normalized_cursor_to_model_space(cursor); + let cursor = self.cursor_to_model_space(cursor); let dir = (cursor - origin).normalize(); let mut min_t = None; diff --git a/crates/fj-viewer/src/input/handler.rs b/crates/fj-viewer/src/input/handler.rs index e9fa6194f..febcc1ad3 100644 --- a/crates/fj-viewer/src/input/handler.rs +++ b/crates/fj-viewer/src/input/handler.rs @@ -35,8 +35,7 @@ impl Handler { camera, ), Event::Zoom(zoom_delta) => { - self.zoom - .apply_to_camera(zoom_delta, &self.focus_point, camera) + self.zoom.apply(zoom_delta, &self.focus_point, camera) } Event::Exit => actions.exit = true, Event::ToggleModel => actions.toggle_model = true, diff --git a/crates/fj-viewer/src/input/movement.rs b/crates/fj-viewer/src/input/movement.rs index cc1c75b1b..058093207 100644 --- a/crates/fj-viewer/src/input/movement.rs +++ b/crates/fj-viewer/src/input/movement.rs @@ -15,8 +15,8 @@ impl Movement { focus_point: &FocusPoint, camera: &mut Camera, ) { - let previous = camera.normalized_cursor_to_model_space(previous); - let cursor = camera.normalized_cursor_to_model_space(current); + let previous = camera.cursor_to_model_space(previous); + let cursor = camera.cursor_to_model_space(current); if let Some(focus_point) = focus_point.0 { let d1 = Point::distance(&camera.position(), &cursor); diff --git a/crates/fj-viewer/src/input/zoom.rs b/crates/fj-viewer/src/input/zoom.rs index 14984408f..c6ddcb212 100644 --- a/crates/fj-viewer/src/input/zoom.rs +++ b/crates/fj-viewer/src/input/zoom.rs @@ -5,7 +5,7 @@ use crate::camera::{Camera, FocusPoint}; pub struct Zoom; impl Zoom { - pub fn apply_to_camera( + pub fn apply( &mut self, zoom_delta: f64, focus_point: &FocusPoint, diff --git a/crates/fj-viewer/src/screen.rs b/crates/fj-viewer/src/screen.rs index d857383bb..09c27dff3 100644 --- a/crates/fj-viewer/src/screen.rs +++ b/crates/fj-viewer/src/screen.rs @@ -14,24 +14,14 @@ pub trait Screen { fn window(&self) -> &Self::Window; } -/// A position on the screen -#[derive(Clone, Copy, Debug)] -pub struct Position { - /// The x coordinate of the position - pub x: f64, - - /// The y coordinate of the position - pub y: f64, -} - /// Cursor position in normalized coordinates (-1 to +1) with aspect ratio taken into account. /// i.e. the center of the screen is at (0, 0) #[derive(Clone, Copy, Debug)] pub struct NormalizedPosition { - /// The x coordinate of the position + /// The x coordinate of the position [-1, 1] pub x: f64, - /// The y coordinate of the position + /// The y coordinate of the position [-1, 1] pub y: f64, } From 19aa5e6f6a737d87799de7913cd8202130dcfd1b Mon Sep 17 00:00:00 2001 From: Sam Jeeves Date: Tue, 12 Jul 2022 11:04:36 +0200 Subject: [PATCH 3/8] Split event handling into window and input --- crates/fj-window/src/run.rs | 64 +++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 35 deletions(-) diff --git a/crates/fj-window/src/run.rs b/crates/fj-window/src/run.rs index 6122e798a..3255daf33 100644 --- a/crates/fj-window/src/run.rs +++ b/crates/fj-window/src/run.rs @@ -112,15 +112,13 @@ pub fn run( .on_event(&renderer.egui.context, window_event); } - // - - let event = match event { + // Window events + match event { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => { *control_flow = ControlFlow::Exit; - None } Event::WindowEvent { event: WindowEvent::Resized(size), @@ -131,9 +129,26 @@ pub fn run( height: size.height, }; renderer.handle_resize(size); + } + Event::MainEventsCleared => { + window.window().request_redraw(); + } + Event::RedrawRequested(_) => { + if let (Some(shape), Some(camera)) = (&shape, &mut camera) { + camera.update_planes(&shape.aabb); - None + if let Err(err) = + renderer.draw(camera, &mut draw_config, window.window()) + { + warn!("Draw error: {}", err); + } + } } + _ => {} + } + + // Viewer events + let event = match event { Event::WindowEvent { event: WindowEvent::KeyboardInput { @@ -190,18 +205,15 @@ pub fn run( ElementState::Pressed => held_mouse_button = Some(button), ElementState::Released => held_mouse_button = None, }; - if let (Some(shape), Some(camera)) = (&shape, &camera) { - match button { - MouseButton::Left | MouseButton::Right => { - Some(input::Event::FocusPoint( - camera - .focus_point(previous_cursor, &shape.mesh), - )) - } - _ => None, - } - } else { - None + match (&shape, &camera, button) { + ( + Some(shape), + Some(camera), + MouseButton::Left | MouseButton::Right, + ) => Some(input::Event::FocusPoint( + camera.focus_point(previous_cursor, &shape.mesh), + )), + _ => None, } } Event::WindowEvent { @@ -215,24 +227,6 @@ pub fn run( y, .. }) => y * ZOOM_FACTOR_PIXEL, })), - Event::MainEventsCleared => { - window.window().request_redraw(); - - None - } - Event::RedrawRequested(_) => { - if let (Some(shape), Some(camera)) = (&shape, &mut camera) { - camera.update_planes(&shape.aabb); - - if let Err(err) = - renderer.draw(camera, &mut draw_config, window.window()) - { - warn!("Draw error: {}", err); - } - } - - None - } _ => None, }; From 9a4f94d8a12581b33d501721351bd52762cf8449 Mon Sep 17 00:00:00 2001 From: Sam Jeeves Date: Tue, 12 Jul 2022 15:41:59 +0200 Subject: [PATCH 4/8] Ensure same focus point behavior --- crates/fj-window/src/run.rs | 209 +++++++++++++++++++++--------------- 1 file changed, 124 insertions(+), 85 deletions(-) diff --git a/crates/fj-window/src/run.rs b/crates/fj-window/src/run.rs index 3255daf33..101ee9bfc 100644 --- a/crates/fj-window/src/run.rs +++ b/crates/fj-window/src/run.rs @@ -6,9 +6,9 @@ use std::error; use fj_host::Watcher; -use fj_operations::shape_processor::ShapeProcessor; +use fj_operations::shape_processor::{ProcessedShape, ShapeProcessor}; use fj_viewer::{ - camera::Camera, + camera::{Camera, FocusPoint}, graphics::{self, DrawConfig, Renderer}, input, screen::{NormalizedPosition, Screen as _, Size}, @@ -130,6 +130,15 @@ pub fn run( }; renderer.handle_resize(size); } + Event::WindowEvent { + event: WindowEvent::MouseInput { state, button, .. }, + .. + } => { + match state { + ElementState::Pressed => held_mouse_button = Some(button), + ElementState::Released => held_mouse_button = None, + }; + } Event::MainEventsCleared => { window.window().request_redraw(); } @@ -147,91 +156,22 @@ pub fn run( _ => {} } - // Viewer events - let event = match event { - Event::WindowEvent { - event: - WindowEvent::KeyboardInput { - input: - KeyboardInput { - state: ElementState::Pressed, - virtual_keycode: Some(virtual_key_code), - .. - }, - .. - }, - .. - } => match virtual_key_code { - VirtualKeyCode::Escape => Some(input::Event::Exit), - VirtualKeyCode::Key1 => Some(input::Event::ToggleModel), - VirtualKeyCode::Key2 => Some(input::Event::ToggleMesh), - VirtualKeyCode::Key3 => Some(input::Event::ToggleDebug), - - _ => None, - }, - Event::WindowEvent { - event: WindowEvent::CursorMoved { position, .. }, - .. - } => { - let [width, height] = window.size().as_f64(); - let aspect_ratio = width / height; - - // Cursor position in normalized coordinates (-1 to +1) with - // aspect ratio taken into account. - let current = NormalizedPosition { - x: position.x / width * 2. - 1., - y: -(position.y / height * 2. - 1.) / aspect_ratio, - }; - let event = match (previous_cursor, held_mouse_button) { - (Some(previous), Some(button)) => match button { - MouseButton::Left => { - Some(input::Event::Orbit { previous, current }) - } - MouseButton::Right => { - Some(input::Event::Pan { previous, current }) - } - _ => None, - }, - _ => None, - }; - previous_cursor = Some(current); - event + if let (Some(shape), Some(camera)) = (&shape, &mut camera) { + if let Some(focus_event) = + focus_event(&event, previous_cursor, shape, camera) + { + input_handler.handle_event(focus_event, camera, &mut actions); } - Event::WindowEvent { - event: WindowEvent::MouseInput { state, button, .. }, - .. - } => { - match state { - ElementState::Pressed => held_mouse_button = Some(button), - ElementState::Released => held_mouse_button = None, - }; - match (&shape, &camera, button) { - ( - Some(shape), - Some(camera), - MouseButton::Left | MouseButton::Right, - ) => Some(input::Event::FocusPoint( - camera.focus_point(previous_cursor, &shape.mesh), - )), - _ => None, - } - } - Event::WindowEvent { - event: WindowEvent::MouseWheel { delta, .. }, - .. - } => Some(input::Event::Zoom(match delta { - MouseScrollDelta::LineDelta(_, y) => { - (y as f64) * ZOOM_FACTOR_LINE - } - MouseScrollDelta::PixelDelta(PhysicalPosition { - y, .. - }) => y * ZOOM_FACTOR_PIXEL, - })), - _ => None, - }; + } - if let (Some(event), Some(camera)) = (event, &mut camera) { - input_handler.handle_event(event, camera, &mut actions); + let input_event = input_event( + event, + &window, + &held_mouse_button, + &mut previous_cursor, + ); + if let (Some(input_event), Some(camera)) = (input_event, &mut camera) { + input_handler.handle_event(input_event, camera, &mut actions); } if actions.exit { @@ -249,6 +189,105 @@ pub fn run( }); } +fn input_event( + event: Event<()>, + window: &Window, + held_mouse_button: &Option, + previous_cursor: &mut Option, +) -> Option { + match event { + Event::WindowEvent { + event: + WindowEvent::KeyboardInput { + input: + KeyboardInput { + state: ElementState::Pressed, + virtual_keycode: Some(virtual_key_code), + .. + }, + .. + }, + .. + } => match virtual_key_code { + VirtualKeyCode::Escape => Some(input::Event::Exit), + VirtualKeyCode::Key1 => Some(input::Event::ToggleModel), + VirtualKeyCode::Key2 => Some(input::Event::ToggleMesh), + VirtualKeyCode::Key3 => Some(input::Event::ToggleDebug), + + _ => None, + }, + Event::WindowEvent { + event: WindowEvent::CursorMoved { position, .. }, + .. + } => { + let [width, height] = window.size().as_f64(); + let aspect_ratio = width / height; + + // Cursor position in normalized coordinates (-1 to +1) with + // aspect ratio taken into account. + let current = NormalizedPosition { + x: position.x / width * 2. - 1., + y: -(position.y / height * 2. - 1.) / aspect_ratio, + }; + let event = match (*previous_cursor, held_mouse_button) { + (Some(previous), Some(button)) => match button { + MouseButton::Left => { + Some(input::Event::Orbit { previous, current }) + } + MouseButton::Right => { + Some(input::Event::Pan { previous, current }) + } + _ => None, + }, + _ => None, + }; + *previous_cursor = Some(current); + event + } + Event::WindowEvent { + event: WindowEvent::MouseWheel { delta, .. }, + .. + } => Some(input::Event::Zoom(match delta { + MouseScrollDelta::LineDelta(_, y) => (y as f64) * ZOOM_FACTOR_LINE, + MouseScrollDelta::PixelDelta(PhysicalPosition { y, .. }) => { + y * ZOOM_FACTOR_PIXEL + } + })), + _ => None, + } +} + +fn focus_event( + event: &Event<()>, + previous_cursor: Option, + shape: &ProcessedShape, + camera: &Camera, +) -> Option { + let focus_point = match event { + Event::WindowEvent { + event: + WindowEvent::MouseInput { + state, + button: MouseButton::Left | MouseButton::Right, + .. + }, + .. + } => match state { + ElementState::Pressed => { + camera.focus_point(previous_cursor, &shape.mesh) + } + ElementState::Released => FocusPoint::none(), + }, + Event::WindowEvent { + event: WindowEvent::MouseWheel { .. }, + .. + } => camera.focus_point(previous_cursor, &shape.mesh), + + _ => return None, + }; + Some(input::Event::FocusPoint(focus_point)) +} + /// Error in main loop #[derive(Debug, thiserror::Error)] pub enum Error { From 99978cfc05a99723d8614e45196e7abf2297d399 Mon Sep 17 00:00:00 2001 From: Sam Jeeves Date: Tue, 12 Jul 2022 15:50:48 +0200 Subject: [PATCH 5/8] Remove Actions --- crates/fj-viewer/src/input/handler.rs | 35 ++------------------------- crates/fj-viewer/src/input/mod.rs | 2 +- crates/fj-window/src/run.rs | 35 ++++++++++++++------------- 3 files changed, 21 insertions(+), 51 deletions(-) diff --git a/crates/fj-viewer/src/input/handler.rs b/crates/fj-viewer/src/input/handler.rs index febcc1ad3..3ba7b1f89 100644 --- a/crates/fj-viewer/src/input/handler.rs +++ b/crates/fj-viewer/src/input/handler.rs @@ -14,12 +14,7 @@ pub struct Handler { impl Handler { /// Handle an input event - pub fn handle_event( - &mut self, - event: Event, - camera: &mut Camera, - actions: &mut Actions, - ) { + pub fn handle_event(&mut self, event: Event, camera: &mut Camera) { match event { Event::FocusPoint(focus_point) => self.focus_point = focus_point, Event::Pan { previous, current } => self.movement.apply( @@ -37,10 +32,7 @@ impl Handler { Event::Zoom(zoom_delta) => { self.zoom.apply(zoom_delta, &self.focus_point, camera) } - Event::Exit => actions.exit = true, - Event::ToggleModel => actions.toggle_model = true, - Event::ToggleMesh => actions.toggle_mesh = true, - Event::ToggleDebug => actions.toggle_debug = true, + _ => {} } } } @@ -56,26 +48,3 @@ impl Default for Handler { } } } - -/// Intermediate input state container -/// -/// Used as a per frame state container for sending application state to `winit`. -#[derive(Default)] -pub struct Actions { - /// Application exit state. - pub exit: bool, - - /// Toggle for the shaded display of the model. - pub toggle_model: bool, - /// Toggle for the model's wireframe. - pub toggle_mesh: bool, - /// Toggle for debug information. - pub toggle_debug: bool, -} - -impl Actions { - /// Returns a new `Actions`. - pub fn new() -> Self { - Self::default() - } -} diff --git a/crates/fj-viewer/src/input/mod.rs b/crates/fj-viewer/src/input/mod.rs index f206600f1..b95683d26 100644 --- a/crates/fj-viewer/src/input/mod.rs +++ b/crates/fj-viewer/src/input/mod.rs @@ -8,5 +8,5 @@ mod zoom; pub use self::{ event::{Event, Key, KeyState, MouseScrollDelta}, - handler::{Actions, Handler}, + handler::Handler, }; diff --git a/crates/fj-window/src/run.rs b/crates/fj-window/src/run.rs index 101ee9bfc..9e04ecae4 100644 --- a/crates/fj-window/src/run.rs +++ b/crates/fj-window/src/run.rs @@ -48,8 +48,6 @@ pub fn run( event_loop.run(move |event, _, control_flow| { trace!("Handling event: {:?}", event); - let mut actions = input::Actions::new(); - if let Some(new_shape) = watcher.receive() { match shape_processor.process(&new_shape) { Ok(new_shape) => { @@ -160,7 +158,7 @@ pub fn run( if let Some(focus_event) = focus_event(&event, previous_cursor, shape, camera) { - input_handler.handle_event(focus_event, camera, &mut actions); + input_handler.handle_event(focus_event, camera); } } @@ -170,21 +168,24 @@ pub fn run( &held_mouse_button, &mut previous_cursor, ); - if let (Some(input_event), Some(camera)) = (input_event, &mut camera) { - input_handler.handle_event(input_event, camera, &mut actions); - } + if let Some(input_event) = input_event { + match input_event { + input::Event::Exit => *control_flow = ControlFlow::Exit, + input::Event::ToggleModel => { + draw_config.draw_model = !draw_config.draw_model + } + input::Event::ToggleMesh => { + draw_config.draw_mesh = !draw_config.draw_mesh + } + input::Event::ToggleDebug => { + draw_config.draw_debug = !draw_config.draw_debug + } + _ => {} + }; - if actions.exit { - *control_flow = ControlFlow::Exit; - } - if actions.toggle_model { - draw_config.draw_model = !draw_config.draw_model; - } - if actions.toggle_mesh { - draw_config.draw_mesh = !draw_config.draw_mesh; - } - if actions.toggle_debug { - draw_config.draw_debug = !draw_config.draw_debug; + if let Some(camera) = &mut camera { + input_handler.handle_event(input_event, camera); + } } }); } From c177f881d49794f5837511a0b5cecd07677cecbb Mon Sep 17 00:00:00 2001 From: Sam Jeeves Date: Tue, 12 Jul 2022 16:04:01 +0200 Subject: [PATCH 6/8] Clearer separation between event types --- crates/fj-viewer/src/input/event.rs | 15 +---- crates/fj-viewer/src/input/handler.rs | 7 ++- crates/fj-window/src/run.rs | 84 ++++++++++++--------------- 3 files changed, 43 insertions(+), 63 deletions(-) diff --git a/crates/fj-viewer/src/input/event.rs b/crates/fj-viewer/src/input/event.rs index 1b142b154..9b49f1ade 100644 --- a/crates/fj-viewer/src/input/event.rs +++ b/crates/fj-viewer/src/input/event.rs @@ -1,10 +1,7 @@ -use crate::{camera::FocusPoint, screen::NormalizedPosition}; +use crate::screen::NormalizedPosition; /// An input event pub enum Event { - /// A new focus point was selected. - FocusPoint(FocusPoint), - /// Move the view up, down, left or right Pan { /// The normalized position of the cursor before input @@ -23,16 +20,6 @@ pub enum Event { /// Move the view forwards and backwards Zoom(f64), - - /// Application should exit - Exit, - - /// Toggle the shaded display of the model. - ToggleModel, - /// Toggle the model's wireframe. - ToggleMesh, - /// Toggle debug information. - ToggleDebug, } /// Describes a difference in the vertical mouse scroll wheel state. diff --git a/crates/fj-viewer/src/input/handler.rs b/crates/fj-viewer/src/input/handler.rs index 3ba7b1f89..d7f539f25 100644 --- a/crates/fj-viewer/src/input/handler.rs +++ b/crates/fj-viewer/src/input/handler.rs @@ -16,7 +16,6 @@ impl Handler { /// Handle an input event pub fn handle_event(&mut self, event: Event, camera: &mut Camera) { match event { - Event::FocusPoint(focus_point) => self.focus_point = focus_point, Event::Pan { previous, current } => self.movement.apply( previous, current, @@ -32,9 +31,13 @@ impl Handler { Event::Zoom(zoom_delta) => { self.zoom.apply(zoom_delta, &self.focus_point, camera) } - _ => {} } } + + /// A new focus point was selected (or deselected) + pub fn focus(&mut self, focus_point: FocusPoint) { + self.focus_point = focus_point; + } } impl Default for Handler { diff --git a/crates/fj-window/src/run.rs b/crates/fj-window/src/run.rs index 9e04ecae4..9fbe62795 100644 --- a/crates/fj-window/src/run.rs +++ b/crates/fj-window/src/run.rs @@ -110,7 +110,7 @@ pub fn run( .on_event(&renderer.egui.context, window_event); } - // Window events + // fj-window events match event { Event::WindowEvent { event: WindowEvent::CloseRequested, @@ -118,6 +118,31 @@ pub fn run( } => { *control_flow = ControlFlow::Exit; } + Event::WindowEvent { + event: + WindowEvent::KeyboardInput { + input: + KeyboardInput { + state: ElementState::Pressed, + virtual_keycode: Some(virtual_key_code), + .. + }, + .. + }, + .. + } => match virtual_key_code { + VirtualKeyCode::Escape => *control_flow = ControlFlow::Exit, + VirtualKeyCode::Key1 => { + draw_config.draw_model = !draw_config.draw_model + } + VirtualKeyCode::Key2 => { + draw_config.draw_mesh = !draw_config.draw_mesh + } + VirtualKeyCode::Key3 => { + draw_config.draw_debug = !draw_config.draw_debug + } + _ => {} + }, Event::WindowEvent { event: WindowEvent::Resized(size), .. @@ -154,69 +179,34 @@ pub fn run( _ => {} } + // fj-viewer events if let (Some(shape), Some(camera)) = (&shape, &mut camera) { if let Some(focus_event) = - focus_event(&event, previous_cursor, shape, camera) + focus(&event, previous_cursor, shape, camera) { - input_handler.handle_event(focus_event, camera); + input_handler.focus(focus_event); } } let input_event = input_event( - event, + &event, &window, &held_mouse_button, &mut previous_cursor, ); - if let Some(input_event) = input_event { - match input_event { - input::Event::Exit => *control_flow = ControlFlow::Exit, - input::Event::ToggleModel => { - draw_config.draw_model = !draw_config.draw_model - } - input::Event::ToggleMesh => { - draw_config.draw_mesh = !draw_config.draw_mesh - } - input::Event::ToggleDebug => { - draw_config.draw_debug = !draw_config.draw_debug - } - _ => {} - }; - - if let Some(camera) = &mut camera { - input_handler.handle_event(input_event, camera); - } + if let (Some(input_event), Some(camera)) = (input_event, &mut camera) { + input_handler.handle_event(input_event, camera); } }); } fn input_event( - event: Event<()>, + event: &Event<()>, window: &Window, held_mouse_button: &Option, previous_cursor: &mut Option, ) -> Option { match event { - Event::WindowEvent { - event: - WindowEvent::KeyboardInput { - input: - KeyboardInput { - state: ElementState::Pressed, - virtual_keycode: Some(virtual_key_code), - .. - }, - .. - }, - .. - } => match virtual_key_code { - VirtualKeyCode::Escape => Some(input::Event::Exit), - VirtualKeyCode::Key1 => Some(input::Event::ToggleModel), - VirtualKeyCode::Key2 => Some(input::Event::ToggleMesh), - VirtualKeyCode::Key3 => Some(input::Event::ToggleDebug), - - _ => None, - }, Event::WindowEvent { event: WindowEvent::CursorMoved { position, .. }, .. @@ -249,7 +239,7 @@ fn input_event( event: WindowEvent::MouseWheel { delta, .. }, .. } => Some(input::Event::Zoom(match delta { - MouseScrollDelta::LineDelta(_, y) => (y as f64) * ZOOM_FACTOR_LINE, + MouseScrollDelta::LineDelta(_, y) => (*y as f64) * ZOOM_FACTOR_LINE, MouseScrollDelta::PixelDelta(PhysicalPosition { y, .. }) => { y * ZOOM_FACTOR_PIXEL } @@ -258,12 +248,12 @@ fn input_event( } } -fn focus_event( +fn focus( event: &Event<()>, previous_cursor: Option, shape: &ProcessedShape, camera: &Camera, -) -> Option { +) -> Option { let focus_point = match event { Event::WindowEvent { event: @@ -286,7 +276,7 @@ fn focus_event( _ => return None, }; - Some(input::Event::FocusPoint(focus_point)) + Some(focus_point) } /// Error in main loop From 7363ab91b09c3ac96e10e30550bfc89f96c213eb Mon Sep 17 00:00:00 2001 From: Sam Jeeves Date: Tue, 12 Jul 2022 16:06:01 +0200 Subject: [PATCH 7/8] Rename events using model manipulation metaphor --- crates/fj-viewer/src/input/event.rs | 47 +++------------------------ crates/fj-viewer/src/input/handler.rs | 4 +-- crates/fj-viewer/src/input/mod.rs | 5 +-- crates/fj-window/src/run.rs | 4 +-- 4 files changed, 9 insertions(+), 51 deletions(-) diff --git a/crates/fj-viewer/src/input/event.rs b/crates/fj-viewer/src/input/event.rs index 9b49f1ade..84f3b63d0 100644 --- a/crates/fj-viewer/src/input/event.rs +++ b/crates/fj-viewer/src/input/event.rs @@ -2,16 +2,16 @@ use crate::screen::NormalizedPosition; /// An input event pub enum Event { - /// Move the view up, down, left or right - Pan { + /// Move the model up, down, left or right + Translate { /// The normalized position of the cursor before input previous: NormalizedPosition, /// The normalized position of the cursor after input current: NormalizedPosition, }, - /// Rotate the view around the focus point - Orbit { + /// Rotate the model around the focus point + Rotation { /// The normalized position of the cursor before input previous: NormalizedPosition, /// The normalized position of the cursor after input @@ -21,42 +21,3 @@ pub enum Event { /// Move the view forwards and backwards Zoom(f64), } - -/// Describes a difference in the vertical mouse scroll wheel state. -/// Positive values indicate movement forward (away from the user). -pub enum MouseScrollDelta { - /// Amount in lines to scroll. - Line(f64), - /// Amount in pixels to scroll. - Pixel(f64), -} - -/// A keyboard or mouse key -pub enum Key { - /// The escape key - Escape, - - /// The numerical key `1` - Key1, - - /// The numerical key `2` - Key2, - - /// The numerical key `3` - Key3, - - /// The left mouse key - MouseLeft, - - /// The right mouse key - MouseRight, -} - -/// Defines the meaning of a key event -pub enum KeyState { - /// A key was pressed - Pressed, - - /// A key was released - Released, -} diff --git a/crates/fj-viewer/src/input/handler.rs b/crates/fj-viewer/src/input/handler.rs index d7f539f25..00b111e33 100644 --- a/crates/fj-viewer/src/input/handler.rs +++ b/crates/fj-viewer/src/input/handler.rs @@ -16,13 +16,13 @@ impl Handler { /// Handle an input event pub fn handle_event(&mut self, event: Event, camera: &mut Camera) { match event { - Event::Pan { previous, current } => self.movement.apply( + Event::Translate { previous, current } => self.movement.apply( previous, current, &self.focus_point, camera, ), - Event::Orbit { previous, current } => self.rotation.apply( + Event::Rotation { previous, current } => self.rotation.apply( previous, current, &self.focus_point, diff --git a/crates/fj-viewer/src/input/mod.rs b/crates/fj-viewer/src/input/mod.rs index b95683d26..6471f9dfb 100644 --- a/crates/fj-viewer/src/input/mod.rs +++ b/crates/fj-viewer/src/input/mod.rs @@ -6,7 +6,4 @@ mod movement; mod rotation; mod zoom; -pub use self::{ - event::{Event, Key, KeyState, MouseScrollDelta}, - handler::Handler, -}; +pub use self::{event::Event, handler::Handler}; diff --git a/crates/fj-window/src/run.rs b/crates/fj-window/src/run.rs index 9fbe62795..6997001da 100644 --- a/crates/fj-window/src/run.rs +++ b/crates/fj-window/src/run.rs @@ -223,10 +223,10 @@ fn input_event( let event = match (*previous_cursor, held_mouse_button) { (Some(previous), Some(button)) => match button { MouseButton::Left => { - Some(input::Event::Orbit { previous, current }) + Some(input::Event::Rotation { previous, current }) } MouseButton::Right => { - Some(input::Event::Pan { previous, current }) + Some(input::Event::Translate { previous, current }) } _ => None, }, From 9db1be4a5142c68b4724b305b02c7b1f14d38e7a Mon Sep 17 00:00:00 2001 From: Sam Jeeves Date: Tue, 12 Jul 2022 16:13:26 +0200 Subject: [PATCH 8/8] Extract and document rotation constant --- crates/fj-viewer/src/input/event.rs | 8 ++++---- crates/fj-viewer/src/input/handler.rs | 10 ++++------ crates/fj-viewer/src/input/rotation.rs | 17 +++-------------- crates/fj-window/src/run.rs | 13 ++++++++++++- 4 files changed, 23 insertions(+), 25 deletions(-) diff --git a/crates/fj-viewer/src/input/event.rs b/crates/fj-viewer/src/input/event.rs index 84f3b63d0..357cded83 100644 --- a/crates/fj-viewer/src/input/event.rs +++ b/crates/fj-viewer/src/input/event.rs @@ -12,10 +12,10 @@ pub enum Event { /// Rotate the model around the focus point Rotation { - /// The normalized position of the cursor before input - previous: NormalizedPosition, - /// The normalized position of the cursor after input - current: NormalizedPosition, + /// The angle around the screen x axis to rotate (in radians) + angle_x: f64, + /// The angle around the screen y axis to rotate (in radians) + angle_y: f64, }, /// Move the view forwards and backwards diff --git a/crates/fj-viewer/src/input/handler.rs b/crates/fj-viewer/src/input/handler.rs index 00b111e33..71f4212bd 100644 --- a/crates/fj-viewer/src/input/handler.rs +++ b/crates/fj-viewer/src/input/handler.rs @@ -22,12 +22,10 @@ impl Handler { &self.focus_point, camera, ), - Event::Rotation { previous, current } => self.rotation.apply( - previous, - current, - &self.focus_point, - camera, - ), + Event::Rotation { angle_x, angle_y } => { + self.rotation + .apply(angle_x, angle_y, &self.focus_point, camera) + } Event::Zoom(zoom_delta) => { self.zoom.apply(zoom_delta, &self.focus_point, camera) } diff --git a/crates/fj-viewer/src/input/rotation.rs b/crates/fj-viewer/src/input/rotation.rs index 71f58118c..ca10260c3 100644 --- a/crates/fj-viewer/src/input/rotation.rs +++ b/crates/fj-viewer/src/input/rotation.rs @@ -1,30 +1,19 @@ use fj_math::{Point, Transform, Vector}; -use crate::{ - camera::{Camera, FocusPoint}, - screen::NormalizedPosition, -}; +use crate::camera::{Camera, FocusPoint}; pub struct Rotation; impl Rotation { pub fn apply( &self, - previous: NormalizedPosition, - current: NormalizedPosition, + angle_x: f64, + angle_y: f64, focus_point: &FocusPoint, camera: &mut Camera, ) { let rotate_around: Vector<3> = focus_point.0.unwrap_or_else(Point::origin).coords; - - let f = -5.; - - let diff_x = current.x - previous.x; - let diff_y = current.y - previous.y; - let angle_x = diff_y * f; - let angle_y = -diff_x * f; - let rotate_around = Transform::translation(rotate_around); // the model rotates not the camera, so invert the transform diff --git a/crates/fj-window/src/run.rs b/crates/fj-window/src/run.rs index 6997001da..d953eab4a 100644 --- a/crates/fj-window/src/run.rs +++ b/crates/fj-window/src/run.rs @@ -223,7 +223,12 @@ fn input_event( let event = match (*previous_cursor, held_mouse_button) { (Some(previous), Some(button)) => match button { MouseButton::Left => { - Some(input::Event::Rotation { previous, current }) + let diff_x = current.x - previous.x; + let diff_y = current.y - previous.y; + let angle_x = -diff_y * ROTATION_SENSITIVITY; + let angle_y = diff_x * ROTATION_SENSITIVITY; + + Some(input::Event::Rotation { angle_x, angle_y }) } MouseButton::Right => { Some(input::Event::Translate { previous, current }) @@ -302,3 +307,9 @@ const ZOOM_FACTOR_LINE: f64 = 0.075; /// Smaller values will move the camera less with the same input. /// Larger values will move the camera more with the same input. const ZOOM_FACTOR_PIXEL: f64 = 0.005; + +/// Affects the speed of rotation given a change in normalized screen position [-1, 1] +/// +/// Smaller values will move the camera less with the same input. +/// Larger values will move the camera more with the same input. +const ROTATION_SENSITIVITY: f64 = 5.;