summaryrefslogtreecommitdiff
path: root/engine/src/camera
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2024-04-16 23:01:40 +0200
committerHampusM <hampus@hampusmat.com>2024-04-16 23:01:40 +0200
commit188c413d6693b3e649820e3f6d9f0842ebba0ce3 (patch)
tree456d10124fa2aff37c1040b29d6edae099637dab /engine/src/camera
parent67d6f1914af5aace3084bb943b00b454a55451ab (diff)
feat(engine): add fly camera extension
Diffstat (limited to 'engine/src/camera')
-rw-r--r--engine/src/camera/fly.rs140
1 files changed, 140 insertions, 0 deletions
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<Keys>,
+ cursor: Single<Cursor>,
+ delta_time: Single<DeltaTime>,
+ mut cursor_state: Local<CursorState>,
+ options: Local<Options>,
+)
+{
+ 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<f64>,
+ 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,
+ }
+ }
+}