use crate::config::{ASSETS_DIST_SUBDIR, ASSETS_FINAL_SUBDIR, ASSETS_SRC_SUBDIR, ASSET_DIR};
use crate::ninja::NinjaWriter;
use std::collections::HashMap;
use std::error::Error;
use std::fs;
use std::fs::File;
use std::path::{Path, PathBuf};
pub fn configure_assets(writer: &mut NinjaWriter<File>, root: &Path) -> Result<(), Box<dyn Error>> {
// scan for assets
let asset_src_dir = root.join(ASSET_DIR).join(ASSETS_SRC_SUBDIR);
let mut found_assets = vec![];
let files_in_src_dir = fs::read_dir(asset_src_dir)?;
for maybe_asset in files_in_src_dir {
let maybe_asset = maybe_asset?;
if maybe_asset.file_name().to_str().unwrap().ends_with(".svg") {
found_assets.push(maybe_asset.path());
println!("[spacetime][DEBUG] asset: {:?}", maybe_asset.path());
}
}
println!(
"[spacetime] asset scan: found {} assets",
found_assets.len()
);
let default_asset_size = 512;
let asset_overrides = HashMap::from([
("earth.svg", 2048),
("moon.svg", 2048),
("mars.svg", 2048),
("starfield.svg", 2048),
]);
// generate an inkscape rule for all required asset sizes
let mut written_rules_for = vec![];
gen_inkscape_rule(default_asset_size, writer, &mut written_rules_for)?;
for size in asset_overrides.values() {
gen_inkscape_rule(*size, writer, &mut written_rules_for)?;
}
println!(
"[spacetime] generated {} image conversion rules",
written_rules_for.len() * 3
);
let mut files_375 = vec![];
let mut files_125 = vec![];
let mut files_full = vec![];
for asset in &found_assets {
gen_convert_rule(
asset,
root,
writer,
&mut files_375,
&mut files_full,
&mut files_125,
asset_size(
asset.to_str().unwrap(),
&asset_overrides,
default_asset_size,
),
)?;
}
println!(
"[spacetime] generated {} image conversion steps",
files_full.len() + files_125.len() + files_375.len()
);
gen_packer_rule(root, writer, &files_375, &files_full, &files_125)?;
println!("[spacetime] generated asset build commands");
Ok(())
}
fn gen_packer_rule(
root: &Path,
writer: &mut NinjaWriter<File>,
files_375: &[PathBuf],
files_full: &[PathBuf],
files_125: &[PathBuf],
) -> Result<(), Box<dyn Error>> {
writer.rule(
"pack",
&format!(
"cd {} && atlasify -m 8096,8096 -o $out $in && touch $out",
root.join(ASSET_DIR)
.join(ASSETS_DIST_SUBDIR)
.to_string_lossy()
),
None,
None,
None,
Some("console"),
None,
None,
None,
None,
)?;
writer.build(
vec![root
.join(ASSET_DIR)
.join(ASSETS_DIST_SUBDIR)
.join("spritesheet-full")
.to_str()
.unwrap()
.to_string()],
"pack".to_string(),
files_full
.iter()
.map(|u| u.to_str().unwrap().to_string())
.collect(),
vec![],
vec![],
HashMap::new(),
vec![
root.join(ASSET_DIR)
.join(ASSETS_DIST_SUBDIR)
.join("spritesheet-full.json")
.to_str()
.unwrap()
.to_string(),
root.join(ASSET_DIR)
.join(ASSETS_DIST_SUBDIR)
.join("spritesheet-full.png")
.to_str()
.unwrap()
.to_string(),
],
None,
None,
)?;
writer.build(
vec!["asset-full".to_string()],
"phony".to_string(),
vec![root
.join(ASSET_DIR)
.join(ASSETS_DIST_SUBDIR)
.join("spritesheet-full")
.to_str()
.unwrap()
.to_string()],
vec![],
vec![],
HashMap::new(),
vec![],
None,
None,
)?;
writer.build(
vec![root
.join(ASSET_DIR)
.join(ASSETS_DIST_SUBDIR)
.join("spritesheet-125")
.to_str()
.unwrap()
.to_string()],
"pack".to_string(),
files_125
.iter()
.map(|u| u.to_str().unwrap().to_string())
.collect(),
vec![],
vec![],
HashMap::new(),
vec![
root.join(ASSET_DIR)
.join(ASSETS_DIST_SUBDIR)
.join("spritesheet-125.json")
.to_str()
.unwrap()
.to_string(),
root.join(ASSET_DIR)
.join(ASSETS_DIST_SUBDIR)
.join("spritesheet-125.png")
.to_str()
.unwrap()
.to_string(),
],
None,
None,
)?;
writer.build(
vec!["asset-125".to_string()],
"phony".to_string(),
vec![root
.join(ASSET_DIR)
.join(ASSETS_DIST_SUBDIR)
.join("spritesheet-125")
.to_str()
.unwrap()
.to_string()],
vec![],
vec![],
HashMap::new(),
vec![],
None,
None,
)?;
writer.build(
vec![root
.join(ASSET_DIR)
.join(ASSETS_DIST_SUBDIR)
.join("spritesheet-375")
.to_str()
.unwrap()
.to_string()],
"pack".to_string(),
files_375
.iter()
.map(|u| u.to_str().unwrap().to_string())
.collect(),
vec![],
vec![],
HashMap::new(),
vec![
root.join(ASSET_DIR)
.join(ASSETS_DIST_SUBDIR)
.join("spritesheet-375.json")
.to_str()
.unwrap()
.to_string(),
root.join(ASSET_DIR)
.join(ASSETS_DIST_SUBDIR)
.join("spritesheet-375.png")
.to_str()
.unwrap()
.to_string(),
],
None,
None,
)?;
writer.build(
vec!["asset-375".to_string()],
"phony".to_string(),
vec![root
.join(ASSET_DIR)
.join(ASSETS_DIST_SUBDIR)
.join("spritesheet-375")
.to_str()
.unwrap()
.to_string()],
vec![],
vec![],
HashMap::new(),
vec![],
None,
None,
)?;
writer.build(
vec!["asset".to_string()],
"phony".to_string(),
vec![
root.join(ASSET_DIR)
.join(ASSETS_DIST_SUBDIR)
.join("spritesheet-375")
.to_str()
.unwrap()
.to_string(),
root.join(ASSET_DIR)
.join(ASSETS_DIST_SUBDIR)
.join("spritesheet-full")
.to_str()
.unwrap()
.to_string(),
root.join(ASSET_DIR)
.join(ASSETS_DIST_SUBDIR)
.join("spritesheet-125")
.to_str()
.unwrap()
.to_string(),
],
vec![],
vec![],
HashMap::new(),
vec![],
None,
None,
)?;
Ok(())
}
fn gen_convert_rule(
asset: &Path,
root: &Path,
writer: &mut NinjaWriter<File>,
files_375: &mut Vec<PathBuf>,
files_full: &mut Vec<PathBuf>,
files_125: &mut Vec<PathBuf>,
size: i32,
) -> Result<(), Box<dyn Error>> {
let out_full = root
.join(ASSET_DIR)
.join(ASSETS_FINAL_SUBDIR)
.join("full/")
.join(asset.file_stem().unwrap().to_str().unwrap().to_string() + ".png");
files_full.push(out_full.clone());
let rule_full = format!("inkscape_{}_px_full", size);
writer.build(
vec![out_full.to_str().unwrap().to_string()],
rule_full,
vec![asset.to_str().unwrap().to_string()],
vec![],
vec![],
HashMap::new(),
vec![],
None,
None,
)?;
let out_375 = root
.join(ASSET_DIR)
.join(ASSETS_FINAL_SUBDIR)
.join("375/")
.join(asset.file_stem().unwrap().to_str().unwrap().to_string() + ".png");
files_375.push(out_375.clone());
let rule_375 = format!("inkscape_{}_px_375", size);
writer.build(
vec![out_375.to_str().unwrap().to_string()],
rule_375,
vec![asset.to_str().unwrap().to_string()],
vec![],
vec![],
HashMap::new(),
vec![],
None,
None,
)?;
let out_125 = root
.join(ASSET_DIR)
.join(ASSETS_FINAL_SUBDIR)
.join("125/")
.join(asset.file_stem().unwrap().to_str().unwrap().to_string() + ".png");
files_125.push(out_125.clone());
let rule_125 = format!("inkscape_{}_px_125", size);
writer.build(
vec![out_125.to_str().unwrap().to_string()],
rule_125,
vec![asset.to_str().unwrap().to_string()],
vec![],
vec![],
HashMap::new(),
vec![],
None,
None,
)?;
Ok(())
}
fn asset_size(asset: &str, overrides: &HashMap<&str, i32>, default: i32) -> i32 {
for (ov, size) in overrides {
if asset.ends_with(ov) {
return *size;
}
}
default
}
fn gen_inkscape_rule(
size: i32,
writer: &mut NinjaWriter<File>,
written: &mut Vec<i32>,
) -> Result<(), Box<dyn Error>> {
if written.contains(&size) {
return Ok(());
}
writer.rule(
&format!("inkscape_{}_px_full", size),
&format!("inkscape -w {} -h {} $in -o $out", size, size),
None,
None,
None,
None,
None,
None,
None,
None,
)?;
writer.rule(
&format!("inkscape_{}_px_375", size),
&format!(
"inkscape -w {} -h {} $in -o $out",
(size as f64 * 0.375) as i32,
(size as f64 * 0.375) as i32
),
None,
None,
None,
None,
None,
None,
None,
None,
)?;
writer.rule(
&format!("inkscape_{}_px_125", size),
&format!(
"inkscape -w {} -h {} $in -o $out",
(size as f64 * 0.125) as i32,
(size as f64 * 0.125) as i32
),
None,
None,
None,
None,
None,
None,
None,
None,
)?;
written.push(size);
Ok(())
}