Wait to call retro_set_environment until we have the Handler registered
This commit is contained in:
parent
e1ab7d69aa
commit
0e3ba53eec
|
@ -5,6 +5,7 @@ extern crate sdl2;
|
|||
use rustro::retro;
|
||||
use rustro::retro::ffi::{GameGeometry, SystemInfo, SystemAvInfo};
|
||||
use rustro::retro::constants::{Input, DeviceIndex, JoypadButton, AnalogAxis, DeviceType};
|
||||
use rustro::retro::wrapper::LibretroWrapper;
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::io::Read;
|
||||
|
@ -199,6 +200,10 @@ impl Drop for MyEmulator {
|
|||
}
|
||||
|
||||
impl retro::wrapper::Handler for MyEmulator {
|
||||
fn libretro_core(&mut self) -> &mut LibretroWrapper {
|
||||
&mut self.retro
|
||||
}
|
||||
|
||||
fn video_refresh(&mut self, data: &[u8], width: u32, height: u32, pitch: u32) {
|
||||
let rect = Rect::new(0, 0, width, height);
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@ use num_enum::TryFromPrimitive;
|
|||
use super::constants::*;
|
||||
use super::ffi::*;
|
||||
use super::loading::*;
|
||||
use failure::_core::convert::Infallible;
|
||||
|
||||
static mut CB_SINGLETON: StaticCallbacks = StaticCallbacks {
|
||||
handler: None,
|
||||
|
@ -32,7 +31,8 @@ extern "C" {
|
|||
|
||||
#[allow(unused)]
|
||||
pub trait Handler: Unpin + 'static {
|
||||
fn _delegate_handler(&self) -> Option<&mut dyn Handler> { None }
|
||||
fn libretro_core(&mut self) -> &mut LibretroWrapper;
|
||||
fn delegate_handler(&self) -> Option<&mut dyn Handler> { None }
|
||||
|
||||
// -- main callbacks --
|
||||
fn video_refresh(&mut self, data: &[u8], width: c_uint, height: c_uint, pitch: c_uint) {}
|
||||
|
@ -139,8 +139,23 @@ impl StaticCallbacks {
|
|||
EnvCmd::GetSystemDirectory => Self::path_into_void(data, handler.get_system_directory()?)?,
|
||||
EnvCmd::SetPixelFormat => handler.set_pixel_format(PixelFormat::from_uint(*Self::from_void(data)?)?),
|
||||
// TODO EnvCmd::SetInputDescriptors => {},
|
||||
// TODO EnvCmd::SetKeyboardCallback => {},
|
||||
// TODO EnvCmd::SetDiskControlInterface => {},
|
||||
EnvCmd::SetKeyboardCallback => {
|
||||
let kc: &mut KeyboardCallback = Self::from_void(data)?;
|
||||
handler.libretro_core().keyboard_event_cb.replace(kc.callback);
|
||||
true
|
||||
},
|
||||
EnvCmd::SetDiskControlInterface => {
|
||||
let dcc: &mut DiskControlCallback = Self::from_void(data)?;
|
||||
let core = handler.libretro_core();
|
||||
core.disk_set_eject_state_cb.replace(dcc.set_eject_state);
|
||||
core.disk_get_eject_state_cb.replace(dcc.get_eject_state);
|
||||
core.disk_set_image_index_cb.replace(dcc.set_image_index);
|
||||
core.disk_get_image_index_cb.replace(dcc.get_image_index);
|
||||
core.disk_get_num_images_cb.replace(dcc.get_num_images);
|
||||
core.disk_replace_image_index_cb.replace(dcc.replace_image_index);
|
||||
core.disk_add_image_index_cb.replace(dcc.add_image_index);
|
||||
true
|
||||
},
|
||||
// TODO EnvCmd::SetHwRender => {},
|
||||
EnvCmd::GetVariable => {
|
||||
let mut var = Self::from_void::<Variable>(data)?;
|
||||
|
@ -158,8 +173,17 @@ impl StaticCallbacks {
|
|||
EnvCmd::GetVariableUpdate => Self::clone_into_void(data, &handler.get_variable_update()?)?,
|
||||
EnvCmd::SetSupportNoGame => handler.set_support_no_game(*Self::from_void(data)?),
|
||||
EnvCmd::GetLibretroPath => Self::path_into_void(data, handler.get_libretro_path()?)?,
|
||||
// TODO EnvCmd::SetFrameTimeCallback => {},
|
||||
// TODO EnvCmd::SetAudioCallback => {},
|
||||
EnvCmd::SetFrameTimeCallback => {
|
||||
let ftc: &mut FrameTimeCallback = Self::from_void(data)?;
|
||||
handler.libretro_core().frame_time_cb.replace(ftc.callback);
|
||||
true
|
||||
},
|
||||
EnvCmd::SetAudioCallback => {
|
||||
let ac: &mut AudioCallback = Self::from_void(data)?;
|
||||
handler.libretro_core().audio_ready_cb.replace(ac.callback);
|
||||
handler.libretro_core().audio_set_state_cb.replace(ac.set_state);
|
||||
true
|
||||
},
|
||||
EnvCmd::GetRumbleInterface => {
|
||||
let ri = RumbleInterface { set_rumble_state: StaticCallbacks::set_rumble_state_cb };
|
||||
Self::clone_into_void(data, &ri)?
|
||||
|
@ -183,7 +207,7 @@ impl StaticCallbacks {
|
|||
for t in types {
|
||||
let orig_name = match DeviceType::try_from(t.id) {
|
||||
Ok(x) => format!("{:?}", x),
|
||||
Err(_) => format!("Device ID {}", t.id),
|
||||
Err(_) => format!("[Device ID 0x{:x?}]", t.id),
|
||||
};
|
||||
let new_name = unsafe { CStr::from_ptr(t.desc) }.to_string_lossy();
|
||||
eprintln!("SetControllerInfo: {} is {}", orig_name, new_name);
|
||||
|
@ -275,41 +299,74 @@ pub struct LibretroWrapper {
|
|||
frame_time_cb: Option<FrameTimeCallbackFn>,
|
||||
audio_ready_cb: Option<AudioCallbackFn>,
|
||||
audio_set_state_cb: Option<AudioSetStateCallbackFn>,
|
||||
disk_get_eject_state_cb: Option<GetEjectStateFn>,
|
||||
disk_set_eject_state_cb: Option<SetEjectStateFn>,
|
||||
disk_get_image_index_cb: Option<GetImageIndexFn>,
|
||||
disk_set_image_index_cb: Option<SetImageIndexFn>,
|
||||
disk_get_num_images_cb: Option<GetNumImagesFn>,
|
||||
disk_replace_image_index_cb: Option<ReplaceImageIndexFn>,
|
||||
disk_add_image_index_cb: Option<AddImageIndexFn>,
|
||||
}
|
||||
|
||||
impl From<LibretroApi> for LibretroWrapper {
|
||||
fn from(api: LibretroApi) -> Self {
|
||||
// TODO: figure out a way to register these *after* we set CB_SINGLETON?
|
||||
api.set_environment(StaticCallbacks::environment_cb);
|
||||
api.set_video_refresh(StaticCallbacks::video_refresh_cb);
|
||||
api.set_audio_sample(StaticCallbacks::audio_sample_cb);
|
||||
api.set_audio_sample_batch(StaticCallbacks::audio_sample_batch_cb);
|
||||
api.set_input_poll(StaticCallbacks::input_poll_cb);
|
||||
api.set_input_state(StaticCallbacks::input_state_cb);
|
||||
unsafe { c_ext_set_log_print_cb(StaticCallbacks::log_print_cb); }
|
||||
LibretroWrapper {
|
||||
api,
|
||||
keyboard_event_cb: None,
|
||||
frame_time_cb: None,
|
||||
audio_ready_cb: None,
|
||||
audio_set_state_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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
self.keyboard_event_cb.map(|f| unsafe { f(down, keycode, character, key_modifiers) });
|
||||
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) {
|
||||
self.frame_time_cb.map(|f| unsafe { f(time.as_micros() as Usec) });
|
||||
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) {
|
||||
self.audio_ready_cb.map(|f| unsafe { f() });
|
||||
pub fn audio_ready(&self) -> Option<()> {
|
||||
self.audio_ready_cb.map(|f| unsafe { f() })
|
||||
}
|
||||
pub fn audio_set_state(&self, enabled: bool) {
|
||||
self.audio_set_state_cb.map(|f| unsafe { f(enabled) });
|
||||
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) -> 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() })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -326,7 +383,18 @@ pub fn set_handler(handler: Pin<&'_ mut (dyn Handler + '_)>) {
|
|||
unsafe {
|
||||
let ptr = handler.get_unchecked_mut() as *mut dyn Handler;
|
||||
CB_SINGLETON.handler.replace(Pin::new_unchecked(ptr.as_mut().unwrap()));
|
||||
|
||||
c_ext_set_log_print_cb(StaticCallbacks::log_print_cb);
|
||||
}
|
||||
// some cores start calling the environment cb as soon as we call retro_set_environment,
|
||||
// not waiting for a call to retro_init - so we'd better have CB_SINGLETON set first
|
||||
let api = unsafe { CB_SINGLETON.handler.as_mut() }.unwrap().libretro_core();
|
||||
api.set_environment(StaticCallbacks::environment_cb);
|
||||
api.set_video_refresh(StaticCallbacks::video_refresh_cb);
|
||||
api.set_audio_sample(StaticCallbacks::audio_sample_cb);
|
||||
api.set_audio_sample_batch(StaticCallbacks::audio_sample_batch_cb);
|
||||
api.set_input_poll(StaticCallbacks::input_poll_cb);
|
||||
api.set_input_state(StaticCallbacks::input_state_cb);
|
||||
}
|
||||
|
||||
pub fn unset_handler() {
|
||||
|
|
Loading…
Reference in New Issue