Start making nicer types for interop with Rust
This commit is contained in:
parent
e34b9daa38
commit
0d0dda356c
|
@ -7,6 +7,7 @@ edition = "2018"
|
|||
[dependencies]
|
||||
failure = "^0.1"
|
||||
libloading = "^0.5"
|
||||
num_enum = "^0.4"
|
||||
|
||||
[build-dependencies]
|
||||
bindgen = "^0.51" # keep an eye on https://github.com/rust-lang/rust-bindgen/issues/1541
|
||||
|
|
|
@ -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::path::Path;
|
||||
|
||||
use failure::Fallible;
|
||||
use libloading;
|
||||
|
||||
use crate::libretro_types::*;
|
||||
use libloading;
|
||||
use std::ffi::OsStr;
|
||||
use crate::libretro_convert::*;
|
||||
|
||||
struct StaticCallbacks {
|
||||
|
||||
}
|
||||
impl StaticCallbacks {
|
||||
|
||||
}
|
||||
|
||||
pub struct LibretroApi<'a> {
|
||||
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) {
|
||||
unsafe { (&self.retro_set_environment)(cb) }
|
||||
}
|
||||
/// video_refresh() must be called before run().
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
// TODO assert!(called retro_set_environment);
|
||||
unsafe { (&self.retro_init)() }
|
||||
|
@ -130,9 +139,8 @@ impl<'a> LibretroApi<'a> {
|
|||
}
|
||||
}
|
||||
/** Gets information about system audio/video timings and geometry.
|
||||
* Can be called only after retro_load_game() has successfully completed.
|
||||
* NOTE: The implementation of this function might not initialize every
|
||||
* variable if needed.
|
||||
* Can be called only after load_game() has successfully completed.
|
||||
* NOTE: The implementation of this function might not initialize every variable if needed.
|
||||
* E.g. geom.aspect_ratio might not be initialized if core doesn't
|
||||
* desire a particular aspect ratio. */
|
||||
pub fn get_system_av_info(&self) -> retro_system_av_info {
|
||||
|
@ -232,10 +240,10 @@ impl<'a> LibretroApi<'a> {
|
|||
pub fn unload_game(&self) {
|
||||
unsafe { (&self.retro_unload_game)() }
|
||||
}
|
||||
pub fn get_region(&self) -> u32 {
|
||||
unsafe { (&self.retro_get_region)() as u32 }
|
||||
pub fn get_region(&self) -> Region {
|
||||
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] {
|
||||
unsafe {
|
||||
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)]
|
||||
mod libretro_types;
|
||||
mod libretro_loading;
|
||||
mod libretro_convert;
|
||||
|
||||
fn main() -> failure::Fallible<()> {
|
||||
let lib = libloading::Library::new("/home/lifning/.config/retroarch/cores/gambatte_libretro.so")?;
|
||||
|
|
Loading…
Reference in New Issue