use anyhow::*; use glob::glob; use std::fs::{read_to_string, write, create_dir_all}; use std::path::PathBuf; struct ShaderData { source: String, src_path: PathBuf, spv_path: PathBuf, kind: shaderc::ShaderKind, } impl ShaderData { // Load data from file pub fn load(src_path: PathBuf) -> Result { // Get extension and filename let filename = src_path.file_name().unwrap().to_str().unwrap(); let extension = src_path.extension().context("File has no extension")?.to_str().unwrap(); // Figure out kind from extension let kind = match extension { "vert" => shaderc::ShaderKind::Vertex, "frag" => shaderc::ShaderKind::Fragment, "comp" => shaderc::ShaderKind::Compute, _ => bail!("Unsupported shader: {}", src_path.display()), }; // Create output path let directory = src_path.parent().unwrap().join(".bin"); create_dir_all(directory.clone()).context("Failed to create output directory")?; let spv_path = directory.join(filename).with_extension(format!("{}.spv", extension)); // Read file let source = read_to_string(src_path.clone())?; // Return struct Ok(Self{ source, src_path, spv_path, kind }) } } fn main() -> Result<()> { // Collect all shaders recursively within /shaders/ let mut shader_paths = [ glob("./src/**/*.vert")?, glob("./src/**/*.frag")?, glob("./src/**/*.comp")?, ]; let shaders = shader_paths.iter_mut().flatten() .map(|glob_result| ShaderData::load(glob_result?)) .collect::>>().into_iter() .collect::>>()?; // Compile all shaders let mut compiler = shaderc::Compiler::new().context("Unable to create shader compiler")?; for shader in shaders { println!("cargo:rerun-if-changed={}", shader.src_path.as_os_str().to_str().unwrap()); let compiled = compiler.compile_into_spirv(&shader.source, shader.kind, &shader.src_path.to_str().unwrap(), "main", None, )?; write(shader.spv_path, compiled.as_binary_u8())?; } Ok(()) }