marss 0.0.1

Mars celestial simulation crate for the MilkyWay SolarSystem workspace
Documentation
use marss::rendering::atmosphere_scattering::*;
use marss::rendering::dust_rendering::*;
use marss::rendering::materials::*;
use marss::rendering::shaders::*;
use marss::rendering::sky::*;

// === Atmosphere Scattering ===

#[test]
fn atmosphere_params_default() {
    let p = MarsAtmosphereParams::default();
    assert!(p.planet_radius > 0.0);
    assert!(p.atmosphere_height > 0.0);
}

#[test]
fn rayleigh_density_decreases_with_alt() {
    let p = MarsAtmosphereParams::default();
    let d0 = p.rayleigh_density(0.0);
    let d10 = p.rayleigh_density(10_000.0);
    assert!(d0 > d10, "Rayleigh decreases: {d0} > {d10}");
}

#[test]
fn dust_density_method() {
    let p = MarsAtmosphereParams::default();
    let d = p.dust_density(0.0);
    assert!(d >= 0.0, "Dust density >= 0: {d}");
}

#[test]
fn sky_color_rgb_range() {
    let p = MarsAtmosphereParams::default();
    let c = p.sky_color(45.0);
    assert!(c[0] >= 0.0 && c[0] <= 1.0);
    assert!(c[1] >= 0.0 && c[1] <= 1.0);
    assert!(c[2] >= 0.0 && c[2] <= 1.0);
}

#[test]
fn direct_transmission_decreases_with_airmass() {
    let p = MarsAtmosphereParams::default();
    let t90 = p.direct_transmission(90.0);
    let t30 = p.direct_transmission(30.0);
    assert!(
        t90 >= t30,
        "Higher elev = more transmission: {t90} vs {t30}"
    );
}

#[test]
fn direct_transmission_bounded() {
    let p = MarsAtmosphereParams::default();
    let t = p.direct_transmission(45.0);
    assert!(t >= 0.0 && t <= 1.0, "Transmission in [0,1]: {t}");
}

#[test]
fn rayleigh_beta_rgb_values() {
    let b = rayleigh_beta_rgb();
    assert!(b[0] > 0.0 && b[1] > 0.0 && b[2] > 0.0);
}

// === Dust Rendering ===

#[test]
fn dust_layer_background_od() {
    let d = DustLayer::background();
    assert!(d.optical_depth > 0.0 && d.optical_depth < 2.0);
}

#[test]
fn dust_layer_global_storm_higher() {
    let d = DustLayer::global_storm();
    let bg = DustLayer::background();
    assert!(d.optical_depth > bg.optical_depth);
}

#[test]
fn density_at_altitude_decreases() {
    let d = DustLayer::background();
    let d0 = d.density_at_altitude(0.0);
    let d10 = d.density_at_altitude(10_000.0);
    assert!(d0 > d10, "Density decreases: {d0} vs {d10}");
}

#[test]
fn surface_solar_fraction_bounded() {
    let d = DustLayer::background();
    let f = d.surface_solar_fraction();
    assert!(f > 0.0 && f <= 1.0, "Solar fraction: {f}");
}

#[test]
fn phase_function_forward_scatter() {
    let d = DustLayer::background();
    let pf = d.phase_function(1.0);
    let pb = d.phase_function(-1.0);
    assert!(pf > pb, "Forward > backward");
}

#[test]
fn effective_dust_radius() {
    let r = effective_dust_radius_um();
    assert!(r > 0.0, "Dust radius: {r}");
}

#[test]
fn dust_color_values() {
    let c = dust_color_linear();
    assert!(c[0] >= 0.0 && c[1] >= 0.0 && c[2] >= 0.0);
}

// === Materials ===

#[test]
fn regolith_material_check() {
    let m = regolith();
    assert!(m.albedo[0] >= 0.0 && m.albedo[0] <= 1.0);
    assert!(m.roughness > 0.0);
}

#[test]
fn bright_dust_brighter_than_dark_dune() {
    let bright = bright_dust();
    let dark = dark_dune();
    let ba = (bright.albedo[0] + bright.albedo[1] + bright.albedo[2]) / 3.0;
    let da = (dark.albedo[0] + dark.albedo[1] + dark.albedo[2]) / 3.0;
    assert!(ba > da);
}

#[test]
fn basalt_material_check() {
    let m = basalt();
    assert!(m.roughness > 0.0);
    assert!(m.metallic >= 0.0 && m.metallic <= 1.0);
}

#[test]
fn water_ice_high_albedo() {
    let m = water_ice();
    let avg = (m.albedo[0] + m.albedo[1] + m.albedo[2]) / 3.0;
    assert!(avg > 0.4, "Ice albedo high: {avg}");
}

#[test]
fn co2_ice_smooth() {
    let m = co2_ice();
    assert!(m.roughness < 0.5, "Ice smooth: {}", m.roughness);
}

#[test]
fn sulfate_salt_check() {
    let m = sulfate_salt();
    assert!(m.albedo[0] >= 0.0);
}

#[test]
fn volcanic_summit_check() {
    let m = volcanic_summit();
    assert!(m.roughness > 0.0);
}

// === Shaders ===

#[test]
fn terrain_shader() {
    let s = terrain();
    assert!(!s.name.is_empty());
    assert!(!s.uniforms.is_empty());
}

#[test]
fn atmosphere_shader() {
    let s = atmosphere();
    assert!(!s.name.is_empty());
}

#[test]
fn dust_storm_shader() {
    let s = dust_storm();
    assert!(!s.uniforms.is_empty());
}

// === Sky ===

#[test]
fn sky_state_zenith_color() {
    let s = SkyState::new(45.0, 0.3);
    let c = s.zenith_color();
    assert!(c[0] >= 0.0 && c[0] <= 1.0);
}

#[test]
fn sky_state_sunset_color() {
    let s = SkyState::new(5.0, 0.3);
    let c = s.sunset_color();
    assert!(c[2] > c[0], "Mars sunset blue > red");
}

#[test]
fn sky_state_horizon_glow() {
    let s = SkyState::new(2.0, 0.5);
    let g = s.horizon_glow();
    assert!(g > 0.0, "Horizon glow > 0 near sunset");
}

#[test]
fn sky_state_night() {
    let s = SkyState::new(-20.0, 0.3);
    let c = s.zenith_color();
    let brightness = c[0] + c[1] + c[2];
    assert!(brightness < 0.5, "Night sky dim: {brightness}");
}