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",
|
||||||
"emulator/mgba-sys",
|
"emulator/mgba-sys",
|
||||||
"emulator/test-runner",
|
"emulator/test-runner",
|
||||||
|
"emulator/screenshot-generator",
|
||||||
"website/backtrace",
|
"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