Playing around with a bunch of things
[kaka/rust-sdl-test.git] / src / core / controller.rs
CommitLineData
bf7b5671 1use common::Point2D;
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
eca25591
TW
91 pub fn to_axis_point(&self) -> Point2D<f64> {
92 point!(self.x as f64, self.y as f64)
bf7b5671
TW
93 }
94
eca25591
TW
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 {
93fc5734 98 p.normalized()
eca25591
TW
99 } else {
100 p
101 }
bf7b5671
TW
102 }
103}
104
105impl 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
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
TW
145}
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
TW
156}
157
3f344b63
TW
158//#[derive(Debug)]
159pub struct Controller {
bf7b5671 160 pub device: Joystick,
3f344b63 161 haptic: Option<Rc<RefCell<Haptic>>>,
bf7b5671
TW
162
163 pub mov: Stick,
164 pub aim: Stick,
165 pub jump: Button,
166 pub start: Button,
167 pub shoot: Button,
168}
169
170impl Controller {
171 pub fn new(device: Joystick, haptic: Option<Rc<RefCell<Haptic>>>) -> Self {
05ba0976
TW
172 let action_map = get_action_mapping();
173 let device_map = get_device_mapping(&device.name());
5d731022 174 let mut ctrl = Controller {
bf7b5671
TW
175 device,
176 haptic,
177 mov: Default::default(),
178 aim: Default::default(),
179 jump: Default::default(),
180 start: Default::default(),
181 shoot: Default::default(),
5d731022 182 };
05ba0976 183 ctrl.set_mapping(&action_map, &device_map);
5d731022
TW
184 ctrl
185 }
186
05ba0976
TW
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();
bf7b5671
TW
195 }
196
902b2b31 197 pub fn update(&mut self, dt: Duration) {
5d731022
TW
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);
bf7b5671
TW
203 }
204
205 /// strength [0 - 1]
902b2b31 206 pub fn rumble(&self, strength: f32, duration: Duration) {
bf7b5671 207 if let Some(h) = &self.haptic {
902b2b31 208 h.borrow_mut().rumble_play(strength, duration.whole_milliseconds() as u32);
bf7b5671
TW
209 }
210 }
211}
212
05ba0976
TW
213fn 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,
3fd8761b 219 ActionControls::Jump => DeviceControls::ButtonA,
05ba0976
TW
220 ActionControls::Shoot => DeviceControls::ButtonR1,
221 ActionControls::Start => DeviceControls::ButtonStart
222 )
223}
224
225fn 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
bf7b5671
TW
256//#[derive(Debug)]
257pub struct ControllerManager {
258 pub joystick: JoystickSubsystem,
259 haptic: Rc<HapticSubsystem>,
260 pub controllers: HashMap<u32, Rc<RefCell<Controller>>>,
3f344b63
TW
261}
262
263impl ControllerManager {
bf7b5671
TW
264 pub fn new(joystick: JoystickSubsystem, haptic: HapticSubsystem) -> Self {
265 joystick.set_event_state(true);
b0566120 266 let mut c = ControllerManager {
bf7b5671 267 joystick,
3f344b63 268 haptic: Rc::new(haptic),
b0566120
TW
269 controllers: HashMap::new(),
270 };
271 c.init();
272 c
273 }
274
275 fn init(&mut self) {
bf7b5671 276 for i in 0..self.joystick.num_joysticks().unwrap() {
b0566120 277 self.add_device(i);
3f344b63
TW
278 }
279 }
280
902b2b31 281 pub fn update(&mut self, dt: Duration) {
bf7b5671
TW
282 self.controllers.iter().for_each(|(_, v)| v.borrow_mut().update(dt));
283 }
284
3f344b63
TW
285 pub fn handle_event(&mut self, event: &Event) {
286 match event {
bf7b5671
TW
287 Event::JoyDeviceAdded { which, .. } => { self.add_device(*which) }
288 Event::JoyDeviceRemoved { which, .. } => { self.remove_device(*which) }
5d731022
TW
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) }
3f344b63
TW
292 _ => {}
293 }
294 }
295
bf7b5671 296 fn add_device(&mut self, id: u32) {
3f344b63 297 println!("device added ({})!", id);
bf7b5671
TW
298 let mut device = self.joystick.open(id).unwrap();
299 println!("opened {}", device.name());
ca99d4d7
TW
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 */
bf7b5671 306 let haptic = match device.set_rumble(0, 256, 100) {
3f344b63
TW
307 Ok(_) => self.haptic.open_from_joystick_id(id).ok(),
308 Err(_) => None
309 };
310
b0566120
TW
311 if self.controllers.contains_key(&id) {
312 return;
313 }
314
bf7b5671 315 let detached = self.controllers.values().find(|c| !c.borrow().device.attached());
ca99d4d7
TW
316 match detached {
317 Some(c) => {
318 let mut c = c.borrow_mut();
bf7b5671 319 c.device = device;
ca99d4d7
TW
320 c.haptic = haptic.map(|h| Rc::new(RefCell::new(h)));
321 }
322 None => {
bf7b5671 323 let c = Rc::new(RefCell::new(Controller::new(device, haptic.map(|h| Rc::new(RefCell::new(h))))));
b0566120 324 self.controllers.insert(id, c);
ca99d4d7
TW
325 }
326 };
3f344b63
TW
327 }
328
bf7b5671 329 fn remove_device(&mut self, id: i32) {
3f344b63 330 println!("device removed ({})!", id);
ca99d4d7 331 // TODO
3f344b63
TW
332 }
333}