Use enum values directly
[kaka/rust-sdl-test.git] / src / core / controller.rs
... / ...
CommitLineData
1use common::Point;
2use {hashmap, point};
3use common::Radians;
4use sdl2::HapticSubsystem;
5use sdl2::JoystickSubsystem;
6use sdl2::event::Event;
7use sdl2::haptic::Haptic;
8use sdl2::joystick::Joystick;
9use std::cell::RefCell;
10use std::collections::HashMap;
11use std::rc::Rc;
12use time::{Duration, prelude::*};
13
14#[derive(Debug, Default)]
15pub 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
24impl 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)]
49pub struct Axis {
50 id: u8,
51 pub val: f32,
52}
53
54impl 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)]
65pub struct Stick {
66 idx: u8,
67 idy: u8,
68 pub x: f32,
69 pub y: f32,
70 pub a: Radians,
71}
72
73impl 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)] 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 }
90
91 pub fn to_axis_point(&self) -> Point<f64> {
92 point!(self.x as f64, self.y as f64)
93 }
94
95 pub fn to_point(&self) -> Point<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
105impl From<&Stick> for Point<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 }
118}
119
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,
145}
146use self::DeviceControls::*;
147
148#[derive(Eq, PartialEq, Hash)]
149enum ActionControls {
150 MovementX,
151 MovementY,
152 AimX,
153 AimY,
154 Jump,
155 Shoot,
156 Start,
157}
158use self::ActionControls::*;
159
160//#[derive(Debug)]
161pub struct Controller {
162 pub device: Joystick,
163 haptic: Option<Rc<RefCell<Haptic>>>,
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 {
174 let action_map = get_action_mapping();
175 let device_map = get_device_mapping(&device.name());
176 let mut ctrl = Controller {
177 device,
178 haptic,
179 mov: Default::default(),
180 aim: Default::default(),
181 jump: Default::default(),
182 start: Default::default(),
183 shoot: Default::default(),
184 };
185 ctrl.set_mapping(&action_map, &device_map);
186 ctrl
187 }
188
189 fn set_mapping(&mut self, action: &HashMap<ActionControls, DeviceControls>, device: &HashMap<DeviceControls, u8>) {
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();
197 }
198
199 pub fn update(&mut self, dt: Duration) {
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);
205 }
206
207 /// strength [0 - 1]
208 pub fn rumble(&self, strength: f32, duration: Duration) {
209 if let Some(h) = &self.haptic {
210 h.borrow_mut().rumble_play(strength, duration.whole_milliseconds() as u32);
211 }
212 }
213}
214
215fn get_action_mapping() -> HashMap<ActionControls, DeviceControls> {
216 hashmap!(
217 MovementX => AxisLX,
218 MovementY => AxisLY,
219 AimX => AxisRX,
220 AimY => AxisRY,
221 Jump => ButtonA,
222 Shoot => ButtonR1,
223 Start => ButtonStart
224 )
225}
226
227fn get_device_mapping(device_name: &str) -> HashMap<DeviceControls, u8> {
228 match device_name {
229 "Sony PLAYSTATION(R)3 Controller" => hashmap!(
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
253 ),
254 _ => panic!("No controller mapping for device '{}'", device_name)
255 }
256}
257
258//#[derive(Debug)]
259pub struct ControllerManager {
260 pub joystick: JoystickSubsystem,
261 haptic: Rc<HapticSubsystem>,
262 pub controllers: HashMap<u32, Rc<RefCell<Controller>>>,
263}
264
265impl ControllerManager {
266 pub fn new(joystick: JoystickSubsystem, haptic: HapticSubsystem) -> Self {
267 joystick.set_event_state(true);
268 let mut c = ControllerManager {
269 joystick,
270 haptic: Rc::new(haptic),
271 controllers: HashMap::new(),
272 };
273 c.init();
274 c
275 }
276
277 fn init(&mut self) {
278 for i in 0..self.joystick.num_joysticks().unwrap() {
279 self.add_device(i);
280 }
281 }
282
283 pub fn update(&mut self, dt: Duration) {
284 self.controllers.iter().for_each(|(_, v)| v.borrow_mut().update(dt));
285 }
286
287 pub fn handle_event(&mut self, event: &Event) {
288 match event {
289 Event::JoyDeviceAdded { which, .. } => { self.add_device(*which) }
290 Event::JoyDeviceRemoved { which, .. } => { self.remove_device(*which) }
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) }
294 _ => {}
295 }
296 }
297
298 fn add_device(&mut self, id: u32) {
299 println!("device added ({})!", id);
300 let mut device = self.joystick.open(id).unwrap();
301 println!("opened {}", device.name());
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 */
308 let haptic = match device.set_rumble(0, 256, 100) {
309 Ok(_) => self.haptic.open_from_joystick_id(id).ok(),
310 Err(_) => None
311 };
312
313 if self.controllers.contains_key(&id) {
314 return;
315 }
316
317 let detached = self.controllers.values().find(|c| !c.borrow().device.attached());
318 match detached {
319 Some(c) => {
320 let mut c = c.borrow_mut();
321 c.device = device;
322 c.haptic = haptic.map(|h| Rc::new(RefCell::new(h)));
323 }
324 None => {
325 let c = Rc::new(RefCell::new(Controller::new(device, haptic.map(|h| Rc::new(RefCell::new(h))))));
326 self.controllers.insert(id, c);
327 }
328 };
329 }
330
331 fn remove_device(&mut self, id: i32) {
332 println!("device removed ({})!", id);
333 // TODO
334 }
335}