1use std::borrow::Cow;
2
3#[derive(Debug, Clone)]
10pub enum ShaderAsset {
11 Path(&'static str),
13 Source {
15 file_name: &'static str,
17 fragment: &'static str,
19 },
20 Stored(&'static str),
22}
23
24impl ShaderAsset {
25 pub fn fragment_source(&self) -> Cow<'static, str> {
30 match self {
31 ShaderAsset::Path(path) => {
32 Cow::Owned(std::fs::read_to_string(path)
33 .unwrap_or_else(|e| panic!("Failed to read shader file '{}': {}", path, e)))
34 }
35 ShaderAsset::Source { fragment, .. } => Cow::Borrowed(fragment),
36 ShaderAsset::Stored(name) => {
37 let mgr = crate::renderer::MATERIAL_MANAGER.lock().unwrap();
38 match mgr.get_source(name) {
39 Some(src) => Cow::Owned(src.to_string()),
40 None => {
41 eprintln!("Shader storage '{}' not found, using fallback", name);
42 Cow::Borrowed(crate::renderer::DEFAULT_FRAGMENT_SHADER)
43 }
44 }
45 }
46 }
47 }
48
49 pub fn cache_key(&self) -> &str {
51 match self {
52 ShaderAsset::Path(path) => path,
53 ShaderAsset::Source { file_name, .. } => file_name,
54 ShaderAsset::Stored(name) => name,
55 }
56 }
57}
58
59#[derive(Debug, Clone)]
62pub struct ShaderConfig {
63 pub fragment: Cow<'static, str>,
65 pub uniforms: Vec<ShaderUniform>,
67 pub name: String,
69}
70
71#[derive(Debug, Clone)]
73pub struct ShaderUniform {
74 pub name: String,
76 pub value: ShaderUniformValue,
78}
79
80#[derive(Debug, Clone)]
82pub enum ShaderUniformValue {
83 Float(f32),
85 Vec2([f32; 2]),
87 Vec3([f32; 3]),
89 Vec4([f32; 4]),
91 Int(i32),
93 Mat4([[f32; 4]; 4]),
95}
96
97impl From<f32> for ShaderUniformValue {
98 fn from(v: f32) -> Self {
99 ShaderUniformValue::Float(v)
100 }
101}
102
103impl From<[f32; 2]> for ShaderUniformValue {
104 fn from(v: [f32; 2]) -> Self {
105 ShaderUniformValue::Vec2(v)
106 }
107}
108
109impl From<[f32; 3]> for ShaderUniformValue {
110 fn from(v: [f32; 3]) -> Self {
111 ShaderUniformValue::Vec3(v)
112 }
113}
114
115impl From<[f32; 4]> for ShaderUniformValue {
116 fn from(v: [f32; 4]) -> Self {
117 ShaderUniformValue::Vec4(v)
118 }
119}
120
121impl From<i32> for ShaderUniformValue {
122 fn from(v: i32) -> Self {
123 ShaderUniformValue::Int(v)
124 }
125}
126
127impl From<[[f32; 4]; 4]> for ShaderUniformValue {
128 fn from(v: [[f32; 4]; 4]) -> Self {
129 ShaderUniformValue::Mat4(v)
130 }
131}
132
133pub struct ShaderBuilder<'a> {
136 source: &'a ShaderAsset,
137 uniforms: Vec<ShaderUniform>,
138}
139
140impl<'a> ShaderBuilder<'a> {
141 pub(crate) fn new(source: &'a ShaderAsset) -> Self {
143 Self {
144 source,
145 uniforms: Vec::new(),
146 }
147 }
148
149 pub fn uniform(&mut self, name: &str, value: impl Into<ShaderUniformValue>) -> &mut Self {
153 self.uniforms.push(ShaderUniform {
154 name: name.to_string(),
155 value: value.into(),
156 });
157 self
158 }
159
160 pub(crate) fn into_config(&mut self) -> ShaderConfig {
162 ShaderConfig {
163 fragment: self.source.fragment_source(),
164 uniforms: std::mem::take(&mut self.uniforms),
165 name: self.source.cache_key().to_string(),
166 }
167 }
168}