mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-23 08:11:33 +11:00
add screenshot generator tool
This commit is contained in:
parent
e25a1c7158
commit
81621c3b5e
|
@ -26,6 +26,7 @@ members = [
|
|||
"emulator/mgba",
|
||||
"emulator/mgba-sys",
|
||||
"emulator/test-runner",
|
||||
"emulator/screenshot-generator",
|
||||
"website/backtrace",
|
||||
]
|
||||
|
||||
|
|
13
emulator/screenshot-generator/Cargo.toml
Normal file
13
emulator/screenshot-generator/Cargo.toml
Normal file
|
@ -0,0 +1,13 @@
|
|||
[package]
|
||||
name = "screenshot-generator"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
mgba = { path = "../mgba" }
|
||||
clap = { version = "4", features = ["derive"] }
|
||||
anyhow = "1"
|
||||
image = { version = "0.24", default-features = false, features = [ "png", "bmp" ] }
|
||||
agb-gbafix = { path = "../../agb-gbafix" }
|
23
emulator/screenshot-generator/src/image_generate.rs
Normal file
23
emulator/screenshot-generator/src/image_generate.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
use image::{DynamicImage, GenericImage, Rgba};
|
||||
|
||||
const WIDTH: usize = 240;
|
||||
const HEIGHT: usize = 160;
|
||||
|
||||
pub fn generate_image(video_buffer: &[u32]) -> DynamicImage {
|
||||
let mut dynamic_image = DynamicImage::new(
|
||||
WIDTH.try_into().unwrap(),
|
||||
HEIGHT.try_into().unwrap(),
|
||||
image::ColorType::Rgba8,
|
||||
);
|
||||
for y in 0..HEIGHT {
|
||||
for x in 0..WIDTH {
|
||||
let video_pixel = video_buffer[x + y * WIDTH];
|
||||
let mut pixels = video_pixel.to_le_bytes();
|
||||
pixels[3] = 255;
|
||||
|
||||
dynamic_image.put_pixel(x.try_into().unwrap(), y.try_into().unwrap(), Rgba(pixels));
|
||||
}
|
||||
}
|
||||
|
||||
dynamic_image
|
||||
}
|
96
emulator/screenshot-generator/src/main.rs
Normal file
96
emulator/screenshot-generator/src/main.rs
Normal file
|
@ -0,0 +1,96 @@
|
|||
use std::{
|
||||
error::Error,
|
||||
fs::File,
|
||||
io::{BufWriter, Read},
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use anyhow::anyhow;
|
||||
use clap::Parser;
|
||||
use image::DynamicImage;
|
||||
use image_generate::generate_image;
|
||||
use mgba::{LogLevel, Logger, MCore, MemoryBacked, VFile};
|
||||
|
||||
mod image_generate;
|
||||
|
||||
static LOGGER: Logger = Logger::new(my_logger);
|
||||
|
||||
fn my_logger(_category: &str, _level: LogLevel, _s: String) {}
|
||||
|
||||
#[derive(Parser)]
|
||||
struct CliArguments {
|
||||
#[arg(long)]
|
||||
rom: PathBuf,
|
||||
#[arg(long)]
|
||||
frames: usize,
|
||||
#[arg(long)]
|
||||
output: PathBuf,
|
||||
}
|
||||
|
||||
struct ScreenshotGenerator {
|
||||
mgba: MCore,
|
||||
}
|
||||
|
||||
impl ScreenshotGenerator {
|
||||
fn new<V: VFile>(rom: V) -> Result<Self, Box<dyn Error>> {
|
||||
let mut mgba = MCore::new().ok_or(anyhow!("cannot create core"))?;
|
||||
|
||||
mgba::set_global_default_logger(&LOGGER);
|
||||
|
||||
mgba.load_rom(rom);
|
||||
|
||||
Ok(Self { mgba })
|
||||
}
|
||||
|
||||
fn run(mut self, frames: usize) -> DynamicImage {
|
||||
for _ in 0..frames {
|
||||
self.mgba.frame();
|
||||
}
|
||||
|
||||
generate_image(self.mgba.video_buffer())
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let args = CliArguments::parse();
|
||||
|
||||
let rom = load_rom(args.rom)?;
|
||||
let rom = MemoryBacked::new(rom);
|
||||
|
||||
let image = ScreenshotGenerator::new(rom)?.run(args.frames);
|
||||
|
||||
let mut output = BufWriter::new(
|
||||
File::options()
|
||||
.write(true)
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.open(args.output)?,
|
||||
);
|
||||
image.write_to(&mut output, image::ImageOutputFormat::Png)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn load_rom<P: AsRef<Path>>(path: P) -> anyhow::Result<Vec<u8>> {
|
||||
let mut input_file = File::open(path)?;
|
||||
let mut input_file_buffer = Vec::new();
|
||||
|
||||
input_file.read_to_end(&mut input_file_buffer)?;
|
||||
|
||||
let mut elf_buffer = Vec::new();
|
||||
|
||||
let inculde_debug_info = false;
|
||||
if agb_gbafix::write_gba_file(
|
||||
&input_file_buffer,
|
||||
Default::default(),
|
||||
agb_gbafix::PaddingBehaviour::DoNotPad,
|
||||
inculde_debug_info,
|
||||
&mut elf_buffer,
|
||||
)
|
||||
.is_ok()
|
||||
{
|
||||
Ok(elf_buffer)
|
||||
} else {
|
||||
Ok(input_file_buffer)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue