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;