The rest of the functions - but not a good answer for callbacks yet

This commit is contained in:
lif 2019-11-07 17:09:47 -08:00
parent 6448c0a040
commit e34b9daa38
1 changed files with 170 additions and 27 deletions

View File

@ -1,35 +1,60 @@
use std::os::raw::{c_char, c_uint, c_void};
use std::path::Path;
use failure::Fallible;
use libloading;
use crate::libretro_types::*;
use libloading;
use std::ffi::OsStr;
pub struct LibretroApi<'a> {
pub retro_set_environment: libloading::Symbol<'a, unsafe extern "C" fn(arg1: retro_environment_t)>,
pub retro_set_video_refresh: libloading::Symbol<'a, unsafe extern "C" fn(arg1: retro_video_refresh_t)>,
pub retro_set_audio_sample: libloading::Symbol<'a, unsafe extern "C" fn(arg1: retro_audio_sample_t)>,
pub retro_set_audio_sample_batch: libloading::Symbol<'a, unsafe extern "C" fn(arg1: retro_audio_sample_batch_t)>,
pub retro_set_input_poll: libloading::Symbol<'a, unsafe extern "C" fn(arg1: retro_input_poll_t)>,
pub retro_set_input_state: libloading::Symbol<'a, unsafe extern "C" fn(arg1: retro_input_state_t)>,
pub retro_set_environment:
libloading::Symbol<'a, unsafe extern "C" fn(arg1: retro_environment_t)>,
pub retro_set_video_refresh:
libloading::Symbol<'a, unsafe extern "C" fn(arg1: retro_video_refresh_t)>,
pub retro_set_audio_sample:
libloading::Symbol<'a, unsafe extern "C" fn(arg1: retro_audio_sample_t)>,
pub retro_set_audio_sample_batch:
libloading::Symbol<'a, unsafe extern "C" fn(arg1: retro_audio_sample_batch_t)>,
pub retro_set_input_poll:
libloading::Symbol<'a, unsafe extern "C" fn(arg1: retro_input_poll_t)>,
pub retro_set_input_state:
libloading::Symbol<'a, unsafe extern "C" fn(arg1: retro_input_state_t)>,
pub retro_init: libloading::Symbol<'a, unsafe extern "C" fn()>,
pub retro_deinit: libloading::Symbol<'a, unsafe extern "C" fn()>,
pub retro_api_version: libloading::Symbol<'a, unsafe extern "C" fn() -> c_uint>,
pub retro_get_system_info: libloading::Symbol<'a, unsafe extern "C" fn(info: *mut retro_system_info)>,
pub retro_get_system_av_info: libloading::Symbol<'a, unsafe extern "C" fn(info: *mut retro_system_av_info)>,
pub retro_set_controller_port_device: libloading::Symbol<'a, unsafe extern "C" fn(port: c_uint, device: c_uint)>,
pub retro_get_system_info:
libloading::Symbol<'a, unsafe extern "C" fn(info: *mut retro_system_info)>,
pub retro_get_system_av_info:
libloading::Symbol<'a, unsafe extern "C" fn(info: *mut retro_system_av_info)>,
pub retro_set_controller_port_device:
libloading::Symbol<'a, unsafe extern "C" fn(port: c_uint, device: c_uint)>,
pub retro_reset: libloading::Symbol<'a, unsafe extern "C" fn()>,
pub retro_run: libloading::Symbol<'a, unsafe extern "C" fn()>,
pub retro_serialize_size: libloading::Symbol<'a, unsafe extern "C" fn() -> usize>,
pub retro_serialize: libloading::Symbol<'a, unsafe extern "C" fn(data: *mut c_void, size: usize) -> bool>,
pub retro_unserialize: libloading::Symbol<'a, unsafe extern "C" fn(data: *const c_void, size: usize) -> bool>,
pub retro_serialize:
libloading::Symbol<'a, unsafe extern "C" fn(data: *mut c_void, size: usize) -> bool>,
pub retro_unserialize:
libloading::Symbol<'a, unsafe extern "C" fn(data: *const c_void, size: usize) -> bool>,
pub retro_cheat_reset: libloading::Symbol<'a, unsafe extern "C" fn()>,
pub retro_cheat_set: libloading::Symbol<'a, unsafe extern "C" fn(index: c_uint, enabled: bool, code: *const c_char)>,
pub retro_load_game: libloading::Symbol<'a, unsafe extern "C" fn(game: *const retro_game_info) -> bool>,
pub retro_load_game_special: libloading::Symbol<'a, unsafe extern "C" fn(game_type: c_uint, info: *const retro_game_info, num_info: usize) -> bool>,
pub retro_cheat_set: libloading::Symbol<
'a,
unsafe extern "C" fn(index: c_uint, enabled: bool, code: *const c_char),
>,
pub retro_load_game:
libloading::Symbol<'a, unsafe extern "C" fn(game: *const retro_game_info) -> bool>,
pub retro_load_game_special: libloading::Symbol<
'a,
unsafe extern "C" fn(
game_type: c_uint,
info: *const retro_game_info,
num_info: usize,
) -> bool,
>,
pub retro_unload_game: libloading::Symbol<'a, unsafe extern "C" fn()>,
pub retro_get_region: libloading::Symbol<'a, unsafe extern "C" fn() -> c_uint>,
pub retro_get_memory_data: libloading::Symbol<'a, unsafe extern "C" fn(id: c_uint) -> *mut c_void>,
pub retro_get_memory_data:
libloading::Symbol<'a, unsafe extern "C" fn(id: c_uint) -> *mut c_void>,
pub retro_get_memory_size: libloading::Symbol<'a, unsafe extern "C" fn(id: c_uint) -> usize>,
}
@ -66,20 +91,37 @@ impl<'a> LibretroApi<'a> {
}
}
/// retro_set_environment() must be called before retro_init().
pub fn init(&self) {
unsafe {
// TODO assert!(called retro_set_environment);
(&self.retro_init)();
}
pub fn set_environment(&self, cb: retro_environment_t) {
unsafe { (&self.retro_set_environment)(cb) }
}
pub fn set_video_refresh(&self, cb: retro_video_refresh_t) {
unsafe { (&self.retro_set_video_refresh)(env) }
}
pub fn set_audio_sample(&self, cb: retro_audio_sample_t) {
unsafe { (&self.retro_set_audio_sample)(env) }
}
pub fn set_audio_sample_batch(&self, cb: retro_audio_sample_batch_t) {
unsafe { (&self.retro_set_audio_sample_batch)(env) }
}
pub fn set_input_poll(&self, cb: retro_input_poll_t) {
unsafe { (&self.retro_set_input_poll)(env) }
}
pub fn set_input_state(&self, cb: retro_input_state_t) {
unsafe { (&self.retro_set_input_state)(env) }
}
/// retro_set_environment() must be called before retro_init().
pub fn retro_set_environment(&self, env: retro_environment_t) {
unsafe {
(&self.retro_set_environment)(env);
}
pub fn init(&self) {
// TODO assert!(called retro_set_environment);
unsafe { (&self.retro_init)() }
}
/** Gets statically known system info.
* Can be called at any time, even before retro_init(). */
pub fn deinit(&self) {
unsafe { (&self.retro_deinit)() }
}
/// Must return RETRO_API_VERSION. Used to validate ABI compatibility when the API is revised.
pub fn api_version(&self) -> u32 {
unsafe { (&self.retro_api_version)() as u32 }
}
/// Gets statically known system info. Can be called at any time, even before retro_init().
pub fn get_system_info(&self) -> retro_system_info {
unsafe {
let mut info = ::std::mem::zeroed::<retro_system_info>();
@ -100,4 +142,105 @@ impl<'a> LibretroApi<'a> {
av_info
}
}
/** Sets device to be used for player 'port'.
* By default, RETRO_DEVICE_JOYPAD is assumed to be plugged into all
* available ports.
* Setting a particular device type is not a guarantee that libretro cores
* will only poll input based on that particular device type. It is only a
* hint to the libretro core when a core cannot automatically detect the
* appropriate input device type on its own. It is also relevant when a
* core can change its behavior depending on device type.
*
* As part of the core's implementation of retro_set_controller_port_device,
* the core should call RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS to notify the
* frontend if the descriptions for any controls have changed as a
* result of changing the device type.
*/
pub fn set_controller_port_device(&self, port: u32, device: u32) {
unsafe { (&self.retro_set_controller_port_device)(port, device) }
}
/// Resets the current game.
pub fn reset(&self) {
unsafe { (&self.retro_reset)() }
}
/** Runs the game for one video frame.
* During retro_run(), input_poll callback must be called at least once.
*
* If a frame is not rendered for reasons where a game "dropped" a frame,
* this still counts as a frame, and retro_run() should explicitly dupe
* a frame if GET_CAN_DUPE returns true.
* In this case, the video callback can take a NULL argument for data.
*/
pub fn run(&self) {
unsafe { (&self.retro_run)() }
}
/// Serializes internal state.
pub fn serialize(&self) -> Fallible<Vec<u8>> {
let size = unsafe { (&self.retro_serialize_size)() };
let mut vec = Vec::with_capacity(size);
vec.resize(size, 0);
if unsafe { (&self.retro_serialize)(vec.as_mut_ptr() as *mut c_void, size) } {
Ok(vec)
} else {
Err(failure::err_msg("Serialize failed"))
}
}
pub fn unserialize(&self, data: &[u8]) -> Fallible<()> {
if unsafe { (&self.retro_unserialize)(data.as_ptr() as *const c_void, data.len()) } {
Ok(())
} else {
Err(failure::err_msg("Unserialize failed"))
}
}
pub fn cheat_reset(&self) {
unsafe { (&self.retro_cheat_reset)() }
}
pub fn cheat_set(&self, index: u32, enabled: bool, code: &str) {
unsafe { (&self.retro_cheat_set)(index, enabled, code.as_bytes().as_ptr() as *const c_char) }
}
/// Loads a game.
pub fn load_game(
&self,
path: Option<&Path>,
data: Option<&[u8]>,
meta: Option<&str>,
) -> Fallible<()> {
let mut game = retro_game_info {
path: std::ptr::null(),
data: std::ptr::null(),
size: 0,
meta: std::ptr::null(),
};
if let Some(p) = path.and_then(Path::to_str) {
game.path = p.as_bytes().as_ptr() as *const c_char;
}
if let Some(d) = data {
game.data = d.as_ptr() as *const c_void;
game.size = d.len();
}
if let Some(m) = meta {
game.meta = m.as_bytes().as_ptr() as *const c_char;
}
if unsafe { (&self.retro_load_game)(&game) } {
Ok(())
} else {
Err(failure::err_msg("Failed to load game"))
}
}
/// Unloads the currently loaded game. Called before deinit().
pub fn unload_game(&self) {
unsafe { (&self.retro_unload_game)() }
}
pub fn get_region(&self) -> u32 {
unsafe { (&self.retro_get_region)() as u32 }
}
/// Gets region of memory
pub fn get_memory(&self, id: u32) -> &mut [u8] {
unsafe {
let data = (&self.retro_get_memory_data)(id);
let size = (&self.retro_get_memory_size)(id);
std::slice::from_raw_parts_mut(data as *mut u8, size)
}
}
}