Start making nicer types for interop with Rust
This commit is contained in:
		
							parent
							
								
									e34b9daa38
								
							
						
					
					
						commit
						0d0dda356c
					
				
					 4 changed files with 163 additions and 15 deletions
				
			
		| 
						 | 
					@ -7,6 +7,7 @@ edition = "2018"
 | 
				
			||||||
[dependencies]
 | 
					[dependencies]
 | 
				
			||||||
failure = "^0.1"
 | 
					failure = "^0.1"
 | 
				
			||||||
libloading = "^0.5"
 | 
					libloading = "^0.5"
 | 
				
			||||||
 | 
					num_enum = "^0.4"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[build-dependencies]
 | 
					[build-dependencies]
 | 
				
			||||||
bindgen = "^0.51" # keep an eye on https://github.com/rust-lang/rust-bindgen/issues/1541
 | 
					bindgen = "^0.51" # keep an eye on https://github.com/rust-lang/rust-bindgen/issues/1541
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										138
									
								
								src/libretro_convert.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								src/libretro_convert.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,138 @@
 | 
				
			||||||
 | 
					use std::convert::TryFrom;
 | 
				
			||||||
 | 
					use std::os::raw::c_uint;
 | 
				
			||||||
 | 
					use num_enum::TryFromPrimitive;
 | 
				
			||||||
 | 
					use crate::libretro_types::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(TryFromPrimitive)]
 | 
				
			||||||
 | 
					#[repr(u32)]
 | 
				
			||||||
 | 
					pub enum Region {
 | 
				
			||||||
 | 
					    NTSC = RETRO_REGION_NTSC,
 | 
				
			||||||
 | 
					    PAL = RETRO_REGION_PAL,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(TryFromPrimitive)]
 | 
				
			||||||
 | 
					#[repr(u32)]
 | 
				
			||||||
 | 
					pub enum DeviceType {
 | 
				
			||||||
 | 
					    None = RETRO_DEVICE_NONE,
 | 
				
			||||||
 | 
					    Joypad = RETRO_DEVICE_JOYPAD,
 | 
				
			||||||
 | 
					    Mouse = RETRO_DEVICE_MOUSE,
 | 
				
			||||||
 | 
					    Keyboard = RETRO_DEVICE_KEYBOARD,
 | 
				
			||||||
 | 
					    LightGun = RETRO_DEVICE_LIGHTGUN,
 | 
				
			||||||
 | 
					    Analog = RETRO_DEVICE_ANALOG,
 | 
				
			||||||
 | 
					    Pointer = RETRO_DEVICE_POINTER,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(TryFromPrimitive)]
 | 
				
			||||||
 | 
					#[repr(u32)]
 | 
				
			||||||
 | 
					pub enum DeviceIndex {
 | 
				
			||||||
 | 
					    Left = RETRO_DEVICE_INDEX_ANALOG_LEFT,
 | 
				
			||||||
 | 
					    Right = RETRO_DEVICE_INDEX_ANALOG_RIGHT,
 | 
				
			||||||
 | 
					    Button = RETRO_DEVICE_INDEX_ANALOG_BUTTON,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(TryFromPrimitive)]
 | 
				
			||||||
 | 
					#[repr(u32)]
 | 
				
			||||||
 | 
					pub enum JoypadButton {
 | 
				
			||||||
 | 
					    B = RETRO_DEVICE_ID_JOYPAD_B,
 | 
				
			||||||
 | 
					    Y = RETRO_DEVICE_ID_JOYPAD_Y,
 | 
				
			||||||
 | 
					    Select = RETRO_DEVICE_ID_JOYPAD_SELECT,
 | 
				
			||||||
 | 
					    Start = RETRO_DEVICE_ID_JOYPAD_START,
 | 
				
			||||||
 | 
					    Up = RETRO_DEVICE_ID_JOYPAD_UP,
 | 
				
			||||||
 | 
					    Down = RETRO_DEVICE_ID_JOYPAD_DOWN,
 | 
				
			||||||
 | 
					    Left = RETRO_DEVICE_ID_JOYPAD_LEFT,
 | 
				
			||||||
 | 
					    Right = RETRO_DEVICE_ID_JOYPAD_RIGHT,
 | 
				
			||||||
 | 
					    A = RETRO_DEVICE_ID_JOYPAD_A,
 | 
				
			||||||
 | 
					    X = RETRO_DEVICE_ID_JOYPAD_X,
 | 
				
			||||||
 | 
					    L = RETRO_DEVICE_ID_JOYPAD_L,
 | 
				
			||||||
 | 
					    R = RETRO_DEVICE_ID_JOYPAD_R,
 | 
				
			||||||
 | 
					    L2 = RETRO_DEVICE_ID_JOYPAD_L2,
 | 
				
			||||||
 | 
					    R2 = RETRO_DEVICE_ID_JOYPAD_R2,
 | 
				
			||||||
 | 
					    L3 = RETRO_DEVICE_ID_JOYPAD_L3,
 | 
				
			||||||
 | 
					    R3 = RETRO_DEVICE_ID_JOYPAD_R3,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(TryFromPrimitive)]
 | 
				
			||||||
 | 
					#[repr(u32)]
 | 
				
			||||||
 | 
					pub enum AnalogAxis {
 | 
				
			||||||
 | 
					    X = RETRO_DEVICE_ID_ANALOG_X,
 | 
				
			||||||
 | 
					    Y = RETRO_DEVICE_ID_ANALOG_Y,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(TryFromPrimitive)]
 | 
				
			||||||
 | 
					#[repr(u32)]
 | 
				
			||||||
 | 
					pub enum MouseButton {
 | 
				
			||||||
 | 
					    X = RETRO_DEVICE_ID_MOUSE_X,
 | 
				
			||||||
 | 
					    Y = RETRO_DEVICE_ID_MOUSE_Y,
 | 
				
			||||||
 | 
					    Left = RETRO_DEVICE_ID_MOUSE_LEFT,
 | 
				
			||||||
 | 
					    Right = RETRO_DEVICE_ID_MOUSE_RIGHT,
 | 
				
			||||||
 | 
					    WheelUp = RETRO_DEVICE_ID_MOUSE_WHEELUP,
 | 
				
			||||||
 | 
					    WheelDown = RETRO_DEVICE_ID_MOUSE_WHEELDOWN,
 | 
				
			||||||
 | 
					    Middle = RETRO_DEVICE_ID_MOUSE_MIDDLE,
 | 
				
			||||||
 | 
					    HorizWheelUp = RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP,
 | 
				
			||||||
 | 
					    HorizWheelDown = RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN,
 | 
				
			||||||
 | 
					    Button4 = RETRO_DEVICE_ID_MOUSE_BUTTON_4,
 | 
				
			||||||
 | 
					    Button5 = RETRO_DEVICE_ID_MOUSE_BUTTON_5,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(TryFromPrimitive)]
 | 
				
			||||||
 | 
					#[repr(u32)]
 | 
				
			||||||
 | 
					pub enum LightGunButton {
 | 
				
			||||||
 | 
					    ScreenX = RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X,
 | 
				
			||||||
 | 
					    ScreenY = RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y,
 | 
				
			||||||
 | 
					    IsOffscreen = RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN,
 | 
				
			||||||
 | 
					    Trigger = RETRO_DEVICE_ID_LIGHTGUN_TRIGGER,
 | 
				
			||||||
 | 
					    Reload = RETRO_DEVICE_ID_LIGHTGUN_RELOAD,
 | 
				
			||||||
 | 
					    Start = RETRO_DEVICE_ID_LIGHTGUN_START,
 | 
				
			||||||
 | 
					    Select = RETRO_DEVICE_ID_LIGHTGUN_SELECT,
 | 
				
			||||||
 | 
					    AuxC = RETRO_DEVICE_ID_LIGHTGUN_AUX_C,
 | 
				
			||||||
 | 
					    DpadUp = RETRO_DEVICE_ID_LIGHTGUN_DPAD_UP,
 | 
				
			||||||
 | 
					    DpadDown = RETRO_DEVICE_ID_LIGHTGUN_DPAD_DOWN,
 | 
				
			||||||
 | 
					    DpadLeft = RETRO_DEVICE_ID_LIGHTGUN_DPAD_LEFT,
 | 
				
			||||||
 | 
					    DpadRight = RETRO_DEVICE_ID_LIGHTGUN_DPAD_RIGHT,
 | 
				
			||||||
 | 
					    X = RETRO_DEVICE_ID_LIGHTGUN_X,
 | 
				
			||||||
 | 
					    Y = RETRO_DEVICE_ID_LIGHTGUN_Y,
 | 
				
			||||||
 | 
					    Cursor = RETRO_DEVICE_ID_LIGHTGUN_CURSOR,
 | 
				
			||||||
 | 
					    Turbo = RETRO_DEVICE_ID_LIGHTGUN_TURBO,
 | 
				
			||||||
 | 
					    Pause = RETRO_DEVICE_ID_LIGHTGUN_PAUSE,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(TryFromPrimitive)]
 | 
				
			||||||
 | 
					#[repr(u32)]
 | 
				
			||||||
 | 
					pub enum PointerStat {
 | 
				
			||||||
 | 
					    X = RETRO_DEVICE_ID_POINTER_X,
 | 
				
			||||||
 | 
					    Y = RETRO_DEVICE_ID_POINTER_Y,
 | 
				
			||||||
 | 
					    Pressed = RETRO_DEVICE_ID_POINTER_PRESSED,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub enum Input {
 | 
				
			||||||
 | 
					    None(c_uint),
 | 
				
			||||||
 | 
					    Joypad(JoypadButton),
 | 
				
			||||||
 | 
					    Mouse(MouseButton),
 | 
				
			||||||
 | 
					    Keyboard(c_uint),
 | 
				
			||||||
 | 
					    LightGun(LightGunButton),
 | 
				
			||||||
 | 
					    Analog(AnalogAxis),
 | 
				
			||||||
 | 
					    Pointer(PointerStat),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<D> From<(D, c_uint)> for Input
 | 
				
			||||||
 | 
					    where D: Into<DeviceType>,
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    fn from(pair: (D, c_uint)) -> Self {
 | 
				
			||||||
 | 
					        let (device, id) = pair;
 | 
				
			||||||
 | 
					        match device.into() {
 | 
				
			||||||
 | 
					            DeviceType::None => Input::None(id),
 | 
				
			||||||
 | 
					            DeviceType::Joypad => Input::Joypad(JoypadButton::try_from(id).expect("Invalid joypad button ID")),
 | 
				
			||||||
 | 
					            DeviceType::Mouse => Input::Mouse(MouseButton::try_from(id).expect("Invalid mouse button ID")),
 | 
				
			||||||
 | 
					            DeviceType::Keyboard => Input::Keyboard(id),
 | 
				
			||||||
 | 
					            DeviceType::LightGun => Input::LightGun(LightGunButton::try_from(id).expect("Invalid lightgun button ID")),
 | 
				
			||||||
 | 
					            DeviceType::Analog => Input::Analog(AnalogAxis::try_from(id).expect("Invalid analog axis ID")),
 | 
				
			||||||
 | 
					            DeviceType::Pointer => Input::Pointer(PointerStat::try_from(id).expect("Invalid pointer stat ID")),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type VideoRefreshCb = dyn FnMut(&[u8], c_uint, c_uint, c_uint); // buffer, width, height, pitch
 | 
				
			||||||
 | 
					type AudioSampleCb = dyn FnMut(i16, i16); // left, right
 | 
				
			||||||
 | 
					type AudioSampleBatchCb = dyn FnMut(&[i16]) -> usize; // pcm16le stereo samples
 | 
				
			||||||
 | 
					type InputPollCb = dyn FnMut();
 | 
				
			||||||
 | 
					type InputStateCb = dyn FnMut(u32, Input, DeviceIndex) -> i16; // port, device, index
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,19 @@
 | 
				
			||||||
 | 
					use std::convert::TryInto;
 | 
				
			||||||
use std::os::raw::{c_char, c_uint, c_void};
 | 
					use std::os::raw::{c_char, c_uint, c_void};
 | 
				
			||||||
use std::path::Path;
 | 
					use std::path::Path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use failure::Fallible;
 | 
					use failure::Fallible;
 | 
				
			||||||
 | 
					use libloading;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::libretro_types::*;
 | 
					use crate::libretro_types::*;
 | 
				
			||||||
use libloading;
 | 
					use crate::libretro_convert::*;
 | 
				
			||||||
use std::ffi::OsStr;
 | 
					
 | 
				
			||||||
 | 
					struct StaticCallbacks {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					impl StaticCallbacks {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct LibretroApi<'a> {
 | 
					pub struct LibretroApi<'a> {
 | 
				
			||||||
    pub retro_set_environment:
 | 
					    pub retro_set_environment:
 | 
				
			||||||
| 
						 | 
					@ -90,26 +98,27 @@ impl<'a> LibretroApi<'a> {
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    /// retro_set_environment() must be called before retro_init().
 | 
					    /// set_environment() must be called before init().
 | 
				
			||||||
    pub fn set_environment(&self, cb: retro_environment_t) {
 | 
					    pub fn set_environment(&self, cb: retro_environment_t) {
 | 
				
			||||||
        unsafe { (&self.retro_set_environment)(cb) }
 | 
					        unsafe { (&self.retro_set_environment)(cb) }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    /// video_refresh() must be called before run().
 | 
				
			||||||
    pub fn set_video_refresh(&self, cb: retro_video_refresh_t) {
 | 
					    pub fn set_video_refresh(&self, cb: retro_video_refresh_t) {
 | 
				
			||||||
        unsafe { (&self.retro_set_video_refresh)(env) }
 | 
					        unsafe { (&self.retro_set_video_refresh)(cb) }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn set_audio_sample(&self, cb: retro_audio_sample_t) {
 | 
					    pub fn set_audio_sample(&self, cb: retro_audio_sample_t) {
 | 
				
			||||||
        unsafe { (&self.retro_set_audio_sample)(env) }
 | 
					        unsafe { (&self.retro_set_audio_sample)(cb) }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn set_audio_sample_batch(&self, cb: retro_audio_sample_batch_t) {
 | 
					    pub fn set_audio_sample_batch(&self, cb: retro_audio_sample_batch_t) {
 | 
				
			||||||
        unsafe { (&self.retro_set_audio_sample_batch)(env) }
 | 
					        unsafe { (&self.retro_set_audio_sample_batch)(cb) }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn set_input_poll(&self, cb: retro_input_poll_t) {
 | 
					    pub fn set_input_poll(&self, cb: retro_input_poll_t) {
 | 
				
			||||||
        unsafe { (&self.retro_set_input_poll)(env) }
 | 
					        unsafe { (&self.retro_set_input_poll)(cb) }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn set_input_state(&self, cb: retro_input_state_t) {
 | 
					    pub fn set_input_state(&self, cb: retro_input_state_t) {
 | 
				
			||||||
        unsafe { (&self.retro_set_input_state)(env) }
 | 
					        unsafe { (&self.retro_set_input_state)(cb) }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    /// retro_set_environment() must be called before retro_init().
 | 
					    /// set_environment() must be called before init().
 | 
				
			||||||
    pub fn init(&self) {
 | 
					    pub fn init(&self) {
 | 
				
			||||||
        // TODO assert!(called retro_set_environment);
 | 
					        // TODO assert!(called retro_set_environment);
 | 
				
			||||||
        unsafe { (&self.retro_init)() }
 | 
					        unsafe { (&self.retro_init)() }
 | 
				
			||||||
| 
						 | 
					@ -130,9 +139,8 @@ impl<'a> LibretroApi<'a> {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    /** Gets information about system audio/video timings and geometry.
 | 
					    /** Gets information about system audio/video timings and geometry.
 | 
				
			||||||
     * Can be called only after retro_load_game() has successfully completed.
 | 
					     * Can be called only after load_game() has successfully completed.
 | 
				
			||||||
     * NOTE: The implementation of this function might not initialize every
 | 
					     * NOTE: The implementation of this function might not initialize every variable if needed.
 | 
				
			||||||
     * variable if needed.
 | 
					 | 
				
			||||||
     * E.g. geom.aspect_ratio might not be initialized if core doesn't
 | 
					     * E.g. geom.aspect_ratio might not be initialized if core doesn't
 | 
				
			||||||
     * desire a particular aspect ratio. */
 | 
					     * desire a particular aspect ratio. */
 | 
				
			||||||
    pub fn get_system_av_info(&self) -> retro_system_av_info {
 | 
					    pub fn get_system_av_info(&self) -> retro_system_av_info {
 | 
				
			||||||
| 
						 | 
					@ -232,10 +240,10 @@ impl<'a> LibretroApi<'a> {
 | 
				
			||||||
    pub fn unload_game(&self) {
 | 
					    pub fn unload_game(&self) {
 | 
				
			||||||
        unsafe { (&self.retro_unload_game)() }
 | 
					        unsafe { (&self.retro_unload_game)() }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn get_region(&self) -> u32 {
 | 
					    pub fn get_region(&self) -> Region {
 | 
				
			||||||
        unsafe { (&self.retro_get_region)() as u32 }
 | 
					        unsafe { (&self.retro_get_region)().try_into().expect("Invalid region") }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    /// Gets region of memory
 | 
					    /// Gets (read/write access to) a region of memory
 | 
				
			||||||
    pub fn get_memory(&self, id: u32) -> &mut [u8] {
 | 
					    pub fn get_memory(&self, id: u32) -> &mut [u8] {
 | 
				
			||||||
        unsafe {
 | 
					        unsafe {
 | 
				
			||||||
            let data = (&self.retro_get_memory_data)(id);
 | 
					            let data = (&self.retro_get_memory_data)(id);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,7 @@ use std::ffi::CStr;
 | 
				
			||||||
#[allow(non_camel_case_types, non_upper_case_globals, non_snake_case, dead_code)]
 | 
					#[allow(non_camel_case_types, non_upper_case_globals, non_snake_case, dead_code)]
 | 
				
			||||||
mod libretro_types;
 | 
					mod libretro_types;
 | 
				
			||||||
mod libretro_loading;
 | 
					mod libretro_loading;
 | 
				
			||||||
 | 
					mod libretro_convert;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn main() -> failure::Fallible<()> {
 | 
					fn main() -> failure::Fallible<()> {
 | 
				
			||||||
    let lib = libloading::Library::new("/home/lifning/.config/retroarch/cores/gambatte_libretro.so")?;
 | 
					    let lib = libloading::Library::new("/home/lifning/.config/retroarch/cores/gambatte_libretro.so")?;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue