From e1ab7d69aa8ec9e7b9181ed6f26056523c1c9c23 Mon Sep 17 00:00:00 2001 From: lif Date: Sun, 17 Nov 2019 02:42:13 -0800 Subject: [PATCH] hacking in 3D Control Pad for NiGHTS and angrylion software rendering for N64... --- src/bin/example.rs | 27 +++++++++++++++------ src/retro/constants.rs | 21 +++++++++++------ src/retro/wrapper.rs | 53 ++++++++++++++++++++++++++++++++++++------ 3 files changed, 80 insertions(+), 21 deletions(-) diff --git a/src/bin/example.rs b/src/bin/example.rs index 23161f0..4baeaf5 100644 --- a/src/bin/example.rs +++ b/src/bin/example.rs @@ -4,7 +4,7 @@ extern crate sdl2; use rustro::retro; use rustro::retro::ffi::{GameGeometry, SystemInfo, SystemAvInfo}; -use rustro::retro::constants::{Input, DeviceIndex, JoypadButton, AnalogAxis}; +use rustro::retro::constants::{Input, DeviceIndex, JoypadButton, AnalogAxis, DeviceType}; use std::ffi::CStr; use std::io::Read; @@ -175,6 +175,11 @@ impl MyEmulator { self.retro .load_game(Some(path), data, None) .unwrap(); + + let saturn_3d_pad = DeviceType::Analog.device_subclass(0); + for i in 0..self.gamepads.len() as u32 { + self.retro.set_controller_port_device(i, saturn_3d_pad); + } } fn send_audio_samples(&mut self) { @@ -262,24 +267,32 @@ impl retro::wrapper::Handler for MyEmulator { true } + fn get_variable(&mut self, key: &str) -> Option { + match key { + "beetle_saturn_analog_stick_deadzone" => Some("15%".to_string()), + "parallel-n64-gfxplugin" => Some("angrylion".to_string()), + _ => { eprintln!("ignored: get_variable({})", key); None } + } + } + fn get_libretro_path(&mut self) -> Option { Some(self.core_path.clone()) } + fn get_input_device_capabilities(&mut self) -> Option { + let bits = (1 << (DeviceType::Joypad as u32)) | (1 << (DeviceType::Analog as u32)); + Some(bits as u64) + } + fn get_save_directory(&mut self) -> Option { Some(std::env::temp_dir()) } - - fn get_variable(&mut self, key: &str) -> Option { - eprintln!("ignored: get_variable({})", key); - None - } - fn set_system_av_info(&mut self, av_info: SystemAvInfo) -> bool { self.set_geometry(av_info.geometry.clone()); self.av_info = av_info; true } + fn set_geometry(&mut self, geom: GameGeometry) -> bool { let _ = self.canvas.window_mut().set_size(geom.base_width, geom.base_height); let _ = self.canvas.set_logical_size(geom.base_width, geom.base_height); diff --git a/src/retro/constants.rs b/src/retro/constants.rs index 39657ee..97cd670 100644 --- a/src/retro/constants.rs +++ b/src/retro/constants.rs @@ -7,7 +7,7 @@ use super::ffi::*; // NB: commented-out stuff is from newer versions of libretro.h not yet represented in libretro-sys -#[derive(TryFromPrimitive, IntoPrimitive)] +#[derive(TryFromPrimitive, IntoPrimitive, Debug)] #[repr(u32)] pub enum DeviceType { None = DEVICE_NONE, @@ -19,7 +19,13 @@ pub enum DeviceType { Pointer = DEVICE_POINTER, } -#[derive(TryFromPrimitive, IntoPrimitive)] +impl DeviceType { + pub fn device_subclass(self, id: u32) -> u32 { + ((id + 1) << DEVICE_TYPE_SHIFT) | u32::from(self) + } +} + +#[derive(TryFromPrimitive, IntoPrimitive, Debug)] #[repr(u32)] pub enum DeviceIndex { Left = DEVICE_INDEX_ANALOG_LEFT, @@ -27,7 +33,7 @@ pub enum DeviceIndex { // Button = DEVICE_INDEX_ANALOG_BUTTON, } -#[derive(TryFromPrimitive, IntoPrimitive)] +#[derive(TryFromPrimitive, IntoPrimitive, Debug)] #[repr(u32)] pub enum JoypadButton { B = DEVICE_ID_JOYPAD_B, @@ -48,14 +54,14 @@ pub enum JoypadButton { R3 = DEVICE_ID_JOYPAD_R3, } -#[derive(TryFromPrimitive, IntoPrimitive)] +#[derive(TryFromPrimitive, IntoPrimitive, Debug)] #[repr(u32)] pub enum AnalogAxis { X = DEVICE_ID_ANALOG_X, Y = DEVICE_ID_ANALOG_Y, } -#[derive(TryFromPrimitive, IntoPrimitive)] +#[derive(TryFromPrimitive, IntoPrimitive, Debug)] #[repr(u32)] pub enum MouseButton { X = DEVICE_ID_MOUSE_X, @@ -69,7 +75,7 @@ pub enum MouseButton { HorizWheelDown = DEVICE_ID_MOUSE_HORIZ_WHEELDOWN, } -#[derive(TryFromPrimitive, IntoPrimitive)] +#[derive(TryFromPrimitive, IntoPrimitive, Debug)] #[repr(u32)] pub enum LightGunButton { // ScreenX = DEVICE_ID_LIGHTGUN_SCREEN_X, @@ -91,7 +97,7 @@ pub enum LightGunButton { Pause = DEVICE_ID_LIGHTGUN_PAUSE, } -#[derive(TryFromPrimitive, IntoPrimitive)] +#[derive(TryFromPrimitive, IntoPrimitive, Debug)] #[repr(u32)] pub enum PointerStat { X = DEVICE_ID_POINTER_X, @@ -99,6 +105,7 @@ pub enum PointerStat { Pressed = DEVICE_ID_POINTER_PRESSED, } +#[derive(Debug)] pub enum Input { None(c_uint), Joypad(JoypadButton), diff --git a/src/retro/wrapper.rs b/src/retro/wrapper.rs index 923fb82..95c265b 100644 --- a/src/retro/wrapper.rs +++ b/src/retro/wrapper.rs @@ -2,18 +2,20 @@ use core::convert::TryInto; use core::ffi::c_void; use core::slice::from_raw_parts; +use std::convert::TryFrom; use std::ffi::{CString, CStr}; use std::ops::Deref; use std::os::raw::{c_uint, c_char}; use std::path::{Path, PathBuf}; use std::pin::Pin; +use std::time::Duration; use num_enum::TryFromPrimitive; use super::constants::*; use super::ffi::*; use super::loading::*; -use std::time::Duration; +use failure::_core::convert::Infallible; static mut CB_SINGLETON: StaticCallbacks = StaticCallbacks { handler: None, @@ -108,8 +110,26 @@ impl StaticCallbacks { T::try_from_primitive(number).ok() } fn environment_cb_inner(cmd: u32, data: *mut c_void) -> Option { - let handler = unsafe { CB_SINGLETON.handler.as_mut() }?; - match cmd.try_into().ok()? { + let maybe_handler = unsafe { CB_SINGLETON.handler.as_mut() }; + if maybe_handler.is_none() { + eprintln!( + "WARNING: env cmd {} called before handler set!", + match EnvCmd::try_from(cmd) { + Ok(x) => format!("{:?}", x), + Err(_) => format!("{}", cmd), + } + ); + } + let handler = maybe_handler?; + let parsed_cmd = cmd.try_into().ok(); + if parsed_cmd.is_none() { + eprintln!( + "Unknown{} env cmd: {}", + if cmd >= ENVIRONMENT_EXPERIMENTAL { ", experimental" } else { "" }, + cmd % ENVIRONMENT_EXPERIMENTAL + ); + } + match parsed_cmd? { EnvCmd::SetRotation => handler.set_rotation(Self::enum_from_void(data)?), EnvCmd::GetOverscan => Self::clone_into_void(data, &handler.get_overscan()?)?, EnvCmd::GetCanDupe => Self::clone_into_void(data, &handler.get_can_dupe()?)?, @@ -124,8 +144,12 @@ impl StaticCallbacks { // TODO EnvCmd::SetHwRender => {}, EnvCmd::GetVariable => { let mut var = Self::from_void::(data)?; - let value = handler - .get_variable(unsafe { CStr::from_ptr(var.key) }.to_str().ok()?)?; + let key = unsafe { CStr::from_ptr(var.key) }.to_str().ok()?; + if !var.value.is_null() { + let placeholder = unsafe { CStr::from_ptr(var.value) }.to_string_lossy(); + eprintln!("querying {}: {}", key, placeholder); + } + let value = handler.get_variable(key)?; // leaks memory. var.value = CString::new(value).ok()?.into_raw(); true @@ -140,6 +164,7 @@ impl StaticCallbacks { let ri = RumbleInterface { set_rumble_state: StaticCallbacks::set_rumble_state_cb }; Self::clone_into_void(data, &ri)? }, + // TODO: wrap this in something nicer than a raw u64 bit field EnvCmd::GetInputDeviceCapabilities => Self::clone_into_void(data, &handler.get_input_device_capabilities()?)?, // TODO EnvCmd::GetSensorInterface => {}, // TODO EnvCmd::GetCameraInterface => {}, @@ -151,14 +176,27 @@ impl StaticCallbacks { EnvCmd::SetSystemAvInfo => handler.set_system_av_info(Self::from_void::(data)?.clone()), // TODO EnvCmd::SetProcAddressCallback => {}, // TODO EnvCmd::SetSubsystemInfo => {}, - // TODO EnvCmd::SetControllerInfo => {}, + EnvCmd::SetControllerInfo => { + // TODO: actually implement (wrap in rustic types and send to Handler) + let info = unsafe { (data as *const ControllerInfo).as_ref() }?; + let types = unsafe { from_raw_parts(info.types, info.num_types as usize) }; + for t in types { + let orig_name = match DeviceType::try_from(t.id) { + Ok(x) => format!("{:?}", x), + Err(_) => format!("Device ID {}", t.id), + }; + let new_name = unsafe { CStr::from_ptr(t.desc) }.to_string_lossy(); + eprintln!("SetControllerInfo: {} is {}", orig_name, new_name); + } + true + }, // TODO EnvCmd::SetMemoryMaps => {}, EnvCmd::SetGeometry => handler.set_geometry(Self::from_void::(data)?.clone()), EnvCmd::GetUsername => Self::string_into_void(data, handler.get_username()?)?, EnvCmd::GetLanguage => Self::clone_into_void(data, &handler.get_language()?)?, // EnvCmd::SetSerializationQuirks => handler.set_serialization_quirks(Self::from_void(data)?), x => { - eprintln!("Unsupported env cmd: {:?}", x); + eprintln!("Known but unsupported env cmd: {:?}", x); false }, }.into() @@ -241,6 +279,7 @@ pub struct LibretroWrapper { impl From 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);