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, root: &Path) -> 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: &Path, writer: &mut NinjaWriter, files_375: &[PathBuf], files_full: &[PathBuf], files_125: &[PathBuf], ) -> 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: &Path, root: &Path, 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(()) }