blade_helpers/
camera.rs

1use super::ExposeHud;
2
3const MAX_FLY_SPEED: f32 = 1000000.0;
4
5pub struct ControlledCamera {
6    pub inner: blade_render::Camera,
7    pub fly_speed: f32,
8}
9
10impl Default for ControlledCamera {
11    fn default() -> Self {
12        Self {
13            inner: blade_render::Camera {
14                pos: mint::Vector3 {
15                    x: 0.0,
16                    y: 0.0,
17                    z: 0.0,
18                },
19                rot: mint::Quaternion {
20                    v: mint::Vector3 {
21                        x: 0.0,
22                        y: 0.0,
23                        z: 0.0,
24                    },
25                    s: 1.0,
26                },
27                fov_y: 0.0,
28                depth: 0.0,
29            },
30            fly_speed: 0.0,
31        }
32    }
33}
34
35impl ControlledCamera {
36    pub fn get_view_matrix(&self) -> glam::Mat4 {
37        glam::Mat4::from_rotation_translation(self.inner.rot.into(), self.inner.pos.into())
38            .inverse()
39    }
40
41    pub fn get_projection_matrix(&self, aspect: f32) -> glam::Mat4 {
42        glam::Mat4::perspective_rh(self.inner.fov_y, aspect, 1.0, self.inner.depth)
43    }
44
45    pub fn move_by(&mut self, offset: glam::Vec3) {
46        let dir = glam::Quat::from(self.inner.rot) * offset;
47        self.inner.pos = (glam::Vec3::from(self.inner.pos) + dir).into();
48    }
49
50    pub fn rotate_z_by(&mut self, angle: f32) {
51        let quat = glam::Quat::from(self.inner.rot);
52        let rotation = glam::Quat::from_rotation_z(angle);
53        self.inner.rot = (quat * rotation).into();
54    }
55
56    pub fn on_key(&mut self, code: winit::keyboard::KeyCode, delta: f32) -> bool {
57        use winit::keyboard::KeyCode as Kc;
58
59        let move_offset = self.fly_speed * delta;
60        let rotate_offset_z = 1000.0 * delta;
61        match code {
62            Kc::KeyW => {
63                self.move_by(glam::Vec3::new(0.0, 0.0, -move_offset));
64            }
65            Kc::KeyS => {
66                self.move_by(glam::Vec3::new(0.0, 0.0, move_offset));
67            }
68            Kc::KeyA => {
69                self.move_by(glam::Vec3::new(-move_offset, 0.0, 0.0));
70            }
71            Kc::KeyD => {
72                self.move_by(glam::Vec3::new(move_offset, 0.0, 0.0));
73            }
74            Kc::KeyZ => {
75                self.move_by(glam::Vec3::new(0.0, -move_offset, 0.0));
76            }
77            Kc::KeyX => {
78                self.move_by(glam::Vec3::new(0.0, move_offset, 0.0));
79            }
80            Kc::KeyQ => {
81                self.rotate_z_by(rotate_offset_z);
82            }
83            Kc::KeyE => {
84                self.rotate_z_by(-rotate_offset_z);
85            }
86            _ => return false,
87        }
88
89        true
90    }
91
92    pub fn on_wheel(&mut self, delta: winit::event::MouseScrollDelta) {
93        let shift = match delta {
94            winit::event::MouseScrollDelta::LineDelta(_, lines) => lines,
95            winit::event::MouseScrollDelta::PixelDelta(position) => position.y as f32,
96        };
97        self.fly_speed = (self.fly_speed * shift.exp()).clamp(1.0, MAX_FLY_SPEED);
98    }
99}
100
101impl ExposeHud for ControlledCamera {
102    fn populate_hud(&mut self, ui: &mut egui::Ui) {
103        ui.horizontal(|ui| {
104            ui.label("Position:");
105            ui.add(egui::DragValue::new(&mut self.inner.pos.x));
106            ui.add(egui::DragValue::new(&mut self.inner.pos.y));
107            ui.add(egui::DragValue::new(&mut self.inner.pos.z));
108        });
109        ui.horizontal(|ui| {
110            ui.label("Rotation:");
111            ui.add(egui::DragValue::new(&mut self.inner.rot.v.x));
112            ui.add(egui::DragValue::new(&mut self.inner.rot.v.y));
113            ui.add(egui::DragValue::new(&mut self.inner.rot.v.z));
114            ui.add(egui::DragValue::new(&mut self.inner.rot.s));
115        });
116        ui.add(egui::Slider::new(&mut self.inner.fov_y, 0.5f32..=2.0f32).text("FOV"));
117        ui.add(
118            egui::Slider::new(&mut self.fly_speed, 1f32..=MAX_FLY_SPEED)
119                .text("Fly speed")
120                .logarithmic(true),
121        );
122    }
123}