three/render/
source.rs

1//! Source for for GLSL shaders used by the renderer.
2
3use data;
4use util;
5
6use std::{io, ops, str};
7use std::borrow::Borrow;
8use std::path::Path;
9
10/// Source code for a single GLSL shader.
11#[derive(Clone, Debug, PartialEq, Eq, Hash)]
12pub struct Source(pub(crate) String);
13
14impl ops::Deref for Source {
15    type Target = [u8];
16    fn deref(&self) -> &Self::Target {
17        self.0.as_bytes()
18    }
19}
20
21impl Source {
22    fn preprocess<P: AsRef<Path>>(
23        root: P,
24        code: &str,
25    ) -> io::Result<String> {
26        let root = root.as_ref();
27        let mut new_code = String::new();
28        for line in code.lines() {
29            if line.starts_with("#include") {
30                if let Some(arg) = line.split_whitespace().skip(1).next() {
31                    if arg.starts_with('<') {
32                        if let Some(pos) = arg[1 ..].find('>') {
33                            let name = &arg[1 .. (pos + 1)];
34                            let path = format!("data/shaders/{}.glsl", name);
35                            let content = &data::FILES.get(&path).unwrap();
36                            new_code += str::from_utf8(content.borrow()).unwrap();
37                        }
38                    } else if arg.starts_with('"') {
39                        if let Some(pos) = arg[1 ..].find('"') {
40                            let relative_path = &arg[1 .. (pos + 1)];
41                            let path = root.join(relative_path);
42                            let content = util::read_file_to_string(&path)?;
43                            let include = Self::preprocess(root, &content)?;
44                            new_code += &include;
45                        }
46                    }
47                }
48            } else {
49                new_code.push_str(&line);
50                new_code.push('\n');
51            }
52        }
53        Ok(new_code)
54    }
55
56    /// Load the named shader from the default set of shaders.
57    pub fn default(
58        name: &str,
59        suffix: &str,
60    ) -> io::Result<Self> {
61        let path = format!("data/shaders/{}_{}.glsl", name, suffix);
62        let unprocessed = data::FILES.get(&path).unwrap();
63        let processed = Self::preprocess("", str::from_utf8(unprocessed.borrow()).unwrap())?;
64        Ok(Source(processed))
65    }
66
67    /// Load the named shader from the given directory path.
68    pub fn user<P: AsRef<Path>>(
69        root: P,
70        name: &str,
71        suffix: &str,
72    ) -> io::Result<Self> {
73        let base_name = format!("{}_{}.glsl", name, suffix);
74        let path = root.as_ref().join(&base_name);
75        let unprocessed = util::read_file_to_string(Path::new(&path))?;
76        let processed = Self::preprocess(root, &unprocessed)?;
77        Ok(Source(processed))
78    }
79}
80
81macro_rules! decl_shaders {
82    { $(($pso:ident, $doc:ident, $ty:ident),)* } => {
83        $( decl_shaders!($pso, $doc, $ty); )*
84
85        /// The set of shaders needed by the `three` renderer.
86        #[derive(Clone, Debug, Default)]
87        pub struct Set {
88            $(
89                #[allow(missing_docs)]
90                pub $pso: $ty,
91            )*
92        }
93    };
94
95    ($pso:ident, $doc:ident, $ty:ident) => {
96        #[allow(missing_docs)]
97        #[derive(Clone, Debug)]
98        pub struct $ty {
99            /// Vertex shader code.
100            pub(crate) vs: Source,
101
102            /// Pixel/fragment shader code.
103            pub(crate) ps: Source,
104        }
105
106        impl $ty {
107            /// Loads user shader code.
108            pub fn user<P: AsRef<Path>>(root: P) -> io::Result<Self> {
109                Ok(Self {
110                    vs: Source::user(&root, stringify!($pso), "vs")?,
111                    ps: Source::user(&root, stringify!($pso), "ps")?,
112                })
113            }
114        }
115
116        impl Default for $ty {
117            fn default() -> Self {
118                Self {
119                    vs: Source::default(stringify!($pso), "vs").unwrap(),
120                    ps: Source::default(stringify!($pso), "ps").unwrap(),
121                }
122            }
123        }
124    };
125}
126
127decl_shaders! {
128    (basic, basic, Basic),
129    (gouraud, Gouraud, Gouraud),
130    (pbr, PBR, Pbr),
131    (phong, Phong, Phong),
132    (quad, quad, Quad),
133    (shadow, shadow, Shadow),
134    (skybox, skybox, Skybox),
135    (sprite, sprite, Sprite),
136}