use std::mem::{offset_of, size_of}; use bytemuck::{bytes_of, Pod, Zeroable}; use glam::{Vec2, Vec3}; #[derive(Debug, Clone, Copy, Pod, Zeroable)] #[repr(C)] pub struct Params { pub seed: u32, pub layers: u32, pub roughness: f32, pub scale: f32, } #[derive(Debug, Clone, Copy, Pod, Zeroable)] #[repr(C)] pub struct Vertex { pub world: Vec3, pub screen: Vec2, } pub struct Pipeline { view_buf: wgpu::Buffer, params_buf: wgpu::Buffer, pipeline: wgpu::RenderPipeline, } static SHADER: &str = include_str!("perlin.wgsl"); impl Pipeline { pub fn new(device: &wgpu::Device) -> Self { let view_buf = device.create_buffer(&wgpu::BufferDescriptor { label: None, size: (4 * size_of::()) as u64, usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, mapped_at_creation: false, }); let params_buf = device.create_buffer(&wgpu::BufferDescriptor { label: None, size: size_of::() as u64, usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, mapped_at_creation: false, }); let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { label: None, source: wgpu::ShaderSource::Wgsl(SHADER.into()), }); let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { label: None, layout: None, vertex: wgpu::VertexState { module: &shader, entry_point: None, compilation_options: wgpu::PipelineCompilationOptions::default(), buffers: &[wgpu::VertexBufferLayout { array_stride: size_of::() as u64, step_mode: wgpu::VertexStepMode::Vertex, attributes: &[ wgpu::VertexAttribute { shader_location: 0, offset: offset_of!(Vertex, screen) as u64, format: wgpu::VertexFormat::Float32x2, }, wgpu::VertexAttribute { shader_location: 1, offset: offset_of!(Vertex, world) as u64, format: wgpu::VertexFormat::Float32x3, }, ], }], }, primitive: wgpu::PrimitiveState { topology: wgpu::PrimitiveTopology::TriangleStrip, ..Default::default() }, depth_stencil: None, multisample: wgpu::MultisampleState { count: 1, mask: !0, alpha_to_coverage_enabled: false, }, fragment: Some(wgpu::FragmentState { module: &shader, entry_point: None, compilation_options: wgpu::PipelineCompilationOptions::default(), targets: &[Some(wgpu::ColorTargetState { format: wgpu::TextureFormat::Bgra8UnormSrgb, blend: Some(wgpu::BlendState::REPLACE), write_mask: wgpu::ColorWrites::ALL, })], }), multiview: None, cache: None, }); Self { view_buf, params_buf, pipeline, } } pub fn set_params(&mut self, queue: &wgpu::Queue, params: Params) { queue.write_buffer(&self.params_buf, 0, bytes_of(¶ms)); } pub fn set_view(&mut self, queue: &wgpu::Queue, vertices: &[Vertex; 4]) { queue.write_buffer(&self.view_buf, 0, bytes_of(vertices)); } pub fn render(&self, pass: &mut wgpu::RenderPass) { pass.set_pipeline(&self.pipeline); pass.set_vertex_buffer(0, self.view_buf.slice(..)); pass.draw(0..4, 0..1); } }