use std::env; fn main() { let args: Vec<_> = env::args().skip(1).collect(); if args.is_empty() { println!("specify kernel radius, eg:"); println!("cargo run 16 > ../Assets/automata/Lenia/lenia_generated_kernel.cginc"); return; } let radius = args[0].parse().unwrap(); let k_offset = 0.435; let k_sharpness = 28.0; let precision = 50.0; // for rounding let mut img = image::RgbImage::new(radius * 2 + 1, radius * 2 + 1); let mut total_max = 0.0; let mut total_lookups = 0; println!("// generated by the rust program"); println!("#define RADIUS {}", radius); println!("const half Kernel[{}][{}] = {{", radius + 1, radius); for y in 0..=radius { print!(" {{"); for x in 1..=radius { let k = (k(x, y, radius, k_offset, k_sharpness) * precision).floor() / precision; total_max += k * 4.0; if k > 0.0 { total_lookups += 1; } print!("{:.2}, ", k); { let pixel = image::Rgb([0, (k * 255.0) as u8, 0]); // let cx = radius img.put_pixel(radius + x, radius + y, pixel); img.put_pixel(radius - y, radius + x, pixel); img.put_pixel(radius - x, radius - y, pixel); img.put_pixel(radius + y, radius - x, pixel); } } println!("}},"); } println!("}};"); println!("const float total_max = {};", total_max); println!( "// Total texture lookups: {} * 4 + 1 = {}", total_lookups, total_lookups * 4 + 1 ); println!("// (lookups multiplied by 0.0 get optimised away by the shader compiler, and this giant table generally only exists at compile time)"); img.save("kernel.png").unwrap(); } fn k(x: u32, y: u32, radius: u32, k_offset: f32, k_sharpness: f32) -> f32 { let x = x as f32; let y = y as f32; let r = (x * x + y * y).sqrt() / radius as f32; f32::exp(-((r - k_offset) * (r - k_offset)) * k_sharpness) // lenia paper example kernel // if r < 1.0 { // f32::exp(4.0 - 4.0 / (4.0 * r * (1.0 - r))) // } else { // 0.0 // } }