1use crate::*;
4
5const DPAD_THRESHOLD: i32 = 100;
6
7#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
12pub struct Pad {
13 pub x: i32,
14 pub y: i32,
15}
16
17impl Pad {
18 pub const MAX: Pad = Pad { x: 1000, y: 1000 };
19 pub const MIN: Pad = Pad { x: -1000, y: -1000 };
20
21 #[must_use]
23 pub fn as_dpad(&self) -> DPad {
24 DPad {
25 left: self.x <= -DPAD_THRESHOLD,
26 right: self.x >= DPAD_THRESHOLD,
27 down: self.y <= -DPAD_THRESHOLD,
28 up: self.y >= DPAD_THRESHOLD,
29 }
30 }
31
32 #[must_use]
34 pub fn radius(self) -> f32 {
35 let r = self.x * self.x + self.y * self.y;
36 #[expect(clippy::cast_precision_loss)]
37 math::sqrt(r as f32)
38 }
39
40 #[must_use]
44 pub fn azimuth(self) -> Angle {
45 #[expect(clippy::cast_precision_loss)]
46 let r = math::atan2(self.y as f32, self.x as f32);
47 Angle::from_radians(r)
48 }
49}
50
51impl From<Pad> for Point {
52 fn from(value: Pad) -> Self {
53 Self {
54 x: value.x,
55 y: value.y,
56 }
57 }
58}
59
60impl From<Point> for Pad {
61 fn from(value: Point) -> Self {
62 Self {
63 x: value.x,
64 y: value.y,
65 }
66 }
67}
68
69impl From<Pad> for Size {
70 fn from(value: Pad) -> Self {
71 Self {
72 width: value.x,
73 height: value.y,
74 }
75 }
76}
77
78impl From<Size> for Pad {
79 fn from(value: Size) -> Self {
80 Self {
81 x: value.width,
82 y: value.height,
83 }
84 }
85}
86
87#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
96pub struct DPad {
97 pub left: bool,
98 pub right: bool,
99 pub up: bool,
100 pub down: bool,
101}
102
103impl From<Pad> for DPad {
104 fn from(value: Pad) -> Self {
105 value.as_dpad()
106 }
107}
108
109impl DPad {
110 #[must_use]
111 pub fn any(&self) -> bool {
112 self.left || self.right || self.up || self.down
113 }
114
115 #[must_use]
117 pub fn just_pressed(&self, old: &Self) -> Self {
118 Self {
119 left: self.left && !old.left,
120 right: self.right && !old.right,
121 up: self.up && !old.up,
122 down: self.down && !old.down,
123 }
124 }
125
126 #[must_use]
128 pub fn just_released(&self, old: &Self) -> Self {
129 Self {
130 left: !self.left && old.left,
131 right: !self.right && old.right,
132 up: !self.up && old.up,
133 down: !self.down && old.down,
134 }
135 }
136
137 #[must_use]
139 pub fn held(&self, old: &Self) -> Self {
140 Self {
141 left: self.left && old.left,
142 right: self.right && old.right,
143 up: self.up && old.up,
144 down: self.down && old.down,
145 }
146 }
147}
148
149#[derive(Default)]
151pub struct Buttons {
152 pub s: bool,
156
157 pub e: bool,
161
162 pub w: bool,
166
167 pub n: bool,
171
172 pub menu: bool,
174}
175
176impl Buttons {
177 #[must_use]
179 pub fn any(&self) -> bool {
180 self.s || self.e || self.w || self.n || self.menu
181 }
182
183 #[must_use]
185 pub fn just_pressed(&self, old: &Self) -> Self {
186 Self {
187 s: self.s && !old.s,
188 e: self.e && !old.e,
189 w: self.w && !old.w,
190 n: self.n && !old.n,
191 menu: self.menu && !old.menu,
192 }
193 }
194
195 #[must_use]
197 pub fn just_released(&self, old: &Self) -> Self {
198 Self {
199 s: !self.s && old.s,
200 e: !self.e && old.e,
201 w: !self.w && old.w,
202 n: !self.n && old.n,
203 menu: !self.menu && old.menu,
204 }
205 }
206
207 #[must_use]
209 pub fn held(&self, old: &Self) -> Self {
210 Self {
211 s: self.s && old.s,
212 e: self.e && old.e,
213 w: self.w && old.w,
214 n: self.n && old.n,
215 menu: self.menu && old.menu,
216 }
217 }
218}
219
220#[must_use]
222pub fn read_pad(p: Peer) -> Option<Pad> {
223 let p = u32::from(p.0);
224 let raw = unsafe { bindings::read_pad(p) };
225 if raw == 0xffff {
226 None
227 } else {
228 Some(Pad {
229 x: i32::from((raw >> 16) as i16),
230 y: i32::from(raw as i16),
231 })
232 }
233}
234
235#[must_use]
237pub fn read_buttons(p: Peer) -> Buttons {
238 let p = u32::from(p.0);
239 let raw = unsafe { bindings::read_buttons(p) };
240 Buttons {
241 s: has_bit_set(raw, 0),
242 e: has_bit_set(raw, 1),
243 w: has_bit_set(raw, 2),
244 n: has_bit_set(raw, 3),
245 menu: has_bit_set(raw, 4),
246 }
247}
248
249#[inline]
251fn has_bit_set(val: u32, bit: usize) -> bool {
252 (val >> bit) & 0b1 != 0
253}
254
255mod bindings {
256 #[link(wasm_import_module = "input")]
257 extern "C" {
258 pub(crate) fn read_pad(peer: u32) -> u32;
259 pub(crate) fn read_buttons(peer: u32) -> u32;
260 }
261}