use winit::event::Event; use winit::event::{WindowEvent, DeviceEvent, KeyboardInput, ElementState, VirtualKeyCode}; use cgmath::{InnerSpace, Matrix4, Rad, Deg, Transform, Vector3}; use crate::renderer::camera::Camera; #[derive(Default)] struct CameraMovement { pub up: bool, pub down: bool, pub fwd: bool, pub back: bool, pub left: bool, pub right: bool, pub shift: bool, pub speed: f32, } #[derive(Default)] struct CameraRotation { pub yaw: f32, // vertical axis pub pitch: f32, // horizontal axis pub sensitivity: f32, } impl CameraRotation { fn yaw_rad(&mut self) -> Rad { Rad::from(Deg(self.yaw)) } fn pitch_rad(&mut self) -> Rad { Rad::from(Deg(self.pitch)) } fn yaw_rot(&mut self) -> Matrix4 { Matrix4::from_angle_y(-self.yaw_rad()) } fn pitch_rot(&mut self)-> Matrix4 { Matrix4::from_angle_x(-self.pitch_rad()) } } pub struct CameraController { enabled: bool, movement: CameraMovement, rotation: CameraRotation, } impl CameraController { pub fn new() -> Self { let mut movement = CameraMovement::default(); movement.speed = 2.0; let mut rotation = CameraRotation::default(); rotation.sensitivity = 0.2; Self { enabled: false, movement, rotation } } pub fn set_enabled(&mut self, enabled: bool) { self.enabled = enabled; } pub fn handle_input(&mut self, event: &Event<()>) -> bool { // Abort if not enabled if !self.enabled { return false; } match event { Event::WindowEvent { ref event, .. } => { match event { WindowEvent::KeyboardInput { input: KeyboardInput { state, virtual_keycode: Some(keycode), .. }, .. } => { let is_pressed = *state == ElementState::Pressed; match keycode { VirtualKeyCode::Q => { self.movement.down = is_pressed; true } VirtualKeyCode::E | VirtualKeyCode::Space => { self.movement.up = is_pressed; true } VirtualKeyCode::W | VirtualKeyCode::Up => { self.movement.fwd = is_pressed; true } VirtualKeyCode::A | VirtualKeyCode::Left => { self.movement.left = is_pressed; true } VirtualKeyCode::S | VirtualKeyCode::Down => { self.movement.back = is_pressed; true } VirtualKeyCode::D | VirtualKeyCode::Right => { self.movement.right = is_pressed; true } VirtualKeyCode::LShift => { self.movement.shift = is_pressed; true } _ => false, } } _ => false } }, Event::DeviceEvent { device_id: _, event } => { match event { DeviceEvent::MouseMotion { delta } => { // Increment self.rotation.yaw += delta.0 as f32 * self.rotation.sensitivity; self.rotation.pitch -= delta.1 as f32 * self.rotation.sensitivity; // Clamp if self.rotation.yaw > 360.0 { self.rotation.yaw -= 360.0; } if self.rotation.yaw < 0.0 { self.rotation.yaw += 360.0; } self.rotation.pitch = self.rotation.pitch.clamp(-70.0, 70.0); true } _ => false } } _ => false } } pub fn update_camera(&mut self, camera: &mut Camera, delta_time: f32) { // Abort if not enabled if !self.enabled { return; } // Rotation let yaw_rot = self.rotation.yaw_rot(); let pitch_rot = self.rotation.pitch_rot(); camera.forward = yaw_rot.transform_vector(pitch_rot.transform_vector(Vector3::unit_z())); camera.up = yaw_rot.transform_vector(pitch_rot.transform_vector(Vector3::unit_y())); // Movement amount let mut amount = delta_time * self.movement.speed; if self.movement.shift { amount *= 2.0; } // Forward and backwards if self.movement.fwd && camera.forward.magnitude() > amount { camera.position += camera.forward.normalize() * amount; } if self.movement.back { camera.position -= camera.forward.normalize() * amount; } // Up and down if self.movement.up { camera.position += camera.up.normalize() * amount; } if self.movement.down { camera.position -= camera.up.normalize() * amount; } // Left and right let right = camera.forward.cross(camera.up); if self.movement.right { camera.position += right * amount; } if self.movement.left { camera.position -= right * amount; } } }