156 lines
5.8 KiB
Rust
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
|
|
}
|
|
}
|