use std::env;
use std::fs;
use std::path::{Path, PathBuf};
fn main() {
println!("cargo:rerun-if-changed=shaders");
let shader_dir = Path::new("shaders");
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
if shader_dir.exists() {
let generated_shaders =
compile_shaders(shader_dir, &out_dir).expect("Failed to compile shaders");
let mut registry = String::from("// Auto-generated shader registry\n\n");
for (const_name, file_name) in generated_shaders {
registry.push_str(&format!(
"pub const {const_name}: &[u8] = include_bytes!(concat!(env!(\"OUT_DIR\"), \"/{file_name}\"));\n"
));
}
fs::write(out_dir.join("shaders_registry.rs"), registry).expect("Failed to write registry");
}
}
fn compile_shaders(
dir: &Path,
out_dir: &Path,
) -> Result<Vec<(String, String)>, Box<dyn std::error::Error>> {
let compiler = shaderc::Compiler::new().unwrap();
let mut options = shaderc::CompileOptions::new().unwrap();
options.set_optimization_level(shaderc::OptimizationLevel::Performance);
let mut generated = Vec::new();
for entry in fs::read_dir(dir)? {
let entry = entry?;
let path = entry.path();
if path.is_dir() {
generated.extend(compile_shaders(&path, out_dir)?);
continue;
}
let extension = match path.extension().and_then(|s| s.to_str()) {
Some(ext) => ext,
None => continue,
};
let kind = match extension {
"vert" => shaderc::ShaderKind::Vertex,
"frag" => shaderc::ShaderKind::Fragment,
"comp" => shaderc::ShaderKind::Compute,
_ => continue,
};
if extension == "spv" {
continue;
}
let src_content = fs::read_to_string(&path)?;
let file_name = path.file_name().unwrap().to_str().unwrap();
let binary_result =
compiler.compile_into_spirv(&src_content, kind, file_name, "main", Some(&options));
match binary_result {
Ok(binary) => {
let out_name = if file_name == "vert.vert" {
"vert.spv".to_string()
} else if file_name == "frag.frag" {
"frag.spv".to_string()
} else {
format!("{file_name}.spv")
};
let out_path = out_dir.join(&out_name);
fs::write(&out_path, binary.as_binary_u8())?;
let const_name = out_name.replace(".", "_").to_uppercase();
generated.push((const_name, out_name));
}
Err(e) => {
eprintln!("Failed to compile shader {}: {}", path.display(), e);
return Err(Box::new(e));
}
}
}
Ok(generated)
}