Commit | Line | Data |
---|---|---|
bf7b5671 TW |
1 | use sdl2::JoystickSubsystem; |
2 | use common::Nanoseconds; | |
3 | use common::Radians; | |
4 | use common::Point2D; | |
3f344b63 | 5 | use sdl2::HapticSubsystem; |
3f344b63 | 6 | use sdl2::event::Event; |
bf7b5671 TW |
7 | use sdl2::haptic::Haptic; |
8 | use sdl2::joystick::Joystick; | |
9 | use std::cell::RefCell; | |
10 | use std::collections::HashMap; | |
3f344b63 TW |
11 | use std::rc::Rc; |
12 | ||
bf7b5671 TW |
13 | #[derive(Debug, Default)] |
14 | pub struct Button { | |
15 | pub time_pressed: Nanoseconds, | |
16 | pub time_released: Nanoseconds, | |
17 | pub is_pressed: bool, | |
18 | pub was_pressed: bool, | |
19 | pub toggle: bool, | |
20 | } | |
21 | ||
22 | impl Button { | |
23 | fn update(&mut self, device: &Joystick, dt: Nanoseconds, btn: u8) { | |
24 | self.was_pressed = self.is_pressed; | |
25 | self.is_pressed = match device.button(btn as u32) { | |
26 | Ok(true) => { | |
27 | if !self.was_pressed { | |
28 | self.time_pressed = 0; | |
29 | self.toggle = !self.toggle; | |
30 | } | |
31 | self.time_pressed += dt; | |
32 | true | |
33 | } | |
34 | Ok(false) => { | |
35 | if self.was_pressed { | |
36 | self.time_released = 0; | |
37 | } | |
38 | self.time_released += dt; | |
39 | false | |
40 | } | |
41 | Err(_) => { panic!("invalid button {}", btn) } | |
42 | } | |
43 | } | |
44 | } | |
45 | ||
46 | #[derive(Debug, Default)] | |
47 | pub struct Axis { | |
48 | pub val: f32, | |
49 | } | |
50 | ||
51 | impl Axis { | |
52 | #[allow(dead_code)] | |
53 | fn update(&mut self, device: &Joystick, _dt: Nanoseconds, axis: u8) { | |
54 | self.val = match device.axis(axis as u32) { | |
55 | Ok(val) => val as f32 / 32768.0, | |
56 | Err(_) => panic!("invalid axis {}", axis), | |
57 | } | |
58 | } | |
59 | } | |
60 | ||
61 | #[derive(Debug, Default)] | |
62 | pub struct Stick { | |
63 | pub x: f32, | |
64 | pub y: f32, | |
65 | pub a: Radians, | |
66 | pub len: f32, | |
67 | } | |
68 | ||
69 | impl Stick { | |
70 | fn update(&mut self, device: &Joystick, _dt: Nanoseconds, x_axis: u8, y_axis: u8) { | |
71 | self.x = match device.axis(x_axis as u32) { | |
72 | Ok(val) => val as f32 / 32768.0, | |
73 | Err(_) => panic!("invalid x axis {}", x_axis), | |
74 | }; | |
75 | self.y = match device.axis(y_axis as u32) { | |
76 | Ok(val) => val as f32 / 32768.0, | |
77 | Err(_) => panic!("invalid y axis {}", y_axis), | |
78 | }; | |
79 | self.a = Radians(self.y.atan2(self.x) as f64); | |
80 | self.len = { | |
81 | let x = (self.x / self.y).abs().min(1.0); | |
82 | let y = (self.y / self.x).abs().min(1.0); | |
83 | (self.x.powi(2) + self.y.powi(2)).sqrt() / (x.powi(2) + y.powi(2)).sqrt() | |
84 | } | |
85 | } | |
86 | ||
87 | #[inline(always)] #[allow(dead_code)] fn up(&self) -> bool { self.y > 0.99 } | |
88 | #[inline(always)] #[allow(dead_code)] fn down(&self) -> bool { self.y < -0.99 } | |
89 | #[inline(always)] #[allow(dead_code)] fn left(&self) -> bool { self.x < -0.99 } | |
90 | #[inline(always)] #[allow(dead_code)] fn right(&self) -> bool { self.x > 0.99 } | |
91 | ||
92 | pub fn to_point(&self) -> Point2D<f64> { | |
93 | Point2D { | |
94 | x: self.x as f64, | |
95 | y: self.y as f64, | |
96 | } | |
97 | } | |
98 | ||
99 | pub fn to_adjusted_point(&self) -> Point2D<f64> { | |
100 | Point2D::from(self.a) * self.len as f64 | |
101 | } | |
102 | } | |
103 | ||
104 | impl From<&Stick> for Point2D<f64> { | |
105 | fn from(item: &Stick) -> Self { | |
106 | Self { | |
107 | x: item.x as f64, | |
108 | y: item.y as f64, | |
109 | } | |
110 | } | |
111 | } | |
112 | ||
113 | impl From<&Stick> for (f64, f64) { | |
114 | fn from(item: &Stick) -> Self { | |
115 | (item.x as f64, item.y as f64) | |
116 | } | |
3f344b63 TW |
117 | } |
118 | ||
119 | //#[derive(Debug)] | |
120 | pub struct Controller { | |
bf7b5671 | 121 | pub device: Joystick, |
3f344b63 | 122 | haptic: Option<Rc<RefCell<Haptic>>>, |
bf7b5671 TW |
123 | |
124 | pub mov: Stick, | |
125 | pub aim: Stick, | |
126 | pub jump: Button, | |
127 | pub start: Button, | |
128 | pub shoot: Button, | |
129 | } | |
130 | ||
131 | impl Controller { | |
132 | pub fn new(device: Joystick, haptic: Option<Rc<RefCell<Haptic>>>) -> Self { | |
133 | Controller { | |
134 | device, | |
135 | haptic, | |
136 | mov: Default::default(), | |
137 | aim: Default::default(), | |
138 | jump: Default::default(), | |
139 | start: Default::default(), | |
140 | shoot: Default::default(), | |
141 | } | |
142 | } | |
143 | ||
144 | pub fn update(&mut self, dt: Nanoseconds) { | |
145 | self.mov.update(&self.device, dt, 0, 1); // left stick | |
146 | self.aim.update(&self.device, dt, 3, 4); // right stick | |
147 | self.jump.update(&self.device, dt, 4); // left shoulder | |
148 | self.shoot.update(&self.device, dt, 5); // right shoulder | |
149 | self.start.update(&self.device, dt, 9); // start | |
150 | } | |
151 | ||
152 | /// strength [0 - 1] | |
153 | pub fn rumble(&self, strength: f32, duration_ms: u32) { | |
154 | if let Some(h) = &self.haptic { | |
155 | h.borrow_mut().rumble_play(strength, duration_ms); | |
156 | } | |
157 | } | |
158 | } | |
159 | ||
160 | //#[derive(Debug)] | |
161 | pub struct ControllerManager { | |
162 | pub joystick: JoystickSubsystem, | |
163 | haptic: Rc<HapticSubsystem>, | |
164 | pub controllers: HashMap<u32, Rc<RefCell<Controller>>>, | |
3f344b63 TW |
165 | } |
166 | ||
167 | impl ControllerManager { | |
bf7b5671 TW |
168 | pub fn new(joystick: JoystickSubsystem, haptic: HapticSubsystem) -> Self { |
169 | joystick.set_event_state(true); | |
b0566120 | 170 | let mut c = ControllerManager { |
bf7b5671 | 171 | joystick, |
3f344b63 | 172 | haptic: Rc::new(haptic), |
b0566120 TW |
173 | controllers: HashMap::new(), |
174 | }; | |
175 | c.init(); | |
176 | c | |
177 | } | |
178 | ||
179 | fn init(&mut self) { | |
bf7b5671 | 180 | for i in 0..self.joystick.num_joysticks().unwrap() { |
b0566120 | 181 | self.add_device(i); |
3f344b63 TW |
182 | } |
183 | } | |
184 | ||
bf7b5671 TW |
185 | pub fn update(&mut self, dt: Nanoseconds) { |
186 | self.controllers.iter().for_each(|(_, v)| v.borrow_mut().update(dt)); | |
187 | } | |
188 | ||
3f344b63 TW |
189 | pub fn handle_event(&mut self, event: &Event) { |
190 | match event { | |
bf7b5671 TW |
191 | Event::JoyDeviceAdded { which, .. } => { self.add_device(*which) } |
192 | Event::JoyDeviceRemoved { which, .. } => { self.remove_device(*which) } | |
193 | Event::JoyButtonDown { which, button_idx, .. } => { println!("device {} button {} down!", which, button_idx) } | |
194 | Event::JoyButtonUp { which, button_idx, .. } => { println!("device {} button {} up!", which, button_idx) } | |
195 | Event::JoyAxisMotion { which, axis_idx, .. } => { println!("device {} axis motion {}!", which, axis_idx) } | |
3f344b63 TW |
196 | _ => {} |
197 | } | |
198 | } | |
199 | ||
bf7b5671 | 200 | fn add_device(&mut self, id: u32) { |
3f344b63 | 201 | println!("device added ({})!", id); |
bf7b5671 TW |
202 | let mut device = self.joystick.open(id).unwrap(); |
203 | println!("opened {}", device.name()); | |
ca99d4d7 TW |
204 | |
205 | /* | |
206 | note about set_rumble (for dualshock 3 at least): | |
207 | the active range for the low frequency is from 65536/4 to 65536 and escalates in large steps throughout the range | |
208 | the active range for the high frequency is from 256 to 65536 and effect is the same throughout the whole range | |
209 | */ | |
bf7b5671 | 210 | let haptic = match device.set_rumble(0, 256, 100) { |
3f344b63 TW |
211 | Ok(_) => self.haptic.open_from_joystick_id(id).ok(), |
212 | Err(_) => None | |
213 | }; | |
214 | ||
b0566120 TW |
215 | if self.controllers.contains_key(&id) { |
216 | return; | |
217 | } | |
218 | ||
bf7b5671 | 219 | let detached = self.controllers.values().find(|c| !c.borrow().device.attached()); |
ca99d4d7 TW |
220 | match detached { |
221 | Some(c) => { | |
222 | let mut c = c.borrow_mut(); | |
bf7b5671 | 223 | c.device = device; |
ca99d4d7 TW |
224 | c.haptic = haptic.map(|h| Rc::new(RefCell::new(h))); |
225 | } | |
226 | None => { | |
bf7b5671 | 227 | let c = Rc::new(RefCell::new(Controller::new(device, haptic.map(|h| Rc::new(RefCell::new(h)))))); |
b0566120 | 228 | self.controllers.insert(id, c); |
ca99d4d7 TW |
229 | } |
230 | }; | |
3f344b63 TW |
231 | } |
232 | ||
bf7b5671 | 233 | fn remove_device(&mut self, id: i32) { |
3f344b63 | 234 | println!("device removed ({})!", id); |
ca99d4d7 | 235 | // TODO |
3f344b63 TW |
236 | } |
237 | } |