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