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, }
35
36impl InputsCommanded {
37 pub fn inputs_present(&self) -> bool {
39 self.fwd
41 || self.back
42 || self.left
43 || self.right
44 || self.up
45 || self.down
46 || self.roll_ccw
47 || self.roll_cw
48 || self.mouse_delta_x.abs() > EPS_MOUSE
49 || self.mouse_delta_y.abs() > EPS_MOUSE
50 || self.scroll_up
51 || self.scroll_down
52 }
53}
54
55pub(crate) fn add_input_cmd(event: &DeviceEvent, inputs: &mut InputsCommanded) {
59 match event {
60 DeviceEvent::Key(key) => {
61 if key.state == ElementState::Pressed {
62 match key.physical_key {
63 Code(key) => match key {
64 KeyCode::KeyW => {
65 inputs.fwd = true;
66 }
67 KeyCode::KeyS => {
68 inputs.back = true;
69 }
70 KeyCode::KeyA => {
71 inputs.left = true;
72 }
73 KeyCode::KeyD => {
74 inputs.right = true;
75 }
76 KeyCode::Space => {
77 inputs.up = true;
78 }
79 KeyCode::KeyC => {
80 inputs.down = true;
81 }
82 KeyCode::KeyQ => {
83 inputs.roll_ccw = true;
84 }
85 KeyCode::KeyE => {
86 inputs.roll_cw = true;
87 }
88 KeyCode::ShiftLeft => {
89 inputs.run = true;
90 }
91 _ => (),
92 },
93 _ => (),
94 }
95 } else if key.state == ElementState::Released {
96 match key.physical_key {
98 Code(key) => match key {
99 KeyCode::KeyW => {
100 inputs.fwd = false;
101 }
102 KeyCode::KeyS => {
103 inputs.back = false;
104 }
105 KeyCode::KeyA => {
106 inputs.left = false;
107 }
108 KeyCode::KeyD => {
109 inputs.right = false;
110 }
111 KeyCode::Space => {
112 inputs.up = false;
113 }
114 KeyCode::KeyC => {
115 inputs.down = false;
116 }
117 KeyCode::KeyQ => {
118 inputs.roll_ccw = false;
119 }
120 KeyCode::KeyE => {
121 inputs.roll_cw = false;
122 }
123 KeyCode::ShiftLeft => {
124 inputs.run = false;
125 }
126 _ => (),
127 },
128 _ => (),
129 }
130 }
131 }
132 DeviceEvent::Button { button, state } => {
133 #[cfg(target_os = "linux")]
135 let left_click = 1;
136 #[cfg(not(target_os = "linux"))]
137 let left_click = 0;
138
139 if *button == left_click {
142 inputs.free_look = match state {
143 ElementState::Pressed => true,
144 ElementState::Released => false,
145 }
146 }
147 }
148 DeviceEvent::MouseMotion { delta } => {
149 inputs.mouse_delta_x += delta.0 as f32;
150 inputs.mouse_delta_y += delta.1 as f32;
151 }
152 DeviceEvent::MouseWheel { delta } => match delta {
154 MouseScrollDelta::PixelDelta(_) => (),
155 MouseScrollDelta::LineDelta(_x, y) => {
156 if *y > 0. {
157 inputs.scroll_down = true;
158 } else {
159 inputs.scroll_up = true;
160 }
161 }
162 },
163 _ => (),
164 }
165}
166
167fn handle_scroll(
168 cam: &mut Camera,
169 inputs: &mut InputsCommanded,
170 input_settings: &InputSettings,
171 dt: f32,
172 movement_vec: &mut Vec3,
173 rotation: &mut Quaternion,
174 cam_moved: &mut bool,
175 cam_rotated: &mut bool,
176) {
177 if inputs.scroll_down || inputs.scroll_up {
178 if let ScrollBehavior::MoveRoll {
179 move_amt,
180 rotate_amt,
181 } = input_settings.scroll_behavior
182 {
183 if inputs.free_look {
184 let fwd = cam.orientation.rotate_vec(FWD_VEC);
186
187 let mut rot_amt = -rotate_amt * dt;
188 if inputs.scroll_down {
189 rot_amt *= -1.; }
191
192 *rotation = Quaternion::from_axis_angle(fwd, rot_amt);
193 *cam_rotated = true;
194 } else {
195 let mut movement = Vec3::new(0., 0., move_amt);
197 if inputs.scroll_up {
198 movement *= -1.;
199 }
200 *movement_vec += movement;
201
202 *cam_moved = true;
203 }
204 }
205
206 inputs.scroll_down = false;
208 inputs.scroll_up = false;
209 }
210}
211
212pub fn arc_rotation(cam: &mut Camera, axis: Vec3, amt: f32, center: Vec3) {
214 let rotation = Quaternion::from_axis_angle(axis, amt);
215
216 cam.orientation = (rotation * cam.orientation).to_normalized();
217
218 let dist = (cam.position - center).magnitude();
219 cam.position = center - cam.orientation.rotate_vec(FWD_VEC) * dist;
221}
222
223pub fn adjust_camera_free(
226 cam: &mut Camera,
227 inputs: &mut InputsCommanded,
228 input_settings: &InputSettings,
229 dt: f32,
230) -> bool {
231 let mut move_amt = input_settings.move_sens * dt;
232 let mut rotate_key_amt = input_settings.rotate_key_sens * dt;
233
234 let mut cam_moved = false;
235 let mut cam_rotated = false;
236
237 let mut movement_vec = Vec3::new_zero();
238 let mut rotation = Quaternion::new_identity();
239
240 if inputs.run {
241 move_amt *= input_settings.run_factor;
242 rotate_key_amt *= input_settings.run_factor;
243 }
244
245 if inputs.fwd {
246 movement_vec.z += move_amt;
247 cam_moved = true;
248 } else if inputs.back {
249 movement_vec.z -= move_amt;
250 cam_moved = true;
251 }
252
253 if inputs.right {
254 movement_vec.x += move_amt;
255 cam_moved = true;
256 } else if inputs.left {
257 movement_vec.x -= move_amt;
258 cam_moved = true;
259 }
260
261 if inputs.up {
262 movement_vec.y += move_amt;
263 cam_moved = true;
264 } else if inputs.down {
265 movement_vec.y -= move_amt;
266 cam_moved = true;
267 }
268
269 if inputs.roll_cw {
270 let fwd = cam.orientation.rotate_vec(FWD_VEC);
271 rotation = Quaternion::from_axis_angle(fwd, -rotate_key_amt);
272 cam_rotated = true;
273 } else if inputs.roll_ccw {
274 let fwd = cam.orientation.rotate_vec(FWD_VEC);
275 rotation = Quaternion::from_axis_angle(fwd, rotate_key_amt);
276 cam_rotated = true;
277 }
278
279 if inputs.free_look
280 && (inputs.mouse_delta_x.abs() > EPS_MOUSE || inputs.mouse_delta_y.abs() > EPS_MOUSE)
281 {
282 let rotate_amt = input_settings.rotate_sens * dt;
283 let up = cam.orientation.rotate_vec(-UP_VEC);
284 let right = cam.orientation.rotate_vec(-RIGHT_VEC);
285
286 rotation = Quaternion::from_axis_angle(up, -inputs.mouse_delta_x * rotate_amt)
287 * Quaternion::from_axis_angle(right, -inputs.mouse_delta_y * rotate_amt)
288 * rotation;
289
290 cam_rotated = true;
291 }
292
293 handle_scroll(
294 cam,
295 inputs,
296 input_settings,
297 dt,
298 &mut movement_vec,
299 &mut rotation,
300 &mut cam_moved,
301 &mut cam_rotated,
302 );
303
304 if cam_rotated {
307 cam.orientation = (rotation * cam.orientation).to_normalized();
308 }
309
310 if cam_moved {
311 cam.position += cam.orientation.rotate_vec(movement_vec);
312 }
313
314 cam_moved || cam_rotated
315}
316
317pub fn adjust_camera_arc(
320 cam: &mut Camera,
321 inputs: &mut InputsCommanded,
322 input_settings: &InputSettings,
323 center: Vec3,
324 dt: f32,
325) -> bool {
326 let mut cam_moved = false;
329 let mut cam_rotated = false;
330
331 let mut movement_vec = Vec3::new_zero();
332 let mut rotation = Quaternion::new_identity();
333
334 let rotate_key_amt = -input_settings.rotate_key_sens * dt;
338
339 if inputs.roll_cw {
340 let fwd = cam.orientation.rotate_vec(FWD_VEC);
341 rotation = Quaternion::from_axis_angle(fwd, -rotate_key_amt);
342 cam_rotated = true;
343 } else if inputs.roll_ccw {
344 let fwd = cam.orientation.rotate_vec(FWD_VEC);
345 rotation = Quaternion::from_axis_angle(fwd, rotate_key_amt);
346 cam_rotated = true;
347 }
348
349 let mut skip_move_vec = false;
350 if inputs.free_look
352 && (inputs.mouse_delta_x.abs() > EPS_MOUSE || inputs.mouse_delta_y.abs() > EPS_MOUSE)
353 {
354 let rotate_amt = input_settings.rotate_sens * dt;
355 let up = cam.orientation.rotate_vec(-UP_VEC);
356 let right = cam.orientation.rotate_vec(-RIGHT_VEC);
357
358 rotation = Quaternion::from_axis_angle(up, -inputs.mouse_delta_x * rotate_amt)
360 * Quaternion::from_axis_angle(right, -inputs.mouse_delta_y * rotate_amt);
361
362 skip_move_vec = true;
364
365 cam_moved = true;
366 cam_rotated = true;
367 }
368
369 handle_scroll(
370 cam,
371 inputs,
372 input_settings,
373 dt,
374 &mut movement_vec,
375 &mut rotation,
376 &mut cam_moved,
377 &mut cam_rotated,
378 );
379
380 if cam_rotated {
386 cam.orientation = (rotation * cam.orientation).to_normalized();
387 }
388
389 if cam_moved && !skip_move_vec {
390 cam.position += cam.orientation.rotate_vec(movement_vec);
391 } else if cam_moved {
392 let dist = (cam.position - center).magnitude();
394 cam.position = center - cam.orientation.rotate_vec(FWD_VEC) * dist;
396 }
397
398 cam_moved || cam_rotated
399}