1use std::{
2 time::Duration,
3 f64::consts::PI,
4
5};
6use sdl2::{
7 event::Event,
8 mouse::{MouseState, RelativeMouseState},
9 keyboard::Keycode,
10};
11use nalgebra::{Vector3, Rotation3};
12use crate::{WindowState, EventHandler};
13
14
15fn clamp(x: f64, a: f64, b: f64) -> f64 {
16 if x < a {
17 a
18 } else if x > b {
19 b
20 } else {
21 x
22 }
23}
24
25const KEYS: [Keycode; 12] = [
26 Keycode::W,
27 Keycode::Up,
28 Keycode::A,
29 Keycode::Left,
30 Keycode::S,
31 Keycode::Down,
32 Keycode::D,
33 Keycode::Right,
34 Keycode::Space,
35 Keycode::C,
36 Keycode::Q,
37 Keycode::E,
38];
39
40fn key_idx(key: Keycode) -> Option<usize> {
41 KEYS.iter().position(|k| *k == key)
42}
43
44fn key_dir(key: Keycode) -> (Vector3<f64>, Vector3<f64>) {
45 match key {
46 Keycode::W | Keycode::Up => (Vector3::new(0.0, 0.0, -1.0), Vector3::zeros()),
47 Keycode::A | Keycode::Left => (Vector3::new(-1.0, 0.0, 0.0), Vector3::zeros()),
48 Keycode::S | Keycode::Down => (Vector3::new(0.0, 0.0, 1.0), Vector3::zeros()),
49 Keycode::D | Keycode::Right => (Vector3::new(1.0, 0.0, 0.0), Vector3::zeros()),
50 Keycode::Space => (Vector3::zeros(), Vector3::new(0.0, 0.0, 1.0)),
51 Keycode::C => (Vector3::zeros(), Vector3::new(0.0, 0.0, -1.0)),
52 _ => (Vector3::zeros(), Vector3::zeros()),
53 }
54}
55
56pub struct Motion {
57 pub updated: bool,
58 pub key_mask: usize,
59
60 pub pos: Vector3<f64>,
61
62 pub phi: f64,
64 pub theta: f64,
65
66 pub speed: f64,
67 pub sens: f64,
68
69 pub fov: f64,
70 pub fov_sens: f64,
71}
72
73impl Motion {
74 pub fn new(pos: Vector3<f64>, ori: Rotation3<f64>) -> Self {
75 let (theta, _, phi) = ori.euler_angles();
76 Self {
77 updated: false, key_mask: 0,
78 pos, phi, theta,
79 speed: 1.0, sens: 4e-3,
80 fov: 1.0, fov_sens: 1e-1,
81 }
82 }
83
84 pub fn set_speed(&mut self, speed: f64) {
85 self.speed = speed;
86 }
87 pub fn set_sensitivity(&mut self, sens: f64) {
88 self.sens = sens;
89 }
90
91 fn handle_keys(&mut self, event: &Event) {
92 match event {
93 Event::KeyDown { keycode: Some(key), .. } => if let Some(i) = key_idx(*key) {
94 self.key_mask |= 1 << i;
95 self.updated = true;
96 },
97 Event::KeyUp { keycode: Some(key), .. } => if let Some(i) = key_idx(*key) {
98 self.key_mask &= !(1 << i);
99 self.updated = true;
100 },
101 Event::MouseWheel { y, .. } => {
102 if *y != 0 {
103 self.fov *= (self.fov_sens*(-*y as f64)).exp();
104 self.updated = true;
105 }
106 }
107 _ => (),
108 }
109 }
110
111 fn handle_mouse(&mut self, mouse: &RelativeMouseState) {
112 if mouse.x() != 0 || mouse.y() != 0 {
113 self.phi -= self.sens*(mouse.x() as f64);
114 let t = (self.phi/(2.0*PI)).floor() as i32;
115 if t != 0 {
116 self.phi -= 2.0*PI*(t as f64);
117 }
118
119 self.theta -= self.sens*(mouse.y() as f64);
120 if self.theta < 0.0 {
121 self.theta = 0.0;
122 } else if self.theta > PI {
123 self.theta = PI;
124 }
125 self.updated = true;
126 }
127 }
128
129 pub fn pos(&self) -> Vector3<f64> {
130 self.pos.clone()
131 }
132 pub fn ori(&self) -> Rotation3<f64> {
133 Rotation3::from_euler_angles(self.theta, 0.0, self.phi)
134 }
135
136 pub fn was_updated(&self) -> bool {
137 self.updated || self.key_mask != 0
138 }
139
140 pub fn step(&mut self, dt: Duration) {
141 let (mut dir, mut idir) = (Vector3::zeros(), Vector3::zeros());
142 for (i, k) in KEYS.iter().enumerate() {
143 if ((self.key_mask >> i) & 1) != 0 {
144 let (dv, di) = key_dir(*k);
145 dir += dv;
146 idir += di;
147 }
148 }
149 dir = dir.map(|x| clamp(x, -1.0, 1.0));
150 if dir.norm() > 1e-4 {
151 dir = dir.normalize();
152 }
153 dir = self.ori()*dir;
154 self.pos += 1e-6*(dt.as_micros() as f64)*self.speed*(dir + idir);
155
156 self.updated = false;
157 }
158}
159
160impl EventHandler for Motion {
161 fn handle_keys(&mut self, _state: &WindowState, event: &Event) -> clay_core::Result<()> {
162 self.handle_keys(event);
163 Ok(())
164 }
165 fn handle_mouse(
166 &mut self, state: &WindowState,
167 ms: &MouseState, rms: &RelativeMouseState,
168 ) -> clay_core::Result<()> {
169 if state.capture {
170 self.handle_mouse(&rms);
171 } else if ms.left() {
172 self.handle_mouse(&rms);
173 }
174 Ok(())
175 }
176}