#[cfg(any(feature = "cli", feature = "ui"))]
use std::path::PathBuf;
#[cfg(feature = "ui")]
use crate::ui::viewer::run_native::run_native;
#[cfg(feature = "cli")]
use {
crate::cli::command::to_blp::to_blp,
crate::cli::command::to_png::to_png,
crate::core::image::MAX_MIPS,
crate::error::error::BlpError,
clap::{Parser, Subcommand, error::ErrorKind},
};
#[cfg(all(feature = "ui", not(feature = "cli")))]
compile_error!("Feature 'ui' requires 'cli'. Use either `--features \"cli\"` or `--features \"ui cli\"`. ");
#[cfg(feature = "cli")]
#[derive(Debug, Subcommand)]
enum Command {
ToBlp {
input: PathBuf,
output: Option<PathBuf>,
#[arg(long = "mips", value_parser = clap::value_parser!(u8).range(1..=16))]
mips: Vec<u8>,
#[arg(long = "mips-limit", value_parser = clap::value_parser!(u8).range(1..=16))]
mips_limit: Option<u8>,
#[arg(short = 'q', long = "quality", default_value_t = 100, value_parser = clap::value_parser!(u8).range(1..=100))]
quality: u8,
},
ToPng {
input: PathBuf,
output: Option<PathBuf>,
},
}
#[cfg(feature = "cli")]
#[derive(Debug, Parser)]
#[cfg_attr(all(feature = "cli", not(feature = "ui")), command(name = "blp", version, about = "BLP ↔ PNG converter", long_about = "blp is a command-line utility for converting Warcraft III textures between BLP and PNG formats.", override_usage = "blp [PATH]\nblp <COMMAND>"))]
#[cfg_attr(all(feature = "cli", feature = "ui"), command(name = "blp", version, about = "BLP ↔ PNG converter and simple viewer for Warcraft III textures", long_about = "blp is a command-line utility for converting Warcraft III textures between BLP and PNG formats. It can also launch a native GUI viewer.", override_usage = "blp [PATH]\nblp <COMMAND>"))]
struct Cli {
#[arg(value_name = "PATH")]
path: Option<PathBuf>,
#[command(subcommand)]
command: Option<Command>,
}
#[cfg(feature = "cli")]
fn run_cli_command(cmd: Command) -> Result<(), BlpError> {
match cmd {
Command::ToBlp { input, output, mips, mips_limit, quality } => {
let mut mip_visible = vec![true; MAX_MIPS];
if !mips.is_empty() {
for (i, &val) in mips.iter().enumerate() {
if i < MAX_MIPS {
mip_visible[i] = val != 0;
}
}
}
if let Some(limit) = mips_limit {
let limit = limit as usize;
for i in limit..MAX_MIPS {
mip_visible[i] = false;
}
}
to_blp(&input, output.as_ref(), quality, &mip_visible)
}
Command::ToPng { input, output } => to_png(&input, output.as_ref()),
}
}
#[cfg(all(feature = "cli", not(feature = "ui")))]
fn sanity_decode_or_exit(path: PathBuf) -> ! {
use crate::core::image::ImageBlp;
use std::fs;
let data = match fs::read(&path) {
Ok(b) => b,
Err(e) => {
eprintln!("read error: {e}");
std::process::exit(3);
}
};
if let Err(e) = ImageBlp::from_buf(&data) {
eprintln!("{e}");
std::process::exit(3);
}
std::process::exit(0);
}
#[cfg(any(feature = "cli", feature = "ui"))]
pub fn run() -> Result<(), BlpError> {
let Some(cli) = (match Cli::try_parse() {
Ok(cli) => Some(cli),
Err(e) => {
match e.kind() {
ErrorKind::DisplayHelp | ErrorKind::DisplayVersion => {
let _ = e.print(); None
}
_ => {
let _ = e.print();
std::process::exit(e.exit_code()); }
}
}
}) else {
return Ok(());
};
#[cfg(all(feature = "cli", feature = "ui"))]
{
return if let Some(cmd) = cli.command { run_cli_command(cmd) } else { run_native(cli.path) };
}
#[cfg(all(feature = "cli", not(feature = "ui")))]
{
match (cli.path, cli.command) {
(Some(p), None) => {
sanity_decode_or_exit(p);
}
(None, Some(cmd)) => run_cli_command(cmd),
(Some(_), Some(cmd)) => run_cli_command(cmd),
(None, None) => {
eprintln!("error: a PATH or a subcommand is required\n\nUse --help for more information.");
std::process::exit(2);
}
}
}
}