use glob::glob; use std::fs::{read_to_string, write, create_dir_all}; use std::path::{Path, PathBuf}; use shaderc::{ResolvedInclude, ShaderKind, IncludeType}; 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, kind: ShaderKind) -> Option { // Get extension and filename let filename = src_path.file_name().unwrap().to_str().unwrap(); let extension = src_path.extension().expect("File has no extension").to_str().unwrap(); // Create output path let directory = src_path.parent().unwrap().join("bin"); create_dir_all(directory.clone()).expect("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()).expect("Failed to read shader file content"); // Return struct Some(Self { source, src_path, spv_path, kind }) } } fn resolve_include(inc_name: &str, _inc_type: IncludeType, src_name: &str, _depth: usize) -> Result { let path = Path::new(src_name).parent().unwrap().join(inc_name); if path.is_file() { let resolved_name = path.to_str().unwrap().to_owned(); let content = read_to_string(path.clone()).unwrap(); return Ok(ResolvedInclude { resolved_name, content }) } Err("".to_string()) } fn main() { // Load all shaders let vert = glob("./src/shaders/**/*.vert").unwrap().filter_map(|p| ShaderData::load(p.unwrap(), ShaderKind::Vertex)); let frag = glob("./src/shaders/**/*.frag").unwrap().filter_map(|p| ShaderData::load(p.unwrap(), ShaderKind::Fragment)); let comp = glob("./src/shaders/**/*.comp").unwrap().filter_map(|p| ShaderData::load(p.unwrap(), ShaderKind::Compute)); let shaders = vert.chain(frag).chain(comp); // Options let mut options = shaderc::CompileOptions::new().expect("Unable to create compile options"); options.set_include_callback(resolve_include); // Compile all shaders let mut compiler = shaderc::Compiler::new().expect("Unable to create shader compiler"); for shader in shaders { println!("cargo:rerun-if-changed={}", shader.src_path.as_os_str().to_str().unwrap()); let result = compiler.compile_into_spirv(&shader.source, shader.kind, &shader.src_path.to_str().unwrap(), "main", Some(&options)); match result { Err(err) => { panic!("Failed: {}", err); }, Ok(data) => { write(shader.spv_path, data.as_binary_u8()).unwrap(); } } } // Rebuild if any of the cginc change for path_str in glob("./src/shaders/**/*.cginc").unwrap() { let path = path_str.unwrap(); println!("cargo:rerun-if-changed={}", path.as_os_str().to_str().unwrap()); } }