Replaced Degrees and Radians with a single Angle type
[kaka/rust-sdl-test.git] / src / core / controller.rs
... / ...
CommitLineData
1use common::{Angle, Point};
2use {hashmap, point};
3use sdl2::HapticSubsystem;
4use sdl2::JoystickSubsystem;
5use sdl2::event::Event;
6use sdl2::haptic::Haptic;
7use sdl2::joystick::Joystick;
8use std::cell::RefCell;
9use std::collections::HashMap;
10use std::rc::Rc;
11use time::{Duration, prelude::*};
12
13#[derive(Debug, Default)]
14pub struct Button {
15 id: u8,
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
23impl Button {
24 fn update(&mut self, device: &Joystick, dt: Duration) {
25 self.was_pressed = self.is_pressed;
26 self.is_pressed = match device.button(self.id as u32) {
27 Ok(true) => {
28 if !self.was_pressed {
29 self.time_pressed = 0.seconds();
30 self.toggle = !self.toggle;
31 }
32 self.time_pressed += dt;
33 true
34 }
35 Ok(false) => {
36 if self.was_pressed {
37 self.time_released = 0.seconds();
38 }
39 self.time_released += dt;
40 false
41 }
42 Err(_) => { panic!("invalid button {}", self.id) }
43 }
44 }
45}
46
47#[derive(Debug, Default)]
48pub struct Axis {
49 id: u8,
50 pub val: f32,
51}
52
53impl Axis {
54 #[allow(dead_code)]
55 fn update(&mut self, device: &Joystick, _dt: Duration) {
56 self.val = match device.axis(self.id as u32) {
57 Ok(val) => val as f32 / 32768.0,
58 Err(_) => panic!("invalid axis {}", self.id),
59 }
60 }
61}
62
63#[derive(Debug, Default)]
64pub struct Stick {
65 idx: u8,
66 idy: u8,
67 pub x: f32,
68 pub y: f32,
69 pub a: Angle,
70}
71
72impl Stick {
73 fn update(&mut self, device: &Joystick, _dt: Duration) {
74 self.x = match device.axis(self.idx as u32) {
75 Ok(val) => val as f32 / 32768.0,
76 Err(_) => panic!("invalid x axis {}", self.idx),
77 };
78 self.y = match device.axis(self.idy as u32) {
79 Ok(val) => val as f32 / 32768.0,
80 Err(_) => panic!("invalid y axis {}", self.idy),
81 };
82 self.a = point!(self.x as f64, self.y as f64).to_angle();
83 }
84
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 }
89
90 pub fn to_axis_point(&self) -> Point<f64> {
91 point!(self.x as f64, self.y as f64)
92 }
93
94 pub fn to_point(&self) -> Point<f64> {
95 let p = point!(self.x as f64, self.y as f64);
96 if p.length() > 1.0 {
97 p.normalized()
98 } else {
99 p
100 }
101 }
102}
103
104impl From<&Stick> for Point<f64> {
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 }
117}
118
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,
144}
145use self::DeviceControls::*;
146
147#[derive(Eq, PartialEq, Hash)]
148enum ActionControls {
149 MovementX,
150 MovementY,
151 AimX,
152 AimY,
153 Jump,
154 Shoot,
155 Start,
156}
157use self::ActionControls::*;
158
159//#[derive(Debug)]
160pub struct Controller {
161 pub device: Joystick,
162 haptic: Option<Rc<RefCell<Haptic>>>,
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 {
173 let action_map = get_action_mapping();
174 let device_map = get_device_mapping(&device.name());
175 let mut ctrl = Controller {
176 device,
177 haptic,
178 mov: Default::default(),
179 aim: Default::default(),
180 jump: Default::default(),
181 start: Default::default(),
182 shoot: Default::default(),
183 };
184 ctrl.set_mapping(&action_map, &device_map);
185 ctrl
186 }
187
188 fn set_mapping(&mut self, action: &HashMap<ActionControls, DeviceControls>, device: &HashMap<DeviceControls, u8>) {
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();
196 }
197
198 pub fn update(&mut self, dt: Duration) {
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);
204 }
205
206 /// strength [0 - 1]
207 pub fn rumble(&self, strength: f32, duration: Duration) {
208 if let Some(h) = &self.haptic {
209 h.borrow_mut().rumble_play(strength, duration.whole_milliseconds() as u32);
210 }
211 }
212}
213
214fn get_action_mapping() -> HashMap<ActionControls, DeviceControls> {
215 hashmap!(
216 MovementX => AxisLX,
217 MovementY => AxisLY,
218 AimX => AxisRX,
219 AimY => AxisRY,
220 Jump => ButtonA,
221 Shoot => ButtonR1,
222 Start => ButtonStart
223 )
224}
225
226fn get_device_mapping(device_name: &str) -> HashMap<DeviceControls, u8> {
227 match device_name {
228 "Sony PLAYSTATION(R)3 Controller" => hashmap!(
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
252 ),
253 _ => panic!("No controller mapping for device '{}'", device_name)
254 }
255}
256
257//#[derive(Debug)]
258pub struct ControllerManager {
259 pub joystick: JoystickSubsystem,
260 haptic: Rc<HapticSubsystem>,
261 pub controllers: HashMap<u32, Rc<RefCell<Controller>>>,
262}
263
264impl ControllerManager {
265 pub fn new(joystick: JoystickSubsystem, haptic: HapticSubsystem) -> Self {
266 joystick.set_event_state(true);
267 let mut c = ControllerManager {
268 joystick,
269 haptic: Rc::new(haptic),
270 controllers: HashMap::new(),
271 };
272 c.init();
273 c
274 }
275
276 fn init(&mut self) {
277 for i in 0..self.joystick.num_joysticks().unwrap() {
278 self.add_device(i);
279 }
280 }
281
282 pub fn update(&mut self, dt: Duration) {
283 self.controllers.iter().for_each(|(_, v)| v.borrow_mut().update(dt));
284 }
285
286 pub fn handle_event(&mut self, event: &Event) {
287 match event {
288 Event::JoyDeviceAdded { which, .. } => { self.add_device(*which) }
289 Event::JoyDeviceRemoved { which, .. } => { self.remove_device(*which) }
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) }
293 _ => {}
294 }
295 }
296
297 fn add_device(&mut self, id: u32) {
298 println!("device added ({})!", id);
299 let mut device = self.joystick.open(id).unwrap();
300 println!("opened {}", device.name());
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 */
307 let haptic = match device.set_rumble(0, 256, 100) {
308 Ok(_) => self.haptic.open_from_joystick_id(id).ok(),
309 Err(_) => None
310 };
311
312 if self.controllers.contains_key(&id) {
313 return;
314 }
315
316 let detached = self.controllers.values().find(|c| !c.borrow().device.attached());
317 match detached {
318 Some(c) => {
319 let mut c = c.borrow_mut();
320 c.device = device;
321 c.haptic = haptic.map(|h| Rc::new(RefCell::new(h)));
322 }
323 None => {
324 let c = Rc::new(RefCell::new(Controller::new(device, haptic.map(|h| Rc::new(RefCell::new(h))))));
325 self.controllers.insert(id, c);
326 }
327 };
328 }
329
330 fn remove_device(&mut self, id: i32) {
331 println!("device removed ({})!", id);
332 // TODO
333 }
334}