hacking in 3D Control Pad for NiGHTS and angrylion software rendering for N64...
This commit is contained in:
parent
b3156a4b04
commit
e1ab7d69aa
|
@ -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);
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue