Replaced mapping struct with hashmap
[kaka/rust-sdl-test.git] / src / core / controller.rs
CommitLineData
bf7b5671 1use common::Point2D;
05ba0976 2use hashmap;
902b2b31 3use common::Radians;
3f344b63 4use sdl2::HapticSubsystem;
902b2b31 5use sdl2::JoystickSubsystem;
3f344b63 6use sdl2::event::Event;
bf7b5671
TW
7use sdl2::haptic::Haptic;
8use sdl2::joystick::Joystick;
9use std::cell::RefCell;
10use std::collections::HashMap;
3f344b63 11use std::rc::Rc;
902b2b31 12use time::{Duration, prelude::*};
3f344b63 13
bf7b5671
TW
14#[derive(Debug, Default)]
15pub struct Button {
5d731022 16 id: u8,
902b2b31
TW
17 pub time_pressed: Duration,
18 pub time_released: Duration,
bf7b5671
TW
19 pub is_pressed: bool,
20 pub was_pressed: bool,
21 pub toggle: bool,
22}
23
24impl Button {
5d731022 25 fn update(&mut self, device: &Joystick, dt: Duration) {
bf7b5671 26 self.was_pressed = self.is_pressed;
5d731022 27 self.is_pressed = match device.button(self.id as u32) {
bf7b5671
TW
28 Ok(true) => {
29 if !self.was_pressed {
902b2b31 30 self.time_pressed = 0.seconds();
bf7b5671
TW
31 self.toggle = !self.toggle;
32 }
33 self.time_pressed += dt;
34 true
35 }
36 Ok(false) => {
37 if self.was_pressed {
902b2b31 38 self.time_released = 0.seconds();
bf7b5671
TW
39 }
40 self.time_released += dt;
41 false
42 }
5d731022 43 Err(_) => { panic!("invalid button {}", self.id) }
bf7b5671
TW
44 }
45 }
46}
47
48#[derive(Debug, Default)]
49pub struct Axis {
5d731022 50 id: u8,
bf7b5671
TW
51 pub val: f32,
52}
53
54impl Axis {
55 #[allow(dead_code)]
5d731022
TW
56 fn update(&mut self, device: &Joystick, _dt: Duration) {
57 self.val = match device.axis(self.id as u32) {
bf7b5671 58 Ok(val) => val as f32 / 32768.0,
5d731022 59 Err(_) => panic!("invalid axis {}", self.id),
bf7b5671
TW
60 }
61 }
62}
63
64#[derive(Debug, Default)]
65pub struct Stick {
5d731022
TW
66 idx: u8,
67 idy: u8,
bf7b5671
TW
68 pub x: f32,
69 pub y: f32,
70 pub a: Radians,
71 pub len: f32,
72}
73
74impl Stick {
5d731022
TW
75 fn update(&mut self, device: &Joystick, _dt: Duration) {
76 self.x = match device.axis(self.idx as u32) {
bf7b5671 77 Ok(val) => val as f32 / 32768.0,
5d731022 78 Err(_) => panic!("invalid x axis {}", self.idx),
bf7b5671 79 };
5d731022 80 self.y = match device.axis(self.idy as u32) {
bf7b5671 81 Ok(val) => val as f32 / 32768.0,
5d731022 82 Err(_) => panic!("invalid y axis {}", self.idy),
bf7b5671
TW
83 };
84 self.a = Radians(self.y.atan2(self.x) as f64);
85 self.len = {
86 let x = (self.x / self.y).abs().min(1.0);
87 let y = (self.y / self.x).abs().min(1.0);
88 (self.x.powi(2) + self.y.powi(2)).sqrt() / (x.powi(2) + y.powi(2)).sqrt()
89 }
90 }
91
92 #[inline(always)] #[allow(dead_code)] fn up(&self) -> bool { self.y > 0.99 }
93 #[inline(always)] #[allow(dead_code)] fn down(&self) -> bool { self.y < -0.99 }
94 #[inline(always)] #[allow(dead_code)] fn left(&self) -> bool { self.x < -0.99 }
95 #[inline(always)] #[allow(dead_code)] fn right(&self) -> bool { self.x > 0.99 }
96
97 pub fn to_point(&self) -> Point2D<f64> {
98 Point2D {
99 x: self.x as f64,
100 y: self.y as f64,
101 }
102 }
103
104 pub fn to_adjusted_point(&self) -> Point2D<f64> {
105 Point2D::from(self.a) * self.len as f64
106 }
107}
108
109impl From<&Stick> for Point2D<f64> {
110 fn from(item: &Stick) -> Self {
111 Self {
112 x: item.x as f64,
113 y: item.y as f64,
114 }
115 }
116}
117
118impl From<&Stick> for (f64, f64) {
119 fn from(item: &Stick) -> Self {
120 (item.x as f64, item.y as f64)
121 }
3f344b63
TW
122}
123
05ba0976
TW
124#[derive(Eq, PartialEq, Hash)]
125enum DeviceControls {
126 AxisLX,
127 AxisLY,
128 AxisRX,
129 AxisRY,
130 AxisL2,
131 AxisR2,
132 ButtonA,
133 ButtonB,
134 ButtonY,
135 ButtonX,
136 ButtonSelect,
137 ButtonStart,
138 ButtonHome,
139 ButtonL3,
140 ButtonR3,
141 ButtonL1,
142 ButtonR1,
143 ButtonL2,
144 ButtonR2,
145 ButtonUp,
146 ButtonDown,
147 ButtonLeft,
148 ButtonRight,
5d731022
TW
149}
150
05ba0976
TW
151#[derive(Eq, PartialEq, Hash)]
152enum ActionControls {
153 MovementX,
154 MovementY,
155 AimX,
156 AimY,
157 Jump,
158 Shoot,
159 Start,
5d731022
TW
160}
161
3f344b63
TW
162//#[derive(Debug)]
163pub struct Controller {
bf7b5671 164 pub device: Joystick,
3f344b63 165 haptic: Option<Rc<RefCell<Haptic>>>,
bf7b5671
TW
166
167 pub mov: Stick,
168 pub aim: Stick,
169 pub jump: Button,
170 pub start: Button,
171 pub shoot: Button,
172}
173
174impl Controller {
175 pub fn new(device: Joystick, haptic: Option<Rc<RefCell<Haptic>>>) -> Self {
05ba0976
TW
176 let action_map = get_action_mapping();
177 let device_map = get_device_mapping(&device.name());
5d731022 178 let mut ctrl = Controller {
bf7b5671
TW
179 device,
180 haptic,
181 mov: Default::default(),
182 aim: Default::default(),
183 jump: Default::default(),
184 start: Default::default(),
185 shoot: Default::default(),
5d731022 186 };
05ba0976 187 ctrl.set_mapping(&action_map, &device_map);
5d731022
TW
188 ctrl
189 }
190
05ba0976
TW
191 fn set_mapping(&mut self, action: &HashMap<ActionControls, DeviceControls>, device: &HashMap<DeviceControls, u8>) {
192 self.mov.idx = *action.get(&ActionControls::MovementX).map(|i| device.get(i)).flatten().unwrap();
193 self.mov.idy = *action.get(&ActionControls::MovementY).map(|i| device.get(i)).flatten().unwrap();
194 self.aim.idx = *action.get(&ActionControls::AimX).map(|i| device.get(i)).flatten().unwrap();
195 self.aim.idy = *action.get(&ActionControls::AimY).map(|i| device.get(i)).flatten().unwrap();
196 self.jump.id = *action.get(&ActionControls::Jump).map(|i| device.get(i)).flatten().unwrap();
197 self.shoot.id = *action.get(&ActionControls::Shoot).map(|i| device.get(i)).flatten().unwrap();
198 self.start.id = *action.get(&ActionControls::Start).map(|i| device.get(i)).flatten().unwrap();
bf7b5671
TW
199 }
200
902b2b31 201 pub fn update(&mut self, dt: Duration) {
5d731022
TW
202 self.mov.update(&self.device, dt);
203 self.aim.update(&self.device, dt);
204 self.jump.update(&self.device, dt);
205 self.shoot.update(&self.device, dt);
206 self.start.update(&self.device, dt);
bf7b5671
TW
207 }
208
209 /// strength [0 - 1]
902b2b31 210 pub fn rumble(&self, strength: f32, duration: Duration) {
bf7b5671 211 if let Some(h) = &self.haptic {
902b2b31 212 h.borrow_mut().rumble_play(strength, duration.whole_milliseconds() as u32);
bf7b5671
TW
213 }
214 }
215}
216
05ba0976
TW
217fn get_action_mapping() -> HashMap<ActionControls, DeviceControls> {
218 hashmap!(
219 ActionControls::MovementX => DeviceControls::AxisLX,
220 ActionControls::MovementY => DeviceControls::AxisLY,
221 ActionControls::AimX => DeviceControls::AxisRX,
222 ActionControls::AimY => DeviceControls::AxisRY,
223 ActionControls::Jump => DeviceControls::ButtonL1,
224 ActionControls::Shoot => DeviceControls::ButtonR1,
225 ActionControls::Start => DeviceControls::ButtonStart
226 )
227}
228
229fn get_device_mapping(device_name: &str) -> HashMap<DeviceControls, u8> {
230 match device_name {
231 "Sony PLAYSTATION(R)3 Controller" => hashmap!(
232 DeviceControls::AxisLX => 0,
233 DeviceControls::AxisLY => 1,
234 DeviceControls::AxisRX => 3,
235 DeviceControls::AxisRY => 4,
236 DeviceControls::AxisL2 => 2,
237 DeviceControls::AxisR2 => 5,
238 DeviceControls::ButtonA => 0,
239 DeviceControls::ButtonB => 1,
240 DeviceControls::ButtonY => 3,
241 DeviceControls::ButtonX => 2,
242 DeviceControls::ButtonSelect => 8,
243 DeviceControls::ButtonStart => 9,
244 DeviceControls::ButtonHome => 10,
245 DeviceControls::ButtonL3 => 11,
246 DeviceControls::ButtonR3 => 12,
247 DeviceControls::ButtonL1 => 4,
248 DeviceControls::ButtonR1 => 5,
249 DeviceControls::ButtonL2 => 6,
250 DeviceControls::ButtonR2 => 7,
251 DeviceControls::ButtonUp => 13,
252 DeviceControls::ButtonDown => 14,
253 DeviceControls::ButtonLeft => 15,
254 DeviceControls::ButtonRight => 16
255 ),
256 _ => panic!("No controller mapping for device '{}'", device_name)
257 }
258}
259
bf7b5671
TW
260//#[derive(Debug)]
261pub struct ControllerManager {
262 pub joystick: JoystickSubsystem,
263 haptic: Rc<HapticSubsystem>,
264 pub controllers: HashMap<u32, Rc<RefCell<Controller>>>,
3f344b63
TW
265}
266
267impl ControllerManager {
bf7b5671
TW
268 pub fn new(joystick: JoystickSubsystem, haptic: HapticSubsystem) -> Self {
269 joystick.set_event_state(true);
b0566120 270 let mut c = ControllerManager {
bf7b5671 271 joystick,
3f344b63 272 haptic: Rc::new(haptic),
b0566120
TW
273 controllers: HashMap::new(),
274 };
275 c.init();
276 c
277 }
278
279 fn init(&mut self) {
bf7b5671 280 for i in 0..self.joystick.num_joysticks().unwrap() {
b0566120 281 self.add_device(i);
3f344b63
TW
282 }
283 }
284
902b2b31 285 pub fn update(&mut self, dt: Duration) {
bf7b5671
TW
286 self.controllers.iter().for_each(|(_, v)| v.borrow_mut().update(dt));
287 }
288
3f344b63
TW
289 pub fn handle_event(&mut self, event: &Event) {
290 match event {
bf7b5671
TW
291 Event::JoyDeviceAdded { which, .. } => { self.add_device(*which) }
292 Event::JoyDeviceRemoved { which, .. } => { self.remove_device(*which) }
5d731022
TW
293 // Event::JoyButtonDown { which, button_idx, .. } => { println!("device {} button {} down!", which, button_idx) }
294 // Event::JoyButtonUp { which, button_idx, .. } => { println!("device {} button {} up!", which, button_idx) }
295 // Event::JoyAxisMotion { which, axis_idx, .. } => { println!("device {} axis motion {}!", which, axis_idx) }
3f344b63
TW
296 _ => {}
297 }
298 }
299
bf7b5671 300 fn add_device(&mut self, id: u32) {
3f344b63 301 println!("device added ({})!", id);
bf7b5671
TW
302 let mut device = self.joystick.open(id).unwrap();
303 println!("opened {}", device.name());
ca99d4d7
TW
304
305 /*
306 note about set_rumble (for dualshock 3 at least):
307 the active range for the low frequency is from 65536/4 to 65536 and escalates in large steps throughout the range
308 the active range for the high frequency is from 256 to 65536 and effect is the same throughout the whole range
309 */
bf7b5671 310 let haptic = match device.set_rumble(0, 256, 100) {
3f344b63
TW
311 Ok(_) => self.haptic.open_from_joystick_id(id).ok(),
312 Err(_) => None
313 };
314
b0566120
TW
315 if self.controllers.contains_key(&id) {
316 return;
317 }
318
bf7b5671 319 let detached = self.controllers.values().find(|c| !c.borrow().device.attached());
ca99d4d7
TW
320 match detached {
321 Some(c) => {
322 let mut c = c.borrow_mut();
bf7b5671 323 c.device = device;
ca99d4d7
TW
324 c.haptic = haptic.map(|h| Rc::new(RefCell::new(h)));
325 }
326 None => {
bf7b5671 327 let c = Rc::new(RefCell::new(Controller::new(device, haptic.map(|h| Rc::new(RefCell::new(h))))));
b0566120 328 self.controllers.insert(id, c);
ca99d4d7
TW
329 }
330 };
3f344b63
TW
331 }
332
bf7b5671 333 fn remove_device(&mut self, id: i32) {
3f344b63 334 println!("device removed ({})!", id);
ca99d4d7 335 // TODO
3f344b63
TW
336 }
337}