diff --git a/ferretro_base/src/dynamic_borrow.rs b/ferretro_base/src/dynamic_borrow.rs new file mode 100644 index 0000000..58cbe86 --- /dev/null +++ b/ferretro_base/src/dynamic_borrow.rs @@ -0,0 +1,112 @@ +use std::cell::RefCell; +use std::os::raw::c_uint; +use std::rc::Rc; +use std::path::PathBuf; + +use crate::prelude::*; +use crate::retro::ffi::*; + +impl RetroCallbacks for Rc> { + fn video_refresh(&mut self, data: &[u8], width: c_uint, height: c_uint, pitch: c_uint) { + RefCell::borrow_mut(self).video_refresh(data, width, height, pitch) + } + fn video_refresh_dupe(&mut self, width: c_uint, height: c_uint, pitch: c_uint) { + RefCell::borrow_mut(self).video_refresh_dupe(width, height, pitch) + } + fn video_refresh_hw(&mut self, width: c_uint, height: c_uint) { + RefCell::borrow_mut(self).video_refresh_hw(width, height) + } + fn audio_sample(&mut self, left: i16, right: i16) { + RefCell::borrow_mut(self).audio_sample(left, right) + } + fn audio_sample_batch(&mut self, stereo_pcm: &[i16]) -> usize { + RefCell::borrow_mut(self).audio_sample_batch(stereo_pcm) + } + fn input_poll(&mut self) { + RefCell::borrow_mut(self).input_poll() + } + fn input_state(&mut self, port: u32, device: InputDeviceId, index: InputIndex) -> i16 { + RefCell::borrow_mut(self).input_state(port, device, index) + } + fn set_rotation(&mut self, rotation: EnvRotation) -> Option { + RefCell::borrow_mut(self).set_rotation(rotation) + } + fn get_overscan(&mut self) -> Option { + RefCell::borrow_mut(self).get_overscan() + } + fn set_message(&mut self, message: &Message) -> Option { + RefCell::borrow_mut(self).set_message(message) + } + fn shutdown(&mut self) -> Option { + RefCell::borrow_mut(self).shutdown() + } + fn set_performance_level(&mut self, level: c_uint) -> Option { + RefCell::borrow_mut(self).set_performance_level(level) + } + fn get_system_directory(&mut self) -> Option { + RefCell::borrow_mut(self).get_system_directory() + } + fn set_pixel_format(&mut self, format: PixelFormat) -> Option { + RefCell::borrow_mut(self).set_pixel_format(format) + } + fn set_input_descriptors(&mut self, input_descriptors: &Vec) -> Option { + RefCell::borrow_mut(self).set_input_descriptors(input_descriptors) + } + fn set_hw_render(&mut self, hw_render_callback: &HwRenderCallback) -> Option { + RefCell::borrow_mut(self).set_hw_render(hw_render_callback) + } + fn get_variable(&mut self, key: &str) -> Option { + RefCell::borrow_mut(self).get_variable(key) + } + fn set_variables(&mut self, variables: &Vec) -> Option { + RefCell::borrow_mut(self).set_variables(variables) + } + fn get_variable_update(&mut self) -> Option { + RefCell::borrow_mut(self).get_variable_update() + } + fn set_support_no_game(&mut self, supports_no_game: bool) -> Option { + RefCell::borrow_mut(self).set_support_no_game(supports_no_game) + } + fn get_libretro_path(&mut self) -> Option { + RefCell::borrow_mut(self).get_libretro_path() + } + fn get_input_device_capabilities(&mut self) -> Option { + RefCell::borrow_mut(self).get_input_device_capabilities() + } + fn get_core_assets_directory(&mut self) -> Option { + RefCell::borrow_mut(self).get_core_assets_directory() + } + fn get_save_directory(&mut self) -> Option { + RefCell::borrow_mut(self).get_save_directory() + } + fn set_system_av_info(&mut self, system_av_info: &SystemAvInfo) -> Option { + RefCell::borrow_mut(self).set_system_av_info(system_av_info) + } + fn set_subsystem_info(&mut self, subsystem_info: &Vec) -> Option { + RefCell::borrow_mut(self).set_subsystem_info(subsystem_info) + } + fn set_controller_info(&mut self, controller_info: &Vec) -> Option { + RefCell::borrow_mut(self).set_controller_info(controller_info) + } + fn set_memory_maps(&mut self, memory_map: &MemoryMap) -> Option { + RefCell::borrow_mut(self).set_memory_maps(memory_map) + } + fn set_geometry(&mut self, game_geometry: &GameGeometry) -> Option { + RefCell::borrow_mut(self).set_geometry(game_geometry) + } + fn get_username(&mut self) -> Option { + RefCell::borrow_mut(self).get_username() + } + fn get_language(&mut self) -> Option { + RefCell::borrow_mut(self).get_language() + } + fn hw_get_current_framebuffer(&mut self) -> Option { + RefCell::borrow_mut(self).hw_get_current_framebuffer() + } + fn hw_get_proc_address(&mut self, sym: &str) -> Option<*const ()> { + RefCell::borrow_mut(self).hw_get_proc_address(sym) + } + // TODO: the rest, dynamically. + // can we proc macro it? + // 's~^\( *\)fn \(.*\)(&mut self\(, \)\?\([^)]*\))\(.*\){$~\1fn \2(\&mut self\3\4)\5{\n\1 RefCell::borrow_mut(self).\2(\4)~' +} diff --git a/ferretro_base/src/lib.rs b/ferretro_base/src/lib.rs index c280b88..1307a5e 100644 --- a/ferretro_base/src/lib.rs +++ b/ferretro_base/src/lib.rs @@ -8,3 +8,5 @@ pub mod prelude { pub use crate::retro::wrapper::{RetroCallbacks, LibretroWrapper, LibretroWrapperAccess}; pub use crate::retro::ffi::{PixelFormat, GameGeometry, HwContextResetFn, HwRenderCallback, SystemAvInfo, SystemInfo}; } + +mod dynamic_borrow; diff --git a/ferretro_components/src/dynamic_borrow.rs b/ferretro_components/src/dynamic_borrow.rs new file mode 100644 index 0000000..2b08967 --- /dev/null +++ b/ferretro_components/src/dynamic_borrow.rs @@ -0,0 +1,33 @@ +use std::cell::RefCell; +use std::rc::Rc; +use std::path::Path; + +use crate::base::ControlFlow; +use crate::base::RetroComponent; +use crate::base::Result; + +use ferretro_base::prelude::*; + +impl RetroComponent for Rc> where + T: RetroComponent, + Rc>: RetroCallbacks, +{ + fn pre_init(&mut self, retro: &mut LibretroWrapper) -> Result<()> { + RefCell::try_borrow_mut(self)?.pre_init(retro) + } + fn post_init(&mut self, retro: &mut LibretroWrapper) -> Result<()> { + RefCell::try_borrow_mut(self)?.post_init(retro) + } + fn pre_load_game(&mut self, retro: &mut LibretroWrapper, rom: &Path) -> Result<()> { + RefCell::try_borrow_mut(self)?.pre_load_game(retro, rom) + } + fn post_load_game(&mut self, retro: &mut LibretroWrapper, rom: &Path) -> Result<()> { + RefCell::try_borrow_mut(self)?.post_load_game(retro, rom) + } + fn pre_run(&mut self, retro: &mut LibretroWrapper) -> ControlFlow { + RefCell::borrow_mut(self).pre_run(retro) + } + fn post_run(&mut self, retro: &mut LibretroWrapper) -> ControlFlow { + RefCell::borrow_mut(self).post_run(retro) + } +} diff --git a/ferretro_components/src/lib.rs b/ferretro_components/src/lib.rs index 0fc18aa..87754d8 100644 --- a/ferretro_components/src/lib.rs +++ b/ferretro_components/src/lib.rs @@ -8,3 +8,5 @@ pub mod prelude { pub use ferretro_base::retro::wrapper::{RetroCallbacks, LibretroWrapper, LibretroWrapperAccess}; pub use ferretro_base::retro::ffi::{PixelFormat, GameGeometry, HwContextResetFn, HwRenderCallback, SystemAvInfo, SystemInfo, MemoryMap}; } + +mod dynamic_borrow; diff --git a/ferretro_components/src/provided/sdl2.rs b/ferretro_components/src/provided/sdl2/mod.rs similarity index 80% rename from ferretro_components/src/provided/sdl2.rs rename to ferretro_components/src/provided/sdl2/mod.rs index c5e1c04..62130be 100644 --- a/ferretro_components/src/provided/sdl2.rs +++ b/ferretro_components/src/provided/sdl2/mod.rs @@ -2,8 +2,10 @@ mod canvas; mod audio; mod gamepad; mod opengl; +mod surface; pub use canvas::SimpleSdl2CanvasComponent; pub use opengl::SimpleSdl2OpenglComponent; pub use audio::SimpleSdl2AudioComponent; pub use gamepad::SimpleSdl2GamepadComponent; +pub use surface::Sdl2SurfaceComponent; diff --git a/ferretro_components/src/provided/sdl2/surface.rs b/ferretro_components/src/provided/sdl2/surface.rs new file mode 100644 index 0000000..3deb9e2 --- /dev/null +++ b/ferretro_components/src/provided/sdl2/surface.rs @@ -0,0 +1,58 @@ +use crate::prelude::*; + +use sdl2::surface::Surface; + +pub struct Sdl2SurfaceComponent { + surface: Surface<'static>, + pixel_format: sdl2::pixels::PixelFormatEnum, +} + +impl Sdl2SurfaceComponent { + pub fn new(retro: &LibretroWrapper) -> Result> { + let geometry = retro.get_system_av_info().geometry; + let pixel_format = sdl2::pixels::PixelFormatEnum::ARGB1555; + + let surface = Surface::new( + geometry.base_width, + geometry.base_height, + pixel_format, + )?; + + Ok(Sdl2SurfaceComponent { + surface, + pixel_format, + }) + } + + pub fn surface(&self) -> &Surface { + &self.surface + } +} + +impl RetroComponent for Sdl2SurfaceComponent {} +impl RetroCallbacks for Sdl2SurfaceComponent { + fn video_refresh(&mut self, data: &[u8], width: u32, height: u32, pitch: u32) { + let data = unsafe { + core::slice::from_raw_parts_mut(data.as_ptr() as *mut u8, data.len()) + }; + if let Ok(surf) = Surface::from_data(data, width, height, pitch, self.pixel_format) { + self.surface = surf; + } + } + + fn set_pixel_format(&mut self, pix_fmt: PixelFormat) -> Option { + self.pixel_format = match pix_fmt { + PixelFormat::ARGB1555 => sdl2::pixels::PixelFormatEnum::RGB555, + PixelFormat::ARGB8888 => sdl2::pixels::PixelFormatEnum::ARGB8888, + PixelFormat::RGB565 => sdl2::pixels::PixelFormatEnum::RGB565, + }; + Some(true) + } + + fn get_variable(&mut self, key: &str) -> Option { + match key { + "parallel-n64-gfxplugin" => Some("angrylion".to_string()), + _ => None, + } + } +}