| 1 | use geometry::{Angle, ToAngle, Point}; |
| 2 | use sdl2::GameControllerSubsystem; |
| 3 | use sdl2::HapticSubsystem; |
| 4 | use sdl2::controller::{GameController, Axis as SDLAxis, Button as SDLButton}; |
| 5 | use sdl2::event::Event; |
| 6 | use sdl2::haptic::Haptic; |
| 7 | use std::cell::RefCell; |
| 8 | use std::collections::HashMap; |
| 9 | use std::rc::Rc; |
| 10 | use time::{Duration, prelude::*}; |
| 11 | use {hashmap, point}; |
| 12 | |
| 13 | #[derive(Debug)] |
| 14 | pub struct Button { |
| 15 | id: SDLButton, |
| 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 | 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) { |
| 36 | self.was_pressed = self.is_pressed; |
| 37 | self.is_pressed = match device.button(self.id) { |
| 38 | true => { |
| 39 | if !self.was_pressed { |
| 40 | self.time_pressed = 0.seconds(); |
| 41 | self.toggle = !self.toggle; |
| 42 | } |
| 43 | self.time_pressed += dt; |
| 44 | true |
| 45 | } |
| 46 | false => { |
| 47 | if self.was_pressed { |
| 48 | self.time_released = 0.seconds(); |
| 49 | } |
| 50 | self.time_released += dt; |
| 51 | false |
| 52 | } |
| 53 | } |
| 54 | } |
| 55 | } |
| 56 | |
| 57 | #[derive(Debug)] |
| 58 | pub struct Axis { |
| 59 | id: SDLAxis, |
| 60 | pub val: f32, |
| 61 | } |
| 62 | |
| 63 | impl Axis { |
| 64 | #[allow(dead_code)] |
| 65 | fn update(&mut self, device: &GameController, _dt: Duration) { |
| 66 | self.val = device.axis(self.id) as f32 / 32768.0; |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | #[derive(Debug)] |
| 71 | pub struct Stick { |
| 72 | id: (SDLAxis, SDLAxis), |
| 73 | pub x: f32, |
| 74 | pub y: f32, |
| 75 | pub a: Angle, |
| 76 | } |
| 77 | |
| 78 | impl Stick { |
| 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; |
| 91 | self.a = point!(self.x as f64, self.y as f64).to_angle(); |
| 92 | } |
| 93 | |
| 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 } |
| 98 | |
| 99 | pub fn to_axis_point(&self) -> Point<f64> { |
| 100 | point!(self.x as f64, self.y as f64) |
| 101 | } |
| 102 | |
| 103 | pub fn to_point(&self) -> Point<f64> { |
| 104 | let p = point!(self.x as f64, self.y as f64); |
| 105 | if p.length() > 1.0 { |
| 106 | p.normalized() |
| 107 | } else { |
| 108 | p |
| 109 | } |
| 110 | } |
| 111 | } |
| 112 | |
| 113 | impl From<&Stick> for Point<f64> { |
| 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 | } |
| 126 | } |
| 127 | |
| 128 | #[derive(Eq, PartialEq, Hash)] |
| 129 | enum ActionControls { |
| 130 | MovementX, |
| 131 | MovementY, |
| 132 | AimX, |
| 133 | AimY, |
| 134 | Jump, |
| 135 | Shoot, |
| 136 | Start, |
| 137 | } |
| 138 | use self::ActionControls::*; |
| 139 | |
| 140 | //#[derive(Debug)] |
| 141 | pub struct Controller { |
| 142 | pub device: GameController, |
| 143 | haptic: Option<Rc<RefCell<Haptic>>>, |
| 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 { |
| 153 | pub fn new(device: GameController, haptic: Option<Rc<RefCell<Haptic>>>) -> Self { |
| 154 | let map = get_action_mapping(); |
| 155 | let mut ctrl = Controller { |
| 156 | device, |
| 157 | haptic, |
| 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()), |
| 163 | }; |
| 164 | ctrl.set_mapping(&map); |
| 165 | ctrl |
| 166 | } |
| 167 | |
| 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(); |
| 176 | } |
| 177 | |
| 178 | pub fn update(&mut self, dt: Duration) { |
| 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); |
| 184 | } |
| 185 | |
| 186 | /// strength [0 - 1] |
| 187 | pub fn rumble(&self, strength: f32, duration: Duration) { |
| 188 | if let Some(h) = &self.haptic { |
| 189 | h.borrow_mut().rumble_play(strength, duration.whole_milliseconds() as u32); |
| 190 | } |
| 191 | } |
| 192 | } |
| 193 | |
| 194 | struct ActionMapping { |
| 195 | axes: HashMap<ActionControls, SDLAxis>, |
| 196 | buttons: HashMap<ActionControls, SDLButton>, |
| 197 | } |
| 198 | |
| 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 |
| 206 | ), |
| 207 | buttons: hashmap!( |
| 208 | Jump => SDLButton::A, |
| 209 | Shoot => SDLButton::RightShoulder, |
| 210 | Start => SDLButton::Start |
| 211 | ) |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | //#[derive(Debug)] |
| 216 | pub struct ControllerManager { |
| 217 | pub subsystem: GameControllerSubsystem, |
| 218 | haptic: Rc<HapticSubsystem>, |
| 219 | pub controllers: HashMap<u32, Rc<RefCell<Controller>>>, |
| 220 | } |
| 221 | |
| 222 | impl ControllerManager { |
| 223 | pub fn new(subsystem: GameControllerSubsystem, haptic: HapticSubsystem) -> Self { |
| 224 | subsystem.set_event_state(true); |
| 225 | let mut c = ControllerManager { |
| 226 | subsystem, |
| 227 | haptic: Rc::new(haptic), |
| 228 | controllers: HashMap::new(), |
| 229 | }; |
| 230 | c.init(); |
| 231 | c |
| 232 | } |
| 233 | |
| 234 | fn init(&mut self) { |
| 235 | for i in 0..self.subsystem.num_joysticks().unwrap() { |
| 236 | self.add_device(i); |
| 237 | } |
| 238 | } |
| 239 | |
| 240 | pub fn update(&mut self, dt: Duration) { |
| 241 | self.controllers.iter().for_each(|(_, v)| v.borrow_mut().update(dt)); |
| 242 | } |
| 243 | |
| 244 | pub fn handle_event(&mut self, event: &Event) { |
| 245 | match event { |
| 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) } |
| 251 | _ => {} |
| 252 | } |
| 253 | } |
| 254 | |
| 255 | fn add_device(&mut self, id: u32) { |
| 256 | println!("device added ({})!", id); |
| 257 | let mut device = self.subsystem.open(id).unwrap(); |
| 258 | println!("opened {}", device.name()); |
| 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 | */ |
| 265 | let haptic = match device.set_rumble(0, 256, 100) { |
| 266 | Ok(_) => self.haptic.open_from_joystick_id(id).ok(), |
| 267 | Err(_) => None |
| 268 | }; |
| 269 | |
| 270 | if self.controllers.contains_key(&id) { |
| 271 | return; |
| 272 | } |
| 273 | |
| 274 | let detached = self.controllers.values().find(|c| !c.borrow().device.attached()); |
| 275 | match detached { |
| 276 | Some(c) => { |
| 277 | let mut c = c.borrow_mut(); |
| 278 | c.device = device; |
| 279 | c.haptic = haptic.map(|h| Rc::new(RefCell::new(h))); |
| 280 | } |
| 281 | None => { |
| 282 | let c = Rc::new(RefCell::new(Controller::new(device, haptic.map(|h| Rc::new(RefCell::new(h)))))); |
| 283 | self.controllers.insert(id, c); |
| 284 | } |
| 285 | }; |
| 286 | } |
| 287 | |
| 288 | fn remove_device(&mut self, id: i32) { |
| 289 | println!("device removed ({})!", id); |
| 290 | // TODO |
| 291 | } |
| 292 | } |