use core::ops::BitOr;
use crate::fixnum::Vector2D;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub enum Tri {
Positive = 1,
Zero = 0,
Negative = -1,
}
impl From<(bool, bool)> for Tri {
fn from(a: (bool, bool)) -> Tri {
let b1 = i8::from(a.0);
let b2 = i8::from(a.1);
unsafe { core::mem::transmute(b2 - b1) }
}
}
#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
#[repr(u16)]
pub enum Button {
A = 1 << 0,
B = 1 << 1,
Select = 1 << 2,
Start = 1 << 3,
Right = 1 << 4,
Left = 1 << 5,
Up = 1 << 6,
Down = 1 << 7,
R = 1 << 8,
L = 1 << 9,
}
const BUTTON_INPUT: *mut u16 = (0x04000130) as *mut u16;
#[derive(Clone, Debug)]
pub struct ButtonController {
previous: ButtonState,
current: ButtonState,
}
impl Default for ButtonController {
fn default() -> Self {
ButtonController::new()
}
}
impl ButtonController {
#[must_use]
pub fn new() -> Self {
let pressed = ButtonState::current();
ButtonController {
previous: pressed,
current: pressed,
}
}
pub fn update(&mut self) {
self.update_with_state(ButtonState::current());
}
pub fn update_with_state(&mut self, state: impl Into<ButtonState>) {
self.previous = self.current;
self.current = state.into();
}
#[must_use]
pub fn x_tri(&self) -> Tri {
let left = self.is_pressed(Button::Left);
let right = self.is_pressed(Button::Right);
(left, right).into()
}
#[must_use]
pub fn y_tri(&self) -> Tri {
let up = self.is_pressed(Button::Up);
let down = self.is_pressed(Button::Down);
(up, down).into()
}
#[must_use]
pub fn lr_tri(&self) -> Tri {
let l = self.is_pressed(Button::L);
let r = self.is_pressed(Button::R);
(l, r).into()
}
#[must_use]
pub fn vector<T>(&self) -> Vector2D<T>
where
T: From<i32> + crate::fixnum::Number,
{
(self.x_tri() as i32, self.y_tri() as i32).into()
}
#[must_use]
pub fn just_pressed_x_tri(&self) -> Tri {
let left = self.is_just_pressed(Button::Left);
let right = self.is_just_pressed(Button::Right);
(left, right).into()
}
#[must_use]
pub fn just_pressed_y_tri(&self) -> Tri {
let up = self.is_just_pressed(Button::Up);
let down = self.is_just_pressed(Button::Down);
(up, down).into()
}
#[must_use]
pub fn just_pressed_lr_tri(&self) -> Tri {
let l = self.is_just_pressed(Button::L);
let r = self.is_just_pressed(Button::R);
(l, r).into()
}
#[must_use]
pub fn just_pressed_vector<T>(&self) -> Vector2D<T>
where
T: From<i32> + crate::fixnum::Number,
{
(
self.just_pressed_x_tri() as i32,
self.just_pressed_y_tri() as i32,
)
.into()
}
#[must_use]
pub fn is_pressed(&self, buttons: impl Into<ButtonState>) -> bool {
self.current.any_pressed(buttons.into())
}
#[must_use]
pub fn is_released(&self, buttons: impl Into<ButtonState>) -> bool {
!self.current.all_pressed(buttons.into())
}
#[must_use]
pub fn is_just_pressed(&self, buttons: impl Into<ButtonState>) -> bool {
let buttons = buttons.into();
ButtonState(self.current.0 & !self.previous.0).any_pressed(buttons)
}
#[must_use]
pub fn is_just_released(&self, buttons: impl Into<ButtonState>) -> bool {
let buttons = buttons.into();
ButtonState(!self.current.0 & self.previous.0).any_pressed(buttons)
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct ButtonState(u16);
impl From<Button> for ButtonState {
fn from(value: Button) -> Self {
Self::single(value)
}
}
impl BitOr for Button {
type Output = ButtonState;
fn bitor(self, rhs: Self) -> Self::Output {
ButtonState(self as u16 | rhs as u16)
}
}
impl BitOr for ButtonState {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
Self(self.0 | rhs.0)
}
}
impl BitOr<Button> for ButtonState {
type Output = Self;
fn bitor(self, rhs: Button) -> Self::Output {
Self(self.0 | rhs as u16)
}
}
impl core::fmt::Debug for ButtonState {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "ButtonState[")?;
let mut is_first = true;
for b in [
Button::A,
Button::B,
Button::Start,
Button::Select,
Button::Up,
Button::Down,
Button::Left,
Button::Right,
Button::L,
Button::R,
] {
if self.is_pressed(b) {
let maybe_space = if is_first { "" } else { " " };
write!(f, "{maybe_space}{b:?}")?;
is_first = false;
}
}
write!(f, "]")
}
}
impl ButtonState {
#[must_use]
pub const fn single(button: Button) -> Self {
Self(button as u16)
}
#[must_use]
pub fn current() -> Self {
Self(!unsafe { BUTTON_INPUT.read_volatile() })
}
#[must_use]
pub const fn all() -> Self {
Self(0b0000_0011_1111_1111)
}
#[must_use]
pub const fn empty() -> Self {
Self(0)
}
#[must_use]
pub const fn is_pressed(self, button: Button) -> bool {
self.any_pressed(Self::single(button))
}
#[must_use]
pub const fn is_released(self, button: Button) -> bool {
!self.is_pressed(button)
}
#[must_use]
pub const fn any_pressed(self, state: ButtonState) -> bool {
self.0 & state.0 != 0
}
#[must_use]
pub const fn all_pressed(self, state: ButtonState) -> bool {
self.0 & state.0 == state.0
}
}
#[cfg(test)]
mod test {
use crate::Gba;
use super::*;
#[test_case]
fn test_tri_bool_tuple_from_impl(_gba: &mut Gba) {
assert_eq!(Tri::from((true, false)), Tri::Negative);
assert_eq!(Tri::from((false, true)), Tri::Positive);
assert_eq!(Tri::from((false, false)), Tri::Zero);
assert_eq!(Tri::from((true, true)), Tri::Zero);
}
#[test_case]
fn test_button_state_is_pressed(_: &mut Gba) {
assert!(ButtonState::from(Button::A).is_pressed(Button::A));
assert!((Button::A | Button::B).is_pressed(Button::A));
assert!(!(Button::A | Button::B).is_pressed(Button::Start));
}
#[test_case]
fn test_button_state_is_released(_: &mut Gba) {
assert!(ButtonState::from(Button::A).is_released(Button::B));
assert!(!ButtonState::from(Button::B).is_released(Button::B));
}
#[test_case]
fn test_button_controller_is_just_pressed(_: &mut Gba) {
let mut controller = ButtonController::new();
controller.update_with_state(Button::B);
controller.update_with_state(Button::A);
assert!(controller.is_just_pressed(Button::A));
assert!(controller.is_just_released(Button::B));
assert!(!controller.is_just_pressed(Button::Start));
assert!(!controller.is_just_released(Button::Select));
}
#[test_case]
fn test_button_controller_tri(_: &mut Gba) {
let mut controller = ButtonController::new();
controller.update_with_state(Button::L | Button::Right);
assert_eq!(controller.lr_tri(), Tri::Negative);
assert_eq!(controller.x_tri(), Tri::Positive);
assert_eq!(controller.y_tri(), Tri::Zero);
}
#[test_case]
fn test_button_state_all(_: &mut Gba) {
assert!(ButtonState::all().is_pressed(Button::A));
assert!(ButtonState::all().is_pressed(Button::L));
}
#[test_case]
fn test_just_pressed_multiple(_: &mut Gba) {
let mut controller = ButtonController::new();
controller.update_with_state(ButtonState::empty());
controller.update_with_state(Button::A | Button::B);
assert!(controller.is_just_pressed(Button::A | Button::Start));
controller.update_with_state(Button::A);
assert!(!controller.is_just_pressed(Button::A | Button::Start));
assert!(controller.is_just_released(Button::B | Button::Select));
}
#[test_case]
fn test_can_or_mulitple_buttons(_: &mut Gba) {
assert_eq!(
Button::A | Button::B | Button::L | Button::R,
(Button::A | Button::B) | (Button::L | Button::R)
);
}
#[test_case]
fn test_debug_format_for_button_state(_: &mut Gba) {
let input = Button::A | Button::Up | Button::Select;
assert_eq!(alloc::format!("{input:?}"), "ButtonState[A Select Up]");
}
}