1pub mod aurora;
36pub mod bloom;
37pub mod colorblind;
38pub mod crt;
39pub mod glow_on_bell;
40pub mod grain;
41pub mod scanlines;
42pub mod snow;
43
44use engawa::{
45 BindingKind, Effect, Material, Node, RenderGraph, ResourceId, ResourceKind,
46 ShaderSource, UniformBinding,
47};
48use pleme_allvariants_derive::AllVariants;
49
50pub const SCENE: &str = "scene";
53
54pub const OUT: &str = "out";
57
58pub const CATALOG_SAMPLER: &str = "catalog:sampler";
61
62pub(crate) fn post_material(
65 name: &str,
66 wgsl: &str,
67 input: &ResourceId,
68 params_resource: &str,
69) -> Material {
70 Material {
71 name: name.to_string(),
72 shader: ShaderSource::inline(wgsl),
73 bindings: vec![
74 UniformBinding {
75 binding: 0,
76 kind: BindingKind::Texture,
77 resource: input.clone(),
78 },
79 UniformBinding {
80 binding: 1,
81 kind: BindingKind::Sampler,
82 resource: CATALOG_SAMPLER.into(),
83 },
84 UniformBinding {
85 binding: 2,
86 kind: BindingKind::Uniform,
87 resource: params_resource.into(),
88 },
89 ],
90 }
91}
92
93#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, AllVariants)]
97pub enum CatalogEffect {
98 Colorblind,
99 Crt,
100 Scanlines,
101 Bloom,
102 GlowOnBell,
103 Snow,
104 Aurora,
105 Grain,
106}
107
108impl CatalogEffect {
109 #[must_use]
112 pub const fn name(self) -> &'static str {
113 match self {
114 Self::Colorblind => colorblind::EFFECT_NAME,
115 Self::Crt => crt::EFFECT_NAME,
116 Self::Scanlines => scanlines::EFFECT_NAME,
117 Self::Bloom => bloom::EFFECT_NAME,
118 Self::GlowOnBell => glow_on_bell::EFFECT_NAME,
119 Self::Snow => snow::EFFECT_NAME,
120 Self::Aurora => aurora::EFFECT_NAME,
121 Self::Grain => grain::EFFECT_NAME,
122 }
123 }
124
125 #[must_use]
128 pub const fn priority(self) -> u16 {
129 match self {
130 Self::Colorblind => colorblind::PRIORITY,
131 Self::Crt => crt::PRIORITY,
132 Self::Scanlines => scanlines::PRIORITY,
133 Self::Bloom => bloom::PRIORITY,
134 Self::GlowOnBell => glow_on_bell::PRIORITY,
135 Self::Snow => snow::PRIORITY,
136 Self::Aurora => aurora::PRIORITY,
137 Self::Grain => grain::PRIORITY,
138 }
139 }
140
141 #[must_use]
143 pub const fn params_resource(self) -> &'static str {
144 match self {
145 Self::Colorblind => colorblind::PARAMS_RESOURCE,
146 Self::Crt => crt::PARAMS_RESOURCE,
147 Self::Scanlines => scanlines::PARAMS_RESOURCE,
148 Self::Bloom => bloom::PARAMS_RESOURCE,
149 Self::GlowOnBell => glow_on_bell::PARAMS_RESOURCE,
150 Self::Snow => snow::PARAMS_RESOURCE,
151 Self::Aurora => aurora::PARAMS_RESOURCE,
152 Self::Grain => grain::PARAMS_RESOURCE,
153 }
154 }
155
156 #[must_use]
160 pub const fn params_size(self) -> usize {
161 match self {
162 Self::Colorblind => size_of::<colorblind::ColorblindParams>(),
163 Self::Crt => size_of::<crt::CrtParams>(),
164 Self::Scanlines => size_of::<scanlines::ScanlinesParams>(),
165 Self::Bloom => size_of::<bloom::BloomParams>(),
166 Self::GlowOnBell => size_of::<glow_on_bell::GlowOnBellParams>(),
167 Self::Snow => size_of::<snow::SnowParams>(),
168 Self::Aurora => size_of::<aurora::AuroraParams>(),
169 Self::Grain => size_of::<grain::GrainParams>(),
170 }
171 }
172
173 #[must_use]
175 pub const fn tlisp_path(self) -> &'static str {
176 match self {
177 Self::Colorblind => "effects/colorblind.tlisp",
178 Self::Crt => "effects/crt.tlisp",
179 Self::Scanlines => "effects/scanlines.tlisp",
180 Self::Bloom => "effects/bloom.tlisp",
181 Self::GlowOnBell => "effects/glow_on_bell.tlisp",
182 Self::Snow => "effects/snow.tlisp",
183 Self::Aurora => "effects/aurora.tlisp",
184 Self::Grain => "effects/grain.tlisp",
185 }
186 }
187
188 #[must_use]
193 pub fn default_params_bytes(self) -> Vec<u8> {
194 match self {
195 Self::Colorblind => {
196 bytemuck::bytes_of(&colorblind::ColorblindParams::default()).to_vec()
197 }
198 Self::Crt => bytemuck::bytes_of(&crt::CrtParams::default()).to_vec(),
199 Self::Scanlines => {
200 bytemuck::bytes_of(&scanlines::ScanlinesParams::default()).to_vec()
201 }
202 Self::Bloom => bytemuck::bytes_of(&bloom::BloomParams::default()).to_vec(),
203 Self::GlowOnBell => {
204 bytemuck::bytes_of(&glow_on_bell::GlowOnBellParams::default()).to_vec()
205 }
206 Self::Snow => bytemuck::bytes_of(&snow::SnowParams::default()).to_vec(),
207 Self::Aurora => bytemuck::bytes_of(&aurora::AuroraParams::default()).to_vec(),
208 Self::Grain => bytemuck::bytes_of(&grain::GrainParams::default()).to_vec(),
209 }
210 }
211
212 #[must_use]
217 pub fn effect(self) -> Effect {
218 match self {
219 Self::Colorblind => colorblind::effect(),
220 Self::Crt => crt::effect(),
221 Self::Scanlines => scanlines::effect(),
222 Self::Bloom => bloom::effect(),
223 Self::GlowOnBell => glow_on_bell::effect(),
224 Self::Snow => snow::effect(),
225 Self::Aurora => aurora::effect(),
226 Self::Grain => grain::effect(),
227 }
228 }
229
230 #[must_use]
234 pub fn lower(self, input: &ResourceId, output: &ResourceId) -> Vec<Node> {
235 match self {
236 Self::Colorblind => colorblind::lower(input, output),
237 Self::Crt => crt::lower(input, output),
238 Self::Scanlines => scanlines::lower(input, output),
239 Self::Bloom => bloom::lower(input, output),
240 Self::GlowOnBell => glow_on_bell::lower(input, output),
241 Self::Snow => snow::lower(input, output),
242 Self::Aurora => aurora::lower(input, output),
243 Self::Grain => grain::lower(input, output),
244 }
245 }
246
247 #[must_use]
252 pub fn aux_resources(self) -> Vec<(&'static str, ResourceKind)> {
253 match self {
254 Self::Bloom => vec![
255 (
256 bloom::BRIGHT_RESOURCE,
257 ResourceKind::Texture { width: None, height: None },
258 ),
259 (
260 bloom::BLUR_H_RESOURCE,
261 ResourceKind::Texture { width: None, height: None },
262 ),
263 (
264 bloom::BLUR_V_RESOURCE,
265 ResourceKind::Texture { width: None, height: None },
266 ),
267 ],
268 Self::Colorblind
269 | Self::Crt
270 | Self::Scanlines
271 | Self::GlowOnBell
272 | Self::Snow
273 | Self::Aurora
274 | Self::Grain => Vec::new(),
275 }
276 }
277
278 #[must_use]
283 pub fn graph(self) -> RenderGraph {
284 let scene: ResourceId = SCENE.into();
285 let out: ResourceId = OUT.into();
286 let params_size =
287 u32::try_from(self.params_size()).expect("catalog params structs are tiny");
288 let mut g = RenderGraph::default()
289 .with_resource(SCENE, ResourceKind::Texture { width: None, height: None })
290 .with_resource(OUT, ResourceKind::Texture { width: None, height: None })
291 .with_resource(CATALOG_SAMPLER, ResourceKind::Sampler)
292 .with_resource(
293 self.params_resource(),
294 ResourceKind::Uniform { size_bytes: params_size },
295 )
296 .with_input(SCENE)
297 .with_input(CATALOG_SAMPLER)
298 .with_input(self.params_resource())
299 .with_output(OUT);
300 for (id, kind) in self.aux_resources() {
301 g = g.with_resource(id, kind);
302 }
303 for node in self.lower(&scene, &out) {
304 g = g.with_node(node);
305 }
306 g
307 }
308}