Moved geometry to root level
[kaka/rust-sdl-test.git] / src / core / controller.rs
1 use geometry::{Angle, Point};
2 use {hashmap, point};
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: Angle,
70 }
71
72 impl 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
104 impl 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
113 impl 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)]
120 enum 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 }
145 use self::DeviceControls::*;
146
147 #[derive(Eq, PartialEq, Hash)]
148 enum ActionControls {
149     MovementX,
150     MovementY,
151     AimX,
152     AimY,
153     Jump,
154     Shoot,
155     Start,
156 }
157 use self::ActionControls::*;
158
159 //#[derive(Debug)]
160 pub 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
171 impl 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
214 fn 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
226 fn 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)]
258 pub struct ControllerManager {
259     pub joystick: JoystickSubsystem,
260     haptic: Rc<HapticSubsystem>,
261     pub controllers: HashMap<u32, Rc<RefCell<Controller>>>,
262 }
263
264 impl 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 }