1use cuneus::prelude::ComputeShader;
2use cuneus::{Core, RenderKit, ShaderApp, ShaderManager};
3use cuneus::WindowEvent;
4cuneus::uniform_params! {
5 struct ShaderParams {
6 lambda: f32,
7 theta: f32,
8 alpha: f32,
9 sigma: f32,
10 gamma: f32,
11 blue: f32,
12 a: f32,
13 b: f32,
14 base_color_r: f32,
15 base_color_g: f32,
16 base_color_b: f32,
17 accent_color_r: f32,
18 accent_color_g: f32,
19 accent_color_b: f32,
20 background_r: f32,
21 background_g: f32,
22 background_b: f32,
23 gamma_correction: f32,
24 aces_tonemapping: f32,
25 _padding: f32}
26}
27
28struct Shader {
29 base: RenderKit,
30 compute_shader: ComputeShader,
31 current_params: ShaderParams}
32fn main() -> Result<(), Box<dyn std::error::Error>> {
33 env_logger::init();
34 let (app, event_loop) = ShaderApp::new("sdvert", 800, 600);
35 app.run(event_loop, Shader::init)
36}
37impl ShaderManager for Shader {
38 fn init(core: &Core) -> Self {
39 let base = RenderKit::new(core);
41
42 let initial_params = ShaderParams {
43 sigma: 0.07,
44 gamma: 1.5,
45 blue: 1.0,
46 a: 2.0,
47 b: 0.5,
48 lambda: 3.0,
49 theta: 2.0,
50 alpha: 0.3,
51 base_color_r: 1.0,
52 base_color_g: 1.0,
53 base_color_b: 1.0,
54 accent_color_r: 1.0,
55 accent_color_g: 1.0,
56 accent_color_b: 1.0,
57 background_r: 0.6,
58 background_g: 0.9,
59 background_b: 0.9,
60 gamma_correction: 0.41,
61 aces_tonemapping: 0.4,
62 _padding: 0.0};
63
64 let config = ComputeShader::builder()
65 .with_entry_point("main")
66 .with_custom_uniforms::<ShaderParams>()
67 .build();
68
69 let compute_shader = cuneus::compute_shader!(core, "shaders/sdvert.wgsl", config);
70
71 compute_shader.set_custom_params(initial_params, &core.queue);
72
73 Self {
74 base,
75 compute_shader,
76 current_params: initial_params}
77 }
78
79 fn update(&mut self, core: &Core) {
80 let current_time = self.base.controls.get_time(&self.base.start_time);
82 let delta = 1.0 / 60.0;
83 self.compute_shader
84 .set_time(current_time, delta, &core.queue);
85 self.compute_shader.handle_export(core, &mut self.base);
87 }
88
89 fn render(&mut self, core: &Core) -> Result<(), cuneus::SurfaceError> {
90 let mut frame = self.base.begin_frame(core)?;
91
92 let mut params = self.current_params;
93 let mut changed = false;
94 let mut should_start_export = false;
95 let mut export_request = self.base.export_manager.get_ui_request();
96 let mut controls_request = self
97 .base
98 .controls
99 .get_ui_request(&self.base.start_time, &core.size, self.base.fps_tracker.fps());
100
101 let full_output = if self.base.key_handler.show_ui {
102 self.base.render_ui(core, |ctx| {
103 RenderKit::apply_default_style(ctx);
104
105 egui::Window::new("SDVert Controls")
106 .collapsible(true)
107 .resizable(true)
108 .default_width(300.0)
109 .show(ctx, |ui| {
110 egui::CollapsingHeader::new("Geometry")
111 .default_open(false)
112 .show(ui, |ui| {
113 changed |= ui
114 .add(
115 egui::Slider::new(&mut params.lambda, 1.0..=20.0)
116 .text("Vertices"),
117 )
118 .changed();
119 changed |= ui
120 .add(
121 egui::Slider::new(&mut params.theta, 0.0..=10.0)
122 .text("Angle Scale"),
123 )
124 .changed();
125 changed |= ui
126 .add(
127 egui::Slider::new(&mut params.gamma, 0.1..=3.0)
128 .text("Layer Size"),
129 )
130 .changed();
131 changed |= ui
132 .add(
133 egui::Slider::new(&mut params.alpha, 0.001..=0.5)
134 .text("Layer Min"),
135 )
136 .changed();
137 changed |= ui
138 .add(
139 egui::Slider::new(&mut params.sigma, 0.01..=0.5)
140 .text("Layer Max"),
141 )
142 .changed();
143 });
144
145 egui::CollapsingHeader::new("Shape Parameters")
146 .default_open(false)
147 .show(ui, |ui| {
148 changed |= ui
149 .add(
150 egui::Slider::new(&mut params.a, 0.0..=5.0)
151 .text("Depth Factor"),
152 )
153 .changed();
154 changed |= ui
155 .add(
156 egui::Slider::new(&mut params.b, 0.0..=5.0)
157 .text("Fold Pattern"),
158 )
159 .changed();
160 changed |= ui
161 .add(
162 egui::Slider::new(&mut params.blue, 0.0..=5.0)
163 .text("Hue Shift"),
164 )
165 .changed();
166 });
167
168 egui::CollapsingHeader::new("Colors")
169 .default_open(false)
170 .show(ui, |ui| {
171 ui.horizontal(|ui| {
172 ui.label("Base:");
173 let mut base_color = [
174 params.base_color_r,
175 params.base_color_g,
176 params.base_color_b,
177 ];
178 if ui.color_edit_button_rgb(&mut base_color).changed() {
179 params.base_color_r = base_color[0];
180 params.base_color_g = base_color[1];
181 params.base_color_b = base_color[2];
182 changed = true;
183 }
184 });
185 ui.horizontal(|ui| {
186 ui.label("Accent:");
187 let mut accent_color = [
188 params.accent_color_r,
189 params.accent_color_g,
190 params.accent_color_b,
191 ];
192 if ui.color_edit_button_rgb(&mut accent_color).changed() {
193 params.accent_color_r = accent_color[0];
194 params.accent_color_g = accent_color[1];
195 params.accent_color_b = accent_color[2];
196 changed = true;
197 }
198 });
199 ui.horizontal(|ui| {
200 ui.label("Background:");
201 let mut bg_color = [
202 params.background_r,
203 params.background_g,
204 params.background_b,
205 ];
206 if ui.color_edit_button_rgb(&mut bg_color).changed() {
207 params.background_r = bg_color[0];
208 params.background_g = bg_color[1];
209 params.background_b = bg_color[2];
210 changed = true;
211 }
212 });
213 });
214
215 egui::CollapsingHeader::new("Post-Processing")
216 .default_open(false)
217 .show(ui, |ui| {
218 changed |= ui
219 .add(
220 egui::Slider::new(&mut params.gamma_correction, 0.1..=3.0)
221 .text("Gamma Correction"),
222 )
223 .changed();
224 changed |= ui
225 .add(
226 egui::Slider::new(&mut params.aces_tonemapping, 0.0..=2.0)
227 .text("ACES Tonemapping"),
228 )
229 .changed();
230 });
231
232 ui.separator();
233 cuneus::ShaderControls::render_controls_widget(ui, &mut controls_request);
234
235 ui.separator();
236 should_start_export =
237 cuneus::ExportManager::render_export_ui_widget(ui, &mut export_request);
238 });
239 })
240 } else {
241 self.base.render_ui(core, |_ctx| {})
242 };
243
244 self.base.export_manager.apply_ui_request(export_request);
245 self.base.apply_control_request(controls_request);
246
247 if changed {
248 self.current_params = params;
249 self.compute_shader.set_custom_params(params, &core.queue);
250 }
251
252 if should_start_export {
253 self.base.export_manager.start_export();
254 }
255
256 let current_time = self.base.controls.get_time(&self.base.start_time);
260 let delta_time = 1.0 / 60.0;
261 self.compute_shader
262 .set_time(current_time, delta_time, &core.queue);
263
264 self.compute_shader.dispatch(&mut frame.encoder, core);
266
267 self.base.renderer.render_to_view(&mut frame.encoder, &frame.view, &self.compute_shader.get_output_texture().bind_group);
268
269 self.base.end_frame(core, frame, full_output);
270
271 Ok(())
272 }
273 fn resize(&mut self, core: &Core) {
274 self.base.default_resize(core, &mut self.compute_shader);
275 }
276 fn handle_input(&mut self, core: &Core, event: &WindowEvent) -> bool {
277 self.base.default_handle_input(core, event)
278 }
279}