// ▄████████▄ + ███ + ▄█████████ ███ + // ███▀ ▀███ + + ███ ███▀ + ███ + + // ███ + ███ ███ ███ █████████ ███ ███ ███ ███ // ███ +███ ███ ███ ███ ███▐██████ ███ ███ ███ // ███ + ███ ███+ ███ +███ ███ + ███ ███ + ███ // ███▄ ▄███ ███▄ ███ ███ + ███ + ███ ███▄ ███ // ▀████████▀ + ▀███████ ███▄ ███▄ ▀████ ▀███████ // + + + ███ // + ▀████████████████████████████████████████████████████▀ // // This module manages the messy, impure parts of our universe. use bevy::math::DVec3; use std::f64::consts::PI as PI64; pub const OXYGEN_USE_KG_PER_S: f32 = 1e-5; pub const OXY_S: f32 = OXYGEN_USE_KG_PER_S; pub const OXY_M: f32 = OXYGEN_USE_KG_PER_S * 60.0; pub const OXY_H: f32 = OXYGEN_USE_KG_PER_S * 60.0 * 60.0; pub const OXY_D: f32 = OXYGEN_USE_KG_PER_S * 60.0 * 60.0 * 24.0; pub const LIGHTYEAR2METER: f64 = 9_460_730_472_580_800.0; pub const PARSEC2METER: f64 = 3.0857e16; pub const DIST_JUPTER_SUN: f64 = 778479.0e6; pub const EARTH_GRAVITY: f32 = 9.81; pub const C: f64 = 299792458.0; // m/s pub const G: f64 = 6.6743015e-11; // Gravitational constant in Nm²/kg² pub const SOL_RADIUS: f64 = 696_300_000.0; pub const JUPITER_RADIUS: f64 = 71_492_000.0; pub const JUPITER_RING_RADIUS: f64 = 229_000_000.0; pub const SOL_MASS: f64 = 1.9885e30; pub const JUPITER_MASS: f64 = 1.8982e27; // Each star's values: (x, y, z, magnitude, color index, distance, name) pub const STARS: &[(f32, f32, f32, f32, f32, f32, &str)] = &include!("data/stars.in"); pub fn star_color_index_to_rgb(color_index: f32) -> (f32, f32, f32) { let temperature = 4600.0 * ((1.0 / (0.92 * color_index + 1.7)) + (1.0 / (0.92 * color_index + 0.62))); let (red, green, blue) = if temperature <= 6600.0 { let red = 255.0; let green = 99.4708025861 * (temperature / 100.0).ln() - 161.1195681661; let blue = if temperature <= 2000.0 { 0.0 } else { 138.5177312231 * ((temperature / 100.0) - 10.0).ln() - 305.0447927307 }; (red, green, blue) } else { let red = 329.698727446 * ((temperature / 100.0 - 60.0).powf(-0.1332047592)); let green = 288.1221695283 * ((temperature / 100.0 - 60.0).powf(-0.0755148492)); let blue = 255.0; (red, green, blue) }; let clamp = |x: f32| -> f32 { (x / 255.0).max(0.0).min(1.0) }; return (clamp(red), clamp(green), clamp(blue)) } fn smooth_edge(start: f32, end: f32, value: f32) -> f32 { let x: f32 = (value - start) / (end - start); return 4.0 * x * x * (1.0 - x * x); } pub fn ring_density(radius: f32) -> f32 { // NOTE: Keep this in sync with assets/shaders/jupiters_rings.wgsl // Input: distance to center of jupiter in million meters // Output: relative brightness of the ring let halo_inner: f32 = 92.0; let halo_outer: f32 = 122.5; let main_inner: f32 = 122.5; let main_outer: f32 = 129.0; let amalthea_inner: f32 = 129.0; let amalthea_outer: f32 = 182.0; let thebe_inner: f32 = 129.0; let thebe_outer: f32 = 229.0; let metis_notch_center: f32 = 128.0; let metis_notch_width: f32 = 0.1; let halo_brightness: f32 = 0.75; let main_brightness: f32 = 1.0; let almathea_brightness: f32 = 0.5; let thebe_brightness: f32 = 0.5; let mut density: f32 = 0.0; if radius >= halo_inner && radius <= halo_outer { density = halo_brightness * smooth_edge(halo_inner, halo_outer, radius); } else if radius >= main_inner && radius <= main_outer { let mut metis_notch_effect: f32 = 1.0; if radius > metis_notch_center - metis_notch_width * 0.5 && radius < metis_notch_center + metis_notch_width * 0.5 { metis_notch_effect = 0.8 * (1.0 - smooth_edge(metis_notch_center - metis_notch_width * 0.5, metis_notch_center + metis_notch_width * 0.5, radius)); } density = main_brightness * metis_notch_effect * smooth_edge(main_inner, main_outer, radius); } else { if radius >= amalthea_inner && radius <= amalthea_outer { density = almathea_brightness * smooth_edge(amalthea_inner, amalthea_outer, radius); } if radius >= thebe_inner && radius <= thebe_outer { density += thebe_brightness * smooth_edge(thebe_inner, thebe_outer, radius); } } return density; } pub fn readable_distance(distance: f64) -> String { let abs_distance = distance.abs(); if abs_distance > LIGHTYEAR2METER * 0.01 { let lightyears = distance / LIGHTYEAR2METER; return format!("{lightyears:.2} ly"); } if abs_distance >= 1.0e10 { let gigameters = distance * 1.0e-9; return format!("{gigameters:.1}Gm"); } if abs_distance >= 1.0e7 { let megameters = distance * 1.0e-6; return format!("{megameters:.1}Mm"); } if abs_distance >= 1.0e4 { let kilometers = distance * 1.0e-3; return format!("{kilometers:.1}km"); } return format!("{distance:.1}m"); } pub fn readable_speed(speed: f64) -> String { let abs = speed.abs(); if abs > C * 0.0005 { let lightyears = abs / C; return format!("{lightyears:.4} c"); } else { let kmh = abs * 1.0e-3 * 3600.0; return format!("{kmh:.0} km/h"); } } pub fn lorenz_factor(speed: f64) -> f64 { (1.0 - (speed.powf(2.0) / C.powf(2.0))).sqrt() } pub fn lorenz_factor_custom_c(speed: f64, c: f64) -> f64 { (1.0 - (speed.powf(2.0) / c.powf(2.0))).sqrt() } pub fn simple_orbital_period(mass: f64, distance: f64) -> f64 { return 2.0 * PI64 * (distance.powf(3.0) / (G * mass)).sqrt(); } pub fn phase_dist_to_coords(phase_radians: f64, distance: f64) -> DVec3 { return DVec3::new( distance * phase_radians.cos(), 0.0, distance * phase_radians.sin(), ); }