use clap::CommandFactory;
use clap::{Parser, Subcommand};
use tessera::tileset::writer::write_tileset;
use tracing::{Level, info};
use tracing_subscriber::FmtSubscriber;
use tessera::calculate_geometric_error;
use tessera::error::TesseraError;
#[derive(Parser)]
#[command(
name = "tessera",
about = "A command line interface for calculating geometric error for 3D Tiles tilesets",
version,
long_about = "Tessera is a CLI tool to traverse a 3D Tiles tileset and calculate a correct geometric error for each tile."
)]
struct Cli {
#[command(subcommand)]
command: Option<Commands>,
#[arg(short, long, global = true)]
debug: bool,
#[arg(short, long, global = true)]
verbose: bool,
}
#[derive(Subcommand)]
enum Commands {
Recalculate {
#[arg(short('i'), long("input"), value_name = "PATH")]
tileset: String,
#[arg(short('o'), long("output"), value_name = "PATH")]
output: String,
#[arg(short('p'), long("pretty"), action = clap::ArgAction::SetTrue)]
pretty: Option<bool>,
},
}
#[tokio::main]
async fn main() -> Result<(), TesseraError> {
let cli = Cli::parse();
let log_level = if cli.debug {
Level::DEBUG
} else if cli.verbose {
Level::INFO
} else {
Level::WARN
};
FmtSubscriber::builder()
.with_max_level(log_level)
.with_target(false)
.with_thread_ids(false)
.with_thread_names(false)
.init();
info!("Starting Tessera CLI");
match cli.command {
Some(Commands::Recalculate {
tileset,
output,
pretty,
}) => {
use std::path::PathBuf;
use tessera::tileset::loader::load_tileset;
let tileset_path = PathBuf::from(&tileset);
let base_dir = tileset_path
.parent()
.unwrap_or_else(|| std::path::Path::new("."));
let mut doc = load_tileset(&tileset_path)?;
calculate_geometric_error(&mut doc, base_dir)?;
write_tileset(&doc, &PathBuf::from(&output), pretty.unwrap_or(false))?;
}
None => {
let mut cmd = Cli::command();
let _ = cmd.print_help();
eprintln!();
std::process::exit(2);
}
}
info!("Tessera CLI completed successfully");
return Ok(());
}