1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
use std::collections::HashSet;
use std::fs::{read_dir,create_dir_all,read_to_string,write,DirEntry};
use std::path::{Path,PathBuf};

use shaderc::ShaderKind;

pub fn build() {
    let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("Failed to get CARGO_MANIFEST_DIR environment variable.");
    let shaders_dir = Path::new(&manifest_dir).join("resources/shaders");
    let output_directory = Path::new(&manifest_dir).join("out");

    let mut shaderc_compiler = shaderc::Compiler::new().expect("Failed to create shaderc compiler.");

    let mut made_directories: HashSet<PathBuf> = HashSet::new();

    let mut entries: Vec<DirEntry> = read_dir(&shaders_dir)
        .expect("Failed to read GLSL input directory.")
        .map(|x| x.expect("Failed to get item in GLSL input directory."))
        .into_iter()
        .collect();

    loop {
        let entry = match entries.pop() {
            Some(entry) => entry,
            None => break
        };

        let shader_path_buf = entry.path();

        println!("cargo:rerun-if-changed={}", shader_path_buf.as_os_str().to_str().unwrap());

        let metadata = entry.metadata().expect("Failed to get metadata of item in GLSL input directory.");

        if metadata.is_dir() {
            entries.extend(
                read_dir(&shader_path_buf)
                    .expect("Failed to read subdirectory item in GLSL input directory.")
                    .map(|x| x.expect("Failed to get subdirectory item in GLSL input directory."))
                    .into_iter()
            );
        } else if metadata.is_file() {
            let shader_source = read_to_string(&shader_path_buf).expect("Failed to read shader file.");

            let shader_file_name = &shader_path_buf.file_name().expect("Failed to get shader file name.")
                .to_str().expect("Failed to get shader file name as string.");

            let shader_file_stem = &shader_path_buf.file_stem().expect("Failed to get shader file stem.")
                .to_str().expect("Failed to get shader file stem as string.");

            let shader_file_stem_prefix: String = shader_file_stem.chars().take_while(|x| x != &'_').collect();

            let shader_kind = match shader_file_stem_prefix.as_str() {
                "vertex" => ShaderKind::DefaultVertex,
                "fragment" => ShaderKind::DefaultFragment,
                "compute" => ShaderKind::DefaultCompute,
                "geometry" => ShaderKind::DefaultGeometry,
                "tessctrl" => ShaderKind::DefaultTessControl,
                "tesseval" => ShaderKind::DefaultTessEvaluation,
                "raygen" => ShaderKind::DefaultRayGeneration,
                "anyhit" => ShaderKind::DefaultAnyHit,
                "closesthit" => ShaderKind::DefaultClosestHit,
                "miss" => ShaderKind::DefaultMiss,
                "intersection" => ShaderKind::Intersection,
                "callable" => ShaderKind::DefaultCallable,
                "task" => ShaderKind::DefaultTask,
                "mesh" => ShaderKind::DefaultMesh,
                _ => ShaderKind::InferFromSource,
            };

            let shader_artifact = shaderc_compiler.compile_into_spirv(
                shader_source.as_str(),
                shader_kind,
                &shader_file_name,
                "main",
                None
            ).expect("Failed to compile shader.");

            let shader_binary = shader_artifact.as_binary_u8();

            let relative_path = &shader_path_buf.strip_prefix(&manifest_dir).expect("Failed to get shader's relative path.");
            let relative_path = relative_path.with_extension("spv");

            let adjusted_path = Path::new(&output_directory).join(relative_path);
            let adjusted_path_directory = adjusted_path.parent().expect("Failed to get directory of SPIR-V output path.");

            if made_directories.get(adjusted_path_directory).is_none() {
                create_dir_all(adjusted_path_directory).expect("Failed to create directory of SPIR-V output.");
                made_directories.insert(adjusted_path_directory.clone().to_path_buf());
            }

            write(&adjusted_path, shader_binary).expect("Failed to write shader.");

            println!("cargo:rerun-if-changed={}", &adjusted_path.as_os_str().to_str().unwrap());
            println!("cargo:rerun-if-changed={}", &adjusted_path_directory.as_os_str().to_str().unwrap());
        }
    }

    println!("cargo:rerun-if-changed={}", &output_directory.as_os_str().to_str().unwrap());
}