@@ -1050,11 +1050,11 @@ pub struct Args {
10501050 #[ arg(
10511051 long = "intensity-mapping" ,
10521052 value_name = "MODE" ,
1053- default_value = intensity_mapping:: DEFAULT_TYPE ,
1054- help = "Intensity-to-color mapping (linear, log, exp, sqrt, square, sigmoid, smoothstep, quantize, perlin, split)"
1053+ help = "Intensity-to-color mapping (linear, log, exp, sqrt, square, sigmoid, smoothstep, quantize, perlin, split) [default: per-preset, currently log]"
10551054 ) ]
10561055 /// Intensity mapping mode for non-linear color distribution.
1057- pub intensity_mapping : String ,
1056+ /// `None` means "use the per-preset render default" (see `RenderArtDefaults`).
1057+ pub intensity_mapping : Option < String > ,
10581058
10591059 #[ arg(
10601060 long = "intensity-mapping-base" ,
@@ -1771,11 +1771,20 @@ impl Args {
17711771 }
17721772 }
17731773
1774+ /// The intensity-mapping type string, falling back to the historical
1775+ /// default when the flag is absent. Used by paths that always need a
1776+ /// concrete mapping (e.g. the pause-logo "sim" passthrough).
1777+ fn intensity_mapping_str ( & self ) -> & str {
1778+ self . intensity_mapping
1779+ . as_deref ( )
1780+ . unwrap_or ( intensity_mapping:: DEFAULT_TYPE )
1781+ }
1782+
17741783 /// Parses the intensity mapping configuration.
17751784 pub fn intensity_mapping ( & self ) -> Result < crate :: render:: palette:: IntensityMapping , String > {
17761785 use crate :: render:: palette:: { IntensityMapping , MappingFunction } ;
17771786
1778- match self . intensity_mapping . to_lowercase ( ) . as_str ( ) {
1787+ match self . intensity_mapping_str ( ) . to_lowercase ( ) . as_str ( ) {
17791788 "linear" => Ok ( IntensityMapping :: linear ( ) ) ,
17801789 "log" | "logarithmic" => Ok ( IntensityMapping :: logarithmic ( self . intensity_mapping_base ) ) ,
17811790 "exp" | "exponential" => Ok ( IntensityMapping :: exponential ( self . intensity_mapping_base ) ) ,
@@ -1818,7 +1827,7 @@ impl Args {
18181827 ) ) ,
18191828 _ => Err ( format ! (
18201829 "Invalid intensity mapping: {}" ,
1821- self . intensity_mapping
1830+ self . intensity_mapping_str ( )
18221831 ) ) ,
18231832 }
18241833 }
@@ -1950,6 +1959,23 @@ impl Args {
19501959 SimConfig :: try_from ( self )
19511960 }
19521961
1962+ /// Resolves the render-layer art defaults: per-preset defaults overridden
1963+ /// by explicit intensity-mapping CLI flags. Render counterpart to
1964+ /// [`Args::to_sim_config`] (spec §5 — render params stay out of `SimConfig`).
1965+ /// When no preset is set, falls back to `RenderArtDefaults::default()` (log10).
1966+ pub ( crate ) fn to_render_art_defaults (
1967+ & self ,
1968+ ) -> Result < crate :: render_art_defaults:: RenderArtDefaults , String > {
1969+ let mut art = match self . preset {
1970+ Some ( preset) => crate :: render_art_defaults:: RenderArtDefaults :: from ( preset) ,
1971+ None => crate :: render_art_defaults:: RenderArtDefaults :: default ( ) ,
1972+ } ;
1973+ if self . intensity_mapping . is_some ( ) {
1974+ art. intensity_mapping = self . intensity_mapping ( ) ?;
1975+ }
1976+ Ok ( art)
1977+ }
1978+
19531979 /// Validates arguments at the CLI boundary.
19541980 ///
19551981 /// Covers terminal/resolution/fps bounds and other CLI-specific options that
@@ -2097,7 +2123,7 @@ impl Default for Args {
20972123 reverse_palette : false ,
20982124 invert_palette : false ,
20992125 palette_shift : 0.0 ,
2100- intensity_mapping : intensity_mapping :: DEFAULT_TYPE . to_string ( ) ,
2126+ intensity_mapping : None ,
21012127 intensity_mapping_base : intensity:: DEFAULT_LOG_BASE ,
21022128 intensity_mapping_gamma : 2.2 ,
21032129 intensity_mapping_levels : 8 ,
@@ -2785,4 +2811,42 @@ mod tests {
27852811 ) ;
27862812 assert ! ( DepositCurve :: from_str( "bogus" ) . is_err( ) ) ;
27872813 }
2814+
2815+ #[ test]
2816+ fn render_art_defaults_uses_preset_default_when_flag_absent ( ) {
2817+ use crate :: render:: palette:: IntensityMapping ;
2818+ let args = Args {
2819+ preset : Some ( crate :: simulation:: config:: Preset :: Vortex ) ,
2820+ intensity_mapping : None ,
2821+ ..Default :: default ( )
2822+ } ;
2823+ let art = args. to_render_art_defaults ( ) . unwrap ( ) ;
2824+ // #32: every preset defaults to log10.
2825+ assert_eq ! ( art. intensity_mapping, IntensityMapping :: logarithmic( 10.0 ) ) ;
2826+ }
2827+
2828+ #[ test]
2829+ fn render_art_defaults_cli_flag_overrides_preset ( ) {
2830+ use crate :: render:: palette:: IntensityMapping ;
2831+ let args = Args {
2832+ preset : Some ( crate :: simulation:: config:: Preset :: Vortex ) ,
2833+ intensity_mapping : Some ( "linear" . to_string ( ) ) ,
2834+ ..Default :: default ( )
2835+ } ;
2836+ let art = args. to_render_art_defaults ( ) . unwrap ( ) ;
2837+ assert_eq ! ( art. intensity_mapping, IntensityMapping :: linear( ) ) ;
2838+ }
2839+
2840+ #[ test]
2841+ fn render_art_defaults_none_preset_falls_back_to_default ( ) {
2842+ use crate :: render:: palette:: IntensityMapping ;
2843+ let args = Args {
2844+ preset : None ,
2845+ intensity_mapping : None ,
2846+ ..Default :: default ( )
2847+ } ;
2848+ let art = args. to_render_art_defaults ( ) . unwrap ( ) ;
2849+ // No preset + no flag → RenderArtDefaults::default() == log10.
2850+ assert_eq ! ( art. intensity_mapping, IntensityMapping :: logarithmic( 10.0 ) ) ;
2851+ }
27882852}
0 commit comments