feat: add clap CLI arg parser, replacing MANDEL_* debug env vars
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,7 @@ png = "0.18.1"
|
|||||||
|
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
env_logger = "0.11.11"
|
env_logger = "0.11.11"
|
||||||
|
clap = { version = "4.5.51", features = ["derive"] }
|
||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
futures-channel = { version = "0.3.34", default-features = false, features = ["alloc", "std"] }
|
futures-channel = { version = "0.3.34", default-features = false, features = ["alloc", "std"] }
|
||||||
|
|||||||
+26
-26
@@ -4,6 +4,8 @@ use eframe::CreationContext;
|
|||||||
use eframe::egui_wgpu;
|
use eframe::egui_wgpu;
|
||||||
use eframe::egui_wgpu::wgpu;
|
use eframe::egui_wgpu::wgpu;
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
use crate::cli::Cli;
|
||||||
use crate::fractal::{
|
use crate::fractal::{
|
||||||
BuddhabrotCallback, BuddhabrotRenderer, BuddhabrotUniforms, ExportRender, FractalCallback,
|
BuddhabrotCallback, BuddhabrotRenderer, BuddhabrotUniforms, ExportRender, FractalCallback,
|
||||||
FractalKind, FractalRenderer, MAX_REF_POINTS, ShareState, Uniforms,
|
FractalKind, FractalRenderer, MAX_REF_POINTS, ShareState, Uniforms,
|
||||||
@@ -15,6 +17,8 @@ use crate::view::{
|
|||||||
Big, DEFAULT_HALF_HEIGHT, ViewState, big_from_decimal_str, big_from_f64, big_to_decimal_str,
|
Big, DEFAULT_HALF_HEIGHT, ViewState, big_from_decimal_str, big_from_f64, big_to_decimal_str,
|
||||||
precision_for,
|
precision_for,
|
||||||
};
|
};
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
use clap::Parser;
|
||||||
|
|
||||||
const BAILOUT_SQ: f32 = 1.0e6;
|
const BAILOUT_SQ: f32 = 1.0e6;
|
||||||
/// Cap on exported image dimension (px), to stay within GPU texture limits.
|
/// Cap on exported image dimension (px), to stay within GPU texture limits.
|
||||||
@@ -338,6 +342,9 @@ pub struct FractalApp {
|
|||||||
export_requested: bool,
|
export_requested: bool,
|
||||||
/// Progress/handle for an in-flight PNG export, if any.
|
/// Progress/handle for an in-flight PNG export, if any.
|
||||||
export: Option<Arc<Mutex<ExportShared>>>,
|
export: Option<Arc<Mutex<ExportShared>>>,
|
||||||
|
/// Output path for `--export` (native CLI only); falls back to a
|
||||||
|
/// timestamped name when unset.
|
||||||
|
export_path: Option<String>,
|
||||||
/// Short status line (saved path, "link copied", errors).
|
/// Short status line (saved path, "link copied", errors).
|
||||||
status: Option<String>,
|
status: Option<String>,
|
||||||
|
|
||||||
@@ -442,6 +449,7 @@ impl FractalApp {
|
|||||||
last_interact_time: -1.0e9,
|
last_interact_time: -1.0e9,
|
||||||
export_requested: false,
|
export_requested: false,
|
||||||
export: None,
|
export: None,
|
||||||
|
export_path: None,
|
||||||
status: None,
|
status: None,
|
||||||
center_re_edit,
|
center_re_edit,
|
||||||
center_im_edit,
|
center_im_edit,
|
||||||
@@ -457,28 +465,19 @@ impl FractalApp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug/testing hooks.
|
// Debug/testing hooks, driven by CLI flags.
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
{
|
{
|
||||||
if let Ok(k) = std::env::var("MANDEL_KIND") {
|
let cli = Cli::parse();
|
||||||
app.kind = match k.trim().to_ascii_lowercase().as_str() {
|
|
||||||
"burningship" | "burning_ship" | "ship" => FractalKind::BurningShip,
|
if let Some(k) = cli.kind {
|
||||||
"tricorn" | "mandelbar" => FractalKind::Tricorn,
|
app.kind = k.into();
|
||||||
"multibrot" | "multi" => FractalKind::Multibrot,
|
if let Some(p) = cli.power {
|
||||||
"celtic" => FractalKind::Celtic,
|
|
||||||
"perpendicular" | "perp" => FractalKind::Perpendicular,
|
|
||||||
"buffalo" => FractalKind::Buffalo,
|
|
||||||
"phoenix" => FractalKind::Phoenix,
|
|
||||||
_ => FractalKind::Mandelbrot,
|
|
||||||
};
|
|
||||||
if let Ok(p) = std::env::var("MANDEL_POWER")
|
|
||||||
&& let Ok(p) = p.trim().parse::<u32>()
|
|
||||||
{
|
|
||||||
app.power = p.clamp(2, 8);
|
app.power = p.clamp(2, 8);
|
||||||
}
|
}
|
||||||
app.view = Self::default_view_for(app.mode, app.kind);
|
app.view = Self::default_view_for(app.mode, app.kind);
|
||||||
}
|
}
|
||||||
if let Ok(jc) = std::env::var("MANDEL_JULIA") {
|
if let Some(jc) = cli.julia {
|
||||||
let p: Vec<&str> = jc.split(',').collect();
|
let p: Vec<&str> = jc.split(',').collect();
|
||||||
if let (Some(Ok(re)), Some(Ok(im))) = (
|
if let (Some(Ok(re)), Some(Ok(im))) = (
|
||||||
p.first().map(|s| s.trim().parse::<f64>()),
|
p.first().map(|s| s.trim().parse::<f64>()),
|
||||||
@@ -489,26 +488,25 @@ impl FractalApp {
|
|||||||
app.view = Self::default_view_for(FractalMode::Julia, app.kind);
|
app.view = Self::default_view_for(FractalMode::Julia, app.kind);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Ok(frag) = std::env::var("MANDEL_SHARE")
|
if let Some(frag) = cli.share
|
||||||
&& let Some(state) = ShareState::decode(&frag)
|
&& let Some(state) = ShareState::decode(&frag)
|
||||||
{
|
{
|
||||||
app.apply_share(&state);
|
app.apply_share(&state);
|
||||||
}
|
}
|
||||||
if let Ok(spec) = std::env::var("MANDEL_VIEW") {
|
if let Some(spec) = cli.view {
|
||||||
app.apply_view_spec(&spec);
|
app.apply_view_spec(&spec);
|
||||||
}
|
}
|
||||||
if std::env::var("MANDEL_DE").is_ok() {
|
if cli.de {
|
||||||
app.de_coloring = true;
|
app.de_coloring = true;
|
||||||
}
|
}
|
||||||
if std::env::var("MANDEL_BUDDHABROT").is_ok() {
|
if cli.buddhabrot {
|
||||||
app.buddhabrot = true;
|
app.buddhabrot = true;
|
||||||
}
|
}
|
||||||
if let Ok(p) = std::env::var("MANDEL_BUDDHA_PALETTE")
|
if let Some(p) = cli.buddha_palette {
|
||||||
&& let Ok(p) = p.trim().parse::<u32>()
|
|
||||||
{
|
|
||||||
app.buddha_palette = p.min(BUDDHA_PALETTE_NAMES.len() as u32 - 1);
|
app.buddha_palette = p.min(BUDDHA_PALETTE_NAMES.len() as u32 - 1);
|
||||||
}
|
}
|
||||||
if std::env::var("MANDEL_EXPORT").is_ok() {
|
app.export_path = cli.export_path;
|
||||||
|
if cli.export {
|
||||||
app.export_requested = true;
|
app.export_requested = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -912,8 +910,10 @@ impl FractalApp {
|
|||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
{
|
{
|
||||||
let name = std::env::var("MANDEL_EXPORT_PATH")
|
let name = self
|
||||||
.unwrap_or_else(|_| format!("fractal-{}.png", unix_timestamp()));
|
.export_path
|
||||||
|
.clone()
|
||||||
|
.unwrap_or_else(|| format!("fractal-{}.png", unix_timestamp()));
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let er = ExportRender::new(
|
let er = ExportRender::new(
|
||||||
&device,
|
&device,
|
||||||
|
|||||||
+84
@@ -0,0 +1,84 @@
|
|||||||
|
// Native command-line arguments. Currently mirrors the old `MANDEL_*` debug
|
||||||
|
// env vars one-for-one; this is the foundation a future headless (no-window,
|
||||||
|
// render-to-file) mode will build on.
|
||||||
|
|
||||||
|
use clap::{Parser, ValueEnum};
|
||||||
|
|
||||||
|
use crate::fractal::FractalKind;
|
||||||
|
|
||||||
|
#[derive(Parser, Debug, Default)]
|
||||||
|
#[command(name = "mandelbrot", about = "Deep-zoom fractal explorer", version)]
|
||||||
|
pub struct Cli {
|
||||||
|
/// Fractal formula to render.
|
||||||
|
#[arg(long, value_enum)]
|
||||||
|
pub kind: Option<KindArg>,
|
||||||
|
|
||||||
|
/// Exponent for the Multibrot kind (z -> z^power + c), clamped to [2, 8].
|
||||||
|
#[arg(long)]
|
||||||
|
pub power: Option<u32>,
|
||||||
|
|
||||||
|
/// Start in Julia mode with this seed constant.
|
||||||
|
#[arg(long, value_name = "RE,IM")]
|
||||||
|
pub julia: Option<String>,
|
||||||
|
|
||||||
|
/// Restore a view from a share-link fragment (the part after '#').
|
||||||
|
#[arg(long, value_name = "FRAGMENT")]
|
||||||
|
pub share: Option<String>,
|
||||||
|
|
||||||
|
/// Jump to a view on startup.
|
||||||
|
#[arg(long, value_name = "RE,IM,HALF_HEIGHT[,ITERATIONS]")]
|
||||||
|
pub view: Option<String>,
|
||||||
|
|
||||||
|
/// Enable distance-estimation shading.
|
||||||
|
#[arg(long)]
|
||||||
|
pub de: bool,
|
||||||
|
|
||||||
|
/// Switch to the Buddhabrot renderer.
|
||||||
|
#[arg(long)]
|
||||||
|
pub buddhabrot: bool,
|
||||||
|
|
||||||
|
/// Buddhabrot tonemap palette index.
|
||||||
|
#[arg(long, value_name = "INDEX")]
|
||||||
|
pub buddha_palette: Option<u32>,
|
||||||
|
|
||||||
|
/// Render a PNG export on startup.
|
||||||
|
#[arg(long)]
|
||||||
|
pub export: bool,
|
||||||
|
|
||||||
|
/// Output path for --export (default: fractal-<timestamp>.png).
|
||||||
|
#[arg(long, value_name = "PATH")]
|
||||||
|
pub export_path: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, ValueEnum)]
|
||||||
|
pub enum KindArg {
|
||||||
|
Mandelbrot,
|
||||||
|
#[value(alias = "ship")]
|
||||||
|
BurningShip,
|
||||||
|
#[value(alias = "mandelbar")]
|
||||||
|
Tricorn,
|
||||||
|
#[value(alias = "multi")]
|
||||||
|
Multibrot,
|
||||||
|
Celtic,
|
||||||
|
#[value(alias = "perp")]
|
||||||
|
Perpendicular,
|
||||||
|
Buffalo,
|
||||||
|
Phoenix,
|
||||||
|
Lambda,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<KindArg> for FractalKind {
|
||||||
|
fn from(k: KindArg) -> Self {
|
||||||
|
match k {
|
||||||
|
KindArg::Mandelbrot => FractalKind::Mandelbrot,
|
||||||
|
KindArg::BurningShip => FractalKind::BurningShip,
|
||||||
|
KindArg::Tricorn => FractalKind::Tricorn,
|
||||||
|
KindArg::Multibrot => FractalKind::Multibrot,
|
||||||
|
KindArg::Celtic => FractalKind::Celtic,
|
||||||
|
KindArg::Perpendicular => FractalKind::Perpendicular,
|
||||||
|
KindArg::Buffalo => FractalKind::Buffalo,
|
||||||
|
KindArg::Phoenix => FractalKind::Phoenix,
|
||||||
|
KindArg::Lambda => FractalKind::Lambda,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-1
@@ -9,10 +9,12 @@
|
|||||||
// and calls the wasm `main`, which boots eframe onto the page's <canvas>.
|
// and calls the wasm `main`, which boots eframe onto the page's <canvas>.
|
||||||
|
|
||||||
mod app;
|
mod app;
|
||||||
mod lights;
|
|
||||||
mod fractal;
|
mod fractal;
|
||||||
|
mod lights;
|
||||||
mod view;
|
mod view;
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
mod cli;
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
mod worker;
|
mod worker;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user