geng_core/shader_lib/
mod.rs1use super::*;
2
3pub struct ShaderLib {
4 ugli: Rc<Ugli>,
5 files: RefCell<HashMap<String, String>>,
6}
7
8impl ShaderLib {
9 pub fn new(ugli: &Rc<Ugli>) -> Self {
10 let lib = Self {
11 ugli: ugli.clone(),
12 files: RefCell::new(HashMap::new()),
13 };
14 lib.add("prelude", include_str!("include/prelude.glsl"));
15 lib
16 }
17
18 pub fn add(&self, file_name: &str, source: &str) {
19 self.files
20 .borrow_mut()
21 .insert(file_name.to_owned(), source.to_owned());
22 }
23
24 fn preprocess(&self, source: &str) -> Result<String, Error> {
25 let mut result = String::new();
26 for line in source.lines() {
27 if line.starts_with("#include") {
28 let mut iter = line.trim().split_whitespace();
29 iter.next();
30 let file = iter.next().expect("Expected path to include");
31 assert!(iter.next().is_none(), "Unexpected token");
32 assert!(
33 file.starts_with('<') && file.ends_with('>'),
34 "include path should be enclosed in angular brackets"
35 );
36 let file = file.trim_start_matches('<').trim_end_matches('>');
37 if let Some(file) = self.files.borrow().get(file) {
38 result.push_str(&self.preprocess(file)?);
39 } else {
40 bail!("{:?} not found in shader library", file);
41 }
42 } else {
43 result.push_str(line);
44 result.push_str("\n");
45 }
46 }
47 Ok(result)
48 }
49 pub fn process(&self, shader_type: ugli::ShaderType, source: &str) -> Result<String, Error> {
50 let mut result = String::new();
51 #[cfg(not(target_arch = "wasm32"))]
52 result.push_str("#version 100\n");
53 result.push_str("precision highp int;\nprecision highp float;\n");
54 result.push_str(match shader_type {
55 ugli::ShaderType::Vertex => "#define VERTEX_SHADER\n",
56 ugli::ShaderType::Fragment => "#define FRAGMENT_SHADER\n",
57 });
58 result.push_str(&self.preprocess("#include <prelude>")?);
59 result.push_str(&self.preprocess(source)?);
60 Ok(result)
61 }
62 pub fn compile(&self, source: &str) -> Result<ugli::Program, Error> {
63 Ok(ugli::Program::new(
64 &self.ugli,
65 &[
66 &ugli::Shader::new(
67 &self.ugli,
68 ugli::ShaderType::Vertex,
69 &self.process(ugli::ShaderType::Vertex, source)?,
70 )?,
71 &ugli::Shader::new(
72 &self.ugli,
73 ugli::ShaderType::Fragment,
74 &self.process(ugli::ShaderType::Fragment, source)?,
75 )?,
76 ],
77 )?)
78 }
79}