leela: rewrite using clap
parent
17856bbe7e
commit
4357a2be84
|
@ -7,7 +7,7 @@ description = "Maraiah testbed program."
|
|||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
argparse = "0.2"
|
||||
clap = "2"
|
||||
maraiah = {path = "../..", features = ["serde_obj"]}
|
||||
memmap = "0.7"
|
||||
serde = "1.0"
|
||||
|
|
|
@ -1,244 +1,110 @@
|
|||
#![allow(clippy::unit_arg)]
|
||||
|
||||
use maraiah::{durandal::{err::*, file::*, image::*, sound::*},
|
||||
marathon::{machdr, map, ppm, shp, snd, tga, wav}};
|
||||
use std::{fs, io, slice::from_ref};
|
||||
|
||||
fn make_tga(_opt: &Options, fname: &str, im: &impl Image) -> ResultS<()>
|
||||
fn open(path: &str) -> ResultS<memmap::Mmap>
|
||||
{
|
||||
let mut out = io::BufWriter::new(fs::File::create(fname)?);
|
||||
|
||||
tga::write_tga(&mut out, im)
|
||||
let fp = fs::File::open(path)?;
|
||||
Ok(unsafe {memmap::Mmap::map(&fp)?})
|
||||
}
|
||||
|
||||
fn make_ppm(_opt: &Options, fname: &str, im: &impl Image) -> ResultS<()>
|
||||
fn file_read<T, F>(path: &str, f: F) -> ResultS<T>
|
||||
where F: FnOnce(&[u8]) -> ResultS<T>
|
||||
{
|
||||
let mut out = io::BufWriter::new(fs::File::create(fname)?);
|
||||
let mm = open(path)?;
|
||||
let bp = &mm[machdr::try_mac_header(&mm)..];
|
||||
|
||||
ppm::write_ppm(&mut out, im)
|
||||
f(bp)
|
||||
}
|
||||
|
||||
fn make_yaml<T>(opt: &Options, data: &T) -> ResultS<()>
|
||||
where T: serde::Serialize + std::fmt::Debug
|
||||
fn exists(path: String) -> Result<(), String>
|
||||
{
|
||||
if opt.out_debug {
|
||||
println!("{:#?}", data);
|
||||
} else {
|
||||
serde_yaml::to_writer(io::stdout(), &data)?;
|
||||
println!();
|
||||
match std::fs::metadata(path) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(e.to_string()),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn make_wav(fname: &str, snd: &impl Sound) -> ResultS<()>
|
||||
{
|
||||
let mut out = io::BufWriter::new(fs::File::create(fname)?);
|
||||
wav::write_wav(&mut out, snd)
|
||||
}
|
||||
|
||||
fn process_wad(opt: &Options, b: &[u8]) -> ResultS<()>
|
||||
{
|
||||
let wad = map::read(b)?;
|
||||
make_yaml(opt, &wad)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn dump_bitmaps(opt: &Options, c: &shp::coll::Collection, i: usize)
|
||||
fn each_value<'a, F>(opt: &'a clap::ArgMatches<'a>, name: &str, mut f: F)
|
||||
-> ResultS<()>
|
||||
where F: FnMut(&'a str) -> ResultS<()>
|
||||
{
|
||||
if !opt.shp_bmp {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
for (j, bmp) in c.bmps.iter().enumerate() {
|
||||
if opt.shp_bmp_all {
|
||||
for (k, tab) in c.tabs.iter().enumerate() {
|
||||
let fname = format!("{}/shape{}_{}_{}.tga", opt.out_dir, i, j, k);
|
||||
make_tga(opt, &fname, &shp::bmap::ImageShp::new(bmp, &tab))?;
|
||||
}
|
||||
} else {
|
||||
let fname = format!("{}/shape{}_{}.tga", opt.out_dir, i, j);
|
||||
make_tga(opt, &fname, &shp::bmap::ImageShp::new(bmp, &c.tabs[0]))?;
|
||||
if let Some(values) = opt.values_of(name) {
|
||||
for value in values {
|
||||
f(value)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_shp_objs(opt: &Options, cl: &shp::coll::Collection) -> ResultS<()>
|
||||
fn dump_info(data: impl std::fmt::Debug)
|
||||
{
|
||||
if opt.shp_tab {make_yaml(opt, &cl.tabs)?;}
|
||||
if opt.shp_frm {make_yaml(opt, &cl.frms)?;}
|
||||
if opt.shp_seq {make_yaml(opt, &cl.seqs)?;}
|
||||
|
||||
Ok(())
|
||||
println!("{:#?}", data);
|
||||
}
|
||||
|
||||
fn process_shp(opt: &Options, b: &[u8]) -> ResultS<()>
|
||||
fn sub_data_c<'a>(_opt: &clap::ArgMatches<'a>) -> ResultS<()>
|
||||
{
|
||||
for (i, cl) in shp::read(b)?.iter().enumerate() {
|
||||
if let Some(cl) = &cl.0 {
|
||||
dump_bitmaps(opt, cl, i)?;
|
||||
write_shp_objs(opt, cl)?;
|
||||
}
|
||||
|
||||
if let Some(cl) = &cl.1 {
|
||||
dump_bitmaps(opt, cl, i + 100)?;
|
||||
write_shp_objs(opt, cl)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn dump_sounds(opt: &Options, st: &snd::SoundTable, c: usize) -> ResultS<()>
|
||||
fn sub_dump_c<'a>(_opt: &clap::ArgMatches<'a>) -> ResultS<()>
|
||||
{
|
||||
if !opt.snd_dump {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
for (k, sd) in st {
|
||||
for (i, snd) in sd.sounds.iter().enumerate() {
|
||||
let fname = format!("{}/snd{}_{}_{}.wav", opt.out_dir, c, k, i);
|
||||
make_wav(&fname, snd)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn process_snd(opt: &Options, b: &[u8]) -> ResultS<()>
|
||||
fn sub_info_c<'a>(opt: &clap::ArgMatches<'a>) -> ResultS<()>
|
||||
{
|
||||
for (c, st) in snd::read(b)?.iter().enumerate() {
|
||||
dump_sounds(opt, st, c)?;
|
||||
}
|
||||
each_value(opt, "map", |f| Ok(dump_info(file_read(f, map::read)?)))?;
|
||||
each_value(opt, "shp", |f| Ok(dump_info(file_read(f, shp::read)?)))?;
|
||||
each_value(opt, "snd", |f| Ok(dump_info(file_read(f, snd::read)?)))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_ppm(opt: &Options, b: &[u8]) -> ResultS<()>
|
||||
{
|
||||
let im = ppm::read_ppm(b)?;
|
||||
|
||||
let fname = format!("{}/out.tga", opt.out_dir);
|
||||
make_tga(opt, &fname, &im)?;
|
||||
|
||||
let fname = format!("{}/out.ppm", opt.out_dir);
|
||||
make_ppm(opt, &fname, &im)
|
||||
}
|
||||
|
||||
fn main() -> ResultS<()>
|
||||
{
|
||||
use argparse::*;
|
||||
use clap::clap_app;
|
||||
|
||||
let mut opt = Options::default();
|
||||
{
|
||||
let mut ap = ArgumentParser::new();
|
||||
let sub_data =
|
||||
clap_app!(@subcommand data =>
|
||||
(about: "Dumps data into a discrete folder/YAML format"));
|
||||
|
||||
macro_rules! arg {
|
||||
($name:expr, $ref:expr, $type:expr, $desc:expr) => {
|
||||
ap.refer(&mut $ref).add_option(from_ref(&$name), $type, $desc);
|
||||
};
|
||||
}
|
||||
let sub_dump =
|
||||
clap_app!(@subcommand dump =>
|
||||
(about: "Dumps particular parts of data"));
|
||||
|
||||
ap.set_description(env!("CARGO_PKG_DESCRIPTION"));
|
||||
let sub_info =
|
||||
clap_app!(@subcommand info =>
|
||||
(about: "Outputs debug info")
|
||||
(@group files =>
|
||||
(@attributes +required +multiple)
|
||||
(@arg map: -m --map [file]... {exists} "Loads a Map file")
|
||||
(@arg shp: -s --shp [file]... {exists} "Loads a Shapes file")
|
||||
(@arg snd: -n --snd [file]... {exists} "Loads a Sounds file")));
|
||||
|
||||
ap.add_option(&["-v", "--version"],
|
||||
Print(concat!(env!("CARGO_PKG_NAME"),
|
||||
" ",
|
||||
env!("CARGO_PKG_VERSION")).to_string()),
|
||||
"Show the version");
|
||||
let opt =
|
||||
clap_app!((env!("CARGO_PKG_NAME")) =>
|
||||
(version: env!("CARGO_PKG_VERSION"))
|
||||
(author: env!("CARGO_PKG_AUTHORS"))
|
||||
(about: env!("CARGO_PKG_DESCRIPTION"))
|
||||
(setting: clap::AppSettings::SubcommandRequiredElseHelp)
|
||||
(subcommand: sub_data)
|
||||
(subcommand: sub_dump)
|
||||
(subcommand: sub_info));
|
||||
|
||||
ap.refer(&mut opt.inputs)
|
||||
.add_argument("inputs", Collect, "Input files");
|
||||
let opt = opt.get_matches();
|
||||
|
||||
arg!("--shp-write-tab",
|
||||
opt.shp_tab,
|
||||
StoreTrue,
|
||||
"shp: Dump all CLUTs as YAML to standard output");
|
||||
|
||||
arg!("--shp-dump-bitmaps",
|
||||
opt.shp_bmp,
|
||||
StoreTrue,
|
||||
"shp: Dump bitmaps into a folder");
|
||||
|
||||
arg!("--shp-dump-more-bitmaps",
|
||||
opt.shp_bmp_all,
|
||||
StoreTrue,
|
||||
"shp: Dump all color variations of each bitmap");
|
||||
|
||||
arg!("--shp-write-frm",
|
||||
opt.shp_frm,
|
||||
StoreTrue,
|
||||
"shp: Dump all frames as YAML to standard output");
|
||||
|
||||
arg!("--shp-write-seq",
|
||||
opt.shp_seq,
|
||||
StoreTrue,
|
||||
"shp: Dump all sequences as YAML to standard output");
|
||||
|
||||
arg!("--snd-dump",
|
||||
opt.snd_dump,
|
||||
StoreTrue,
|
||||
"snd: Dump all sounds to WAVE files");
|
||||
|
||||
arg!("--out-dir",
|
||||
opt.out_dir,
|
||||
Store,
|
||||
"Sets output directory for dump options");
|
||||
|
||||
arg!("--out-debug",
|
||||
opt.out_debug,
|
||||
StoreTrue,
|
||||
"Writes debugging output rather than YAML");
|
||||
|
||||
ap.parse_args_or_exit();
|
||||
}
|
||||
|
||||
if opt.shp_bmp_all {
|
||||
opt.shp_bmp = true;
|
||||
}
|
||||
|
||||
if opt.out_dir.is_empty() {
|
||||
opt.out_dir = ".".to_string();
|
||||
}
|
||||
|
||||
validate_folder_path(&opt.out_dir)?;
|
||||
|
||||
for arg in &opt.inputs {
|
||||
let (typ, fna) = if let Some(st) = arg.find(':') {
|
||||
arg.split_at(st + 1)
|
||||
} else {
|
||||
("wad:", arg.as_str())
|
||||
};
|
||||
|
||||
let fp = fs::File::open(fna)?;
|
||||
let mm = unsafe {memmap::Mmap::map(&fp)?};
|
||||
let b = &mm[machdr::try_mac_header(&mm)..];
|
||||
|
||||
match typ {
|
||||
"wad:" => process_wad(&opt, b),
|
||||
"shp:" => process_shp(&opt, b),
|
||||
"snd:" => process_snd(&opt, b),
|
||||
"ppm:" => process_ppm(&opt, b),
|
||||
_ => Err(err_msg("invalid file type specified on commandline")),
|
||||
}?;
|
||||
match opt.subcommand() {
|
||||
("data", Some(opt)) => sub_data_c(opt)?,
|
||||
("dump", Some(opt)) => sub_dump_c(opt)?,
|
||||
("info", Some(opt)) => sub_info_c(opt)?,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct Options
|
||||
{
|
||||
inputs: Vec<String>,
|
||||
out_dir: String,
|
||||
out_debug: bool,
|
||||
shp_tab: bool,
|
||||
shp_bmp: bool,
|
||||
shp_bmp_all: bool,
|
||||
shp_frm: bool,
|
||||
shp_seq: bool,
|
||||
snd_dump: bool,
|
||||
}
|
||||
|
||||
// EOF
|
||||
|
|
Loading…
Reference in New Issue