Use enum values directly
[kaka/rust-sdl-test.git] / src / core / controller.rs
CommitLineData
e570927a 1use common::Point;
eca25591 2use {hashmap, point};
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,
bf7b5671
TW
71}
72
73impl Stick {
5d731022
TW
74 fn update(&mut self, device: &Joystick, _dt: Duration) {
75 self.x = match device.axis(self.idx as u32) {
bf7b5671 76 Ok(val) => val as f32 / 32768.0,
5d731022 77 Err(_) => panic!("invalid x axis {}", self.idx),
bf7b5671 78 };
5d731022 79 self.y = match device.axis(self.idy as u32) {
bf7b5671 80 Ok(val) => val as f32 / 32768.0,
5d731022 81 Err(_) => panic!("invalid y axis {}", self.idy),
bf7b5671
TW
82 };
83 self.a = Radians(self.y.atan2(self.x) as f64);
bf7b5671
TW
84 }
85
3fd8761b
TW
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 }
bf7b5671 90
e570927a 91 pub fn to_axis_point(&self) -> Point<f64> {
eca25591 92 point!(self.x as f64, self.y as f64)
bf7b5671
TW
93 }
94
e570927a 95 pub fn to_point(&self) -> Point<f64> {
eca25591
TW
96 let p = point!(self.x as f64, self.y as f64);
97 if p.length() > 1.0 {
93fc5734 98 p.normalized()
eca25591
TW
99 } else {
100 p
101 }
bf7b5671
TW
102 }
103}
104
e570927a 105impl From<&Stick> for Point<f64> {
bf7b5671
TW
106 fn from(item: &Stick) -> Self {
107 Self {
108 x: item.x as f64,
109 y: item.y as f64,
110 }
111 }
112}
113
114impl From<&Stick> for (f64, f64) {
115 fn from(item: &Stick) -> Self {
116 (item.x as f64, item.y as f64)
117 }
3f344b63
TW
118}
119
05ba0976
TW
120#[derive(Eq, PartialEq, Hash)]
121enum 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,
5d731022 145}
5d42eba1 146use self::DeviceControls::*;
5d731022 147
05ba0976
TW
148#[derive(Eq, PartialEq, Hash)]
149enum ActionControls {
150 MovementX,
151 MovementY,
152 AimX,
153 AimY,
154 Jump,
155 Shoot,
156 Start,
5d731022 157}
5d42eba1 158use self::ActionControls::*;
5d731022 159
3f344b63
TW
160//#[derive(Debug)]
161pub struct Controller {
bf7b5671 162 pub device: Joystick,
3f344b63 163 haptic: Option<Rc<RefCell<Haptic>>>,
bf7b5671
TW
164
165 pub mov: Stick,
166 pub aim: Stick,
167 pub jump: Button,
168 pub start: Button,
169 pub shoot: Button,
170}
171
172impl Controller {
173 pub fn new(device: Joystick, haptic: Option<Rc<RefCell<Haptic>>>) -> Self {
05ba0976
TW
174 let action_map = get_action_mapping();
175 let device_map = get_device_mapping(&device.name());
5d731022 176 let mut ctrl = Controller {
bf7b5671
TW
177 device,
178 haptic,
179 mov: Default::default(),
180 aim: Default::default(),
181 jump: Default::default(),
182 start: Default::default(),
183 shoot: Default::default(),
5d731022 184 };
05ba0976 185 ctrl.set_mapping(&action_map, &device_map);
5d731022
TW
186 ctrl
187 }
188
05ba0976 189 fn set_mapping(&mut self, action: &HashMap<ActionControls, DeviceControls>, device: &HashMap<DeviceControls, u8>) {
5d42eba1
TW
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();
bf7b5671
TW
197 }
198
902b2b31 199 pub fn update(&mut self, dt: Duration) {
5d731022
TW
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);
bf7b5671
TW
205 }
206
207 /// strength [0 - 1]
902b2b31 208 pub fn rumble(&self, strength: f32, duration: Duration) {
bf7b5671 209 if let Some(h) = &self.haptic {
902b2b31 210 h.borrow_mut().rumble_play(strength, duration.whole_milliseconds() as u32);
bf7b5671
TW
211 }
212 }
213}
214
05ba0976
TW
215fn get_action_mapping() -> HashMap<ActionControls, DeviceControls> {
216 hashmap!(
5d42eba1
TW
217 MovementX => AxisLX,
218 MovementY => AxisLY,
219 AimX => AxisRX,
220 AimY => AxisRY,
221 Jump => ButtonA,
222 Shoot => ButtonR1,
223 Start => ButtonStart
05ba0976
TW
224 )
225}
226
227fn get_device_mapping(device_name: &str) -> HashMap<DeviceControls, u8> {
228 match device_name {
229 "Sony PLAYSTATION(R)3 Controller" => hashmap!(
5d42eba1
TW
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
05ba0976
TW
253 ),
254 _ => panic!("No controller mapping for device '{}'", device_name)
255 }
256}
257
bf7b5671
TW
258//#[derive(Debug)]
259pub struct ControllerManager {
260 pub joystick: JoystickSubsystem,
261 haptic: Rc<HapticSubsystem>,
262 pub controllers: HashMap<u32, Rc<RefCell<Controller>>>,
3f344b63
TW
263}
264
265impl ControllerManager {
bf7b5671
TW
266 pub fn new(joystick: JoystickSubsystem, haptic: HapticSubsystem) -> Self {
267 joystick.set_event_state(true);
b0566120 268 let mut c = ControllerManager {
bf7b5671 269 joystick,
3f344b63 270 haptic: Rc::new(haptic),
b0566120
TW
271 controllers: HashMap::new(),
272 };
273 c.init();
274 c
275 }
276
277 fn init(&mut self) {
bf7b5671 278 for i in 0..self.joystick.num_joysticks().unwrap() {
b0566120 279 self.add_device(i);
3f344b63
TW
280 }
281 }
282
902b2b31 283 pub fn update(&mut self, dt: Duration) {
bf7b5671
TW
284 self.controllers.iter().for_each(|(_, v)| v.borrow_mut().update(dt));
285 }
286
3f344b63
TW
287 pub fn handle_event(&mut self, event: &Event) {
288 match event {
bf7b5671
TW
289 Event::JoyDeviceAdded { which, .. } => { self.add_device(*which) }
290 Event::JoyDeviceRemoved { which, .. } => { self.remove_device(*which) }
5d731022
TW
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) }
3f344b63
TW
294 _ => {}
295 }
296 }
297
bf7b5671 298 fn add_device(&mut self, id: u32) {
3f344b63 299 println!("device added ({})!", id);
bf7b5671
TW
300 let mut device = self.joystick.open(id).unwrap();
301 println!("opened {}", device.name());
ca99d4d7
TW
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 */
bf7b5671 308 let haptic = match device.set_rumble(0, 256, 100) {
3f344b63
TW
309 Ok(_) => self.haptic.open_from_joystick_id(id).ok(),
310 Err(_) => None
311 };
312
b0566120
TW
313 if self.controllers.contains_key(&id) {
314 return;
315 }
316
bf7b5671 317 let detached = self.controllers.values().find(|c| !c.borrow().device.attached());
ca99d4d7
TW
318 match detached {
319 Some(c) => {
320 let mut c = c.borrow_mut();
bf7b5671 321 c.device = device;
ca99d4d7
TW
322 c.haptic = haptic.map(|h| Rc::new(RefCell::new(h)));
323 }
324 None => {
bf7b5671 325 let c = Rc::new(RefCell::new(Controller::new(device, haptic.map(|h| Rc::new(RefCell::new(h))))));
b0566120 326 self.controllers.insert(id, c);
ca99d4d7
TW
327 }
328 };
3f344b63
TW
329 }
330
bf7b5671 331 fn remove_device(&mut self, id: i32) {
3f344b63 332 println!("device removed ({})!", id);
ca99d4d7 333 // TODO
3f344b63
TW
334 }
335}