use crate::*;
const DPAD_THRESHOLD: i32 = 100;
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
pub struct Pad {
pub x: i32,
pub y: i32,
}
impl Pad {
pub const MAX: Pad = Pad { x: 1000, y: 1000 };
pub const MIN: Pad = Pad { x: -1000, y: -1000 };
#[must_use]
pub fn as_dpad(&self) -> DPad {
DPad {
left: self.x <= -DPAD_THRESHOLD,
right: self.x >= DPAD_THRESHOLD,
down: self.y <= -DPAD_THRESHOLD,
up: self.y >= DPAD_THRESHOLD,
}
}
#[must_use]
pub fn radius(self) -> f32 {
let r = self.x * self.x + self.y * self.y;
#[expect(clippy::cast_precision_loss)]
math::sqrt(r as f32)
}
#[must_use]
pub fn azimuth(self) -> Angle {
#[expect(clippy::cast_precision_loss)]
let r = math::atan(self.y as f32 / self.x as f32);
Angle::from_radians(r)
}
}
impl From<Pad> for Point {
fn from(value: Pad) -> Self {
Self {
x: value.x,
y: value.y,
}
}
}
impl From<Point> for Pad {
fn from(value: Point) -> Self {
Self {
x: value.x,
y: value.y,
}
}
}
impl From<Pad> for Size {
fn from(value: Pad) -> Self {
Self {
width: value.x,
height: value.y,
}
}
}
impl From<Size> for Pad {
fn from(value: Size) -> Self {
Self {
x: value.width,
y: value.height,
}
}
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
pub struct DPad {
pub left: bool,
pub right: bool,
pub up: bool,
pub down: bool,
}
impl From<Pad> for DPad {
fn from(value: Pad) -> Self {
value.as_dpad()
}
}
impl DPad {
#[must_use]
pub fn just_pressed(&self, old: &Self) -> Self {
Self {
left: self.left && !old.left,
right: self.right && !old.right,
up: self.up && !old.up,
down: self.down && !old.down,
}
}
#[must_use]
pub fn just_released(&self, old: &Self) -> Self {
Self {
left: !self.left && old.left,
right: !self.right && old.right,
up: !self.up && old.up,
down: !self.down && old.down,
}
}
#[must_use]
pub fn held(&self, old: &Self) -> Self {
Self {
left: self.left && old.left,
right: self.right && old.right,
up: self.up && old.up,
down: self.down && old.down,
}
}
}
#[derive(Default)]
pub struct Buttons {
pub s: bool,
pub e: bool,
pub w: bool,
pub n: bool,
pub menu: bool,
}
impl Buttons {
#[must_use]
pub fn any(&self) -> bool {
self.s || self.e || self.w || self.n || self.menu
}
#[must_use]
pub fn just_pressed(&self, old: &Self) -> Self {
Self {
s: self.s && !old.s,
e: self.e && !old.e,
w: self.w && !old.w,
n: self.n && !old.n,
menu: self.menu && !old.menu,
}
}
#[must_use]
pub fn just_released(&self, old: &Self) -> Self {
Self {
s: !self.s && old.s,
e: !self.e && old.e,
w: !self.w && old.w,
n: !self.n && old.n,
menu: !self.menu && old.menu,
}
}
#[must_use]
pub fn held(&self, old: &Self) -> Self {
Self {
s: self.s && old.s,
e: self.e && old.e,
w: self.w && old.w,
n: self.n && old.n,
menu: self.menu && old.menu,
}
}
}
#[must_use]
pub fn read_pad(p: Peer) -> Option<Pad> {
let p = u32::from(p.0);
let raw = unsafe { bindings::read_pad(p) };
if raw == 0xffff {
None
} else {
Some(Pad {
x: i32::from((raw >> 16) as i16),
y: i32::from(raw as i16),
})
}
}
#[must_use]
pub fn read_buttons(p: Peer) -> Buttons {
let p = u32::from(p.0);
let raw = unsafe { bindings::read_buttons(p) };
Buttons {
s: has_bit_set(raw, 0),
e: has_bit_set(raw, 1),
w: has_bit_set(raw, 2),
n: has_bit_set(raw, 3),
menu: has_bit_set(raw, 4),
}
}
#[inline]
fn has_bit_set(val: u32, bit: usize) -> bool {
(val >> bit) & 0b1 != 0
}
mod bindings {
#[link(wasm_import_module = "input")]
extern {
pub(crate) fn read_pad(peer: u32) -> u32;
pub(crate) fn read_buttons(peer: u32) -> u32;
}
}