1use std::fmt;
3
4use crate::{resources::Resources, BIND_GROUP_INDEX, FRAGMENT_ENTRYPOINT};
5
6pub const DEFAULT_TEMPLATE_WGSL_BODY: &str = "
7 let uv = pos.xy/iResolution.xy;
8 let col = 0.5 + 0.5 * cos(iTime + uv.xyx + vec3<f32>(0.0, 2.0, 4.0));
9
10 return vec4<f32>(col, 1.0);
11";
12
13pub const DEFAULT_TEMPLATE_GLSL_BODY: &str = "
14 // Normalized pixel coordinates (from 0 to 1)
15 vec2 uv = gl_FragCoord.xy/iResolution.xy;
16
17 // Time varying pixel color
18 vec3 col = 0.5 + 0.5*cos(iTime+uv.xyx+vec3(0,2,4));
19
20 // Output to screen
21 fragColor = vec4(col,1.0);
22";
23
24#[derive(Debug, Clone, Copy, Hash)]
36pub enum TemplateLang {
37 Wgsl,
39
40 Glsl,
42}
43
44pub(crate) trait TemplateGenerator {
45 fn write_wgsl_template(
46 writer: &mut dyn fmt::Write,
47 bind_group_index: u32,
48 ) -> Result<(), fmt::Error>;
49
50 fn write_glsl_template(writer: &mut dyn fmt::Write) -> Result<(), fmt::Error>;
51}
52
53impl TemplateLang {
54 pub fn generate_to_string(self, body: Option<&str>) -> Result<String, fmt::Error> {
69 let mut string = String::new();
70 self.generate(&mut string, body)?;
71 Ok(string)
72 }
73
74 pub fn generate(
92 self,
93 writer: &mut dyn std::fmt::Write,
94 body: Option<&str>,
95 ) -> Result<(), fmt::Error> {
96 match self {
97 TemplateLang::Wgsl => {
98 Resources::write_wgsl_template(writer, BIND_GROUP_INDEX)?;
99
100 writer.write_fmt(format_args!(
101 "
102@fragment
103fn {}(@builtin(position) pos: vec4<f32>) -> @location(0) vec4<f32> {{
104{}
105}}
106",
107 FRAGMENT_ENTRYPOINT,
108 body.unwrap_or(DEFAULT_TEMPLATE_WGSL_BODY)
109 ))?;
110 }
111
112 TemplateLang::Glsl => {
113 Resources::write_glsl_template(writer)?;
114
115 writer.write_fmt(format_args!(
116 "
117// the color which the pixel should have
118layout(location = 0) out vec4 fragColor;
119
120void {}() {{
121{}
122}}
123",
124 FRAGMENT_ENTRYPOINT,
125 body.unwrap_or(DEFAULT_TEMPLATE_GLSL_BODY)
126 ))?;
127 }
128 };
129
130 Ok(())
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use wgpu::naga::{front::glsl::Options, ShaderStage};
137
138 use super::*;
139
140 #[test]
142 fn valid_wgsl_template() {
143 let template = TemplateLang::Wgsl.generate_to_string(None).unwrap();
144
145 if let Err(err) = wgpu::naga::front::wgsl::parse_str(&template) {
146 let msg = err.emit_to_string(&template);
147 panic!("{}", msg);
148 }
149 }
150
151 #[test]
153 fn valid_glsl_template() {
154 let template = TemplateLang::Glsl.generate_to_string(None).unwrap();
155
156 let mut parser = wgpu::naga::front::glsl::Frontend::default();
157 if let Err(err) = parser.parse(&Options::from(ShaderStage::Fragment), &template) {
158 let msg = err.emit_to_string(&template);
159 panic!("{}", msg);
160 }
161 }
162}