use fimg::DynImage;
use rand::Rng;
use std::fs::File;
use std::io::Write as _;
use std::iter::Iterator;
use std::path::Path;
use walkdir::WalkDir;
macro_rules! wr {
($dst:expr => $($arg:tt)*) => { writeln!($dst, $($arg)*).unwrap() };
}
fn kebab2bigsnek(kebab: &str) -> String {
let mut n = String::new();
n.reserve(kebab.len());
for c in kebab.chars() {
if c == '-' {
n.push('_');
} else {
n.push(c.to_ascii_uppercase());
}
}
n
}
fn main() {
let _ = std::fs::remove_dir_all("target/out");
let walkdir = WalkDir::new("assets");
println!("cargo:rerun-if-changed=assets/");
println!("cargo:rerun-if-changed=build.rs");
let o = std::env::var("OUT_DIR").unwrap();
let o = Path::new(&o);
let mut full = File::create(o.join("full.rs")).unwrap();
let mut quar = File::create(o.join("quar.rs")).unwrap();
let mut eigh = File::create(o.join("eigh.rs")).unwrap();
let mut n = 22usize;
wr!(full => "pub mod full {{");
wr!(full => "pub static EMPTY4: Image<&[u8], 4> = Image::make::<32, 32>();");
wr!(full => "pub static EMPTY: Image<&[u8], 3> = Image::make::<32, 32>();");
wr!(quar => "pub mod quar {{");
wr!(quar => "pub static EMPTY4: Image<&[u8], 4> = Image::make::<8, 8>();");
wr!(quar => "pub static EMPTY: Image<&[u8], 3> = Image::make::<8, 8>();");
wr!(eigh => "pub mod eigh {{");
wr!(eigh => "pub static EMPTY4: Image<&[u8], 4> = Image::make::<4, 4>();");
wr!(eigh => "pub static EMPTY: Image<&[u8], 3> = Image::make::<4, 4>();");
for mut file in [&full, &quar, &eigh] {
wr!(file => "use crate::utils::Image;");
wr!(file => "pub static CLIFF: Image<&[u8], 4> = EMPTY4.copy();");
for i in 1..=16 {
wr!(file => "pub static BUILD{}: Image<&[u8], 4> = EMPTY4.copy();", i);
}
}
for e in walkdir.into_iter().filter_map(Result::ok) {
let path = e.path();
if path.is_file()
&& let Some(e) = path.extension()
&& e == "png"
{
let mut p = DynImage::open(path);
let rgb = p.clone().to_rgba().chunked().all(|x| x[3] == 255);
if path
.file_name()
.unwrap()
.to_str()
.unwrap()
.contains("-liquid.png")
{
continue;
}
let f = path.file_name().unwrap().to_str().unwrap();
if f.contains("bottom")
|| f.contains("-team")
|| f.contains("-end")
|| f.contains("stack")
{
continue;
}
let env = path.components().any(|c| c.as_os_str() == "environment");
let path = kebab2bigsnek(
path.with_extension("")
.file_name()
.unwrap()
.to_str()
.unwrap(),
);
if matches!(
path.as_str(),
"CLIFF_CRUSHER_ROTATOR"
| "NEOPLASIA_REACTOR_CENTER"
| "FLUX_REACTOR_MID"
| "EDGE"
| "BRIDGE_ARROW"
| "LAUNCHPOD"
| "PLATED_CONDUIT_CAP"
) {
continue;
}
println!("do {path}");
macro_rules! writ {
($ext:ident / $scale:literal) => {
let mut buf = File::create(o.join(n.to_string() + "-" + stringify!($ext))).unwrap();
let out_path = format!("{}/{n}-{}", o.display(), stringify!($ext));
let (mx, my) = if env && p.width() + p.height() == 48+48 {
(32, 32)
} else if path.contains("_VENT")
|| matches!(path.as_str(), "YELLOWCORAL" | "WHITE_TREE" | "WHITE_TREE_DEAD" | "REDWEED" | "SPORE_CLUSTER" | "CRYSTAL_BLOCKS" | "CRYSTAL_CLUSTER" | "VIBRANT_CRYSTAL_CLUSTER" | "CRYSTAL_ORBS") {
(32, 32)
} else {
(p.height(), p.height())
};
let new = if $scale == 1 {
p.clone()
} else {
p.scale::<fimg::scale::Nearest>(mx / $scale, my / $scale)
};
let rgb = env && rgb;
let x = new.width();
let y = new.height();
if rgb {
buf.write_all(&new.to_rgb().bytes()).unwrap();
wr!($ext => r#"pub(crate) static {path}: Image<&[u8], 3> = unsafe {{ Image::new(std::num::NonZeroU32::new({x}).unwrap(), std::num::NonZeroU32::new({y}).unwrap(), include_bytes!(r"{out_path}")) }};"#);
} else {
buf.write_all(&new.to_rgba().bytes()).unwrap();
wr!($ext => r#"pub(crate) static {path}: Image<&[u8], 4> = unsafe {{ Image::new(std::num::NonZeroU32::new({x}).unwrap(), std::num::NonZeroU32::new({y}).unwrap(), include_bytes!(r"{out_path}")) }};"#);
}
};
}
writ!(full / 1);
writ!(quar / 4);
writ!(eigh / 8);
n += 1;
}
}
for f in std::fs::read_dir("assets/blocks/environment")
.unwrap()
.filter_map(Result::ok)
.filter_map(|x| x.file_name().to_str().map(String::from))
.filter(|x| x.contains("1"))
.filter(|x| !x.contains("dark-panel"))
{
dbg!(&f);
let f = &f[..f.len() - 5];
let count = WalkDir::new("assets/blocks/environment")
.into_iter()
.filter_map(Result::ok)
.filter_map(|x| x.file_name().to_str().map(String::from))
.filter(|x| &x[..x.len() - 5] == f)
.count();
let f = kebab2bigsnek(f);
for n in count + 1..=8 {
let r = rand::rng().random_range(1..=count);
wr!(full => r#"pub(crate) static {f}{n}: Image<&[u8], {{{f}1.channels()}}> = {f}{r}.copy();"#);
wr!(quar => r#"pub(crate) static {f}{n}: Image<&[u8], {{{f}1.channels()}}> = {f}{r}.copy();"#);
wr!(eigh => r#"pub(crate) static {f}{n}: Image<&[u8], {{{f}1.channels()}}> = {f}{r}.copy();"#);
}
println!("{count} {f}");
}
for mut f in [full, eigh, quar] {
f.write_all(b"}").unwrap();
}
}