1use lin_alg::f32::{Quaternion, Vec3};
4use winit::event::{DeviceEvent, ElementState, MouseScrollDelta};
6use winit::keyboard::{KeyCode, PhysicalKey::Code};
7
8use crate::{
9 ScrollBehavior,
10 camera::Camera,
11 graphics::{FWD_VEC, RIGHT_VEC, UP_VEC},
12 types::InputSettings,
13};
14
15const EPS_MOUSE: f32 = 0.00001;
16
17#[derive(Default, Debug)]
18pub struct InputsCommanded {
19 pub fwd: bool,
20 pub back: bool,
21 pub left: bool,
22 pub right: bool,
23 pub up: bool,
24 pub down: bool,
25 pub roll_ccw: bool,
26 pub roll_cw: bool,
27 pub mouse_delta_x: f32,
28 pub mouse_delta_y: f32,
29 pub run: bool,
30 pub scroll_up: bool,
31 pub scroll_down: bool,
32 pub free_look: bool,
33 pub panning: bool, pub cursor_out_of_window: bool,
37}
38
39impl InputsCommanded {
40 pub fn inputs_present(&self) -> bool {
42 self.fwd
44 || self.back
45 || self.left
46 || self.right
47 || self.up
48 || self.down
49 || self.roll_ccw
50 || self.roll_cw
51 || self.mouse_delta_x.abs() > EPS_MOUSE
52 || self.mouse_delta_y.abs() > EPS_MOUSE
53 || self.scroll_up
54 || self.scroll_down
55 }
56}
57
58pub(crate) fn add_input_cmd(event: &DeviceEvent, inputs: &mut InputsCommanded) {
62 if inputs.cursor_out_of_window {
65 *inputs = InputsCommanded {
68 cursor_out_of_window: true,
69 ..Default::default()
70 };
71 return;
72 }
73
74 match event {
75 DeviceEvent::Key(key) => {
76 let Code(key_code) = key.physical_key else {
77 return;
78 };
79
80 if key.state == ElementState::Pressed {
81 match key_code {
82 KeyCode::KeyW => {
83 inputs.fwd = true;
84 }
85 KeyCode::KeyS => {
86 inputs.back = true;
87 }
88 KeyCode::KeyA => {
89 inputs.left = true;
90 }
91 KeyCode::KeyD => {
92 inputs.right = true;
93 }
94 KeyCode::Space => {
95 inputs.up = true;
96 }
97 KeyCode::KeyC => {
98 inputs.down = true;
99 }
100 KeyCode::KeyQ => {
101 inputs.roll_ccw = true;
102 }
103 KeyCode::KeyE => {
104 inputs.roll_cw = true;
105 }
106 KeyCode::ShiftLeft => {
107 inputs.run = true;
108 }
109 _ => (),
110 }
111 } else if key.state == ElementState::Released {
112 match key_code {
114 KeyCode::KeyW => {
115 inputs.fwd = false;
116 }
117 KeyCode::KeyS => {
118 inputs.back = false;
119 }
120 KeyCode::KeyA => {
121 inputs.left = false;
122 }
123 KeyCode::KeyD => {
124 inputs.right = false;
125 }
126 KeyCode::Space => {
127 inputs.up = false;
128 }
129 KeyCode::KeyC => {
130 inputs.down = false;
131 }
132 KeyCode::KeyQ => {
133 inputs.roll_ccw = false;
134 }
135 KeyCode::KeyE => {
136 inputs.roll_cw = false;
137 }
138 KeyCode::ShiftLeft => {
139 inputs.run = false;
140 }
141 _ => (),
142 }
143 }
144 }
145 DeviceEvent::Button { button, state } => {
146 #[cfg(target_os = "linux")]
148 let left_click = 1;
149 #[cfg(not(target_os = "linux"))]
150 let left_click = 0;
151
152 if *button == left_click {
155 inputs.free_look = match state {
156 ElementState::Pressed => true,
157 ElementState::Released => false,
158 }
159 }
160 }
161 DeviceEvent::MouseMotion { delta } => {
162 inputs.mouse_delta_x += delta.0 as f32;
163 inputs.mouse_delta_y += delta.1 as f32;
164 }
165 DeviceEvent::MouseWheel { delta } => match delta {
167 MouseScrollDelta::PixelDelta(_) => (),
168 MouseScrollDelta::LineDelta(_x, y) => {
169 if *y > 0. {
170 inputs.scroll_down = true;
171 } else {
172 inputs.scroll_up = true;
173 }
174 }
175 },
176 _ => (),
177 }
178}
179
180fn handle_scroll(
181 cam: &mut Camera,
182 inputs: &mut InputsCommanded,
183 input_settings: &InputSettings,
184 dt: f32,
185 movement_vec: &mut Vec3,
186 rotation: &mut Quaternion,
187 cam_moved: &mut bool,
188 cam_rotated: &mut bool,
189) {
190 if inputs.scroll_down || inputs.scroll_up {
191 if let ScrollBehavior::MoveRoll {
192 move_amt,
193 rotate_amt,
194 } = input_settings.scroll_behavior
195 {
196 if inputs.free_look {
197 let fwd = cam.orientation.rotate_vec(FWD_VEC);
199
200 let mut rot_amt = -rotate_amt * dt;
201 if inputs.scroll_down {
202 rot_amt *= -1.; }
204
205 *rotation = Quaternion::from_axis_angle(fwd, rot_amt);
206 *cam_rotated = true;
207 } else {
208 let mut movement = Vec3::new(0., 0., move_amt);
210 if inputs.scroll_up {
211 movement *= -1.;
212 }
213 *movement_vec += movement;
214
215 *cam_moved = true;
216 }
217 }
218
219 inputs.scroll_down = false;
221 inputs.scroll_up = false;
222 }
223}
224
225pub fn arc_rotation(cam: &mut Camera, axis: Vec3, amt: f32, center: Vec3) {
227 let rotation = Quaternion::from_axis_angle(axis, amt);
228
229 cam.orientation = (rotation * cam.orientation).to_normalized();
230
231 let dist = (cam.position - center).magnitude();
232 cam.position = center - cam.orientation.rotate_vec(FWD_VEC) * dist;
234}
235
236pub fn adjust_camera_free(
239 cam: &mut Camera,
240 inputs: &mut InputsCommanded,
241 input_settings: &InputSettings,
242 dt: f32,
243) -> bool {
244 let mut move_amt = input_settings.move_sens * dt;
245 let mut rotate_key_amt = input_settings.rotate_key_sens * dt;
246
247 let mut cam_moved = false;
248 let mut cam_rotated = false;
249
250 let mut movement_vec = Vec3::new_zero();
251 let mut rotation = Quaternion::new_identity();
252
253 if inputs.run {
254 move_amt *= input_settings.run_factor;
255 rotate_key_amt *= input_settings.run_factor;
256 }
257
258 if inputs.fwd {
259 movement_vec.z += move_amt;
260 cam_moved = true;
261 } else if inputs.back {
262 movement_vec.z -= move_amt;
263 cam_moved = true;
264 }
265
266 if inputs.right {
267 movement_vec.x += move_amt;
268 cam_moved = true;
269 } else if inputs.left {
270 movement_vec.x -= move_amt;
271 cam_moved = true;
272 }
273
274 if inputs.up {
275 movement_vec.y += move_amt;
276 cam_moved = true;
277 } else if inputs.down {
278 movement_vec.y -= move_amt;
279 cam_moved = true;
280 }
281
282 if inputs.roll_cw {
283 let fwd = cam.orientation.rotate_vec(FWD_VEC);
284 rotation = Quaternion::from_axis_angle(fwd, -rotate_key_amt);
285 cam_rotated = true;
286 } else if inputs.roll_ccw {
287 let fwd = cam.orientation.rotate_vec(FWD_VEC);
288 rotation = Quaternion::from_axis_angle(fwd, rotate_key_amt);
289 cam_rotated = true;
290 }
291
292 if inputs.free_look
293 && (inputs.mouse_delta_x.abs() > EPS_MOUSE || inputs.mouse_delta_y.abs() > EPS_MOUSE)
294 {
295 let rotate_amt = input_settings.rotate_sens * dt;
296 let up = cam.orientation.rotate_vec(-UP_VEC);
297 let right = cam.orientation.rotate_vec(-RIGHT_VEC);
298
299 rotation = Quaternion::from_axis_angle(up, -inputs.mouse_delta_x * rotate_amt)
300 * Quaternion::from_axis_angle(right, -inputs.mouse_delta_y * rotate_amt)
301 * rotation;
302
303 cam_rotated = true;
304 }
305
306 handle_scroll(
307 cam,
308 inputs,
309 input_settings,
310 dt,
311 &mut movement_vec,
312 &mut rotation,
313 &mut cam_moved,
314 &mut cam_rotated,
315 );
316
317 if cam_rotated {
320 cam.orientation = (rotation * cam.orientation).to_normalized();
321 }
322
323 if cam_moved {
324 cam.position += cam.orientation.rotate_vec(movement_vec);
325 }
326
327 cam_moved || cam_rotated
328}
329
330pub fn adjust_camera_arc(
333 cam: &mut Camera,
334 inputs: &mut InputsCommanded,
335 input_settings: &InputSettings,
336 center: Vec3,
337 dt: f32,
338) -> bool {
339 let mut cam_moved = false;
342 let mut cam_rotated = false;
343
344 let mut movement_vec = Vec3::new_zero();
345 let mut rotation = Quaternion::new_identity();
346
347 let rotate_key_amt = -input_settings.rotate_key_sens * dt;
351
352 if inputs.roll_cw {
353 let fwd = cam.orientation.rotate_vec(FWD_VEC);
354 rotation = Quaternion::from_axis_angle(fwd, -rotate_key_amt);
355 cam_rotated = true;
356 } else if inputs.roll_ccw {
357 let fwd = cam.orientation.rotate_vec(FWD_VEC);
358 rotation = Quaternion::from_axis_angle(fwd, rotate_key_amt);
359 cam_rotated = true;
360 }
361
362 let mut skip_move_vec = false;
363 if inputs.free_look
365 && (inputs.mouse_delta_x.abs() > EPS_MOUSE || inputs.mouse_delta_y.abs() > EPS_MOUSE)
366 {
367 let rotate_amt = input_settings.rotate_sens * dt;
368 let up = cam.orientation.rotate_vec(-UP_VEC);
369 let right = cam.orientation.rotate_vec(-RIGHT_VEC);
370
371 rotation = Quaternion::from_axis_angle(up, -inputs.mouse_delta_x * rotate_amt)
373 * Quaternion::from_axis_angle(right, -inputs.mouse_delta_y * rotate_amt);
374
375 skip_move_vec = true;
377
378 cam_moved = true;
379 cam_rotated = true;
380 }
381
382 handle_scroll(
383 cam,
384 inputs,
385 input_settings,
386 dt,
387 &mut movement_vec,
388 &mut rotation,
389 &mut cam_moved,
390 &mut cam_rotated,
391 );
392
393 if cam_rotated {
399 cam.orientation = (rotation * cam.orientation).to_normalized();
400 }
401
402 if cam_moved && !skip_move_vec {
403 cam.position += cam.orientation.rotate_vec(movement_vec);
404 } else if cam_moved {
405 let dist = (cam.position - center).magnitude();
407 cam.position = center - cam.orientation.rotate_vec(FWD_VEC) * dist;
409 }
410
411 cam_moved || cam_rotated
412}