lib.rsannotatedlib.rssource193 lines · 5.8 KB · raw
1use bincode::{Decode, Encode};
2use jgenesis_common::define_controller_inputs;
3use jgenesis_common::frontend::{FiniteF64, MappableInputs, Modal};
4use jgenesis_common::input::Player;
5use jgenesis_proc_macros::{EnumAll, EnumDisplay, EnumFromStr};
6
7define_controller_inputs! {
8    buttons: GbaButton {
9        Up -> up "Up",
10        Left -> left "Left",
11        Right -> right "Right",
12        Down -> down "Down",
13        A -> a "A",
14        B -> b "B",
15        L -> l "L",
16        R -> r "R",
17        Start -> start "Start",
18        Select -> select "Select",
19    },
20    non_gamepad_buttons: [
21        SolarIncreaseBrightness "Increase brightness",
22        SolarDecreaseBrightness "Decrease brightness",
23        SolarMinBrightness "Set brightness to minimum",
24        SolarMaxBrightness "Set brightness to maximum",
25    ],
26    joypad: GbaJoypadInputs impl with_allow_opposing_directions,
27}
28
29impl GbaButton {
30    #[must_use]
31    pub fn is_joypad(self) -> bool {
32        #[allow(clippy::wildcard_imports)]
33        use GbaButton::*;
34        matches!(self, Up | Left | Right | Down | A | B | L | R | Start | Select)
35    }
36
37    #[must_use]
38    pub fn is_solar_sensor(self) -> bool {
39        #[allow(clippy::wildcard_imports)]
40        use GbaButton::*;
41        matches!(
42            self,
43            SolarIncreaseBrightness
44                | SolarDecreaseBrightness
45                | SolarMinBrightness
46                | SolarMaxBrightness
47        )
48    }
49}
50
51pub const DEFAULT_SOLAR_BRIGHTNESS_STEP: u8 = 5;
52pub const DEFAULT_SOLAR_MIN_BRIGHTNESS: u8 = 255 - 0xE8;
53pub const DEFAULT_SOLAR_MAX_BRIGHTNESS: u8 = 255 - 0x50;
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)]
56pub struct SolarSensorState {
57    pub brightness: u8,
58    pub brightness_step: u8,
59    pub min_brightness: u8,
60    pub max_brightness: u8,
61}
62
63impl Default for SolarSensorState {
64    fn default() -> Self {
65        Self {
66            brightness: DEFAULT_SOLAR_MIN_BRIGHTNESS,
67            brightness_step: DEFAULT_SOLAR_BRIGHTNESS_STEP,
68            min_brightness: DEFAULT_SOLAR_MIN_BRIGHTNESS,
69            max_brightness: DEFAULT_SOLAR_MAX_BRIGHTNESS,
70        }
71    }
72}
73
74impl SolarSensorState {
75    pub fn handle_button_press(&mut self, button: GbaButton) {
76        match button {
77            GbaButton::SolarIncreaseBrightness => {
78                self.brightness =
79                    self.brightness.saturating_add(self.brightness_step).min(self.max_brightness);
80            }
81            GbaButton::SolarDecreaseBrightness => {
82                self.brightness =
83                    self.brightness.saturating_sub(self.brightness_step).max(self.min_brightness);
84            }
85            GbaButton::SolarMinBrightness => {
86                self.brightness = self.min_brightness;
87            }
88            GbaButton::SolarMaxBrightness => {
89                self.brightness = self.max_brightness;
90            }
91            _ => {}
92        }
93    }
94}
95
96#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode)]
97pub struct GbaInputs {
98    pub joypad: GbaJoypadInputs,
99    pub solar: SolarSensorState,
100}
101
102impl MappableInputs<GbaButton> for GbaInputs {
103    fn set_field(&mut self, button: GbaButton, _player: Player, pressed: bool) {
104        if button.is_solar_sensor() {
105            if pressed {
106                self.solar.handle_button_press(button);
107            }
108        } else {
109            self.joypad.set_button(button, pressed);
110        }
111    }
112
113    fn modal_for_input(&self, button: GbaButton, _player: Player, pressed: bool) -> Option<Modal> {
114        if !pressed || !button.is_solar_sensor() {
115            return None;
116        }
117
118        let text = format!("Solar sensor brightness: {}", self.solar.brightness);
119        Some(Modal { id: Some("solar_sensor".into()), text })
120    }
121}
122
123#[derive(
124    Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode, EnumAll, EnumFromStr, EnumDisplay,
125)]
126#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
127#[cfg_attr(feature = "clap", derive(jgenesis_proc_macros::CustomValueEnum))]
128pub enum GbaAspectRatio {
129    #[default]
130    SquarePixels,
131    Stretched,
132}
133
134impl GbaAspectRatio {
135    #[must_use]
136    pub fn to_pixel_aspect_ratio(self) -> Option<FiniteF64> {
137        match self {
138            Self::SquarePixels => Some(FiniteF64::ONE),
139            Self::Stretched => None,
140        }
141    }
142}
143
144#[derive(
145    Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode, EnumAll, EnumFromStr, EnumDisplay,
146)]
147#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
148#[cfg_attr(feature = "clap", derive(jgenesis_proc_macros::CustomValueEnum))]
149pub enum GbaColorCorrection {
150    None,
151    #[default]
152    GbaLcd,
153}
154
155#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode, EnumAll, EnumFromStr, EnumDisplay)]
156#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
157#[cfg_attr(feature = "clap", derive(jgenesis_proc_macros::CustomValueEnum))]
158pub enum GbaSaveMemory {
159    Sram,
160    EepromUnknownSize,
161    Eeprom512,
162    Eeprom8K,
163    FlashRom64K,
164    FlashRom128K,
165    None,
166}
167
168impl GbaSaveMemory {
169    #[must_use]
170    pub fn name(self) -> &'static str {
171        match self {
172            Self::Sram => "SRAM",
173            Self::EepromUnknownSize => "EEPROM (unspecified size)",
174            Self::Eeprom512 => "EEPROM 512 bytes",
175            Self::Eeprom8K => "EEPROM 8 KB",
176            Self::FlashRom64K => "Flash ROM 64 KB",
177            Self::FlashRom128K => "Flash ROM 128 KB",
178            Self::None => "None",
179        }
180    }
181}
182
183#[derive(
184    Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode, EnumAll, EnumFromStr, EnumDisplay,
185)]
186#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
187#[cfg_attr(feature = "clap", derive(jgenesis_proc_macros::CustomValueEnum))]
188pub enum GbaAudioInterpolation {
189    #[default]
190    NearestNeighbor,
191    CubicHermite,
192    WindowedSinc,
193}