97 lines
2.6 KiB
Rust
97 lines
2.6 KiB
Rust
mod atlasset;
|
|
|
|
use atlasset::AtlasSet;
|
|
|
|
use anyhow::{bail, Context, Result};
|
|
use image::io::Reader;
|
|
use std::path::{Path, PathBuf};
|
|
use walkdir::WalkDir;
|
|
|
|
// TODO: warning when images have extra transparency
|
|
// TODO: dynamic packing (for plugins)
|
|
// TODO: standalone cli (galactica should ask to run this)
|
|
// TODO: randomly assign sprites to textures, for efficiency
|
|
// TODO: group images by use case
|
|
|
|
fn main() -> Result<()> {
|
|
let mut files = Vec::new();
|
|
|
|
let asset_root = Path::new("./assets/render");
|
|
|
|
// Total number of pixels we want to add
|
|
let mut total_dim = 0f64;
|
|
|
|
for e in WalkDir::new(&asset_root).into_iter().filter_map(|e| e.ok()) {
|
|
if e.metadata().unwrap().is_file() {
|
|
// TODO: better warnings
|
|
match e.path().extension() {
|
|
Some(t) => {
|
|
if t.to_str() != Some("png") && t.to_str() != Some("jpg") {
|
|
println!("[WARNING] {e:#?} is not a png file, skipping.");
|
|
continue;
|
|
}
|
|
}
|
|
None => {
|
|
println!("[WARNING] {e:#?} is not a png file, skipping.");
|
|
continue;
|
|
}
|
|
}
|
|
|
|
let path = e.path().to_path_buf();
|
|
let reader = Reader::open(&path)
|
|
.with_context(|| format!("While reading file `{}`", path.display()))?;
|
|
let dim = reader.into_dimensions().with_context(|| {
|
|
format!("While reading dimensions of file `{}`", path.display())
|
|
})?;
|
|
files.push((path, [dim.0, dim.1]));
|
|
total_dim += dim.0 as f64 * dim.1 as f64;
|
|
}
|
|
}
|
|
|
|
// Sort by image size
|
|
files.sort_by(|a, b| {
|
|
let a = a.1[0] * a.1[1];
|
|
let b = b.1[0] * b.1[1];
|
|
b.cmp(&a)
|
|
});
|
|
|
|
// Make sure we have enough pixels.
|
|
// This check is conservative and imperfect:
|
|
// Our tiling algorithm usually has efficiency better than 80% (~90%, as of writing)
|
|
// We need room for error, though, since this check doesn't guarante success.
|
|
if total_dim / 0.80 >= (8192.0 * 8192.0 * 16.0) {
|
|
bail!("Texture atlas is too small")
|
|
}
|
|
|
|
// Create atlas set
|
|
let mut atlas_set = AtlasSet::new(8192, 8192, 16, &asset_root, 1);
|
|
let total = files.len();
|
|
let mut i = 0;
|
|
let mut peak_efficiency = 0f64;
|
|
for (path, _) in files {
|
|
i += 1;
|
|
let atlas_idx = atlas_set.write_image(&path)?;
|
|
println!(
|
|
"({i} of {total}, atlas {atlas_idx}, efficiency {:.02}%) Added {}",
|
|
100.0 * atlas_set.get_efficiency(),
|
|
path.display()
|
|
);
|
|
peak_efficiency = peak_efficiency.max(atlas_set.get_efficiency());
|
|
}
|
|
|
|
println!(
|
|
"Packing efficiency: {:.02}%",
|
|
100.0 * atlas_set.get_efficiency()
|
|
);
|
|
|
|
println!("Peak efficiency: {:.02}%", 100.0 * peak_efficiency);
|
|
|
|
println!("Saving files...");
|
|
atlas_set.save_files(
|
|
|x| PathBuf::from(format!("cache/atlas-{x:0.2}.bmp")),
|
|
&PathBuf::from("cache/spriteatlas.toml"),
|
|
)?;
|
|
|
|
return Ok(());
|
|
}
|