diff --git a/ferretro_base/src/retro/wrapper.rs b/ferretro_base/src/retro/wrapper.rs index 02d3915..5844a7b 100644 --- a/ferretro_base/src/retro/wrapper.rs +++ b/ferretro_base/src/retro/wrapper.rs @@ -365,6 +365,11 @@ pub trait RetroCallbacks: Unpin + 'static { fn perf_stop(&mut self, counter: &mut PerfCounter) {} fn set_sensor_state(&mut self, port: c_uint, action: SensorAction, rate: c_uint) -> bool { false } fn get_sensor_input(&mut self, port: c_uint, id: c_uint) -> f32 { 0.0 } + fn get_camera_interface(&mut self, width: c_uint, height: c_uint, cap_raw_fb: bool, cap_gl_tex: bool) -> Option { None } + /// Starts the camera driver. Can only be called in retro_run(). + fn camera_start(&mut self) -> Option { None } + /// Stops the camera driver. Can only be called in retro_run(). + fn camera_stop(&mut self) -> Option<()> { None } /// Gets current framebuffer which is to be rendered to. /// Could change every frame potentially. fn hw_get_current_framebuffer(&mut self) -> Option { None } @@ -547,7 +552,27 @@ impl StaticCallbacks { }; Self::clone_into_void(data, &si)? } - // TODO (apathy) EnvCmd::GetCameraInterface => {}, + EnvCmd::GetCameraInterface => { + let cc: &mut CameraCallback = Self::from_void(data)?; + let gl_tex = (cc.caps & 1 << (CameraBuffer::OpenGLTexture as u64)) != 0; + let raw_fb = (cc.caps & 1 << (CameraBuffer::RawFramebuffer as u64)) != 0; + let wrapper = handler.libretro_core(); + if !(cc.frame_raw_framebuffer as *const ()).is_null() { + wrapper.camera_frame_raw_framebuffer_cb.replace(cc.frame_raw_framebuffer); + } + if !(cc.frame_opengl_texture as *const ()).is_null() { + wrapper.camera_frame_opengl_texture_cb.replace(cc.frame_opengl_texture); + } + if !(cc.initialized as *const ()).is_null() { + wrapper.camera_lifetime_initialized_cb.replace(cc.initialized); + } + if !(cc.deinitialized as *const ()).is_null() { + wrapper.camera_lifetime_deinitialized_cb.replace(cc.deinitialized); + } + cc.start = Self::camera_start; + cc.stop = Self::camera_stop; + handler.get_camera_interface(cc.width, cc.height, gl_tex, raw_fb)? + } EnvCmd::GetLogInterface => unsafe { c_ext_handle_get_log_interface(data as *mut LogCallback) } @@ -750,6 +775,17 @@ impl StaticCallbacks { }.unwrap_or_default() } + extern "C" fn camera_start() -> bool { + unsafe { + CB_SINGLETON.handler.as_mut().and_then(|cb| cb.camera_start()) + }.unwrap_or_default() + } + extern "C" fn camera_stop() -> () { + unsafe { + CB_SINGLETON.handler.as_mut().and_then(|cb| cb.camera_stop()) + }.unwrap_or_default() + } + extern "C" fn hw_get_proc_address_fn(sym: *const c_char) -> ProcAddressFn { unsafe { std::mem::transmute( @@ -781,6 +817,10 @@ pub struct LibretroWrapper { disk_get_num_images_cb: Option, disk_replace_image_index_cb: Option, disk_add_image_index_cb: Option, + camera_frame_raw_framebuffer_cb: Option, + camera_frame_opengl_texture_cb: Option, + camera_lifetime_initialized_cb: Option, + camera_lifetime_deinitialized_cb: Option, hw_context_reset_cb: Option, hw_context_destroy_cb: Option, // same signature, libretro-sys deduplicated... get_proc_address_cb: Option, @@ -801,6 +841,10 @@ impl From for LibretroWrapper { disk_get_num_images_cb: None, disk_replace_image_index_cb: None, disk_add_image_index_cb: None, + camera_frame_raw_framebuffer_cb: None, + camera_frame_opengl_texture_cb: None, + camera_lifetime_initialized_cb: None, + camera_lifetime_deinitialized_cb: None, hw_context_reset_cb: None, hw_context_destroy_cb: None, get_proc_address_cb: None, @@ -820,16 +864,19 @@ impl LibretroWrapper { self.keyboard_event_cb .map(|f| unsafe { f(down, keycode, character, key_modifiers) }) } + 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) -> Option<()> { self.audio_ready_cb.map(|f| unsafe { f() }) } 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 { self.disk_get_eject_state_cb.map(|f| unsafe { f() }) } @@ -857,6 +904,20 @@ impl LibretroWrapper { pub fn disk_add_image_index(&self) -> Option { self.disk_add_image_index_cb.map(|f| unsafe { f() }) } + + pub fn camera_frame_raw_framebuffer(&self, buffer: *const u32, width: c_uint, height: c_uint, pitch: usize) -> Option<()> { + self.camera_frame_raw_framebuffer_cb.map(|f| unsafe { f(buffer, width, height, pitch) }) + } + pub fn camera_frame_opengl_texture(&self, texture_id: c_uint, texture_target: c_uint, affine: *const f32) -> Option<()> { + self.camera_frame_opengl_texture_cb.map(|f| unsafe { f(texture_id, texture_target, affine) }) + } + pub fn camera_lifetime_initialized(&self) -> Option<()> { + self.camera_lifetime_initialized_cb.map(|f| unsafe { f() }) + } + pub fn camera_lifetime_deinitialized(&self) -> Option<()> { + self.camera_lifetime_deinitialized_cb.map(|f| unsafe { f() }) + } + pub fn hw_context_reset(&self) -> Option<()> { self.hw_context_reset_cb.map(|f| unsafe { f() }) } diff --git a/ferretro_components/examples/multifunction_emulator.rs b/ferretro_components/examples/multifunction_emulator.rs index 0114afd..49a3c70 100644 --- a/ferretro_components/examples/multifunction_emulator.rs +++ b/ferretro_components/examples/multifunction_emulator.rs @@ -14,6 +14,7 @@ use ferretro_components::provided::{ stdlib::{PathBufComponent, StderrLogComponent, SleepFramerateLimitComponent}, }; use ferretro_components::base::ControlFlow; +use ferretro_components::provided::stdlib::{StderrCallTraceComponent, StderrSysInfoLogComponent}; #[derive(StructOpt)] struct Opt { @@ -42,8 +43,10 @@ pub fn main() { let mut sdl_context = sdl2::init().unwrap(); emu.register_component(StderrLogComponent { prefix: "{log} ".to_string() }); + emu.register_component(StderrCallTraceComponent { prefix: "{trace} ".to_string() }); + emu.register_component(StderrSysInfoLogComponent { prefix: "{sysinfo} ".to_string() }); - let sdl2_ogl = SimpleSdl2OpenglComponent::new(&mut sdl_context, emu.libretro_core()).unwrap(); + let sdl2_ogl = SimpleSdl2CanvasComponent::new(&mut sdl_context, emu.libretro_core()).unwrap(); emu.register_component(sdl2_ogl); let sdl2_audio = SimpleSdl2AudioComponent::new(&mut sdl_context, emu.libretro_core()); diff --git a/ferretro_components/src/provided/sdl2/canvas.rs b/ferretro_components/src/provided/sdl2/canvas.rs index ac9e71a..d0bf059 100644 --- a/ferretro_components/src/provided/sdl2/canvas.rs +++ b/ferretro_components/src/provided/sdl2/canvas.rs @@ -63,8 +63,11 @@ impl RetroCallbacks for SimpleSdl2CanvasComponent { } fn get_variable(&mut self, key: &str) -> Option { + eprintln!("get_variable({})", key); match key { "parallel-n64-gfxplugin" => Some("angrylion".to_string()), + "mupen64plus-rdp-plugin" => Some("angrylion".to_string()), + "mupen64plus-rsp-plugin" => Some("cxd4".to_string()), _ => None, } } diff --git a/ferretro_components/src/provided/stdlib.rs b/ferretro_components/src/provided/stdlib.rs index 80920ac..3bad5db 100644 --- a/ferretro_components/src/provided/stdlib.rs +++ b/ferretro_components/src/provided/stdlib.rs @@ -4,7 +4,7 @@ use std::time::{Duration, Instant}; use crate::base::ControlFlow; use crate::prelude::*; -use ferretro_base::retro::ffi::{Message, Language}; +use ferretro_base::retro::ffi::{Message, Language, LogLevel, RumbleEffect, Time, PerfTick, PerfCounter, SensorAction}; #[derive(Default)] pub struct PathBufComponent { @@ -197,6 +197,18 @@ impl RetroCallbacks for StderrCallTraceComponent { eprintln!("{}get_language()", self.prefix); None } + fn get_camera_interface(&mut self, width: c_uint, height: c_uint, cap_raw_fb: bool, cap_gl_tex: bool) -> Option { + eprintln!("{}get_camera_interface(width={}, height={}, fb={}, gl={})", self.prefix, width, height, cap_raw_fb, cap_gl_tex); + None + } + fn camera_start(&mut self) -> Option { + eprintln!("{}camera_start()", self.prefix); + None + } + fn camera_stop(&mut self) -> Option<()> { + eprintln!("{}camera_stop()", self.prefix); + None + } fn hw_get_current_framebuffer(&mut self) -> Option { eprintln!("{}hw_get_current_framebuffer()", self.prefix); None