The rest of the functions - but not a good answer for callbacks yet
This commit is contained in:
		
							parent
							
								
									6448c0a040
								
							
						
					
					
						commit
						e34b9daa38
					
				
					 1 changed files with 170 additions and 27 deletions
				
			
		| 
						 | 
				
			
			@ -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)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue