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