diff --git a/src/compiler.rs b/src/compiler.rs index e5dff76..8b97095 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1,8 +1,9 @@ +use crate::error::CompileError; +use shaderc::{IncludeType, ResolvedInclude}; +use shaderc::{ShaderKind, CompileOptions}; use std::fs::File; -use std::path::Path; -use shaderc::ShaderKind; use std::io::Read; -use crate::error::CompileError; +use std::path::{Path, PathBuf}; pub fn compile(path: T, shader_kind: ShaderKind) -> Result, CompileError> where @@ -10,16 +11,58 @@ where { // TODO Probably shouldn't create this every time. let mut compiler = shaderc::Compiler::new().ok_or(CompileError::CreateCompiler)?; + let mut options = CompileOptions::new().ok_or(CompileError::CreateCompiler)?; let mut f = File::open(&path).map_err(CompileError::Open)?; let mut src = String::new(); f.read_to_string(&mut src).map_err(CompileError::Open)?; - let result = compiler.compile_into_spirv( - src.as_str(), - shader_kind, - path.as_ref().to_str().ok_or(CompileError::InvalidPath)?, - "main", - None, - ).map_err(CompileError::Compile)?; + options.set_include_callback(|path, include_type, folder_path, depth| { + get_include(path, include_type, folder_path, depth) + }); + let result = compiler + .compile_into_spirv( + src.as_str(), + shader_kind, + path.as_ref().to_str().ok_or(CompileError::InvalidPath)?, + "main", + Some(&options), + ) + .map_err(CompileError::Compile)?; let data = result.as_binary(); Ok(data.to_owned()) } + +fn get_include( + path: &str, + include_type: IncludeType, + folder_path: &str, + depth: usize, +) -> Result { + match include_type { + IncludeType::Relative => { + let p = Path::new(path); + let mut folder = PathBuf::from(folder_path); + folder.pop(); + folder.push(p); + let p = folder; + if !p.is_file() { + return Err("Include doesn't point to file".to_string()); + } + + let resolved_name = p + .to_str() + .ok_or("Path has invalid characters".to_string())? + .to_owned(); + let p = p.canonicalize().map_err(|_|"Failed to parse include path".to_string())?; + let mut content = String::new(); + File::open(p) + .map_err(|_|"Couldn't open include directory".to_string())? + .read_to_string(&mut content) + .map_err(|_|"Failed to read included shader".to_string())?; + Ok(ResolvedInclude { + resolved_name, + content, + }) + } + IncludeType::Standard => Err("Standard includes are unimplemented".to_string()), + } +}