2eec33ade4cfcf255647aad6e7f008f1a3e045cc
[kaka/rust-sdl-test.git] / src / core / controller.rs
1 use common::Point2D;
2 use common::Radians;
3 use sdl2::HapticSubsystem;
4 use sdl2::JoystickSubsystem;
5 use sdl2::event::Event;
6 use sdl2::haptic::Haptic;
7 use sdl2::joystick::Joystick;
8 use std::cell::RefCell;
9 use std::collections::HashMap;
10 use std::rc::Rc;
11 use time::{Duration, prelude::*};
12
13 #[derive(Debug, Default)]
14 pub 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
23 impl 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)]
48 pub struct Axis {
49     id: u8,
50     pub val: f32,
51 }
52
53 impl 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)]
64 pub struct Stick {
65     idx: u8,
66     idy: u8,
67     pub x: f32,
68     pub y: f32,
69     pub a: Radians,
70     pub len: f32,
71 }
72
73 impl 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         self.len = {
85             let x = (self.x / self.y).abs().min(1.0);
86             let y = (self.y / self.x).abs().min(1.0);
87             (self.x.powi(2) + self.y.powi(2)).sqrt() / (x.powi(2) + y.powi(2)).sqrt()
88         }
89     }
90
91     #[inline(always)] #[allow(dead_code)] fn up(&self) -> bool { self.y > 0.99 }
92     #[inline(always)] #[allow(dead_code)] fn down(&self) -> bool { self.y < -0.99 }
93     #[inline(always)] #[allow(dead_code)] fn left(&self) -> bool { self.x < -0.99 }
94     #[inline(always)] #[allow(dead_code)] fn right(&self) -> bool { self.x > 0.99 }
95
96     pub fn to_point(&self) -> Point2D<f64> {
97         Point2D {
98             x: self.x as f64,
99             y: self.y as f64,
100         }
101     }
102
103     pub fn to_adjusted_point(&self) -> Point2D<f64> {
104         Point2D::from(self.a) * self.len as f64
105     }
106 }
107
108 impl From<&Stick> for Point2D<f64> {
109     fn from(item: &Stick) -> Self {
110         Self {
111             x: item.x as f64,
112             y: item.y as f64,
113         }
114     }
115 }
116
117 impl From<&Stick> for (f64, f64) {
118     fn from(item: &Stick) -> Self {
119         (item.x as f64, item.y as f64)
120     }
121 }
122
123 #[allow(dead_code)]
124 struct Axes {
125     left_x: u8,
126     left_y: u8,
127     right_x: u8,
128     right_y: u8,
129     trigger_left: u8,
130     trigger_right: u8,
131 }
132
133 #[allow(dead_code)]
134 struct Buttons {
135     a: u8,
136     b: u8,
137     x: u8,
138     y: u8,
139     select: u8,
140     start: u8,
141     left_stick: u8,
142     right_stick: u8,
143     left_shoulder: u8,
144     right_shoulder: u8,
145     left_trigger: u8,
146     right_trigger: u8,
147     d_pad_up: u8,
148     d_pad_down: u8,
149     d_pad_left: u8,
150     d_pad_right: u8,
151 }
152
153 struct Mapping {
154     axis: Axes,
155     btn: Buttons,
156 }
157
158 //#[derive(Debug)]
159 pub struct Controller {
160     pub device: Joystick,
161     haptic: Option<Rc<RefCell<Haptic>>>,
162
163     pub mov: Stick,
164     pub aim: Stick,
165     pub jump: Button,
166     pub start: Button,
167     pub shoot: Button,
168 }
169
170 impl Controller {
171     pub fn new(device: Joystick, haptic: Option<Rc<RefCell<Haptic>>>) -> Self {
172         let mut ctrl = Controller {
173             device,
174             haptic,
175             mov: Default::default(),
176             aim: Default::default(),
177             jump: Default::default(),
178             start: Default::default(),
179             shoot: Default::default(),
180         };
181         let dualshock3 = Mapping {
182             axis: Axes {
183                 left_x: 0,
184                 left_y: 1,
185                 right_x: 3,
186                 right_y: 4,
187                 trigger_left: 2,
188                 trigger_right: 5,
189             },
190             btn: Buttons {
191                 a: 0,
192                 b: 1,
193                 x: 3,
194                 y: 2,
195                 select: 8,
196                 start: 9,
197                 left_stick: 11,
198                 right_stick: 12,
199                 left_shoulder: 4,
200                 right_shoulder: 5,
201                 left_trigger: 6,
202                 right_trigger: 7,
203                 d_pad_up: 13,
204                 d_pad_down: 14,
205                 d_pad_left: 15,
206                 d_pad_right: 16,
207             },
208         };
209         ctrl.set_mapping(&dualshock3);
210         ctrl
211     }
212
213     fn set_mapping(&mut self, map: &Mapping) {
214         self.mov.idx = map.axis.left_x;
215         self.mov.idy = map.axis.left_y;
216         self.aim.idx = map.axis.right_x;
217         self.aim.idy = map.axis.right_y;
218         self.jump.id = map.btn.left_shoulder;
219         self.shoot.id = map.btn.right_shoulder;
220         self.start.id = map.btn.start;
221     }
222
223     pub fn update(&mut self, dt: Duration) {
224         self.mov.update(&self.device, dt);
225         self.aim.update(&self.device, dt);
226         self.jump.update(&self.device, dt);
227         self.shoot.update(&self.device, dt);
228         self.start.update(&self.device, dt);
229     }
230
231     /// strength [0 - 1]
232     pub fn rumble(&self, strength: f32, duration: Duration) {
233         if let Some(h) = &self.haptic {
234             h.borrow_mut().rumble_play(strength, duration.whole_milliseconds() as u32);
235         }
236     }
237 }
238
239 //#[derive(Debug)]
240 pub struct ControllerManager {
241     pub joystick: JoystickSubsystem,
242     haptic: Rc<HapticSubsystem>,
243     pub controllers: HashMap<u32, Rc<RefCell<Controller>>>,
244 }
245
246 impl ControllerManager {
247     pub fn new(joystick: JoystickSubsystem, haptic: HapticSubsystem) -> Self {
248         joystick.set_event_state(true);
249         let mut c = ControllerManager {
250             joystick,
251             haptic: Rc::new(haptic),
252             controllers: HashMap::new(),
253         };
254         c.init();
255         c
256     }
257
258     fn init(&mut self) {
259         for i in 0..self.joystick.num_joysticks().unwrap() {
260             self.add_device(i);
261         }
262     }
263
264     pub fn update(&mut self, dt: Duration) {
265         self.controllers.iter().for_each(|(_, v)| v.borrow_mut().update(dt));
266     }
267
268     pub fn handle_event(&mut self, event: &Event) {
269         match event {
270             Event::JoyDeviceAdded { which, .. } => { self.add_device(*which) }
271             Event::JoyDeviceRemoved { which, .. } => { self.remove_device(*which) }
272             // Event::JoyButtonDown { which, button_idx, .. } => { println!("device {} button {} down!", which, button_idx) }
273             // Event::JoyButtonUp { which, button_idx, .. } => { println!("device {} button {} up!", which, button_idx) }
274             // Event::JoyAxisMotion { which, axis_idx, .. } => { println!("device {} axis motion {}!", which, axis_idx) }
275             _ => {}
276         }
277     }
278
279     fn add_device(&mut self, id: u32) {
280         println!("device added ({})!", id);
281         let mut device = self.joystick.open(id).unwrap();
282         println!("opened {}", device.name());
283
284         /*
285         note about set_rumble (for dualshock 3 at least):
286         the active range for the low frequency is from 65536/4 to 65536 and escalates in large steps throughout the range
287         the active range for the high frequency is from 256 to 65536 and effect is the same throughout the whole range
288          */
289         let haptic = match device.set_rumble(0, 256, 100) {
290             Ok(_) => self.haptic.open_from_joystick_id(id).ok(),
291             Err(_) => None
292         };
293
294         if self.controllers.contains_key(&id) {
295             return;
296         }
297
298         let detached = self.controllers.values().find(|c| !c.borrow().device.attached());
299         match detached {
300             Some(c) => {
301                 let mut c = c.borrow_mut();
302                 c.device = device;
303                 c.haptic = haptic.map(|h| Rc::new(RefCell::new(h)));
304             }
305             None => {
306                 let c = Rc::new(RefCell::new(Controller::new(device, haptic.map(|h| Rc::new(RefCell::new(h))))));
307                 self.controllers.insert(id, c);
308             }
309         };
310     }
311
312     fn remove_device(&mut self, id: i32) {
313         println!("device removed ({})!", id);
314         // TODO
315     }
316 }