ferretro/src/bin/example.rs

187 lines
5.8 KiB
Rust
Raw Normal View History

2019-11-15 10:15:51 +01:00
/*extern crate sdl2;
use sdl2::pixels::PixelFormatEnum;
use sdl2::rect::Rect;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
pub fn main() -> Result<(), String> {
let sdl_context = sdl2::init()?;
let video_subsystem = sdl_context.video()?;
let window = video_subsystem.window("rust-sdl2 demo: Video", 800, 600)
.position_centered()
.opengl()
.build()
.map_err(|e| e.to_string())?;
let mut canvas = window.into_canvas().build().map_err(|e| e.to_string())?;
let texture_creator = canvas.texture_creator();
let mut texture = texture_creator.create_texture_streaming(PixelFormatEnum::RGB24, 256, 256)
.map_err(|e| e.to_string())?;
// Create a red-green gradient
texture.with_lock(None, |buffer: &mut [u8], pitch: usize| {
for y in 0..256 {
for x in 0..256 {
let offset = y*pitch + x*3;
buffer[offset] = x as u8;
buffer[offset + 1] = y as u8;
buffer[offset + 2] = 0;
}
}
})?;
canvas.clear();
canvas.copy(&texture, None, Some(Rect::new(100, 100, 256, 256)))?;
canvas.copy_ex(&texture, None,
Some(Rect::new(450, 100, 256, 256)), 30.0, None, false, false)?;
canvas.present();
let mut event_pump = sdl_context.event_pump()?;
'running: loop {
for event in event_pump.poll_iter() {
match event {
Event::Quit {..}
| Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
break 'running
},
_ => {}
}
}
// The rest of the game loop goes here...
}
Ok(())
}
*/
2019-11-15 04:16:44 +01:00
extern crate rustro;
2019-11-15 06:21:58 +01:00
extern crate sdl2;
use rustro::retro;
use rustro::retro::ffi::GameGeometry;
2019-11-15 10:15:51 +01:00
use rustro::retro::ffi::SystemAvInfo;
use std::ffi::CStr;
2019-11-15 06:21:58 +01:00
use std::path::{PathBuf, Path};
use std::time::Duration;
use structopt::StructOpt;
2019-11-15 10:15:51 +01:00
use sdl2::render::{WindowCanvas, Texture, TextureCreator};
2019-11-15 06:21:58 +01:00
use sdl2::rect::Rect;
2019-11-15 10:15:51 +01:00
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::video::WindowContext;
use std::io::Write;
2019-11-15 06:21:58 +01:00
struct MyEmulator {
retro: retro::wrapper::LibretroWrapper,
2019-11-15 10:15:51 +01:00
av_info: SystemAvInfo,
2019-11-15 06:21:58 +01:00
pixel_format: sdl2::pixels::PixelFormatEnum,
2019-11-15 10:15:51 +01:00
texture: Option<Texture>,
2019-11-15 06:21:58 +01:00
}
impl MyEmulator {
pub fn with_core(core: impl AsRef<Path>) -> Self {
let lib = libloading::Library::new(core.as_ref()).unwrap();
let raw_retro = retro::loading::LibretroApi::from_library(lib).unwrap();
let retro = retro::wrapper::LibretroWrapper::from(raw_retro);
println!("api version: {}", retro.as_ref().api_version());
println!("name: {}", unsafe { CStr::from_ptr(retro.as_ref().get_system_info().library_name) }.to_string_lossy());
2019-11-15 10:15:51 +01:00
let av_info = retro.as_ref().get_system_av_info();
2019-11-15 06:21:58 +01:00
let pixel_format = sdl2::pixels::PixelFormatEnum::ABGR1555;
2019-11-15 10:15:51 +01:00
let mut result = MyEmulator { retro, av_info, pixel_format, texture: None };
2019-11-15 06:21:58 +01:00
retro::wrapper::register_handler(&mut result);
result.retro.as_ref().init();
result
}
2019-11-15 06:21:58 +01:00
pub fn run(&self) {
self.retro.as_ref().run();
2019-11-15 10:15:51 +01:00
}
pub fn base_dimensions(&self) -> (u32, u32) {
(self.av_info.geometry.base_width, self.av_info.geometry.base_height)
2019-11-15 06:21:58 +01:00
}
pub fn load_game(&self, rom: impl AsRef<Path>) {
self.retro.as_ref().load_game(Some(rom.as_ref()), None, None);
}
}
impl retro::convert::Handler for MyEmulator {
fn video_refresh(&mut self, data: &[u8], width: u32, height: u32, pitch: u32) {
2019-11-15 10:15:51 +01:00
//println!("video_refresh {}x{}", width, height);
//let rect = Rect::new(0, 0, width, height);
println!("{:?}", self.texture.is_some());
if let Some(ref mut tex) = self.texture {
tex.update(None, data, pitch as usize).unwrap();
}
2019-11-15 06:21:58 +01:00
}
fn set_pixel_format(&mut self, pix_fmt: retro::ffi::PixelFormat) -> bool {
self.pixel_format = match pix_fmt {
retro::ffi::PixelFormat::ARGB1555 => sdl2::pixels::PixelFormatEnum::RGB555,
retro::ffi::PixelFormat::ARGB8888 => sdl2::pixels::PixelFormatEnum::ARGB8888,
retro::ffi::PixelFormat::RGB565 => sdl2::pixels::PixelFormatEnum::RGB565,
};
true
}
}
2019-11-15 10:15:51 +01:00
pub fn main() -> failure::Fallible<()> {
2019-11-15 06:21:58 +01:00
let opt: Opt = Opt::from_args();
let mut emu = MyEmulator::with_core(&opt.core);
emu.load_game(&opt.rom);
2019-11-15 10:15:51 +01:00
let sdl_context = sdl2::init().map_err(failure::err_msg)?;
let video_subsystem = sdl_context.video().map_err(failure::err_msg)?;
let (width, height) = emu.base_dimensions();
let window = video_subsystem.window("rust libretro", width, height)
.position_centered()
.opengl()
.build()?;
let mut canvas = window.into_canvas().build()?;
let texture_creator = canvas.texture_creator();
emu.texture = texture_creator.create_texture_streaming(emu.pixel_format, width, height).ok();
println!("{:?}", emu.texture.is_some());
let mut event_pump = sdl_context.event_pump().map_err(failure::err_msg)?;
'running: loop {
for event in event_pump.poll_iter() {
match event {
Event::Quit {..}
| Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
break 'running
},
_ => {}
}
}
// The rest of the game loop goes here...
2019-11-15 06:21:58 +01:00
emu.run();
2019-11-15 10:15:51 +01:00
canvas.clear();
canvas.copy(emu.texture.as_ref().unwrap(), None, Some(Rect::new(0, 0, width, height))).map_err(failure::err_msg)?;
canvas.present();
2019-11-15 06:21:58 +01:00
::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60));
}
2019-11-15 10:15:51 +01:00
Ok(())
2019-11-15 06:21:58 +01:00
}
#[derive(StructOpt)]
struct Opt {
/// Core module to use.
#[structopt(short, long, parse(from_os_str))]
core: PathBuf,
/// Rom to load using the core.
#[structopt(short, long, parse(from_os_str))]
rom: PathBuf,
}