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 precision = 100.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 float Kernel[{}][{}] = {{", radius + 1, radius);
	for y in 0..=radius {
		print!("	{{");
		for x in 1..=radius {
			let k = (k(x, y, radius) * 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) -> f32 {
	let x = x as f32;
	let y = y as f32;
	let r = (x * x + y * y).sqrt() / radius as f32;
	// let k_offset = 0.435;
	// let k_sharpness = 28.0;
	// 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
	}
}
