ferretro/ferretro_base/src/retro/wrapper.rs

156 lines
5.8 KiB
Rust

#![allow(clippy::option_map_unit_fn)] // sorry clippy, we really need the conciseness
use core::ops::{Deref, DerefMut};
use core::time::Duration;
use std::ffi::CString;
use std::os::raw::c_uint;
use super::ffi::*;
use super::loading::*;
// #[cfg(doc)] <- broken as of (at least) 1.56
#[allow(unused_imports)]
use libretro_sys::{self, CoreAPI};
pub struct LibretroWrapper {
pub(crate) api: LibretroApi,
pub(crate) keyboard_event_cb: Option<KeyboardEventFn>,
pub(crate) frame_time_cb: Option<FrameTimeCallbackFn>,
pub(crate) audio_ready_cb: Option<AudioCallbackFn>,
pub(crate) audio_set_state_cb: Option<AudioSetStateCallbackFn>,
pub(crate) disk_get_eject_state_cb: Option<GetEjectStateFn>,
pub(crate) disk_set_eject_state_cb: Option<SetEjectStateFn>,
pub(crate) disk_get_image_index_cb: Option<GetImageIndexFn>,
pub(crate) disk_set_image_index_cb: Option<SetImageIndexFn>,
pub(crate) disk_get_num_images_cb: Option<GetNumImagesFn>,
pub(crate) disk_replace_image_index_cb: Option<ReplaceImageIndexFn>,
pub(crate) disk_add_image_index_cb: Option<AddImageIndexFn>,
pub(crate) camera_frame_raw_framebuffer_cb: Option<CameraFrameRawFramebufferFn>,
pub(crate) camera_frame_opengl_texture_cb: Option<CameraFrameOpenglTextureFn>,
pub(crate) camera_lifetime_initialized_cb: Option<CameraLifetimeStatusFn>,
pub(crate) camera_lifetime_deinitialized_cb: Option<CameraLifetimeStatusFn>,
pub(crate) hw_context_reset_cb: Option<HwContextResetFn>,
// same signature as above, libretro-sys deduplicated the type...
pub(crate) hw_context_destroy_cb: Option<HwContextResetFn>,
pub(crate) get_proc_address_cb: Option<GetProcAddressFn>,
}
impl From<LibretroApi> for LibretroWrapper {
fn from(api: LibretroApi) -> Self {
LibretroWrapper {
api,
keyboard_event_cb: None,
frame_time_cb: None,
audio_ready_cb: None,
audio_set_state_cb: None,
disk_set_eject_state_cb: None,
disk_get_eject_state_cb: None,
disk_get_image_index_cb: None,
disk_set_image_index_cb: None,
disk_get_num_images_cb: None,
disk_replace_image_index_cb: None,
disk_add_image_index_cb: None,
camera_frame_raw_framebuffer_cb: None,
camera_frame_opengl_texture_cb: None,
camera_lifetime_initialized_cb: None,
camera_lifetime_deinitialized_cb: None,
hw_context_reset_cb: None,
hw_context_destroy_cb: None,
get_proc_address_cb: None,
}
}
}
impl LibretroWrapper {
// TODO: enum for the RETROK_* constants instead of c_uint for keycode...
pub fn keyboard_event(
&self,
down: bool,
keycode: c_uint,
character: u32,
key_modifiers: u16,
) -> Option<()> {
self.keyboard_event_cb
.map(|f| unsafe { f(down, keycode, character, key_modifiers) })
}
pub fn frame_time(&self, time: Duration) -> Option<()> {
self.frame_time_cb
.map(|f| unsafe { f(time.as_micros() as Usec) })
}
pub fn audio_ready(&self) -> Option<()> {
self.audio_ready_cb.map(|f| unsafe { f() })
}
pub fn audio_set_state(&self, enabled: bool) -> Option<()> {
self.audio_set_state_cb.map(|f| unsafe { f(enabled) })
}
pub fn disk_get_eject_state(&self) -> Option<bool> {
self.disk_get_eject_state_cb.map(|f| unsafe { f() })
}
pub fn disk_set_eject_state(&self, ejected: bool) -> Option<bool> {
self.disk_set_eject_state_cb.map(|f| unsafe { f(ejected) })
}
pub fn disk_get_image_index(&self) -> Option<c_uint> {
self.disk_get_image_index_cb.map(|f| unsafe { f() })
}
pub fn disk_set_image_index(&self, index: c_uint) -> Option<bool> {
self.disk_set_image_index_cb.map(|f| unsafe { f(index) })
}
pub fn disk_get_num_images(&self) -> Option<c_uint> {
self.disk_get_num_images_cb.map(|f| unsafe { f() })
}
pub fn disk_replace_image_index(&self, index: c_uint, info: Option<GameInfo>) -> Option<bool> {
self.disk_replace_image_index_cb.map(|f| unsafe {
let info_ptr = match info {
None => ::core::ptr::null(),
Some(x) => &x,
};
f(index, info_ptr)
})
}
pub fn disk_add_image_index(&self) -> Option<bool> {
self.disk_add_image_index_cb.map(|f| unsafe { f() })
}
pub fn camera_frame_raw_framebuffer(&self, buffer: *const u32, width: c_uint, height: c_uint, pitch: usize) -> Option<()> {
self.camera_frame_raw_framebuffer_cb.map(|f| unsafe { f(buffer, width, height, pitch) })
}
pub fn camera_frame_opengl_texture(&self, texture_id: c_uint, texture_target: c_uint, affine: *const f32) -> Option<()> {
self.camera_frame_opengl_texture_cb.map(|f| unsafe { f(texture_id, texture_target, affine) })
}
pub fn camera_lifetime_initialized(&self) -> Option<()> {
self.camera_lifetime_initialized_cb.map(|f| unsafe { f() })
}
pub fn camera_lifetime_deinitialized(&self) -> Option<()> {
self.camera_lifetime_deinitialized_cb.map(|f| unsafe { f() })
}
pub fn hw_context_reset(&self) -> Option<()> {
self.hw_context_reset_cb.map(|f| unsafe { f() })
}
pub fn hw_context_destroy(&self) -> Option<()> {
self.hw_context_destroy_cb.map(|f| unsafe { f() })
}
pub fn get_proc_address(&self, sym: &str) -> Option<ProcAddressFn> {
self.get_proc_address_cb.and_then(|f| unsafe {
let csym = CString::new(sym).ok()?;
Some(f(csym.as_ptr()))
})
}
}
impl Deref for LibretroWrapper {
type Target = LibretroApi;
fn deref(&self) -> &LibretroApi {
&self.api
}
}
impl DerefMut for LibretroWrapper {
fn deref_mut(&mut self) -> &mut LibretroApi {
&mut self.api
}
}