use std::collections::HashMap; use std::error::Error; use std::fs; use std::fs::File; use std::path::PathBuf; use crate::config::{ASSET_DIR, ASSETS_DIST_SUBDIR, ASSETS_FINAL_SUBDIR, ASSETS_SRC_SUBDIR}; use crate::ninja::NinjaWriter; pub fn configure_assets(writer: &mut NinjaWriter, root: &PathBuf) -> Result<(), Box> { // 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] asset scan: found {} assets", found_assets.len()); let default_asset_size = 512; let asset_overrides = HashMap::from([ ("earth.ink.svg", 2048), ("moon.ink.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: &PathBuf, writer: &mut NinjaWriter, files_375: &Vec, files_full: &Vec, files_125: &Vec) -> Result<(), Box> { writer.rule("pack", &format!("cd {} && atlasify -m 4096,4096 -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: &PathBuf, root: &PathBuf, writer: &mut NinjaWriter, files_375: &mut Vec, files_full: &mut Vec, files_125: &mut Vec, size: i32) -> Result<(), Box> { 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 { *overrides.get(asset).unwrap_or(&default) } fn gen_inkscape_rule(size: i32, writer: &mut NinjaWriter, written: &mut Vec) -> Result<(), Box> { 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(()) }