283 lines
8.8 KiB
Rust
283 lines
8.8 KiB
Rust
use crate::prelude::*;
|
|
use crate::retro::ffi::*;
|
|
use std::os::raw::c_uint;
|
|
use std::path::PathBuf;
|
|
|
|
pub struct RetroComponentBase {
|
|
retro: LibretroWrapper,
|
|
pub components: Vec<Box<dyn RetroCallbacks>>,
|
|
}
|
|
|
|
impl LibretroWrapperAccess for RetroComponentBase {
|
|
fn libretro_core(&mut self) -> &mut LibretroWrapper {
|
|
&mut self.retro
|
|
}
|
|
}
|
|
|
|
impl RetroCallbacks for RetroComponentBase {
|
|
fn video_refresh(&mut self, data: &[u8], width: c_uint, height: c_uint, pitch: c_uint) {
|
|
for comp in &mut self.components {
|
|
comp.video_refresh(data, width, height, pitch);
|
|
}
|
|
}
|
|
|
|
fn video_refresh_dupe(&mut self, width: c_uint, height: c_uint, pitch: c_uint) {
|
|
for comp in &mut self.components {
|
|
comp.video_refresh_dupe(width, height, pitch);
|
|
}
|
|
}
|
|
|
|
fn audio_sample(&mut self, left: i16, right: i16) {
|
|
for comp in &mut self.components {
|
|
comp.audio_sample(left, right);
|
|
}
|
|
}
|
|
|
|
fn audio_sample_batch(&mut self, stereo_pcm: &[i16]) -> usize {
|
|
self.components.iter_mut()
|
|
.map(|comp| comp.audio_sample_batch(stereo_pcm))
|
|
.max()
|
|
.unwrap_or_default()
|
|
}
|
|
|
|
fn input_poll(&mut self) {
|
|
for comp in &mut self.components {
|
|
comp.input_poll();
|
|
}
|
|
}
|
|
|
|
fn input_state(&mut self, port: u32, device: InputDeviceId, index: InputIndex) -> i16 {
|
|
self.components.iter_mut()
|
|
.map(|comp| comp.input_state(port, device, index))
|
|
.filter(|x| *x != 0)
|
|
// TODO: is this really the semantic we want?
|
|
.last()
|
|
.unwrap_or_default()
|
|
}
|
|
|
|
fn set_rotation(&mut self, rotation: EnvRotation) -> bool {
|
|
self.components.iter_mut()
|
|
.map(|comp| comp.set_rotation(rotation))
|
|
.fold(false, |x, y| x || y) // not "any" because we don't short-circuit
|
|
}
|
|
|
|
fn get_overscan(&mut self) -> Option<bool> {
|
|
self.components.iter_mut()
|
|
.map(|comp| comp.get_overscan())
|
|
.fold(None, |x, y| match (x, y) {
|
|
(Some(a), Some(b)) => Some(a || b),
|
|
(Some(a), None) | (None, Some(a)) => Some(a),
|
|
(None, None) => None,
|
|
})
|
|
}
|
|
|
|
fn set_message(&mut self, message: &Message) -> bool {
|
|
self.components.iter_mut()
|
|
.map(|comp| comp.set_message(message))
|
|
.fold(false, |x, y| x || y) // not "any" because we don't short-circuit
|
|
}
|
|
|
|
fn shutdown(&mut self) -> bool {
|
|
self.components.iter_mut()
|
|
.map(|comp| comp.shutdown())
|
|
.all(|x| x)
|
|
}
|
|
|
|
fn set_performance_level(&mut self, level: c_uint) -> bool {
|
|
self.components.iter_mut()
|
|
.map(|comp| comp.set_performance_level(level))
|
|
.all(|x| x)
|
|
}
|
|
|
|
fn get_system_directory(&mut self) -> Option<PathBuf> {
|
|
self.components.iter_mut()
|
|
.map(|comp| comp.get_system_directory())
|
|
.flatten()
|
|
.next()
|
|
}
|
|
|
|
fn set_pixel_format(&mut self, format: PixelFormat) -> bool {
|
|
self.components.iter_mut()
|
|
.map(|comp| comp.set_pixel_format(format))
|
|
.all(|x| x)
|
|
}
|
|
|
|
fn set_input_descriptors(&mut self, input_descriptors: &Vec<InputDescriptor2>) -> bool {
|
|
self.components.iter_mut()
|
|
.map(|comp| comp.set_input_descriptors(input_descriptors))
|
|
.fold(false, |x, y| x || y)
|
|
}
|
|
|
|
fn set_hw_render(&mut self, hw_render_callback: &HwRenderCallback) -> bool {
|
|
self.components.iter_mut()
|
|
.map(|comp| comp.set_hw_render(hw_render_callback))
|
|
.all(|x| x)
|
|
}
|
|
|
|
fn get_variable(&mut self, key: &str) -> Option<String> {
|
|
self.components.iter_mut()
|
|
.map(|comp| comp.get_variable(key))
|
|
.flatten()
|
|
.next()
|
|
}
|
|
|
|
fn set_variables(&mut self, variables: &Vec<Variable2>) -> bool {
|
|
self.components.iter_mut()
|
|
.map(|comp| comp.set_variables(variables))
|
|
.fold(false, |x, y| x || y)
|
|
}
|
|
|
|
fn get_variable_update(&mut self) -> Option<bool> {
|
|
self.components.iter_mut()
|
|
.map(|comp| comp.get_variable_update())
|
|
.flatten()
|
|
.reduce(|x, y| x || y)
|
|
}
|
|
|
|
fn set_support_no_game(&mut self, supports_no_game: bool) -> bool {
|
|
self.components.iter_mut()
|
|
.map(|comp| comp.set_support_no_game(supports_no_game))
|
|
.all(|x| x)
|
|
}
|
|
|
|
fn get_libretro_path(&mut self) -> Option<PathBuf> {
|
|
self.components.iter_mut()
|
|
.map(|comp| comp.get_libretro_path())
|
|
.flatten()
|
|
.next()
|
|
}
|
|
|
|
fn get_input_device_capabilities(&mut self) -> Option<u64> {
|
|
self.components.iter_mut()
|
|
.map(|comp| comp.get_input_device_capabilities())
|
|
.flatten()
|
|
.reduce(|x, y| x & y)
|
|
}
|
|
|
|
fn get_core_assets_directory(&mut self) -> Option<PathBuf> {
|
|
self.components.iter_mut()
|
|
.map(|comp| comp.get_core_assets_directory())
|
|
.flatten()
|
|
.next()
|
|
}
|
|
|
|
fn get_save_directory(&mut self) -> Option<PathBuf> {
|
|
self.components.iter_mut()
|
|
.map(|comp| comp.get_save_directory())
|
|
.flatten()
|
|
.next()
|
|
}
|
|
|
|
fn set_system_av_info(&mut self, system_av_info: &SystemAvInfo) -> bool {
|
|
self.components.iter_mut()
|
|
.map(|comp| comp.set_system_av_info(system_av_info))
|
|
.fold(false, |x, y| x || y) // not "any" because we don't short-circuit
|
|
}
|
|
|
|
fn set_subsystem_info(&mut self, subsystem_info: &Vec<SubsystemInfo2>) -> bool {
|
|
self.components.iter_mut()
|
|
.map(|comp| comp.set_subsystem_info(subsystem_info))
|
|
.all(|x| x)
|
|
}
|
|
|
|
fn set_controller_info(&mut self, controller_info: &Vec<ControllerDescription2>) -> bool {
|
|
self.components.iter_mut()
|
|
.map(|comp| comp.set_controller_info(controller_info))
|
|
.all(|x| x)
|
|
}
|
|
|
|
fn set_memory_maps(&mut self, memory_map: &MemoryMap) -> bool {
|
|
self.components.iter_mut()
|
|
.map(|comp| comp.set_memory_maps(memory_map))
|
|
.all(|x| x)
|
|
}
|
|
|
|
fn set_geometry(&mut self, game_geometry: &GameGeometry) -> bool {
|
|
self.components.iter_mut()
|
|
.map(|comp| comp.set_geometry(game_geometry))
|
|
.fold(false, |x, y| x || y) // not "any" because we don't short-circuit
|
|
}
|
|
|
|
fn get_username(&mut self) -> Option<String> {
|
|
self.components.iter_mut()
|
|
.map(|comp| comp.get_username())
|
|
.flatten()
|
|
.next()
|
|
}
|
|
|
|
fn get_language(&mut self) -> Option<Language> {
|
|
self.components.iter_mut()
|
|
.map(|comp| comp.get_language())
|
|
.flatten()
|
|
.next()
|
|
}
|
|
|
|
fn log_print(&mut self, level: LogLevel, msg: &str) {
|
|
for comp in &mut self.components {
|
|
comp.log_print(level, msg);
|
|
}
|
|
}
|
|
|
|
fn set_rumble_state(&mut self, port: c_uint, effect: RumbleEffect, strength: u16) -> bool {
|
|
self.components.iter_mut()
|
|
.map(|comp| comp.set_rumble_state(port, effect, strength))
|
|
.fold(false, |x, y| x || y) // not "any" because we don't short-circuit
|
|
}
|
|
|
|
fn perf_get_time_usec_cb(&mut self) -> Time {
|
|
self.components.first_mut()
|
|
.map(|comp| comp.perf_get_time_usec_cb())
|
|
.unwrap_or_default()
|
|
}
|
|
|
|
fn perf_get_counter_cb(&mut self) -> PerfTick {
|
|
self.components.first_mut()
|
|
.map(|comp| comp.perf_get_counter_cb())
|
|
.unwrap_or_default()
|
|
}
|
|
|
|
fn perf_get_cpu_features_cb(&mut self) -> u64 {
|
|
self.components.first_mut()
|
|
.map(|comp| comp.perf_get_cpu_features_cb())
|
|
.unwrap_or_default()
|
|
}
|
|
|
|
fn perf_log_cb(&mut self) {
|
|
if let Some(comp) = self.components.first_mut() {
|
|
comp.perf_log_cb()
|
|
}
|
|
}
|
|
|
|
fn perf_register_cb(&mut self, counter: &mut PerfCounter) {
|
|
if let Some(comp) = self.components.first_mut() {
|
|
comp.perf_register_cb(counter)
|
|
}
|
|
}
|
|
|
|
fn perf_start_cb(&mut self, counter: &mut PerfCounter) {
|
|
if let Some(comp) = self.components.first_mut() {
|
|
comp.perf_start_cb(counter)
|
|
}
|
|
}
|
|
|
|
fn perf_stop_cb(&mut self, counter: &mut PerfCounter) {
|
|
if let Some(comp) = self.components.first_mut() {
|
|
comp.perf_stop_cb(counter)
|
|
}
|
|
}
|
|
|
|
fn set_sensor_state(&mut self, port: c_uint, action: SensorAction, rate: c_uint) -> bool {
|
|
self.components.iter_mut()
|
|
.map(|comp| comp.set_sensor_state(port, action, rate))
|
|
.fold(false, |x, y| x || y) // not "any" because we don't short-circuit
|
|
}
|
|
|
|
fn get_sensor_input(&mut self, port: c_uint, id: c_uint) -> f32 {
|
|
self.components.iter_mut()
|
|
.map(|comp| comp.get_sensor_input(port, id))
|
|
.filter(|x| *x != 0.0)
|
|
.last()
|
|
.unwrap_or_default()
|
|
}
|
|
}
|