input.rsannotatedinput.rssource223 lines · 6.6 KB · raw
1use crate::frontend::{DisplayInfo, Rotation};
2
3#[non_exhaustive]
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
5pub enum Player {
6    One,
7    Two,
8    Three,
9    Four,
10    Five,
11}
12
13#[inline]
14#[must_use]
15pub fn viewport_position_to_frame_position(
16    x: f32,
17    y: f32,
18    DisplayInfo { frame_size, display_area, rotation }: DisplayInfo,
19) -> Option<(u16, u16)> {
20    let display_left = display_area.x as f32;
21    let display_right = display_left + display_area.width as f32;
22    let display_top = display_area.y as f32;
23    let display_bottom = display_top + display_area.height as f32;
24
25    if !(display_left..display_right).contains(&x) || !(display_top..display_bottom).contains(&y) {
26        return None;
27    }
28
29    let x: f64 = (x * display_area.pixel_density).into();
30    let y: f64 = (y * display_area.pixel_density).into();
31
32    let display_left: f64 = display_left.into();
33    let display_width: f64 = display_area.width.into();
34    let frame_width: f64 = frame_size.width.into();
35    let display_top: f64 = display_top.into();
36    let display_height: f64 = display_area.height.into();
37    let frame_height: f64 = frame_size.height.into();
38
39    let normalized_x = (x - display_left) / display_width;
40    let normalized_y = (y - display_top) / display_height;
41
42    let (rotated_x, rotated_y) = match rotation {
43        Rotation::None => (normalized_x, normalized_y),
44        Rotation::Clockwise => (normalized_y, 1.0 - normalized_x),
45        Rotation::OneEighty => (1.0 - normalized_x, 1.0 - normalized_y),
46        Rotation::Counterclockwise => (1.0 - normalized_y, normalized_x),
47    };
48
49    let frame_x = (rotated_x * frame_width).round() as u16;
50    let frame_y = (rotated_y * frame_height).round() as u16;
51
52    log::trace!(
53        "Mapped mouse position ({x}, {y}) to ({frame_x}, {frame_y}) (frame size {frame_size:?}, display_area {display_area:?})"
54    );
55
56    Some((frame_x, frame_y))
57}
58
59#[macro_export]
60macro_rules! define_controller_inputs {
61    (
62        buttons: $button_enum:ident {
63            $($button:ident -> $button_field:ident $button_label:literal),* $(,)?
64        }
65        $(, non_gamepad_buttons: [$($non_gamepad_button:ident $non_gamepad_label:literal),* $(,)?])?
66        , joypad: $joypad_struct:ident $(impl $with_allow_opposing_directions:ident)?
67        $(
68            , inputs: $inputs_struct:ident {
69                players: {
70                    $($player_field:ident: Player::$player_value:ident),* $(,)?
71                }
72                $(, buttons: [$($ex_button:ident -> $ex_button_field:ident),* $(,)?])?
73                $(,)?
74            }
75        )?
76        $(,)?
77    ) => {
78        #[derive(
79            Debug,
80            Clone,
81            Copy,
82            PartialEq,
83            Eq,
84            ::std::hash::Hash,
85            ::bincode::Encode,
86            ::bincode::Decode,
87            ::jgenesis_proc_macros::EnumAll,
88            ::jgenesis_proc_macros::EnumDisplay,
89            ::jgenesis_proc_macros::EnumFromStr,
90        )]
91        pub enum $button_enum {
92            $(
93                $button,
94            )*
95            $($(
96                $non_gamepad_button,
97            )*)?
98        }
99
100        impl $button_enum {
101            #[must_use]
102            pub fn label(self) -> &'static str {
103                match self {
104                    $(
105                        Self::$button => $button_label,
106                    )*
107                    $($(
108                        Self::$non_gamepad_button => $non_gamepad_label,
109                    )*)?
110                }
111            }
112        }
113
114        #[derive(
115            Debug,
116            Clone,
117            Copy,
118            PartialEq,
119            Eq,
120            Default,
121            ::std::hash::Hash,
122            ::bincode::Encode,
123            ::bincode::Decode,
124        )]
125        pub struct $joypad_struct {
126            $(
127                pub $button_field: bool,
128            )*
129        }
130
131        impl $joypad_struct {
132            #[inline]
133            pub fn set_button(&mut self, button: $button_enum, pressed: bool) {
134                match button {
135                    $(
136                        $button_enum::$button => self.$button_field = pressed,
137                    )*
138                    $(
139                        $(
140                            $button_enum::$non_gamepad_button => {}
141                        )*
142                    )?
143                }
144            }
145
146            #[inline]
147            pub fn with_button(mut self, button: $button_enum, pressed: bool) -> Self {
148                self.set_button(button, pressed);
149                self
150            }
151
152            $(
153                #[inline]
154                #[must_use]
155                pub fn $with_allow_opposing_directions(mut self, allow_opposing_directions: bool) -> Self {
156                    if allow_opposing_directions {
157                        return self;
158                    }
159
160                    if self.left && self.right {
161                        self.left = false;
162                        self.right = false;
163                    }
164
165                    if self.up && self.down {
166                        self.up = false;
167                        self.down = false;
168                    }
169
170                    self
171                }
172            )?
173        }
174
175        $(
176            #[derive(
177                Debug,
178                Clone,
179                Copy,
180                PartialEq,
181                Eq,
182                Default,
183                ::std::hash::Hash,
184                ::bincode::Encode,
185                ::bincode::Decode,
186            )]
187            pub struct $inputs_struct {
188                $(
189                    pub $player_field: $joypad_struct,
190                )*
191                $($(
192                    pub $ex_button_field: bool,
193                )*)?
194            }
195
196            impl ::jgenesis_common::frontend::MappableInputs<$button_enum> for $inputs_struct {
197                #[inline]
198                fn set_field(
199                    &mut self,
200                    button: $button_enum,
201                    player: ::jgenesis_common::input::Player,
202                    pressed: bool,
203                ) {
204                    match (button, player) {
205                        $($(
206                            ($button_enum::$ex_button, _) => {
207                                self.$ex_button_field = pressed;
208                            }
209                        )*)?
210                        $(
211                            (button, ::jgenesis_common::input::Player::$player_value) => {
212                                self.$player_field.set_button(button, pressed);
213                            }
214                        )*
215                        _ => {}
216                    }
217                }
218            }
219        )?
220    }
221}
222
223pub use define_controller_inputs;