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::atan(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]
112 pub fn just_pressed(&self, old: &Self) -> Self {
113 Self {
114 left: self.left && !old.left,
115 right: self.right && !old.right,
116 up: self.up && !old.up,
117 down: self.down && !old.down,
118 }
119 }
120
121 #[must_use]
123 pub fn just_released(&self, old: &Self) -> Self {
124 Self {
125 left: !self.left && old.left,
126 right: !self.right && old.right,
127 up: !self.up && old.up,
128 down: !self.down && old.down,
129 }
130 }
131
132 #[must_use]
134 pub fn held(&self, old: &Self) -> Self {
135 Self {
136 left: self.left && old.left,
137 right: self.right && old.right,
138 up: self.up && old.up,
139 down: self.down && old.down,
140 }
141 }
142}
143
144#[derive(Default)]
146pub struct Buttons {
147 pub s: bool,
151
152 pub e: bool,
156
157 pub w: bool,
161
162 pub n: bool,
166
167 pub menu: bool,
169}
170
171impl Buttons {
172 #[must_use]
174 pub fn any(&self) -> bool {
175 self.s || self.e || self.w || self.n || self.menu
176 }
177
178 #[must_use]
180 pub fn just_pressed(&self, old: &Self) -> Self {
181 Self {
182 s: self.s && !old.s,
183 e: self.e && !old.e,
184 w: self.w && !old.w,
185 n: self.n && !old.n,
186 menu: self.menu && !old.menu,
187 }
188 }
189
190 #[must_use]
192 pub fn just_released(&self, old: &Self) -> Self {
193 Self {
194 s: !self.s && old.s,
195 e: !self.e && old.e,
196 w: !self.w && old.w,
197 n: !self.n && old.n,
198 menu: !self.menu && old.menu,
199 }
200 }
201
202 #[must_use]
204 pub fn held(&self, old: &Self) -> Self {
205 Self {
206 s: self.s && old.s,
207 e: self.e && old.e,
208 w: self.w && old.w,
209 n: self.n && old.n,
210 menu: self.menu && old.menu,
211 }
212 }
213}
214
215#[must_use]
217pub fn read_pad(p: Peer) -> Option<Pad> {
218 let p = u32::from(p.0);
219 let raw = unsafe { bindings::read_pad(p) };
220 if raw == 0xffff {
221 None
222 } else {
223 Some(Pad {
224 x: i32::from((raw >> 16) as i16),
225 y: i32::from(raw as i16),
226 })
227 }
228}
229
230#[must_use]
232pub fn read_buttons(p: Peer) -> Buttons {
233 let p = u32::from(p.0);
234 let raw = unsafe { bindings::read_buttons(p) };
235 Buttons {
236 s: has_bit_set(raw, 0),
237 e: has_bit_set(raw, 1),
238 w: has_bit_set(raw, 2),
239 n: has_bit_set(raw, 3),
240 menu: has_bit_set(raw, 4),
241 }
242}
243
244#[inline]
246fn has_bit_set(val: u32, bit: usize) -> bool {
247 (val >> bit) & 0b1 != 0
248}
249
250mod bindings {
251 #[link(wasm_import_module = "input")]
252 extern {
253 pub(crate) fn read_pad(peer: u32) -> u32;
254 pub(crate) fn read_buttons(peer: u32) -> u32;
255 }
256}