fullscreen option, add keyboard component
This commit is contained in:
parent
8efff459c4
commit
2dd8556fe2
|
@ -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())?;
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue