normalize() to normalized()
[kaka/rust-sdl-test.git] / src / core / controller.rs
1 use common::Point2D;
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)] fn up(&self) -> bool { self.y > 0.99 }
87     #[inline(always)] #[allow(dead_code)] fn down(&self) -> bool { self.y < -0.99 }
88     #[inline(always)] #[allow(dead_code)] fn left(&self) -> bool { self.x < -0.99 }
89     #[inline(always)] #[allow(dead_code)] fn right(&self) -> bool { self.x > 0.99 }
90
91     pub fn to_axis_point(&self) -> Point2D<f64> {
92         point!(self.x as f64, self.y as f64)
93     }
94
95     pub fn to_point(&self) -> Point2D<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 Point2D<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
147 #[derive(Eq, PartialEq, Hash)]
148 enum ActionControls {
149     MovementX,
150     MovementY,
151     AimX,
152     AimY,
153     Jump,
154     Shoot,
155     Start,
156 }
157
158 //#[derive(Debug)]
159 pub struct Controller {
160     pub device: Joystick,
161     haptic: Option<Rc<RefCell<Haptic>>>,
162
163     pub mov: Stick,
164     pub aim: Stick,
165     pub jump: Button,
166     pub start: Button,
167     pub shoot: Button,
168 }
169
170 impl Controller {
171     pub fn new(device: Joystick, haptic: Option<Rc<RefCell<Haptic>>>) -> Self {
172         let action_map = get_action_mapping();
173         let device_map = get_device_mapping(&device.name());
174         let mut ctrl = Controller {
175             device,
176             haptic,
177             mov: Default::default(),
178             aim: Default::default(),
179             jump: Default::default(),
180             start: Default::default(),
181             shoot: Default::default(),
182         };
183         ctrl.set_mapping(&action_map, &device_map);
184         ctrl
185     }
186
187     fn set_mapping(&mut self, action: &HashMap<ActionControls, DeviceControls>, device: &HashMap<DeviceControls, u8>) {
188         self.mov.idx = *action.get(&ActionControls::MovementX).map(|i| device.get(i)).flatten().unwrap();
189         self.mov.idy = *action.get(&ActionControls::MovementY).map(|i| device.get(i)).flatten().unwrap();
190         self.aim.idx = *action.get(&ActionControls::AimX).map(|i| device.get(i)).flatten().unwrap();
191         self.aim.idy = *action.get(&ActionControls::AimY).map(|i| device.get(i)).flatten().unwrap();
192         self.jump.id = *action.get(&ActionControls::Jump).map(|i| device.get(i)).flatten().unwrap();
193         self.shoot.id = *action.get(&ActionControls::Shoot).map(|i| device.get(i)).flatten().unwrap();
194         self.start.id = *action.get(&ActionControls::Start).map(|i| device.get(i)).flatten().unwrap();
195     }
196
197     pub fn update(&mut self, dt: Duration) {
198         self.mov.update(&self.device, dt);
199         self.aim.update(&self.device, dt);
200         self.jump.update(&self.device, dt);
201         self.shoot.update(&self.device, dt);
202         self.start.update(&self.device, dt);
203     }
204
205     /// strength [0 - 1]
206     pub fn rumble(&self, strength: f32, duration: Duration) {
207         if let Some(h) = &self.haptic {
208             h.borrow_mut().rumble_play(strength, duration.whole_milliseconds() as u32);
209         }
210     }
211 }
212
213 fn get_action_mapping() -> HashMap<ActionControls, DeviceControls> {
214     hashmap!(
215         ActionControls::MovementX => DeviceControls::AxisLX,
216         ActionControls::MovementY => DeviceControls::AxisLY,
217         ActionControls::AimX => DeviceControls::AxisRX,
218         ActionControls::AimY => DeviceControls::AxisRY,
219         ActionControls::Jump => DeviceControls::ButtonL1,
220         ActionControls::Shoot => DeviceControls::ButtonR1,
221         ActionControls::Start => DeviceControls::ButtonStart
222     )
223 }
224
225 fn get_device_mapping(device_name: &str) -> HashMap<DeviceControls, u8> {
226     match device_name {
227         "Sony PLAYSTATION(R)3 Controller" => hashmap!(
228             DeviceControls::AxisLX => 0,
229             DeviceControls::AxisLY => 1,
230             DeviceControls::AxisRX => 3,
231             DeviceControls::AxisRY => 4,
232             DeviceControls::AxisL2 => 2,
233             DeviceControls::AxisR2 => 5,
234             DeviceControls::ButtonA => 0,
235             DeviceControls::ButtonB => 1,
236             DeviceControls::ButtonY => 3,
237             DeviceControls::ButtonX => 2,
238             DeviceControls::ButtonSelect => 8,
239             DeviceControls::ButtonStart => 9,
240             DeviceControls::ButtonHome => 10,
241             DeviceControls::ButtonL3 => 11,
242             DeviceControls::ButtonR3 => 12,
243             DeviceControls::ButtonL1 => 4,
244             DeviceControls::ButtonR1 => 5,
245             DeviceControls::ButtonL2 => 6,
246             DeviceControls::ButtonR2 => 7,
247             DeviceControls::ButtonUp => 13,
248             DeviceControls::ButtonDown => 14,
249             DeviceControls::ButtonLeft => 15,
250             DeviceControls::ButtonRight => 16
251         ),
252         _ => panic!("No controller mapping for device '{}'", device_name)
253     }
254 }
255
256 //#[derive(Debug)]
257 pub struct ControllerManager {
258     pub joystick: JoystickSubsystem,
259     haptic: Rc<HapticSubsystem>,
260     pub controllers: HashMap<u32, Rc<RefCell<Controller>>>,
261 }
262
263 impl ControllerManager {
264     pub fn new(joystick: JoystickSubsystem, haptic: HapticSubsystem) -> Self {
265         joystick.set_event_state(true);
266         let mut c = ControllerManager {
267             joystick,
268             haptic: Rc::new(haptic),
269             controllers: HashMap::new(),
270         };
271         c.init();
272         c
273     }
274
275     fn init(&mut self) {
276         for i in 0..self.joystick.num_joysticks().unwrap() {
277             self.add_device(i);
278         }
279     }
280
281     pub fn update(&mut self, dt: Duration) {
282         self.controllers.iter().for_each(|(_, v)| v.borrow_mut().update(dt));
283     }
284
285     pub fn handle_event(&mut self, event: &Event) {
286         match event {
287             Event::JoyDeviceAdded { which, .. } => { self.add_device(*which) }
288             Event::JoyDeviceRemoved { which, .. } => { self.remove_device(*which) }
289             // Event::JoyButtonDown { which, button_idx, .. } => { println!("device {} button {} down!", which, button_idx) }
290             // Event::JoyButtonUp { which, button_idx, .. } => { println!("device {} button {} up!", which, button_idx) }
291             // Event::JoyAxisMotion { which, axis_idx, .. } => { println!("device {} axis motion {}!", which, axis_idx) }
292             _ => {}
293         }
294     }
295
296     fn add_device(&mut self, id: u32) {
297         println!("device added ({})!", id);
298         let mut device = self.joystick.open(id).unwrap();
299         println!("opened {}", device.name());
300
301         /*
302         note about set_rumble (for dualshock 3 at least):
303         the active range for the low frequency is from 65536/4 to 65536 and escalates in large steps throughout the range
304         the active range for the high frequency is from 256 to 65536 and effect is the same throughout the whole range
305          */
306         let haptic = match device.set_rumble(0, 256, 100) {
307             Ok(_) => self.haptic.open_from_joystick_id(id).ok(),
308             Err(_) => None
309         };
310
311         if self.controllers.contains_key(&id) {
312             return;
313         }
314
315         let detached = self.controllers.values().find(|c| !c.borrow().device.attached());
316         match detached {
317             Some(c) => {
318                 let mut c = c.borrow_mut();
319                 c.device = device;
320                 c.haptic = haptic.map(|h| Rc::new(RefCell::new(h)));
321             }
322             None => {
323                 let c = Rc::new(RefCell::new(Controller::new(device, haptic.map(|h| Rc::new(RefCell::new(h))))));
324                 self.controllers.insert(id, c);
325             }
326         };
327     }
328
329     fn remove_device(&mut self, id: i32) {
330         println!("device removed ({})!", id);
331         // TODO
332     }
333 }