rust-libretro 0.3.1

libretro API abstractions
Documentation
//! The [`CoreWrapper`] is an _internal_ data structure.
//!
//! It stores runtime information provided by the libretro frontend without interfering with your [`Core`] implementation.
use crate::*;
use std::sync::{Arc, RwLock};

pub type Interfaces = Arc<RwLock<InterfaceList>>;

#[derive(Debug, Default)]
#[proc::unstable]
pub struct InterfaceList {
    pub location_interface: Option<retro_location_callback>,
    pub perf_interface: PerfCounters,
    pub rumble_interface: Option<retro_rumble_interface>,

    #[unstable(feature = "env-commands")]
    pub camera_interface: Option<retro_camera_callback>,

    #[unstable(feature = "env-commands")]
    pub led_interface: Option<retro_led_interface>,

    #[unstable(feature = "env-commands")]
    pub sensor_interface: Option<retro_sensor_interface>,

    #[unstable(feature = "env-commands")]
    pub midi_interface: Option<retro_midi_interface>,

    #[unstable(feature = "env-commands")]
    pub vfs_interface_info: VfsInterfaceInfo,

    #[unstable(feature = "env-commands")]
    pub hw_render_context_negotiation_interface:
        Option<Box<dyn HwRenderContextNegotiationInterface>>,
}

/// Holds the core instance as well as runtime information from the libretro frontend.
///
/// This struct gets used in the code generated by the [`retro_core!()`]-macro.
pub(crate) struct CoreWrapper {
    pub(crate) environment_set: bool,
    pub(crate) environment_callback: retro_environment_t,

    /// Render a frame. Pixel format is 15-bit `0RGB1555` native endian
    /// unless changed (see [`RETRO_ENVIRONMENT_SET_PIXEL_FORMAT`]).
    ///
    /// Width and height specify dimensions of buffer.
    /// Pitch specifices length in bytes between two lines in buffer.
    ///
    /// For performance reasons, it is highly recommended to have a frame
    /// that is packed in memory, i.e. `pitch == width * byte_per_pixel`.
    /// Certain graphic APIs, such as OpenGL ES, do not like textures
    /// that are not packed in memory.
    pub(crate) video_refresh_callback: retro_video_refresh_t,

    /// Renders a single audio frame. Should only be used if implementation
    /// generates a single sample at a time.
    /// Format is signed 16-bit native endian.
    pub(crate) audio_sample_callback: retro_audio_sample_t,

    /// Renders multiple audio frames in one go.
    ///
    /// One frame is defined as a sample of left and right channels, interleaved.
    /// I.e. `int16_t buf[4] = { l, r, l, r };` would be 2 frames.
    /// Only one of the audio callbacks must ever be used.
    pub(crate) audio_sample_batch_callback: retro_audio_sample_batch_t,

    /// Polls input.
    pub(crate) input_poll_callback: retro_input_poll_t,

    /// Queries for input for player `port`. device will be masked with
    /// [`RETRO_DEVICE_MASK`].
    ///
    /// Specialization of devices such as `RETRO_DEVICE_JOYPAD_MULTITAP` that
    /// have been set with [`Core::on_set_controller_port_device`]
    /// will still use the higher level [`RETRO_DEVICE_JOYPAD`] to request input.
    pub(crate) input_state_callback: retro_input_state_t,

    pub(crate) can_dupe: bool,
    pub(crate) had_frame: bool,
    pub(crate) last_width: u32,
    pub(crate) last_height: u32,
    pub(crate) last_pitch: usize,

    pub(crate) supports_bitmasks: bool,

    pub(crate) frame_delta: Option<i64>,

    pub(crate) interfaces: Interfaces,

    /// The wrapped [`Core`] implementation.
    pub(crate) core: Box<dyn Core>,
}

impl CoreWrapper {
    pub(crate) fn new<C: 'static + Core>(core: C) -> Self {
        Self {
            environment_set: false,
            environment_callback: None,

            core: Box::new(core),

            // Callbacks
            video_refresh_callback: None,
            audio_sample_callback: None,
            audio_sample_batch_callback: None,
            input_poll_callback: None,
            input_state_callback: None,

            interfaces: Arc::new(RwLock::new(InterfaceList::default())),

            can_dupe: false,
            had_frame: false,
            last_width: 0,
            last_height: 0,
            last_pitch: 0,

            frame_delta: None,

            supports_bitmasks: false,
        }
    }

    #[inline(always)]
    pub(crate) fn on_set_video_refresh(&mut self, arg1: retro_video_refresh_t) {
        self.video_refresh_callback = arg1;
    }

    #[inline(always)]
    pub(crate) fn on_set_audio_sample(&mut self, arg1: retro_audio_sample_t) {
        self.audio_sample_callback = arg1;
    }

    #[inline(always)]
    pub(crate) fn on_set_audio_sample_batch(&mut self, arg1: retro_audio_sample_batch_t) {
        self.audio_sample_batch_callback = arg1;
    }

    #[inline(always)]
    pub(crate) fn on_set_input_poll(&mut self, arg1: retro_input_poll_t) {
        self.input_poll_callback = arg1;
    }

    #[inline(always)]
    pub(crate) fn on_set_input_state(&mut self, arg1: retro_input_state_t) {
        self.input_state_callback = arg1;
    }
}