Commit | Line | Data |
---|---|---|
09cd68fe TW |
1 | use geometry::{Angle, ToAngle, Point}; |
2 | use sdl2::GameControllerSubsystem; | |
3f344b63 | 3 | use sdl2::HapticSubsystem; |
09cd68fe | 4 | use sdl2::controller::{GameController, Axis as SDLAxis, Button as SDLButton}; |
3f344b63 | 5 | use sdl2::event::Event; |
bf7b5671 | 6 | use sdl2::haptic::Haptic; |
bf7b5671 TW |
7 | use std::cell::RefCell; |
8 | use std::collections::HashMap; | |
3f344b63 | 9 | use std::rc::Rc; |
902b2b31 | 10 | use time::{Duration, prelude::*}; |
09cd68fe | 11 | use {hashmap, point}; |
3f344b63 | 12 | |
09cd68fe | 13 | #[derive(Debug)] |
bf7b5671 | 14 | pub struct Button { |
09cd68fe | 15 | id: SDLButton, |
902b2b31 TW |
16 | pub time_pressed: Duration, |
17 | pub time_released: Duration, | |
bf7b5671 TW |
18 | pub is_pressed: bool, |
19 | pub was_pressed: bool, | |
20 | pub toggle: bool, | |
21 | } | |
22 | ||
23 | impl Button { | |
09cd68fe TW |
24 | pub fn new(id: SDLButton) -> Self { |
25 | Button { | |
26 | id, | |
27 | time_pressed: Duration::zero(), | |
28 | time_released: Duration::zero(), | |
29 | is_pressed: false, | |
30 | was_pressed: false, | |
31 | toggle: false, | |
32 | } | |
33 | } | |
34 | ||
35 | fn update(&mut self, device: &GameController, dt: Duration) { | |
bf7b5671 | 36 | self.was_pressed = self.is_pressed; |
09cd68fe TW |
37 | self.is_pressed = match device.button(self.id) { |
38 | true => { | |
bf7b5671 | 39 | if !self.was_pressed { |
902b2b31 | 40 | self.time_pressed = 0.seconds(); |
bf7b5671 TW |
41 | self.toggle = !self.toggle; |
42 | } | |
43 | self.time_pressed += dt; | |
44 | true | |
45 | } | |
09cd68fe | 46 | false => { |
bf7b5671 | 47 | if self.was_pressed { |
902b2b31 | 48 | self.time_released = 0.seconds(); |
bf7b5671 TW |
49 | } |
50 | self.time_released += dt; | |
51 | false | |
52 | } | |
bf7b5671 TW |
53 | } |
54 | } | |
55 | } | |
56 | ||
09cd68fe | 57 | #[derive(Debug)] |
bf7b5671 | 58 | pub struct Axis { |
09cd68fe | 59 | id: SDLAxis, |
bf7b5671 TW |
60 | pub val: f32, |
61 | } | |
62 | ||
63 | impl Axis { | |
64 | #[allow(dead_code)] | |
09cd68fe TW |
65 | fn update(&mut self, device: &GameController, _dt: Duration) { |
66 | self.val = device.axis(self.id) as f32 / 32768.0; | |
bf7b5671 TW |
67 | } |
68 | } | |
69 | ||
09cd68fe | 70 | #[derive(Debug)] |
bf7b5671 | 71 | pub struct Stick { |
09cd68fe | 72 | id: (SDLAxis, SDLAxis), |
bf7b5671 TW |
73 | pub x: f32, |
74 | pub y: f32, | |
40742678 | 75 | pub a: Angle, |
bf7b5671 TW |
76 | } |
77 | ||
78 | impl Stick { | |
09cd68fe TW |
79 | pub fn new(idx: SDLAxis, idy: SDLAxis) -> Self { |
80 | Stick { | |
81 | id: (idx, idy), | |
82 | x: 0.0, | |
83 | y: 0.0, | |
84 | a: 0.radians(), | |
85 | } | |
86 | } | |
87 | ||
88 | fn update(&mut self, device: &GameController, _dt: Duration) { | |
89 | self.x = device.axis(self.id.0) as f32 / 32768.0; | |
90 | self.y = device.axis(self.id.1) as f32 / 32768.0; | |
40742678 | 91 | self.a = point!(self.x as f64, self.y as f64).to_angle(); |
bf7b5671 TW |
92 | } |
93 | ||
3fd8761b TW |
94 | #[inline(always)] #[allow(dead_code)] pub fn up(&self) -> bool { self.y < -0.99 } |
95 | #[inline(always)] #[allow(dead_code)] pub fn down(&self) -> bool { self.y > 0.99 } | |
96 | #[inline(always)] #[allow(dead_code)] pub fn left(&self) -> bool { self.x < -0.99 } | |
97 | #[inline(always)] #[allow(dead_code)] pub fn right(&self) -> bool { self.x > 0.99 } | |
bf7b5671 | 98 | |
e570927a | 99 | pub fn to_axis_point(&self) -> Point<f64> { |
eca25591 | 100 | point!(self.x as f64, self.y as f64) |
bf7b5671 TW |
101 | } |
102 | ||
e570927a | 103 | pub fn to_point(&self) -> Point<f64> { |
eca25591 TW |
104 | let p = point!(self.x as f64, self.y as f64); |
105 | if p.length() > 1.0 { | |
93fc5734 | 106 | p.normalized() |
eca25591 TW |
107 | } else { |
108 | p | |
109 | } | |
bf7b5671 TW |
110 | } |
111 | } | |
112 | ||
e570927a | 113 | impl From<&Stick> for Point<f64> { |
bf7b5671 TW |
114 | fn from(item: &Stick) -> Self { |
115 | Self { | |
116 | x: item.x as f64, | |
117 | y: item.y as f64, | |
118 | } | |
119 | } | |
120 | } | |
121 | ||
122 | impl From<&Stick> for (f64, f64) { | |
123 | fn from(item: &Stick) -> Self { | |
124 | (item.x as f64, item.y as f64) | |
125 | } | |
3f344b63 TW |
126 | } |
127 | ||
05ba0976 | 128 | #[derive(Eq, PartialEq, Hash)] |
05ba0976 TW |
129 | enum ActionControls { |
130 | MovementX, | |
131 | MovementY, | |
132 | AimX, | |
133 | AimY, | |
134 | Jump, | |
135 | Shoot, | |
136 | Start, | |
5d731022 | 137 | } |
5d42eba1 | 138 | use self::ActionControls::*; |
5d731022 | 139 | |
3f344b63 TW |
140 | //#[derive(Debug)] |
141 | pub struct Controller { | |
09cd68fe | 142 | pub device: GameController, |
3f344b63 | 143 | haptic: Option<Rc<RefCell<Haptic>>>, |
bf7b5671 TW |
144 | |
145 | pub mov: Stick, | |
146 | pub aim: Stick, | |
147 | pub jump: Button, | |
148 | pub start: Button, | |
149 | pub shoot: Button, | |
150 | } | |
151 | ||
152 | impl Controller { | |
09cd68fe TW |
153 | pub fn new(device: GameController, haptic: Option<Rc<RefCell<Haptic>>>) -> Self { |
154 | let map = get_action_mapping(); | |
5d731022 | 155 | let mut ctrl = Controller { |
bf7b5671 TW |
156 | device, |
157 | haptic, | |
09cd68fe TW |
158 | mov: Stick::new(*map.axes.get(&MovementX).unwrap(), *map.axes.get(&MovementY).unwrap()), |
159 | aim: Stick::new(*map.axes.get(&AimX).unwrap(), *map.axes.get(&AimY).unwrap()), | |
160 | jump: Button::new(*map.buttons.get(&Jump).unwrap()), | |
161 | start: Button::new(*map.buttons.get(&Start).unwrap()), | |
162 | shoot: Button::new(*map.buttons.get(&Shoot).unwrap()), | |
5d731022 | 163 | }; |
09cd68fe | 164 | ctrl.set_mapping(&map); |
5d731022 TW |
165 | ctrl |
166 | } | |
167 | ||
09cd68fe TW |
168 | fn set_mapping(&mut self, map: &ActionMapping) { |
169 | self.mov.id.0 = *map.axes.get(&MovementX).unwrap(); | |
170 | self.mov.id.1 = *map.axes.get(&MovementY).unwrap(); | |
171 | self.aim.id.0 = *map.axes.get(&AimX).unwrap(); | |
172 | self.aim.id.1 = *map.axes.get(&AimY).unwrap(); | |
173 | self.jump.id = *map.buttons.get(&Jump).unwrap(); | |
174 | self.shoot.id = *map.buttons.get(&Shoot).unwrap(); | |
175 | self.start.id = *map.buttons.get(&Start).unwrap(); | |
bf7b5671 TW |
176 | } |
177 | ||
902b2b31 | 178 | pub fn update(&mut self, dt: Duration) { |
5d731022 TW |
179 | self.mov.update(&self.device, dt); |
180 | self.aim.update(&self.device, dt); | |
181 | self.jump.update(&self.device, dt); | |
182 | self.shoot.update(&self.device, dt); | |
183 | self.start.update(&self.device, dt); | |
bf7b5671 TW |
184 | } |
185 | ||
186 | /// strength [0 - 1] | |
902b2b31 | 187 | pub fn rumble(&self, strength: f32, duration: Duration) { |
bf7b5671 | 188 | if let Some(h) = &self.haptic { |
902b2b31 | 189 | h.borrow_mut().rumble_play(strength, duration.whole_milliseconds() as u32); |
bf7b5671 TW |
190 | } |
191 | } | |
192 | } | |
193 | ||
09cd68fe TW |
194 | struct ActionMapping { |
195 | axes: HashMap<ActionControls, SDLAxis>, | |
196 | buttons: HashMap<ActionControls, SDLButton>, | |
05ba0976 TW |
197 | } |
198 | ||
09cd68fe TW |
199 | fn get_action_mapping() -> ActionMapping { |
200 | ActionMapping { | |
201 | axes: hashmap!( | |
202 | MovementX => SDLAxis::LeftX, | |
203 | MovementY => SDLAxis::LeftY, | |
204 | AimX => SDLAxis::RightX, | |
205 | AimY => SDLAxis::RightY | |
05ba0976 | 206 | ), |
09cd68fe TW |
207 | buttons: hashmap!( |
208 | Jump => SDLButton::A, | |
209 | Shoot => SDLButton::RightShoulder, | |
210 | Start => SDLButton::Start | |
211 | ) | |
05ba0976 TW |
212 | } |
213 | } | |
214 | ||
bf7b5671 TW |
215 | //#[derive(Debug)] |
216 | pub struct ControllerManager { | |
09cd68fe | 217 | pub subsystem: GameControllerSubsystem, |
bf7b5671 TW |
218 | haptic: Rc<HapticSubsystem>, |
219 | pub controllers: HashMap<u32, Rc<RefCell<Controller>>>, | |
3f344b63 TW |
220 | } |
221 | ||
222 | impl ControllerManager { | |
09cd68fe TW |
223 | pub fn new(subsystem: GameControllerSubsystem, haptic: HapticSubsystem) -> Self { |
224 | subsystem.set_event_state(true); | |
b0566120 | 225 | let mut c = ControllerManager { |
09cd68fe | 226 | subsystem, |
3f344b63 | 227 | haptic: Rc::new(haptic), |
b0566120 TW |
228 | controllers: HashMap::new(), |
229 | }; | |
230 | c.init(); | |
231 | c | |
232 | } | |
233 | ||
234 | fn init(&mut self) { | |
09cd68fe | 235 | for i in 0..self.subsystem.num_joysticks().unwrap() { |
b0566120 | 236 | self.add_device(i); |
3f344b63 TW |
237 | } |
238 | } | |
239 | ||
902b2b31 | 240 | pub fn update(&mut self, dt: Duration) { |
bf7b5671 TW |
241 | self.controllers.iter().for_each(|(_, v)| v.borrow_mut().update(dt)); |
242 | } | |
243 | ||
3f344b63 TW |
244 | pub fn handle_event(&mut self, event: &Event) { |
245 | match event { | |
09cd68fe TW |
246 | Event::ControllerDeviceAdded { which, .. } => { self.add_device(*which) } |
247 | Event::ControllerDeviceRemoved { which, .. } => { self.remove_device(*which) } | |
248 | // Event::ControllerButtonDown { which, button_idx, .. } => { println!("device {} button {} down!", which, button_idx) } | |
249 | // Event::ControllerButtonUp { which, button_idx, .. } => { println!("device {} button {} up!", which, button_idx) } | |
250 | // Event::ControllerAxisMotion { which, axis_idx, .. } => { println!("device {} axis motion {}!", which, axis_idx) } | |
3f344b63 TW |
251 | _ => {} |
252 | } | |
253 | } | |
254 | ||
bf7b5671 | 255 | fn add_device(&mut self, id: u32) { |
3f344b63 | 256 | println!("device added ({})!", id); |
09cd68fe | 257 | let mut device = self.subsystem.open(id).unwrap(); |
bf7b5671 | 258 | println!("opened {}", device.name()); |
ca99d4d7 TW |
259 | |
260 | /* | |
261 | note about set_rumble (for dualshock 3 at least): | |
262 | the active range for the low frequency is from 65536/4 to 65536 and escalates in large steps throughout the range | |
263 | the active range for the high frequency is from 256 to 65536 and effect is the same throughout the whole range | |
264 | */ | |
bf7b5671 | 265 | let haptic = match device.set_rumble(0, 256, 100) { |
3f344b63 TW |
266 | Ok(_) => self.haptic.open_from_joystick_id(id).ok(), |
267 | Err(_) => None | |
268 | }; | |
269 | ||
b0566120 TW |
270 | if self.controllers.contains_key(&id) { |
271 | return; | |
272 | } | |
273 | ||
bf7b5671 | 274 | let detached = self.controllers.values().find(|c| !c.borrow().device.attached()); |
ca99d4d7 TW |
275 | match detached { |
276 | Some(c) => { | |
277 | let mut c = c.borrow_mut(); | |
bf7b5671 | 278 | c.device = device; |
ca99d4d7 TW |
279 | c.haptic = haptic.map(|h| Rc::new(RefCell::new(h))); |
280 | } | |
281 | None => { | |
bf7b5671 | 282 | let c = Rc::new(RefCell::new(Controller::new(device, haptic.map(|h| Rc::new(RefCell::new(h)))))); |
b0566120 | 283 | self.controllers.insert(id, c); |
ca99d4d7 TW |
284 | } |
285 | }; | |
3f344b63 TW |
286 | } |
287 | ||
bf7b5671 | 288 | fn remove_device(&mut self, id: i32) { |
3f344b63 | 289 | println!("device removed ({})!", id); |
ca99d4d7 | 290 | // TODO |
3f344b63 TW |
291 | } |
292 | } |