// ▄████████▄ + ███ + ▄█████████ ███ + // ███▀ ▀███ + + ███ ███▀ + ███ + + // ███ + ███ ███ ███ █████████ ███ ███ ███ ███ // ███ +███ ███ ███ ███ ███▐██████ ███ ███ ███ // ███ + ███ ███+ ███ +███ ███ + ███ ███ + ███ // ███▄ ▄███ ███▄ ███ ███ + ███ + ███ ███▄ ███ // ▀████████▀ + ▀███████ ███▄ ███▄ ▀████ ▀███████ // + + + ███ // + ▀████████████████████████████████████████████████████▀ use blend::Blend; use std::fs; use std::fs::File; use std::io::Write; fn main() -> std::io::Result<()> { let target = std::env::var("TARGET").unwrap(); if target.contains("windows") { println!("cargo:warning=Embedding Windows Icon"); embed_resource::compile("build/windows/icon.rc"); } let file = File::create("src/data/scenes.in"); if let Ok(mut file) = file { write!(&file, "// THIS FILE IS AUTOGENERATED BY build.rs BASED ON DATA IN src/blender/scene_*.blend FILES!\n")?; write!( &file, "// DO NOT MODIFY MANUALLY, CHANGES WILL BE OVERWRITTEN!\n" )?; write!(&file, "[\n")?; // find all scene_*.blend files and extract+export their scenes for entry in fs::read_dir("src/blender")? { let path = entry?.path(); if let Some(file_name) = path.file_name().and_then(|s| s.to_str()) { if file_name.starts_with("scene_") && file_name.ends_with(".blend") { let scene_name = &file_name["scene_".len()..file_name.len() - ".blend".len()]; extract_scene(&mut file, scene_name, path.to_str().unwrap())?; } } } write!(&file, "]\n")?; } Ok(()) } fn extract_scene(file: &mut File, scene_name: &str, blend_file: &str) -> std::io::Result<()> { // Info about .blender file format: // https://www.janwalter.org/jekyll/blender/rust/blendinfo/2019/05/28/blend_info.html let blend = Blend::from_path(blend_file).expect("error loading blend file"); for obj in blend.instances_with_code(*b"OB") { let loc: Vec = if obj.is_valid("loc") { obj.get_f32_vec("loc") } else { vec![0.0, 0.0, 0.0] }; let rot: Vec = if obj.is_valid("rot") { obj.get_f32_vec("rot") } else { vec![0.0, 0.0, 0.0] }; let scale: Vec = if obj.is_valid("size") { obj.get_f32_vec("size") } else { vec![1.0, 1.0, 1.0] }; let name = obj.get("id").get_string("name"); if let Some(name) = get_scene_object_name(name.as_str()) { write!( file, "({scene_name:?}, {name:?}, {loc:?}, {rot:?}, {scale:?}),\n" )?; } } Ok(()) } fn get_scene_object_name(full_id: &str) -> Option<&str> { let prefix = "OBLOAD="; if full_id.starts_with(prefix) { let remainder: &str = &full_id[prefix.len()..]; let parts: Vec<&str> = remainder.split('.').collect(); let name = parts[0]; return Some(name); } return None; }