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 #[expect(clippy::cast_precision_loss)]
75 let r = math::atan2(self.y as f32, self.x as f32);
76 Angle::from_radians(r)
77 }
78}
79
80impl From<Pad> for Point {
81 fn from(value: Pad) -> Self {
82 Self {
83 x: value.x,
84 y: value.y,
85 }
86 }
87}
88
89impl From<Point> for Pad {
90 fn from(value: Point) -> Self {
91 Self {
92 x: value.x,
93 y: value.y,
94 }
95 }
96}
97
98impl From<Pad> for Size {
99 fn from(value: Pad) -> Self {
100 Self {
101 width: value.x,
102 height: value.y,
103 }
104 }
105}
106
107impl From<Size> for Pad {
108 fn from(value: Size) -> Self {
109 Self {
110 x: value.width,
111 y: value.height,
112 }
113 }
114}
115
116#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
139pub struct DPad8 {
140 pub left: bool,
141 pub right: bool,
142 pub up: bool,
143 pub down: bool,
144}
145
146impl DPad8 {
147 #[must_use]
149 pub fn any(&self) -> bool {
150 self.left || self.right || self.up || self.down
151 }
152
153 #[must_use]
155 pub fn just_pressed(&self, old: &Self) -> Self {
156 Self {
157 left: self.left && !old.left,
158 right: self.right && !old.right,
159 up: self.up && !old.up,
160 down: self.down && !old.down,
161 }
162 }
163
164 #[must_use]
166 pub fn just_released(&self, old: &Self) -> Self {
167 Self {
168 left: !self.left && old.left,
169 right: !self.right && old.right,
170 up: !self.up && old.up,
171 down: !self.down && old.down,
172 }
173 }
174
175 #[must_use]
177 pub fn held(&self, old: &Self) -> Self {
178 Self {
179 left: self.left && old.left,
180 right: self.right && old.right,
181 up: self.up && old.up,
182 down: self.down && old.down,
183 }
184 }
185}
186
187impl From<Pad> for DPad8 {
188 fn from(value: Pad) -> Self {
189 value.as_dpad8()
190 }
191}
192
193impl From<Option<DPad8>> for DPad8 {
194 fn from(value: Option<DPad8>) -> Self {
195 value.unwrap_or_default()
196 }
197}
198
199impl From<DPad4> for DPad8 {
200 fn from(value: DPad4) -> Self {
201 let mut pad = Self::default();
202 match value {
203 DPad4::None => {}
204 DPad4::Left => pad.left = true,
205 DPad4::Right => pad.right = true,
206 DPad4::Up => pad.up = true,
207 DPad4::Down => pad.down = true,
208 }
209 pad
210 }
211}
212
213#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
220pub enum DPad4 {
221 #[default]
222 None,
223 Left,
224 Right,
225 Up,
226 Down,
227}
228
229impl DPad4 {
230 #[must_use]
232 pub fn any(self) -> bool {
233 self != Self::None
234 }
235
236 #[must_use]
238 pub fn just_pressed(self, old: Self) -> Self {
239 if self == old { Self::None } else { self }
240 }
241
242 #[must_use]
244 pub fn just_released(self, old: Self) -> Self {
245 if self == old { Self::None } else { old }
246 }
247
248 #[must_use]
250 pub fn held(self, old: Self) -> Self {
251 if self == old { self } else { Self::None }
252 }
253}
254
255impl From<Pad> for DPad4 {
256 fn from(value: Pad) -> Self {
257 value.as_dpad4()
258 }
259}
260
261impl From<Option<DPad4>> for DPad4 {
262 fn from(value: Option<DPad4>) -> Self {
263 value.unwrap_or_default()
264 }
265}
266
267#[derive(Default)]
269pub struct Buttons {
270 pub s: bool,
274
275 pub e: bool,
279
280 pub w: bool,
284
285 pub n: bool,
289
290 pub menu: bool,
292}
293
294impl Buttons {
295 #[must_use]
297 pub fn any(&self) -> bool {
298 self.s || self.e || self.w || self.n || self.menu
299 }
300
301 #[must_use]
303 pub fn just_pressed(&self, old: &Self) -> Self {
304 Self {
305 s: self.s && !old.s,
306 e: self.e && !old.e,
307 w: self.w && !old.w,
308 n: self.n && !old.n,
309 menu: self.menu && !old.menu,
310 }
311 }
312
313 #[must_use]
315 pub fn just_released(&self, old: &Self) -> Self {
316 Self {
317 s: !self.s && old.s,
318 e: !self.e && old.e,
319 w: !self.w && old.w,
320 n: !self.n && old.n,
321 menu: !self.menu && old.menu,
322 }
323 }
324
325 #[must_use]
327 pub fn held(&self, old: &Self) -> Self {
328 Self {
329 s: self.s && old.s,
330 e: self.e && old.e,
331 w: self.w && old.w,
332 n: self.n && old.n,
333 menu: self.menu && old.menu,
334 }
335 }
336}
337
338#[must_use]
340pub fn read_pad(p: Peer) -> Option<Pad> {
341 let p = u32::from(p.0);
342 let raw = unsafe { bindings::read_pad(p) };
343 if raw == 0xffff {
344 None
345 } else {
346 Some(Pad {
347 x: i32::from((raw >> 16) as i16),
348 y: i32::from(raw as i16),
349 })
350 }
351}
352
353#[must_use]
355pub fn read_buttons(p: Peer) -> Buttons {
356 let p = u32::from(p.0);
357 let raw = unsafe { bindings::read_buttons(p) };
358 Buttons {
359 s: has_bit_set(raw, 0),
360 e: has_bit_set(raw, 1),
361 w: has_bit_set(raw, 2),
362 n: has_bit_set(raw, 3),
363 menu: has_bit_set(raw, 4),
364 }
365}
366
367#[inline]
369fn has_bit_set(val: u32, bit: usize) -> bool {
370 (val >> bit) & 0b1 != 0
371}
372
373mod bindings {
374 #[link(wasm_import_module = "input")]
375 unsafe extern "C" {
376 pub(crate) fn read_pad(peer: u32) -> u32;
377 pub(crate) fn read_buttons(peer: u32) -> u32;
378 }
379}