input.rsannotatedinput.rssource122 lines · 3.6 KB · raw
1use bincode::{Decode, Encode};
2use jgenesis_common::frontend::{DisplayInfo, MappableInputs};
3use jgenesis_common::input::Player;
4use nes_config::{NesButton, NesJoypadState};
5
6pub(crate) trait NesJoypadStateExt {
7    #[must_use]
8    fn latch(self) -> LatchedJoypadState;
9}
10
11impl NesJoypadStateExt for NesJoypadState {
12    fn latch(self) -> LatchedJoypadState {
13        let bitstream = (u8::from(self.right) << 7)
14            | (u8::from(self.left) << 6)
15            | (u8::from(self.down) << 5)
16            | (u8::from(self.up) << 4)
17            | (u8::from(self.start) << 3)
18            | (u8::from(self.select) << 2)
19            | (u8::from(self.b) << 1)
20            | u8::from(self.a);
21        LatchedJoypadState(bitstream)
22    }
23}
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode)]
25pub struct ZapperState {
26    pub fire: bool,
27    pub force_offscreen: bool,
28    // Position in NES pixels, or None if offscreen
29    // X value should be in the range 0..=255
30    // Y value should be in the range 0..=223 (NTSC) or 0..=239 (PAL)
31    // Out-of-bounds values will be considered offscreen
32    pub position: Option<(u16, u16)>,
33}
34
35impl ZapperState {
36    pub(crate) fn position(self) -> Option<(u16, u16)> {
37        if self.force_offscreen { None } else { self.position }
38    }
39}
40
41#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)]
42pub enum NesInputDevice {
43    Controller(NesJoypadState),
44    Zapper(ZapperState),
45}
46
47impl Default for NesInputDevice {
48    fn default() -> Self {
49        Self::Controller(NesJoypadState::default())
50    }
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode)]
54pub struct NesInputs {
55    pub p1: NesJoypadState,
56    pub p2: NesInputDevice,
57}
58
59impl MappableInputs<NesButton> for NesInputs {
60    #[inline]
61    fn set_field(&mut self, button: NesButton, player: Player, pressed: bool) {
62        match (button, player) {
63            (NesButton::ZapperFire | NesButton::ZapperForceOffscreen, _) => {
64                if let NesInputDevice::Zapper(zapper_state) = &mut self.p2 {
65                    match button {
66                        NesButton::ZapperFire => zapper_state.fire = pressed,
67                        NesButton::ZapperForceOffscreen => zapper_state.force_offscreen = pressed,
68                        _ => {}
69                    }
70                }
71            }
72            (button, Player::One) => self.p1.set_button(button, pressed),
73            (button, Player::Two) => {
74                if let NesInputDevice::Controller(joypad_state) = &mut self.p2 {
75                    joypad_state.set_button(button, pressed);
76                }
77            }
78            _ => {}
79        }
80    }
81
82    #[inline]
83    fn handle_mouse_motion(
84        &mut self,
85        (x, y): (f32, f32),
86        _delta: (f32, f32),
87        display_info: DisplayInfo,
88    ) {
89        if let NesInputDevice::Zapper(zapper_state) = &mut self.p2 {
90            zapper_state.position =
91                jgenesis_common::input::viewport_position_to_frame_position(x, y, display_info);
92            log::debug!("Set Zapper position to {:?}", zapper_state.position);
93        }
94    }
95
96    #[inline]
97    fn handle_mouse_leave(&mut self) {
98        if let NesInputDevice::Zapper(zapper_state) = &mut self.p2 {
99            zapper_state.position = None;
100        }
101    }
102}
103
104#[derive(Debug, Clone, Copy, Encode, Decode)]
105pub(crate) struct LatchedJoypadState(u8);
106
107impl Default for LatchedJoypadState {
108    fn default() -> Self {
109        Self(0xFF)
110    }
111}
112
113impl LatchedJoypadState {
114    pub fn next_bit(self) -> u8 {
115        self.0 & 0x01
116    }
117
118    #[must_use]
119    pub fn shift(self) -> Self {
120        Self((self.0 >> 1) | 0x80)
121    }
122}