Use GameControllers instead of Joysticks
[kaka/rust-sdl-test.git] / src / core / controller.rs
1 use geometry::{Angle, ToAngle, Point};
2 use sdl2::GameControllerSubsystem;
3 use sdl2::HapticSubsystem;
4 use sdl2::controller::{GameController, Axis as SDLAxis, Button as SDLButton};
5 use sdl2::event::Event;
6 use sdl2::haptic::Haptic;
7 use std::cell::RefCell;
8 use std::collections::HashMap;
9 use std::rc::Rc;
10 use time::{Duration, prelude::*};
11 use {hashmap, point};
12
13 #[derive(Debug)]
14 pub struct Button {
15     id: SDLButton,
16     pub time_pressed: Duration,
17     pub time_released: Duration,
18     pub is_pressed: bool,
19     pub was_pressed: bool,
20     pub toggle: bool,
21 }
22
23 impl Button {
24     pub fn new(id: SDLButton) -> Self {
25         Button {
26             id,
27             time_pressed: Duration::zero(),
28             time_released: Duration::zero(),
29             is_pressed: false,
30             was_pressed: false,
31             toggle: false,
32         }
33     }
34
35     fn update(&mut self, device: &GameController, dt: Duration) {
36         self.was_pressed = self.is_pressed;
37         self.is_pressed = match device.button(self.id) {
38             true => {
39                 if !self.was_pressed {
40                     self.time_pressed = 0.seconds();
41                     self.toggle = !self.toggle;
42                 }
43                 self.time_pressed += dt;
44                 true
45             }
46             false => {
47                 if self.was_pressed {
48                     self.time_released = 0.seconds();
49                 }
50                 self.time_released += dt;
51                 false
52             }
53         }
54     }
55 }
56
57 #[derive(Debug)]
58 pub struct Axis {
59     id: SDLAxis,
60     pub val: f32,
61 }
62
63 impl Axis {
64     #[allow(dead_code)]
65     fn update(&mut self, device: &GameController, _dt: Duration) {
66         self.val = device.axis(self.id) as f32 / 32768.0;
67     }
68 }
69
70 #[derive(Debug)]
71 pub struct Stick {
72     id: (SDLAxis, SDLAxis),
73     pub x: f32,
74     pub y: f32,
75     pub a: Angle,
76 }
77
78 impl Stick {
79     pub fn new(idx: SDLAxis, idy: SDLAxis) -> Self {
80         Stick {
81             id: (idx, idy),
82             x: 0.0,
83             y: 0.0,
84             a: 0.radians(),
85         }
86     }
87
88     fn update(&mut self, device: &GameController, _dt: Duration) {
89         self.x = device.axis(self.id.0) as f32 / 32768.0;
90         self.y = device.axis(self.id.1) as f32 / 32768.0;
91         self.a = point!(self.x as f64, self.y as f64).to_angle();
92     }
93
94     #[inline(always)] #[allow(dead_code)] pub fn up(&self) -> bool { self.y < -0.99 }
95     #[inline(always)] #[allow(dead_code)] pub fn down(&self) -> bool { self.y > 0.99 }
96     #[inline(always)] #[allow(dead_code)] pub fn left(&self) -> bool { self.x < -0.99 }
97     #[inline(always)] #[allow(dead_code)] pub fn right(&self) -> bool { self.x > 0.99 }
98
99     pub fn to_axis_point(&self) -> Point<f64> {
100         point!(self.x as f64, self.y as f64)
101     }
102
103     pub fn to_point(&self) -> Point<f64> {
104         let p = point!(self.x as f64, self.y as f64);
105         if p.length() > 1.0 {
106             p.normalized()
107         } else {
108             p
109         }
110     }
111 }
112
113 impl From<&Stick> for Point<f64> {
114     fn from(item: &Stick) -> Self {
115         Self {
116             x: item.x as f64,
117             y: item.y as f64,
118         }
119     }
120 }
121
122 impl From<&Stick> for (f64, f64) {
123     fn from(item: &Stick) -> Self {
124         (item.x as f64, item.y as f64)
125     }
126 }
127
128 #[derive(Eq, PartialEq, Hash)]
129 enum ActionControls {
130     MovementX,
131     MovementY,
132     AimX,
133     AimY,
134     Jump,
135     Shoot,
136     Start,
137 }
138 use self::ActionControls::*;
139
140 //#[derive(Debug)]
141 pub struct Controller {
142     pub device: GameController,
143     haptic: Option<Rc<RefCell<Haptic>>>,
144
145     pub mov: Stick,
146     pub aim: Stick,
147     pub jump: Button,
148     pub start: Button,
149     pub shoot: Button,
150 }
151
152 impl Controller {
153     pub fn new(device: GameController, haptic: Option<Rc<RefCell<Haptic>>>) -> Self {
154         let map = get_action_mapping();
155         let mut ctrl = Controller {
156             device,
157             haptic,
158             mov: Stick::new(*map.axes.get(&MovementX).unwrap(), *map.axes.get(&MovementY).unwrap()),
159             aim: Stick::new(*map.axes.get(&AimX).unwrap(), *map.axes.get(&AimY).unwrap()),
160             jump: Button::new(*map.buttons.get(&Jump).unwrap()),
161             start: Button::new(*map.buttons.get(&Start).unwrap()),
162             shoot: Button::new(*map.buttons.get(&Shoot).unwrap()),
163         };
164         ctrl.set_mapping(&map);
165         ctrl
166     }
167
168     fn set_mapping(&mut self, map: &ActionMapping) {
169         self.mov.id.0 = *map.axes.get(&MovementX).unwrap();
170         self.mov.id.1 = *map.axes.get(&MovementY).unwrap();
171         self.aim.id.0 = *map.axes.get(&AimX).unwrap();
172         self.aim.id.1 = *map.axes.get(&AimY).unwrap();
173         self.jump.id = *map.buttons.get(&Jump).unwrap();
174         self.shoot.id = *map.buttons.get(&Shoot).unwrap();
175         self.start.id = *map.buttons.get(&Start).unwrap();
176     }
177
178     pub fn update(&mut self, dt: Duration) {
179         self.mov.update(&self.device, dt);
180         self.aim.update(&self.device, dt);
181         self.jump.update(&self.device, dt);
182         self.shoot.update(&self.device, dt);
183         self.start.update(&self.device, dt);
184     }
185
186     /// strength [0 - 1]
187     pub fn rumble(&self, strength: f32, duration: Duration) {
188         if let Some(h) = &self.haptic {
189             h.borrow_mut().rumble_play(strength, duration.whole_milliseconds() as u32);
190         }
191     }
192 }
193
194 struct ActionMapping {
195     axes: HashMap<ActionControls, SDLAxis>,
196     buttons: HashMap<ActionControls, SDLButton>,
197 }
198
199 fn get_action_mapping() -> ActionMapping {
200     ActionMapping {
201         axes: hashmap!(
202             MovementX => SDLAxis::LeftX,
203             MovementY => SDLAxis::LeftY,
204             AimX => SDLAxis::RightX,
205             AimY => SDLAxis::RightY
206         ),
207         buttons: hashmap!(
208             Jump => SDLButton::A,
209             Shoot => SDLButton::RightShoulder,
210             Start => SDLButton::Start
211         )
212     }
213 }
214
215 //#[derive(Debug)]
216 pub struct ControllerManager {
217     pub subsystem: GameControllerSubsystem,
218     haptic: Rc<HapticSubsystem>,
219     pub controllers: HashMap<u32, Rc<RefCell<Controller>>>,
220 }
221
222 impl ControllerManager {
223     pub fn new(subsystem: GameControllerSubsystem, haptic: HapticSubsystem) -> Self {
224         subsystem.set_event_state(true);
225         let mut c = ControllerManager {
226             subsystem,
227             haptic: Rc::new(haptic),
228             controllers: HashMap::new(),
229         };
230         c.init();
231         c
232     }
233
234     fn init(&mut self) {
235         for i in 0..self.subsystem.num_joysticks().unwrap() {
236             self.add_device(i);
237         }
238     }
239
240     pub fn update(&mut self, dt: Duration) {
241         self.controllers.iter().for_each(|(_, v)| v.borrow_mut().update(dt));
242     }
243
244     pub fn handle_event(&mut self, event: &Event) {
245         match event {
246             Event::ControllerDeviceAdded { which, .. } => { self.add_device(*which) }
247             Event::ControllerDeviceRemoved { which, .. } => { self.remove_device(*which) }
248             // Event::ControllerButtonDown { which, button_idx, .. } => { println!("device {} button {} down!", which, button_idx) }
249             // Event::ControllerButtonUp { which, button_idx, .. } => { println!("device {} button {} up!", which, button_idx) }
250             // Event::ControllerAxisMotion { which, axis_idx, .. } => { println!("device {} axis motion {}!", which, axis_idx) }
251             _ => {}
252         }
253     }
254
255     fn add_device(&mut self, id: u32) {
256         println!("device added ({})!", id);
257         let mut device = self.subsystem.open(id).unwrap();
258         println!("opened {}", device.name());
259
260         /*
261         note about set_rumble (for dualshock 3 at least):
262         the active range for the low frequency is from 65536/4 to 65536 and escalates in large steps throughout the range
263         the active range for the high frequency is from 256 to 65536 and effect is the same throughout the whole range
264          */
265         let haptic = match device.set_rumble(0, 256, 100) {
266             Ok(_) => self.haptic.open_from_joystick_id(id).ok(),
267             Err(_) => None
268         };
269
270         if self.controllers.contains_key(&id) {
271             return;
272         }
273
274         let detached = self.controllers.values().find(|c| !c.borrow().device.attached());
275         match detached {
276             Some(c) => {
277                 let mut c = c.borrow_mut();
278                 c.device = device;
279                 c.haptic = haptic.map(|h| Rc::new(RefCell::new(h)));
280             }
281             None => {
282                 let c = Rc::new(RefCell::new(Controller::new(device, haptic.map(|h| Rc::new(RefCell::new(h))))));
283                 self.controllers.insert(id, c);
284             }
285         };
286     }
287
288     fn remove_device(&mut self, id: i32) {
289         println!("device removed ({})!", id);
290         // TODO
291     }
292 }