fullscreen option, add keyboard component

This commit is contained in:
lifning 2021-12-10 02:33:43 -08:00
parent 8efff459c4
commit 2dd8556fe2
5 changed files with 139 additions and 24 deletions

View File

@ -4,6 +4,7 @@ extern crate ffmpeg_next as ffmpeg;
extern crate sdl2;
use std::path::PathBuf;
use sdl2::video::FullscreenType;
use structopt::StructOpt;
use ferretro_components::prelude::*;
@ -21,7 +22,7 @@ struct Opt {
#[structopt(short, long, parse(from_os_str))]
core: PathBuf,
/// ROM to load using the core.
#[structopt(short, long, parse(from_os_str))]
#[structopt(parse(from_os_str))]
rom: PathBuf,
/// Save state to load at startup.
#[structopt(long, parse(from_os_str))]
@ -35,6 +36,9 @@ struct Opt {
/// Disable OpenGL context creation.
#[structopt(long)]
no_opengl: bool,
/// Fullscreen (borderless).
#[structopt(short, long)]
fullscreen: bool,
/// Print core-provided system information to stderr.
#[structopt(long)]
sys_info: bool,
@ -71,16 +75,22 @@ pub fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
emu.register_component(ffmpeg_comp)?;
}
let ft = if opt.fullscreen {
FullscreenType::Desktop
} else {
FullscreenType::Off
};
let sdl2_ogl_res = if opt.no_opengl {
Err("OpenGL disabled".into())
} else {
SimpleSdl2OpenglComponent::new(&mut sdl_context, emu.libretro_core())
SimpleSdl2OpenglComponent::new(&mut sdl_context, ft)
};
if let Ok(sdl2_ogl) = sdl2_ogl_res {
emu.register_component(sdl2_ogl)?;
} else {
match SimpleSdl2CanvasComponent::new(&mut sdl_context, emu.libretro_core()) {
match SimpleSdl2CanvasComponent::new(&mut sdl_context, ft) {
Ok(sdl2_canvas) => emu.register_component(sdl2_canvas)?,
Err(e) => eprintln!("Couldn't initialize SDL2 video component: {:?}", e),
}
@ -88,6 +98,7 @@ pub fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
emu.register_component(SimpleSdl2AudioComponent::new(&mut sdl_context)?)?;
emu.register_component(SimpleSdl2KeyboardComponent::new(&mut sdl_context)?)?;
emu.register_component(SimpleSdl2GamepadComponent::new(&mut sdl_context))?;
emu.register_component(SleepFramerateLimitComponent::default())?;

View File

@ -6,6 +6,7 @@ use std::path::Path;
use sdl2::Sdl;
use sdl2::rect::Rect;
use sdl2::render::WindowCanvas;
use sdl2::video::FullscreenType;
pub(crate) fn paint_frame_on_canvas(frame: &VideoFrame, canvas: &mut WindowCanvas) -> bool {
if let Some((pixel_data, pitch)) = frame.data_pitch_as_bytes() {
@ -56,19 +57,18 @@ pub struct SimpleSdl2CanvasComponent {
}
impl SimpleSdl2CanvasComponent {
pub fn new(sdl_context: &mut Sdl, retro: &LibretroWrapper) -> Result<Self, Box<dyn std::error::Error>> {
let sys_info = retro.get_system_info();
let title = format!(
"{} - ferretro SDL",
unsafe { CStr::from_ptr(sys_info.library_name) }.to_string_lossy()
);
pub fn new(sdl_context: &mut Sdl, ft: FullscreenType) -> Result<Self, Box<dyn std::error::Error>> {
// default to old libsnes 256x224 window size until load_game (prereq of get_system_av_info)
let canvas = sdl_context
let mut window = sdl_context
.video()?
.window(title.as_str(), 256, 224)
.window("ferretro SDL", 256, 224)
.resizable()
.build()?
.hidden()
.build()?;
window.set_fullscreen(ft)?;
let canvas = window
.into_canvas()
.build()?;
@ -79,7 +79,15 @@ impl SimpleSdl2CanvasComponent {
}
impl RetroComponent for SimpleSdl2CanvasComponent {
fn post_load_game(&mut self, retro: &mut LibretroWrapper, _rom: &Path) -> crate::base::Result<()> {
fn post_load_game(&mut self, retro: &mut LibretroWrapper, rom: &Path) -> crate::base::Result<()> {
let sys_info = retro.get_system_info();
let title = format!(
"{} - {} - ferretro SDL",
unsafe { CStr::from_ptr(sys_info.library_name) }.to_string_lossy(),
rom.file_stem().unwrap_or_default().to_string_lossy(),
);
self.canvas.window_mut().set_title(&title)?;
self.canvas.window_mut().show();
self.set_geometry(&retro.get_system_av_info().geometry);
Ok(())
}

View File

@ -0,0 +1,88 @@
use std::collections::HashMap;
use crate::base::ControlFlow;
use crate::prelude::*;
use sdl2::Sdl;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
// FIXME: make it not hard require EventPump ownership, or allow user-provided function?
/// Maps the first "RetroPad" layout to the keyboard.
///
/// NOTE: This component is intended for exceedingly simple use-cases, and *must own* the
/// [sdl2::EventPump].
pub struct SimpleSdl2KeyboardComponent {
button_map: HashMap<Keycode, InputDeviceId>,
button_state: HashMap<InputDeviceId, i16>,
event_pump: sdl2::EventPump,
}
impl RetroCallbacks for SimpleSdl2KeyboardComponent {
fn input_state(&mut self, port: u32, device: InputDeviceId, _index: InputIndex) -> i16 {
if port != 0 {
return 0;
}
self.button_state.get(&device).cloned().unwrap_or_default()
}
fn get_input_device_capabilities(&mut self) -> Option<u64> {
let bits = 1 << (DeviceType::Joypad as u32);
Some(bits as u64)
}
}
impl RetroComponent for SimpleSdl2KeyboardComponent {
fn pre_run(&mut self, _retro: &mut LibretroWrapper) -> ControlFlow {
for event in self.event_pump.poll_iter() {
match event {
Event::Quit { .. }
| Event::KeyDown {
keycode: Some(Keycode::Escape),
..
} => return ControlFlow::Break,
Event::KeyDown { keycode: Some(k), .. } => {
if let Some(button) = self.button_map.get(&k) {
self.button_state.insert(button.to_owned(), 1);
}
}
Event::KeyUp { keycode: Some(k), .. } => {
if let Some(button) = self.button_map.get(&k) {
self.button_state.remove(button);
}
}
_ => {}
}
}
ControlFlow::Continue
}
}
impl SimpleSdl2KeyboardComponent {
pub fn new(sdl_context: &mut Sdl) -> crate::base::Result<Self> {
let event_pump = sdl_context.event_pump()?;
Ok(SimpleSdl2KeyboardComponent {
button_map: [
(Keycode::Up, InputDeviceId::Joypad(JoypadButton::Up)),
(Keycode::Down, InputDeviceId::Joypad(JoypadButton::Down)),
(Keycode::Left, InputDeviceId::Joypad(JoypadButton::Left)),
(Keycode::Right, InputDeviceId::Joypad(JoypadButton::Right)),
(Keycode::X, InputDeviceId::Joypad(JoypadButton::A)),
(Keycode::Z, InputDeviceId::Joypad(JoypadButton::B)),
(Keycode::S, InputDeviceId::Joypad(JoypadButton::X)),
(Keycode::A, InputDeviceId::Joypad(JoypadButton::Y)),
(Keycode::Q, InputDeviceId::Joypad(JoypadButton::L)),
(Keycode::W, InputDeviceId::Joypad(JoypadButton::R)),
(Keycode::E, InputDeviceId::Joypad(JoypadButton::L2)),
(Keycode::R, InputDeviceId::Joypad(JoypadButton::R2)),
(Keycode::T, InputDeviceId::Joypad(JoypadButton::L3)),
(Keycode::Y, InputDeviceId::Joypad(JoypadButton::R3)),
(Keycode::Return, InputDeviceId::Joypad(JoypadButton::Start)),
(Keycode::Backspace, InputDeviceId::Joypad(JoypadButton::Select)),
(Keycode::Tab, InputDeviceId::Joypad(JoypadButton::Select)),
].into_iter().collect(),
button_state: Default::default(),
event_pump,
})
}
}

View File

@ -6,6 +6,7 @@ mod audio_ratecontrol;
mod canvas;
mod fps;
mod gamepad;
mod keyboard;
mod opengl;
mod surface;
@ -14,5 +15,6 @@ pub use audio_ratecontrol::Sdl2RateControlledAudioComponent;
pub use canvas::SimpleSdl2CanvasComponent;
pub use fps::SimpleSdl2FramerateLimitComponent;
pub use gamepad::SimpleSdl2GamepadComponent;
pub use keyboard::SimpleSdl2KeyboardComponent;
pub use opengl::SimpleSdl2OpenglComponent;
pub use surface::Sdl2SurfaceComponent;

View File

@ -6,6 +6,7 @@ use std::path::Path;
use sdl2::Sdl;
use sdl2::render::WindowCanvas;
use sdl2::video::FullscreenType;
use super::canvas::paint_frame_on_canvas;
@ -28,21 +29,18 @@ pub struct SimpleSdl2OpenglComponent {
}
impl SimpleSdl2OpenglComponent {
pub fn new(sdl_context: &mut Sdl, retro: &LibretroWrapper) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
let sys_info = retro.get_system_info();
let title = format!(
"{} - ferretro SDL GL",
unsafe { CStr::from_ptr(sys_info.library_name) }.to_string_lossy()
);
pub fn new(sdl_context: &mut Sdl, ft: FullscreenType) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
let video = sdl_context.video()?;
// default to old libsnes 256x224 window size until load_game (prereq of get_system_av_info)
let window = video
.window(title.as_str(), 256, 224)
let mut window = video
.window("ferretro SDL GL", 256, 224)
.opengl()
.resizable()
.hidden()
.build()?;
window.set_fullscreen(ft)?;
#[allow(non_snake_case)]
let glGetIntegerv: unsafe extern "C" fn(c_uint, *mut c_uint) = unsafe {
std::mem::transmute(video.gl_get_proc_address("glGetIntegerv"))
@ -90,7 +88,15 @@ impl SimpleSdl2OpenglComponent {
}
impl RetroComponent for SimpleSdl2OpenglComponent {
fn post_load_game(&mut self, retro: &mut LibretroWrapper, _rom: &Path) -> crate::base::Result<()> {
fn post_load_game(&mut self, retro: &mut LibretroWrapper, rom: &Path) -> crate::base::Result<()> {
let sys_info = retro.get_system_info();
let title = format!(
"{} - {} - ferretro SDL GL",
unsafe { CStr::from_ptr(sys_info.library_name) }.to_string_lossy(),
rom.file_stem().unwrap_or_default().to_string_lossy(),
);
self.canvas.window_mut().set_title(&title)?;
self.canvas.window_mut().show();
self.set_geometry(&retro.get_system_av_info().geometry);
Ok(())
}