1use std::f32;
8
9use crate::context::Context;
10use crate::post_processing::post_processing_effect::{PostProcessingContext, PostProcessingEffect};
11use crate::resource::RenderTarget;
12use bytemuck::{Pod, Zeroable};
13
14#[repr(C)]
16#[derive(Copy, Clone, Debug, Pod, Zeroable)]
17struct QuadVertex {
18 position: [f32; 2],
19}
20
21#[repr(C)]
23#[derive(Copy, Clone, Debug, Pod, Zeroable)]
24struct WavesUniforms {
25 offset: f32,
26 _padding: [f32; 3],
27}
28
29pub struct Waves {
33 pipeline: wgpu::RenderPipeline,
34 texture_bind_group_layout: wgpu::BindGroupLayout,
35 #[allow(dead_code)]
36 uniform_bind_group_layout: wgpu::BindGroupLayout,
37 uniform_buffer: wgpu::Buffer,
38 uniform_bind_group: wgpu::BindGroup,
39 vertex_buffer: wgpu::Buffer,
40 time: f32,
41}
42
43impl Default for Waves {
44 fn default() -> Self {
45 Self::new()
46 }
47}
48
49impl Waves {
50 pub fn new() -> Waves {
52 let ctxt = Context::get();
53
54 let texture_bind_group_layout =
56 ctxt.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
57 label: Some("waves_texture_bind_group_layout"),
58 entries: &[
59 wgpu::BindGroupLayoutEntry {
60 binding: 0,
61 visibility: wgpu::ShaderStages::FRAGMENT,
62 ty: wgpu::BindingType::Texture {
63 sample_type: wgpu::TextureSampleType::Float { filterable: true },
64 view_dimension: wgpu::TextureViewDimension::D2,
65 multisampled: false,
66 },
67 count: None,
68 },
69 wgpu::BindGroupLayoutEntry {
70 binding: 1,
71 visibility: wgpu::ShaderStages::FRAGMENT,
72 ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
73 count: None,
74 },
75 ],
76 });
77
78 let uniform_bind_group_layout =
80 ctxt.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
81 label: Some("waves_uniform_bind_group_layout"),
82 entries: &[wgpu::BindGroupLayoutEntry {
83 binding: 0,
84 visibility: wgpu::ShaderStages::FRAGMENT,
85 ty: wgpu::BindingType::Buffer {
86 ty: wgpu::BufferBindingType::Uniform,
87 has_dynamic_offset: false,
88 min_binding_size: None,
89 },
90 count: None,
91 }],
92 });
93
94 let pipeline_layout = ctxt.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
95 label: Some("waves_pipeline_layout"),
96 bind_group_layouts: &[&texture_bind_group_layout, &uniform_bind_group_layout],
97 push_constant_ranges: &[],
98 });
99
100 let shader =
102 ctxt.create_shader_module(Some("waves_shader"), include_str!("../builtin/waves.wgsl"));
103
104 let vertex_buffer_layout = wgpu::VertexBufferLayout {
106 array_stride: std::mem::size_of::<QuadVertex>() as wgpu::BufferAddress,
107 step_mode: wgpu::VertexStepMode::Vertex,
108 attributes: &[wgpu::VertexAttribute {
109 offset: 0,
110 shader_location: 0,
111 format: wgpu::VertexFormat::Float32x2,
112 }],
113 };
114
115 let pipeline = ctxt.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
116 label: Some("waves_pipeline"),
117 layout: Some(&pipeline_layout),
118 vertex: wgpu::VertexState {
119 module: &shader,
120 entry_point: Some("vs_main"),
121 buffers: &[vertex_buffer_layout],
122 compilation_options: Default::default(),
123 },
124 fragment: Some(wgpu::FragmentState {
125 module: &shader,
126 entry_point: Some("fs_main"),
127 targets: &[Some(wgpu::ColorTargetState {
128 format: ctxt.surface_format,
129 blend: None,
130 write_mask: wgpu::ColorWrites::ALL,
131 })],
132 compilation_options: Default::default(),
133 }),
134 primitive: wgpu::PrimitiveState {
135 topology: wgpu::PrimitiveTopology::TriangleStrip,
136 strip_index_format: None,
137 front_face: wgpu::FrontFace::Ccw,
138 cull_mode: None,
139 polygon_mode: wgpu::PolygonMode::Fill,
140 unclipped_depth: false,
141 conservative: false,
142 },
143 depth_stencil: None,
144 multisample: wgpu::MultisampleState {
145 count: 1,
146 mask: !0,
147 alpha_to_coverage_enabled: false,
148 },
149 multiview: None,
150 cache: None,
151 });
152
153 let vertices = [
155 QuadVertex {
156 position: [-1.0, -1.0],
157 },
158 QuadVertex {
159 position: [1.0, -1.0],
160 },
161 QuadVertex {
162 position: [-1.0, 1.0],
163 },
164 QuadVertex {
165 position: [1.0, 1.0],
166 },
167 ];
168
169 let vertex_buffer = ctxt.create_buffer_init(
170 Some("waves_vertex_buffer"),
171 bytemuck::cast_slice(&vertices),
172 wgpu::BufferUsages::VERTEX,
173 );
174
175 let uniform_buffer = ctxt.create_buffer_simple(
177 Some("waves_uniform_buffer"),
178 std::mem::size_of::<WavesUniforms>() as u64,
179 wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
180 );
181
182 let uniform_bind_group = ctxt.create_bind_group(&wgpu::BindGroupDescriptor {
184 label: Some("waves_uniform_bind_group"),
185 layout: &uniform_bind_group_layout,
186 entries: &[wgpu::BindGroupEntry {
187 binding: 0,
188 resource: uniform_buffer.as_entire_binding(),
189 }],
190 });
191
192 Waves {
193 pipeline,
194 texture_bind_group_layout,
195 uniform_bind_group_layout,
196 uniform_buffer,
197 uniform_bind_group,
198 vertex_buffer,
199 time: 0.0,
200 }
201 }
202}
203
204impl PostProcessingEffect for Waves {
205 fn update(&mut self, dt: f32, _: f32, _: f32, _: f32, _: f32) {
206 self.time += dt;
207 }
208
209 fn draw(&mut self, target: &RenderTarget, context: &mut PostProcessingContext) {
210 let ctxt = Context::get();
211
212 let (color_view, sampler) = match target {
214 RenderTarget::Offscreen(o) => (&o.color_view, &o.sampler),
215 RenderTarget::Screen => return, };
217
218 let move_amount = self.time * 2.0 * f32::consts::PI * 0.75; let uniforms = WavesUniforms {
221 offset: move_amount,
222 _padding: [0.0; 3],
223 };
224 ctxt.write_buffer(&self.uniform_buffer, 0, bytemuck::bytes_of(&uniforms));
225
226 let texture_bind_group = ctxt.create_bind_group(&wgpu::BindGroupDescriptor {
228 label: Some("waves_texture_bind_group"),
229 layout: &self.texture_bind_group_layout,
230 entries: &[
231 wgpu::BindGroupEntry {
232 binding: 0,
233 resource: wgpu::BindingResource::TextureView(color_view),
234 },
235 wgpu::BindGroupEntry {
236 binding: 1,
237 resource: wgpu::BindingResource::Sampler(sampler),
238 },
239 ],
240 });
241
242 {
244 let mut render_pass = context
245 .encoder
246 .begin_render_pass(&wgpu::RenderPassDescriptor {
247 label: Some("waves_render_pass"),
248 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
249 view: context.output_view,
250 resolve_target: None,
251 ops: wgpu::Operations {
252 load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
253 store: wgpu::StoreOp::Store,
254 },
255 depth_slice: None,
256 })],
257 depth_stencil_attachment: None,
258 timestamp_writes: None,
259 occlusion_query_set: None,
260 });
261
262 render_pass.set_pipeline(&self.pipeline);
263 render_pass.set_bind_group(0, &texture_bind_group, &[]);
264 render_pass.set_bind_group(1, &self.uniform_bind_group, &[]);
265 render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
266 render_pass.draw(0..4, 0..1);
267 }
268 }
269}