1use euclid::Vector2D;
2use qwac_sys::input::{gamepad_axis, gamepad_buttons};
3pub use qwac_sys::input::{GamepadAxis, GamepadButton};
4
5#[derive(Clone, Copy, Hash, Debug, Eq, PartialEq, Ord, PartialOrd)]
7pub struct GamepadButtons(u64);
8
9const fn button_bit(player: u8, button: GamepadButton) -> u64 {
11 1u64 << player * 16 + button as u8
12}
13
14impl GamepadButtons {
15 pub fn poll() -> Self {
16 Self(unsafe { gamepad_buttons() } as u64)
17 }
18
19 pub fn pressed(&self, player: u8, button: GamepadButton) -> bool {
20 (self.0 & button_bit(player, button)) != 0
21 }
22}
23
24#[derive(Clone, Copy, Debug)]
26pub struct ButtonTracker {
27 previous_frame: GamepadButtons,
28 current_frame: GamepadButtons,
29}
30
31impl Default for ButtonTracker {
32 fn default() -> Self {
33 Self {
34 previous_frame: GamepadButtons(0),
35 current_frame: GamepadButtons(0),
36 }
37 }
38}
39
40impl ButtonTracker {
41 pub fn new() -> Self {
42 Default::default()
43 }
44
45 pub fn frame(&mut self, frame: GamepadButtons) {
47 self.previous_frame = std::mem::replace(&mut self.current_frame, frame);
48 }
49
50 pub fn poll(&mut self) {
52 self.frame(GamepadButtons::poll());
53 }
54
55 pub fn state(&self, player: u8, button: GamepadButton) -> (bool, bool) {
57 (
58 self.previous_frame.pressed(player, button),
59 self.current_frame.pressed(player, button),
60 )
61 }
62
63 pub fn pressed(&self, player: u8, button: GamepadButton) -> bool {
64 self.current_frame.pressed(player, button)
65 }
66
67 pub fn just_pressed(&self, player: u8, button: GamepadButton) -> bool {
68 let (previous, current) = self.state(player, button);
69 !previous && current
70 }
71
72 pub fn just_released(&self, player: u8, button: GamepadButton) -> bool {
73 let (previous, current) = self.state(player, button);
74 previous && !current
75 }
76
77 pub fn held(&self, player: u8, button: GamepadButton) -> bool {
78 let (previous, current) = self.state(player, button);
79 previous && current
80 }
81}
82
83#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
85pub struct Tilt;
86
87#[derive(Clone, Copy, Debug)]
88pub struct GamepadSticks {
89 left: Vector2D<f32, Tilt>,
90 right: Vector2D<f32, Tilt>,
91}
92
93fn with_dead_zone(
94 stick: Vector2D<f32, Tilt>,
95 dead_zone: f32,
96 square_dead_zone: f32,
97) -> Vector2D<f32, Tilt> {
98 let square_length = stick.square_length();
99 if square_length == 0.0 || square_length < square_dead_zone {
100 Vector2D::zero()
101 } else {
102 let length = square_length.sqrt();
103 let t = (length - dead_zone) / (1.0 - dead_zone);
105 let new_length = t.clamp(0.0, 1.0);
106 let normalized = stick / length;
107 normalized * new_length
108 }
109}
110
111impl GamepadSticks {
112 pub fn poll(player: u8) -> Self {
113 let player = player as i32;
114 let left_up = unsafe { gamepad_axis(player, GamepadAxis::LeftUp as i32) };
115 let left_down = unsafe { gamepad_axis(player, GamepadAxis::LeftDown as i32) };
116 let left_left = unsafe { gamepad_axis(player, GamepadAxis::LeftLeft as i32) };
117 let left_right = unsafe { gamepad_axis(player, GamepadAxis::LeftRight as i32) };
118 let right_up = unsafe { gamepad_axis(player, GamepadAxis::RightUp as i32) };
119 let right_down = unsafe { gamepad_axis(player, GamepadAxis::RightDown as i32) };
120 let right_left = unsafe { gamepad_axis(player, GamepadAxis::RightLeft as i32) };
121 let right_right = unsafe { gamepad_axis(player, GamepadAxis::RightRight as i32) };
122 Self {
123 left: Vector2D::new(left_right - left_left, left_up - left_down),
124 right: Vector2D::new(right_right - right_left, right_up - right_down),
125 }
126 }
127
128 pub fn apply_dead_zone(&self, dead_zone: f32) -> Self {
129 if dead_zone == 0.0 {
130 self.clone()
131 } else {
132 let square_dead_zone = dead_zone.powi(2);
133 Self {
134 left: with_dead_zone(self.left, dead_zone, square_dead_zone),
135 right: with_dead_zone(self.right, dead_zone, square_dead_zone),
136 }
137 }
138 }
139
140 pub fn left(&self) -> Vector2D<f32, Tilt> {
141 self.left
142 }
143
144 pub fn right(&self) -> Vector2D<f32, Tilt> {
145 self.right
146 }
147}