From 188c413d6693b3e649820e3f6d9f0842ebba0ce3 Mon Sep 17 00:00:00 2001 From: HampusM Date: Tue, 16 Apr 2024 23:01:40 +0200 Subject: feat(engine): add fly camera extension --- engine/src/camera.rs | 2 + engine/src/camera/fly.rs | 140 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 engine/src/camera/fly.rs (limited to 'engine') diff --git a/engine/src/camera.rs b/engine/src/camera.rs index 640c1f4..5b71e2f 100644 --- a/engine/src/camera.rs +++ b/engine/src/camera.rs @@ -3,6 +3,8 @@ use ecs::Component; use crate::projection::{Perspective, Projection}; use crate::vector::Vec3; +pub mod fly; + #[derive(Debug, Component)] pub struct Camera { diff --git a/engine/src/camera/fly.rs b/engine/src/camera/fly.rs new file mode 100644 index 0000000..7fa435b --- /dev/null +++ b/engine/src/camera/fly.rs @@ -0,0 +1,140 @@ +use ecs::component::local::Local; +use ecs::sole::Single; +use ecs::system::{Into, System}; +use ecs::{Component, Query}; +use glfw::window::{Key, KeyState}; + +use crate::camera::Camera; +use crate::delta_time::DeltaTime; +use crate::event::Update as UpdateEvent; +use crate::input::{Cursor, Keys}; +use crate::vector::{Vec2, Vec3}; + +/// Fly camera extension. +pub struct Extension(pub Options); + +impl ecs::extension::Extension for Extension +{ + fn collect(self, mut collector: ecs::extension::Collector<'_>) + { + collector.add_system( + UpdateEvent, + update.into_system().initialize(( + CursorState { + current_yaw: -90.0, + ..Default::default() + }, + self.0, + )), + ); + } +} + +#[derive(Debug, Component)] +pub struct Options +{ + pub camera_speed: f32, + pub mouse_sensitivity: f32, +} + +fn update( + camera_query: Query<(Camera,)>, + keys: Single, + cursor: Single, + delta_time: Single, + mut cursor_state: Local, + options: Local, +) +{ + let Some((mut camera,)) = camera_query.iter().next() else { + #[cfg(feature = "debug")] + tracing::warn!("No camera"); + + return; + }; + + if cursor.has_moved && cursor_state.first_mouse { + println!("First cursor move"); + + cursor_state.last_pos = cursor.position; + cursor_state.first_mouse = false; + } + + let delta_time = delta_time.duration; + + let mut x_offset = cursor.position.x - cursor_state.last_pos.x; + let mut y_offset = cursor_state.last_pos.y - cursor.position.y; + + cursor_state.last_pos = cursor.position; + + x_offset *= f64::from(options.mouse_sensitivity); + y_offset *= f64::from(options.mouse_sensitivity); + + cursor_state.current_yaw += x_offset; + cursor_state.current_pitch += y_offset; + + if cursor_state.current_pitch > 89.0 { + cursor_state.current_pitch = 89.0; + } else if cursor_state.current_pitch < -89.0 { + cursor_state.current_pitch = -89.0; + } + + // TODO: This casting to a f32 from a f64 is horrible. fix it + #[allow(clippy::cast_possible_truncation)] + let direction = Vec3 { + x: (cursor_state.current_yaw.to_radians().cos() + * cursor_state.current_pitch.to_radians().cos()) as f32, + y: cursor_state.current_pitch.to_radians().sin() as f32, + z: (cursor_state.current_yaw.to_radians().sin() + * cursor_state.current_pitch.to_radians().cos()) as f32, + } + .normalize(); + + let cam_right = direction.cross(&Vec3::UP).normalize(); + + camera.global_up = cam_right.cross(&direction).normalize(); + + if matches!(keys.get_key_state(Key::W), KeyState::Pressed) { + camera.position += direction * options.camera_speed * delta_time.as_secs_f32(); + } + + if matches!(keys.get_key_state(Key::S), KeyState::Pressed) { + camera.position -= direction * options.camera_speed * delta_time.as_secs_f32(); + } + + if matches!(keys.get_key_state(Key::A), KeyState::Pressed) { + let cam_left = -direction.cross(&Vec3::UP).normalize(); + + camera.position += cam_left * options.camera_speed * delta_time.as_secs_f32(); + } + + if matches!(keys.get_key_state(Key::D), KeyState::Pressed) { + let cam_right = direction.cross(&Vec3::UP).normalize(); + + camera.position += cam_right * options.camera_speed * delta_time.as_secs_f32(); + } + + camera.target = camera.position + direction; +} + +#[derive(Debug, Component)] +struct CursorState +{ + last_pos: Vec2, + current_pitch: f64, + current_yaw: f64, + first_mouse: bool, +} + +impl Default for CursorState +{ + fn default() -> Self + { + Self { + last_pos: Vec2::default(), + current_pitch: 0.0, + current_yaw: 0.0, + first_mouse: true, + } + } +} -- cgit v1.2.3-18-g5258