polyscope_render/
shader.rs1use crate::error::{RenderError, RenderResult};
4
5pub struct ShaderProgram {
7 pub pipeline: wgpu::RenderPipeline,
9 pub bind_group_layouts: Vec<wgpu::BindGroupLayout>,
11}
12
13pub struct ShaderBuilder {
15 vertex_source: Option<String>,
16 fragment_source: Option<String>,
17 vertex_entry: String,
18 fragment_entry: String,
19 label: Option<String>,
20}
21
22impl ShaderBuilder {
23 #[must_use]
25 pub fn new() -> Self {
26 Self {
27 vertex_source: None,
28 fragment_source: None,
29 vertex_entry: "vs_main".to_string(),
30 fragment_entry: "fs_main".to_string(),
31 label: None,
32 }
33 }
34
35 #[must_use]
37 pub fn with_vertex(mut self, source: impl Into<String>) -> Self {
38 self.vertex_source = Some(source.into());
39 self
40 }
41
42 #[must_use]
44 pub fn with_fragment(mut self, source: impl Into<String>) -> Self {
45 self.fragment_source = Some(source.into());
46 self
47 }
48
49 #[must_use]
51 pub fn with_vertex_entry(mut self, entry: impl Into<String>) -> Self {
52 self.vertex_entry = entry.into();
53 self
54 }
55
56 #[must_use]
58 pub fn with_fragment_entry(mut self, entry: impl Into<String>) -> Self {
59 self.fragment_entry = entry.into();
60 self
61 }
62
63 #[must_use]
65 pub fn with_label(mut self, label: impl Into<String>) -> Self {
66 self.label = Some(label.into());
67 self
68 }
69
70 pub fn build_module(self, device: &wgpu::Device) -> RenderResult<wgpu::ShaderModule> {
72 let source = self.combined_source()?;
73
74 let module = device.create_shader_module(wgpu::ShaderModuleDescriptor {
75 label: self.label.as_deref(),
76 source: wgpu::ShaderSource::Wgsl(source.into()),
77 });
78
79 Ok(module)
80 }
81
82 fn combined_source(&self) -> RenderResult<String> {
83 let vertex = self
84 .vertex_source
85 .as_ref()
86 .ok_or_else(|| RenderError::ShaderCompilationFailed("missing vertex shader".into()))?;
87
88 let fragment = self.fragment_source.as_ref().ok_or_else(|| {
89 RenderError::ShaderCompilationFailed("missing fragment shader".into())
90 })?;
91
92 if vertex == fragment {
94 return Ok(vertex.clone());
95 }
96
97 Ok(format!("{vertex}\n\n{fragment}"))
99 }
100}
101
102impl Default for ShaderBuilder {
103 fn default() -> Self {
104 Self::new()
105 }
106}