Skip to main content

glsl_to_spirv_macros_impl/
lib.rs

1extern crate glsl_to_spirv;
2extern crate proc_macro;
3extern crate syn;
4#[macro_use]
5extern crate quote;
6
7use proc_macro::TokenStream;
8use std::fs::File;
9use std::io::Read;
10use std::path::Path;
11
12/*
13static foo: &'static [u32] = {
14    struct Dummy;
15    static DATA: [u32; 1] = [1];
16    &DATA as &'static [u32]
17};
18fn bar() {
19    //let foo =
20}*/
21
22/*#[macro_export]
23macro_rules! glsl {
24    ($source:tt) => {{
25        #[derive(GLSLEmbedImpl)]
26        #[src=$source]
27        struct Dummy;
28        &DATA as &'static [u8]
29    }};
30}*/
31
32#[proc_macro_derive(GLSLEmbedImpl, attributes(src, path, ty))]
33pub fn macro_impl(input: TokenStream) -> TokenStream {
34    let source = input.to_string();
35    let ast = syn::parse_macro_input(&source).ok().expect("Invalid shader macro arguments - you must specify a single string literal.");
36    let mut source_string = None;
37    let mut path_string = None;
38    let mut ty_string = None;
39    for attr in &ast.attrs {
40        match attr.value {
41            syn::MetaItem::NameValue(ref ident, syn::Lit::Str(ref value, _)) => {
42                if ident == "src" {
43                    source_string = Some(value.clone());
44                } else if ident == "path" {
45                    path_string = Some(value.clone());
46                } else if ident == "ty" {
47                    ty_string = Some(value.clone());
48                } else {
49                    panic!("Invalid shader macro arguments - you must specify a single string literal.")
50                }
51            }
52            syn::MetaItem::List(ref ident, _) if ident == "allow" => {}
53            _ => panic!("Invalid shader macro arguments - you must specify a single string literal.")
54        }
55    };
56    let source_string = if let Some(source_string) = source_string {
57        source_string
58    } else {
59        let root = std::env::var("CARGO_MANIFEST_DIR").unwrap_or(".".into());
60        let path = path_string.unwrap();
61        let full_path = Path::new(&root).join(&path);
62        let mut s = String::new();
63        File::open(full_path)
64            .and_then(|mut file| file.read_to_string(&mut s))
65            .expect(&format!("Error reading shader source file: {:?}", path));
66        s
67    };
68    let ty = match &*ty_string.unwrap() {
69        "vs" => glsl_to_spirv::ShaderType::Vertex,
70        "fs" => glsl_to_spirv::ShaderType::Fragment,
71        "gs" => glsl_to_spirv::ShaderType::Geometry,
72        "tcs" => glsl_to_spirv::ShaderType::TessellationControl,
73        "tes" => glsl_to_spirv::ShaderType::TessellationEvaluation,
74        "cs" => glsl_to_spirv::ShaderType::Compute,
75        _ => panic!()
76    };
77    let mut spirv_file: File = match glsl_to_spirv::compile(&source_string, ty) {
78        Ok(compiled) => compiled,
79        Err(message) => panic!("{}\nfailed to compile shader", message),
80    };
81    let mut spirv_data = Vec::new();
82    spirv_file.read_to_end(&mut spirv_data).unwrap();
83    let count = spirv_data.len();
84    let expanded = quote! {
85        static DATA: [u8; #count] = #spirv_data;
86    };
87
88    expanded.parse().unwrap()
89}