logo
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
use super::*;

/// Static information about the [`Core`] implementation.
#[derive(Debug, Default)]
pub struct SystemInfo {
    /// Descriptive name of library. Should not
    /// contain any version numbers, etc.
    pub library_name: CString,

    /// Descriptive version of the core.
    pub library_version: CString,

    /// A string listing probably content extensions the core will be able to
    /// load, separated with pipe. I.e. "bin|rom|iso".
    /// Typically used for a GUI to filter out extensions.
    pub valid_extensions: CString,

    /// libretro cores that need to have direct access to their content
    /// files, including cores which use the path of the content files to
    /// determine the paths of other files, should set `need_fullpath` to true.
    ///
    /// Cores should strive for setting `need_fullpath` to [`false`],
    /// as it allows the frontend to perform patching, etc.
    ///
    /// If `need_fullpath` is [`true`] and [`Core::on_load_game`] is called:
    ///    - [`retro_game_info::path`] is guaranteed to have a valid path
    ///    - [`retro_game_info::data`] and [`retro_game_info::size`] are invalid
    ///
    /// If `need_fullpath` is [`false`] and [`Core::on_load_game`] is called:
    ///    - [`retro_game_info::path`] may be NULL
    ///    - [`retro_game_info::data`] and [`retro_game_info::size`] are guaranteed
    ///      to be valid
    ///
    /// See also:
    ///    - [`environment::get_system_directory`]
    ///    - [`environment::get_save_directory`]
    pub need_fullpath: bool,

    /// If [`true`], the frontend is not allowed to extract any archives before
    /// loading the real content.
    /// Necessary for certain libretro implementations that load games
    /// from zipped archives.
    pub block_extract: bool,
}

bitflags::bitflags! {
    pub struct EnabledCallbacks: u32 {
        const KEYBOARD                      = 1 << 0;
        const DISK_CONTROL                  = 1 << 1;
        const HW_RENDER_CALLBACK            = 1 << 2;
        const FRAME_TIME                    = 1 << 3;
        const AUDIO                         = 1 << 4;
        const RUMBLE                        = 1 << 5;
        const SENSOR                        = 1 << 6;
        const CAMERA                        = 1 << 7;
        const PERFORMANCE                   = 1 << 8;
        const LOCATION                      = 1 << 9;
        const PROC_ADDRESS                  = 1 << 10;
        const HW_RENDER_INTERFACE           = 1 << 11;
        const HW_RENDER_CONTEXT_NEGOTIATION = 1 << 12;
        const VFS                           = 1 << 13;
        const LED                           = 1 << 14;
        const MIDI                          = 1 << 15;
        const DISC_CONTROL_EXT              = 1 << 16;
        const AUDIO_BUFFER_STATUS           = 1 << 17;
    }
}

