95 lines
3.2 KiB
Rust
95 lines
3.2 KiB
Rust
use crate::prelude::*;
|
|
|
|
use std::ffi::CStr;
|
|
|
|
use sdl2::Sdl;
|
|
use sdl2::rect::Rect;
|
|
use sdl2::render::WindowCanvas;
|
|
|
|
/// Creates a root window in SDL2, then displays each 2D video frame provided by the core
|
|
/// by converting it to a [sdl2::render::Texture] and copying it to the window's canvas.
|
|
///
|
|
/// This component has no public interface and manages the SDL2 window on its own.
|
|
pub struct SimpleSdl2CanvasComponent {
|
|
canvas: WindowCanvas,
|
|
pixel_format: sdl2::pixels::PixelFormatEnum,
|
|
}
|
|
|
|
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()
|
|
);
|
|
|
|
let geometry = retro.get_system_av_info().geometry;
|
|
let pixel_format = sdl2::pixels::PixelFormatEnum::ARGB1555;
|
|
|
|
let window = sdl_context
|
|
.video()?
|
|
.window(title.as_str(), geometry.base_width, geometry.base_height)
|
|
.build()?;
|
|
|
|
let canvas = window.into_canvas().build()?;
|
|
|
|
Ok(SimpleSdl2CanvasComponent {
|
|
canvas,
|
|
pixel_format,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl RetroComponent for SimpleSdl2CanvasComponent {}
|
|
impl RetroCallbacks for SimpleSdl2CanvasComponent {
|
|
fn video_refresh(&mut self, frame: &VideoFrame) {
|
|
match frame {
|
|
VideoFrame::XRGB1555 { width, height, .. }
|
|
| VideoFrame::RGB565 { width, height, .. }
|
|
| VideoFrame::XRGB8888 { width, height, .. } => {
|
|
let rect = Rect::new(0, 0, *width, *height);
|
|
|
|
if let Ok(mut tex) = self.canvas
|
|
.texture_creator()
|
|
.create_texture_static(self.pixel_format, *width, *height)
|
|
{
|
|
let (pixel_data, pitch) = frame.data_pitch_as_bytes().unwrap();
|
|
if tex.update(rect, pixel_data, pitch).is_ok() {
|
|
self.canvas.clear();
|
|
self.canvas.copy(&tex, None, None).unwrap();
|
|
}
|
|
}
|
|
self.canvas.present();
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
|
|
fn set_pixel_format(&mut self, pix_fmt: PixelFormat) -> Option<bool> {
|
|
self.pixel_format = match pix_fmt {
|
|
PixelFormat::ARGB1555 => sdl2::pixels::PixelFormatEnum::RGB555,
|
|
PixelFormat::ARGB8888 => sdl2::pixels::PixelFormatEnum::ARGB8888,
|
|
PixelFormat::RGB565 => sdl2::pixels::PixelFormatEnum::RGB565,
|
|
};
|
|
Some(true)
|
|
}
|
|
|
|
fn get_variable(&mut self, key: &str) -> Option<String> {
|
|
match key {
|
|
"parallel-n64-gfxplugin" => Some("angrylion".to_string()),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
fn set_system_av_info(&mut self, av_info: &SystemAvInfo) -> Option<bool> {
|
|
self.set_geometry(&av_info.geometry);
|
|
Some(true)
|
|
}
|
|
|
|
fn set_geometry(&mut self, geom: &GameGeometry) -> Option<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);
|
|
Some(true)
|
|
}
|
|
}
|