fullscreen option, add keyboard component
This commit is contained in:
		
							parent
							
								
									8efff459c4
								
							
						
					
					
						commit
						2dd8556fe2
					
				
					 5 changed files with 139 additions and 24 deletions
				
			
		| 
						 | 
				
			
			@ -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(())
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										88
									
								
								ferretro_components/src/provided/sdl2/keyboard.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								ferretro_components/src/provided/sdl2/keyboard.rs
									
										
									
									
									
										Normal 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,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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…
	
	Add table
		
		Reference in a new issue