bitflags::bitflags! {
    /// Bitflags indicating the type of input device
    pub struct RetroDevice: u8 {
        /// Input disabled
        const NONE = (1 << RETRO_DEVICE_NONE);

        /// The JOYPAD is called RetroPad. It is essentially a Super Nintendo
        /// controller, but with additional L2/R2/L3/R3 buttons, similar to a
        /// PS1 DualShock.
        const JOYPAD = (1 << RETRO_DEVICE_JOYPAD);

        /// The mouse is a simple mouse, similar to Super Nintendo's mouse.
        /// X and Y coordinates are reported relatively to last poll (poll callback).
        /// It is up to the libretro implementation to keep track of where the mouse
        /// pointer is supposed to be on the screen.
        /// The frontend must make sure not to interfere with its own hardware
        /// mouse pointer.
        const MOUSE = (1 << RETRO_DEVICE_MOUSE);

        /// KEYBOARD device lets one poll for raw key pressed.
        /// It is poll based, so input callback will return with the current
        /// pressed state.
        /// For event/text based keyboard input, see
        /// [`RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK`].
        const KEYBOARD = (1 << RETRO_DEVICE_KEYBOARD);

        /// LIGHTGUN device is similar to Guncon-2 for PlayStation 2.
        /// It reports X/Y coordinates in screen space (similar to the pointer)
        /// in the range `[-0x8000, 0x7fff]` in both axes, with zero being center and
        /// `-0x8000` being out of bounds.
        /// As well as reporting on/off screen state. It features a trigger,
        /// start/select buttons, auxiliary action buttons and a
        /// directional pad. A forced off-screen shot can be requested for
        /// auto-reloading function in some games.
        const LIGHTGUN = (1 << RETRO_DEVICE_LIGHTGUN);

        /// The ANALOG device is an extension to JOYPAD (RetroPad).
        /// Similar to DualShock2 it adds two analog sticks and all buttons can
        /// be analog. This is treated as a separate device type as it returns
        /// axis values in the full analog range of `[-0x7fff, 0x7fff]`,
        /// although some devices may return `-0x8000`.
        /// Positive X axis is right. Positive Y axis is down.
        /// Buttons are returned in the range `[0, 0x7fff]`.
        /// Only use ANALOG type when polling for analog values.
        const ANALOG = (1 << RETRO_DEVICE_ANALOG);

        /// Abstracts the concept of a pointing mechanism, e.g. touch.
        /// This allows libretro to query in absolute coordinates where on the
        /// screen a mouse (or something similar) is being placed.
        /// For a touch centric device, coordinates reported are the coordinates
        /// of the press.
        ///
        /// Coordinates in X and Y are reported as:
        /// `[-0x7fff, 0x7fff]`: `-0x7fff` corresponds to the far left/top of the screen,
        /// and `0x7fff` corresponds to the far right/bottom of the screen.
        /// The "screen" is here defined as area that is passed to the frontend and
        /// later displayed on the monitor.
        ///
        /// The frontend is free to scale/resize this screen as it sees fit, however,
        /// `(X, Y) = (-0x7fff, -0x7fff)` will correspond to the top-left pixel of the
        /// game image, etc.
        ///
        /// To check if the pointer coordinates are valid (e.g. a touch display
        /// actually being touched), PRESSED returns 1 or 0.
        ///
        /// If using a mouse on a desktop, PRESSED will usually correspond to the
        /// left mouse button, but this is a frontend decision.
        /// PRESSED will only return 1 if the pointer is inside the game screen.
        ///
        /// For multi-touch, the index variable can be used to successively query
        /// more presses.
        /// If `index = 0` returns `true` for `_PRESSED`, coordinates can be extracted
        /// with `_X, _Y` for `index = 0`. One can then query `_PRESSED, _X, _Y` with
        /// `index = 1`, and so on.
        /// Eventually `_PRESSED` will return `false` for an index. No further presses
        /// are registered at this point.
        const POINTER = (1 << RETRO_DEVICE_POINTER);
    }
}
#[test]
fn retro_device_struct_size() {
    assert_eq!(
        std::mem::size_of::<RetroDevice>(),
        ((RETRO_DEVICE_MASK + 1) >> RETRO_DEVICE_TYPE_SHIFT) as usize
    );
}

bitflags::bitflags! {
    /// Signifies quirks of the [`Core`]’s serialization feature (if any).
    pub struct SerializationQuirks: u32 {
        /// Serialized state is incomplete in some way. Set if serialization is
        /// usable in typical end-user cases but should not be relied upon to
        /// implement frame-sensitive frontend features such as netplay or
        /// rerecording.
        const INCOMPLETE = RETRO_SERIALIZATION_QUIRK_INCOMPLETE;

        /// The core must spend some time initializing before serialization is
        /// supported. [`Core::on_serialize`] will initially fail; [`Core::on_unserialize`]
        /// and [`Core::get_serialize_size`] may or may not work correctly either.
        const MUST_INITIALIZE = RETRO_SERIALIZATION_QUIRK_MUST_INITIALIZE;

        /// Serialization size may change within a session.
        const CORE_VARIABLE_SIZE = RETRO_SERIALIZATION_QUIRK_CORE_VARIABLE_SIZE;

        /// Set by the frontend to acknowledge that it supports variable-sized
        /// states.
        const FRONT_VARIABLE_SIZE = RETRO_SERIALIZATION_QUIRK_FRONT_VARIABLE_SIZE;

        /// Serialized state can only be loaded during the same session.
        const SINGLE_SESSION = RETRO_SERIALIZATION_QUIRK_SINGLE_SESSION;

        /// Serialized state cannot be loaded on an architecture with a different
        /// endianness from the one it was saved on.
        const ENDIAN_DEPENDENT = RETRO_SERIALIZATION_QUIRK_ENDIAN_DEPENDENT;

        /// Serialized state cannot be loaded on a different platform from the one it
        /// was saved on for reasons other than endianness, such as word size
        /// dependence
        const PLATFORM_DEPENDENT = RETRO_SERIALIZATION_QUIRK_PLATFORM_DEPENDENT;
    }
}

/// Used in [`environment::set_message_ext`] to signal some ongoing progress.
pub enum MessageProgress {
    /// The message is unmetered or the progress cannot be determined.
    Indeterminate,

    /// The progress as a percentage (0 - 100).
    Percentage(u8),
}

impl MessageProgress {
    pub fn indeterminate() -> Self {
        MessageProgress::Indeterminate
    }

    pub fn percentage(value: u8) -> Option<Self> {
        if value <= 100 {
            Some(MessageProgress::Percentage(value))
        } else {
            None
        }
    }

    pub fn as_i8(&self) -> i8 {
        match *self {
            MessageProgress::Percentage(value) => value as i8,
            MessageProgress::Indeterminate => -1,
        }
    }
}

/// Screen rotation in degrees
pub enum Rotation {
    None,

    Clockwise90,
    Clockwise180,
    Clockwise270,

    CounterClockwise90,
    CounterClockwise180,
    CounterClockwise270,
}

impl Rotation {
    pub fn get_env_value(&self) -> u32 {
        match self {
            Rotation::None => 0,

            Rotation::Clockwise90 => 3,
            Rotation::Clockwise180 => 2,
            Rotation::Clockwise270 => 1,

            Rotation::CounterClockwise90 => 1,
            Rotation::CounterClockwise180 => 2,
            Rotation::CounterClockwise270 => 3,
        }
    }
}

/// Data structures used by experimental libretro environment function calls
#[proc::unstable(feature = "env-commands")]
pub mod unstable {
    bitflags::bitflags! {
        /// Tells the core if the frontend wants audio or video.
        pub struct AudioVideoEnable: u32 {
            /// When this bit is **not** set:
            /// * The frontend wants the core: to not generate any video,
            ///   including presenting frames via hardware acceleration.
            /// * The frontend's video frame callback will do nothing.
            /// * After running the frame, the video output of the next frame should be
            ///   no different than if video was enabled, and saving and loading state
            ///   should have no issues.
            const ENABLE_VIDEO = 0b0001;

            /// When this bit is **not** set:
            /// * The frontend wants the core to not generate any audio.
            /// * The frontend's audio callbacks will do nothing.
            /// * After running the frame, the audio output of the next frame should be
            ///   no different than if audio was enabled, and saving and loading state
            ///   should have no issues.
            const ENABLE_AUDIO = 0b0010;

            /// When this bit is set:
            /// * Guaranteed to be created by the same binary that will load them.
            /// * Will not be written to or read from the disk.
            /// * Suggest that the core assumes loading state will succeed.
            /// * Suggest that the core updates its memory buffers in-place if possible.
            /// * Suggest that the core skips clearing memory.
            /// * Suggest that the core skips resetting the system.
            /// * Suggest that the core may skip validation steps.
            const USE_FAST_SAVESTATES = 0b0100;

            /// When this bit is set:
            /// * Used for a secondary core when running ahead.
            /// * Indicates that the frontend will never need audio from the core.
            /// * Suggests that the core may stop synthesizing audio, but this should not
            ///   compromise emulation accuracy.
            /// * Audio output for the next frame does not matter, and the frontend will
            ///   never need an accurate audio state in the future.
            /// * State will never be saved when using Hard Disable Audio.
            const HARD_DISABLE_AUDIO = 0b1000;
        }
    }

    bitflags::bitflags! {
        /// Joypad button mask
        pub struct JoypadState: u16 {
            const B      = 0b0000_0000_0000_0001;
            const Y      = 0b0000_0000_0000_0010;
            const SELECT = 0b0000_0000_0000_0100;
            const START  = 0b0000_0000_0000_1000;

            const UP     = 0b0000_0000_0001_0000;
            const DOWN   = 0b0000_0000_0010_0000;
            const LEFT   = 0b0000_0000_0100_0000;
            const RIGHT  = 0b0000_0000_1000_0000;

            const A      = 0b0000_0001_0000_0000;
            const X      = 0b0000_0010_0000_0000;
            const L      = 0b0000_0100_0000_0000;
            const R      = 0b0000_1000_0000_0000;

            const L2     = 0b0001_0000_0000_0000;
            const R2     = 0b0010_0000_0000_0000;
            const L3     = 0b0100_0000_0000_0000;
            const R3     = 0b1000_0000_0000_0000;
        }
    }
}
pub use unstable::*;