1use crate::*;
4
5const DPAD4_THRESHOLD: i32 = 300;
6const DPAD8_THRESHOLD: i32 = 300;
7
8#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
17pub struct Pad {
18 pub x: i32,
19 pub y: i32,
20}
21
22impl Pad {
23 pub const MAX: Pad = Pad { x: 1000, y: 1000 };
25 pub const MIN: Pad = Pad { x: -1000, y: -1000 };
27
28 #[must_use]
32 pub fn as_dpad4(&self) -> DPad4 {
33 let x = self.x;
34 let y = self.y;
35 if y > DPAD4_THRESHOLD && y > x.abs() {
36 DPad4::Up
37 } else if y < -DPAD4_THRESHOLD && -y > x.abs() {
38 DPad4::Down
39 } else if x > DPAD4_THRESHOLD && x > y.abs() {
40 DPad4::Right
41 } else if x < -DPAD4_THRESHOLD && -x > y.abs() {
42 DPad4::Left
43 } else {
44 DPad4::None
45 }
46 }
47
48 #[must_use]
52 pub fn as_dpad8(&self) -> DPad8 {
53 DPad8 {
54 left: self.x <= -DPAD8_THRESHOLD,
55 right: self.x >= DPAD8_THRESHOLD,
56 down: self.y <= -DPAD8_THRESHOLD,
57 up: self.y >= DPAD8_THRESHOLD,
58 }
59 }
60
61 #[must_use]
63 pub fn radius(self) -> f32 {
64 let r = self.x * self.x + self.y * self.y;
65 #[expect(clippy::cast_precision_loss)]
66 math::sqrt(r as f32)
67 }
68
69 #[must_use]
73 pub fn azimuth(self) -> Angle {
74 if self.x == 0 && self.y == 0 {
75 return Angle::ZERO;
76 }
77 #[expect(clippy::cast_precision_loss)]
78 let r = math::atan2(self.y as f32, self.x as f32);
79 Angle::from_radians(r)
80 }
81}
82
83impl From<Pad> for Point {
84 fn from(value: Pad) -> Self {
85 Self {
86 x: value.x,
87 y: value.y,
88 }
89 }
90}
91
92impl From<Point> for Pad {
93 fn from(value: Point) -> Self {
94 Self {
95 x: value.x,
96 y: value.y,
97 }
98 }
99}
100
101impl From<Pad> for Size {
102 fn from(value: Pad) -> Self {
103 Self {
104 width: value.x,
105 height: value.y,
106 }
107 }
108}
109
110impl From<Size> for Pad {
111 fn from(value: Size) -> Self {
112 Self {
113 x: value.width,
114 y: value.height,
115 }
116 }
117}
118
119#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
142pub struct DPad8 {
143 pub left: bool,
144 pub right: bool,
145 pub up: bool,
146 pub down: bool,
147}
148
149impl DPad8 {
150 #[must_use]
152 pub fn any(&self) -> bool {
153 self.left || self.right || self.up || self.down
154 }
155
156 #[must_use]
158 pub fn just_pressed(&self, old: &Self) -> Self {
159 Self {
160 left: self.left && !old.left,
161 right: self.right && !old.right,
162 up: self.up && !old.up,
163 down: self.down && !old.down,
164 }
165 }
166
167 #[must_use]
169 pub fn just_released(&self, old: &Self) -> Self {
170 Self {
171 left: !self.left && old.left,
172 right: !self.right && old.right,
173 up: !self.up && old.up,
174 down: !self.down && old.down,
175 }
176 }
177
178 #[must_use]
180 pub fn held(&self, old: &Self) -> Self {
181 Self {
182 left: self.left && old.left,
183 right: self.right && old.right,
184 up: self.up && old.up,
185 down: self.down && old.down,
186 }
187 }
188}
189
190impl From<Pad> for DPad8 {
191 fn from(value: Pad) -> Self {
192 value.as_dpad8()
193 }
194}
195
196impl From<Option<DPad8>> for DPad8 {
197 fn from(value: Option<DPad8>) -> Self {
198 value.unwrap_or_default()
199 }
200}
201
202impl From<DPad4> for DPad8 {
203 fn from(value: DPad4) -> Self {
204 let mut pad = Self::default();
205 match value {
206 DPad4::None => {}
207 DPad4::Left => pad.left = true,
208 DPad4::Right => pad.right = true,
209 DPad4::Up => pad.up = true,
210 DPad4::Down => pad.down = true,
211 }
212 pad
213 }
214}
215
216#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
223pub enum DPad4 {
224 #[default]
225 None,
226 Left,
227 Right,
228 Up,
229 Down,
230}
231
232impl DPad4 {
233 #[must_use]
235 pub fn any(self) -> bool {
236 self != Self::None
237 }
238
239 #[must_use]
241 pub fn just_pressed(self, old: Self) -> Self {
242 if self == old { Self::None } else { self }
243 }
244
245 #[must_use]
247 pub fn just_released(self, old: Self) -> Self {
248 if self == old { Self::None } else { old }
249 }
250
251 #[must_use]
253 pub fn held(self, old: Self) -> Self {
254 if self == old { self } else { Self::None }
255 }
256}
257
258impl From<Pad> for DPad4 {
259 fn from(value: Pad) -> Self {
260 value.as_dpad4()
261 }
262}
263
264impl From<Option<DPad4>> for DPad4 {
265 fn from(value: Option<DPad4>) -> Self {
266 value.unwrap_or_default()
267 }
268}
269
270#[derive(Default, Clone, Copy)]
272pub struct Buttons {
273 pub s: bool,
277
278 pub e: bool,
282
283 pub w: bool,
287
288 pub n: bool,
292
293 pub menu: bool,
295}
296
297impl Buttons {
298 #[must_use]
300 pub fn any(&self) -> bool {
301 self.s || self.e || self.w || self.n || self.menu
302 }
303
304 #[must_use]
306 pub fn just_pressed(&self, old: &Self) -> Self {
307 Self {
308 s: self.s && !old.s,
309 e: self.e && !old.e,
310 w: self.w && !old.w,
311 n: self.n && !old.n,
312 menu: self.menu && !old.menu,
313 }
314 }
315
316 #[must_use]
318 pub fn just_released(&self, old: &Self) -> Self {
319 Self {
320 s: !self.s && old.s,
321 e: !self.e && old.e,
322 w: !self.w && old.w,
323 n: !self.n && old.n,
324 menu: !self.menu && old.menu,
325 }
326 }
327
328 #[must_use]
330 pub fn held(&self, old: &Self) -> Self {
331 Self {
332 s: self.s && old.s,
333 e: self.e && old.e,
334 w: self.w && old.w,
335 n: self.n && old.n,
336 menu: self.menu && old.menu,
337 }
338 }
339}
340
341#[must_use]
343pub fn read_pad(p: Peer) -> Option<Pad> {
344 let p = u32::from(p.0);
345 let raw = unsafe { bindings::read_pad(p) };
346 if raw == 0xffff {
347 None
348 } else {
349 Some(Pad {
350 x: i32::from((raw >> 16) as i16),
351 y: i32::from(raw as i16),
352 })
353 }
354}
355
356#[must_use]
358pub fn read_buttons(p: Peer) -> Buttons {
359 let p = u32::from(p.0);
360 let raw = unsafe { bindings::read_buttons(p) };
361 Buttons {
362 s: has_bit_set(raw, 0),
363 e: has_bit_set(raw, 1),
364 w: has_bit_set(raw, 2),
365 n: has_bit_set(raw, 3),
366 menu: has_bit_set(raw, 4),
367 }
368}
369
370#[inline]
372fn has_bit_set(val: u32, bit: usize) -> bool {
373 (val >> bit) & 0b1 != 0
374}
375
376mod bindings {
377 #[link(wasm_import_module = "input")]
378 unsafe extern "C" {
379 pub(crate) fn read_pad(peer: u32) -> u32;
380 pub(crate) fn read_buttons(peer: u32) -> u32;
381 }
382}