hacking in 3D Control Pad for NiGHTS and angrylion software rendering for N64...

This commit is contained in:
lif 2019-11-17 02:42:13 -08:00
parent b3156a4b04
commit e1ab7d69aa
3 changed files with 80 additions and 21 deletions

View File

@ -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<String> {
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<PathBuf> {
Some(self.core_path.clone())
}
fn get_input_device_capabilities(&mut self) -> Option<u64> {
let bits = (1 << (DeviceType::Joypad as u32)) | (1 << (DeviceType::Analog as u32));
Some(bits as u64)
}
fn get_save_directory(&mut self) -> Option<PathBuf> {
Some(std::env::temp_dir())
}
fn get_variable(&mut self, key: &str) -> Option<String> {
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);

View File

@ -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),

View File

@ -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<bool> {
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::<Variable>(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::<SystemAvInfo>(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::<GameGeometry>(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<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);