use crate::renderer::viewer::Camera;
use crate::window::event::{Event, Key, MouseButton};
use glam::Vec3;
pub struct FirstPersonControl {
pub move_speed: f32,
pub mouse_sensitivity: f32,
pub sprint_multiplier: f32,
pitch: f32,
yaw: f32,
move_forward: bool,
move_backward: bool,
move_left: bool,
move_right: bool,
move_up: bool,
move_down: bool,
sprint: bool,
mouse_captured: bool,
}
impl FirstPersonControl {
pub fn new(move_speed: f32, mouse_sensitivity: f32) -> Self {
Self {
move_speed,
mouse_sensitivity,
sprint_multiplier: 2.0,
pitch: 0.0,
yaw: 0.0,
move_forward: false,
move_backward: false,
move_left: false,
move_right: false,
move_up: false,
move_down: false,
sprint: false,
mouse_captured: false,
}
}
pub fn from_camera(camera: &Camera, move_speed: f32, mouse_sensitivity: f32) -> Self {
let direction = (camera.target - camera.position).normalize();
let pitch = direction.y.asin();
let yaw = direction.x.atan2(direction.z);
let mut control = Self::new(move_speed, mouse_sensitivity);
control.pitch = pitch;
control.yaw = yaw;
control
}
pub fn handle_events(&mut self, camera: &mut Camera, events: &mut [Event], delta_time: f32) {
for event in events.iter_mut() {
if event.is_handled() {
continue;
}
match event {
Event::KeyPress { key, .. } => {
self.handle_key_press(*key);
event.set_handled();
}
Event::KeyRelease { key, .. } => {
self.handle_key_release(*key);
event.set_handled();
}
Event::MousePress { button, .. } => {
if *button == MouseButton::Right {
self.mouse_captured = true;
event.set_handled();
}
}
Event::MouseRelease { button, .. } => {
if *button == MouseButton::Right {
self.mouse_captured = false;
event.set_handled();
}
}
Event::MouseMotion { delta, .. } => {
if self.mouse_captured {
self.handle_mouse_motion(delta.0, delta.1);
event.set_handled();
}
}
_ => {}
}
}
self.update_camera(camera, delta_time);
}
fn handle_key_press(&mut self, key: Key) {
match key {
Key::W | Key::Up => self.move_forward = true,
Key::S | Key::Down => self.move_backward = true,
Key::A | Key::Left => self.move_left = true,
Key::D | Key::Right => self.move_right = true,
Key::Space => self.move_up = true,
Key::Control => self.move_down = true,
Key::Shift => self.sprint = true,
_ => {}
}
}
fn handle_key_release(&mut self, key: Key) {
match key {
Key::W | Key::Up => self.move_forward = false,
Key::S | Key::Down => self.move_backward = false,
Key::A | Key::Left => self.move_left = false,
Key::D | Key::Right => self.move_right = false,
Key::Space => self.move_up = false,
Key::Control => self.move_down = false,
Key::Shift => self.sprint = false,
_ => {}
}
}
fn handle_mouse_motion(&mut self, dx: f32, dy: f32) {
self.yaw -= dx * self.mouse_sensitivity;
self.pitch = (self.pitch - dy * self.mouse_sensitivity).clamp(
-std::f32::consts::FRAC_PI_2 + 0.01,
std::f32::consts::FRAC_PI_2 - 0.01,
);
}
fn update_camera(&self, camera: &mut Camera, delta_time: f32) {
let forward = Vec3::new(
self.yaw.sin() * self.pitch.cos(),
self.pitch.sin(),
self.yaw.cos() * self.pitch.cos(),
)
.normalize();
let right = forward.cross(Vec3::Y).normalize();
let up = Vec3::Y;
let mut velocity = Vec3::ZERO;
if self.move_forward {
velocity += forward;
}
if self.move_backward {
velocity -= forward;
}
if self.move_right {
velocity += right;
}
if self.move_left {
velocity -= right;
}
if self.move_up {
velocity += up;
}
if self.move_down {
velocity -= up;
}
if velocity.length_squared() > 0.0 {
velocity = velocity.normalize();
}
let speed = if self.sprint {
self.move_speed * self.sprint_multiplier
} else {
self.move_speed
};
camera.position += velocity * speed * delta_time;
camera.target = camera.position + forward;
}
pub fn is_mouse_captured(&self) -> bool {
self.mouse_captured
}
pub fn pitch(&self) -> f32 {
self.pitch
}
pub fn yaw(&self) -> f32 {
self.yaw
}
}
impl Default for FirstPersonControl {
fn default() -> Self {
Self::new(5.0, 0.002)
}
}