Skip to main content

flow_ngin/pipelines/
gui.rs

1use crate::data_structures::texture::{self, Texture};
2
3#[repr(C)]
4#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
5pub struct Vertex {
6    pub position: [f32; 3],
7    pub tex_coords: [f32; 2],
8}
9
10impl Vertex {
11    pub fn desc() -> wgpu::VertexBufferLayout<'static> {
12        use std::mem;
13        wgpu::VertexBufferLayout {
14            array_stride: mem::size_of::<Vertex>() as wgpu::BufferAddress,
15            step_mode: wgpu::VertexStepMode::Vertex,
16            attributes: &[
17                wgpu::VertexAttribute {
18                    offset: 0,
19                    shader_location: 0,
20                    format: wgpu::VertexFormat::Float32x3,
21                },
22                wgpu::VertexAttribute {
23                    offset: mem::size_of::<[f32; 3]>() as wgpu::BufferAddress,
24                    shader_location: 1,
25                    format: wgpu::VertexFormat::Float32x2,
26                },
27            ],
28        }
29    }
30}
31
32#[allow(dead_code)]
33fn mk_shader(device: &wgpu::Device) -> wgpu::ShaderModule {
34    device.create_shader_module(wgpu::ShaderModuleDescriptor {
35        label: Some("Shader"),
36        source: wgpu::ShaderSource::Wgsl(include_str!("icon.wgsl").into()),
37    })
38}
39
40pub fn mk_bind_group_layout(device: &wgpu::Device) -> wgpu::BindGroupLayout {
41    device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
42        entries: &[
43            wgpu::BindGroupLayoutEntry {
44                binding: 0,
45                visibility: wgpu::ShaderStages::FRAGMENT,
46                ty: wgpu::BindingType::Texture {
47                    multisampled: false,
48                    view_dimension: wgpu::TextureViewDimension::D2,
49                    sample_type: wgpu::TextureSampleType::Float { filterable: true },
50                },
51                count: None,
52            },
53            wgpu::BindGroupLayoutEntry {
54                binding: 1,
55                visibility: wgpu::ShaderStages::FRAGMENT,
56                ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
57                count: None,
58            },
59        ],
60        label: Some("Menu texture_bind_group_layout"),
61    })
62}
63
64/**
65 * Warning: make sure the texture atlas is smaller than 2048x2048 bytes as not all browsers
66 * support graphics APIs that can handle larger images.
67 */
68pub fn mk_bind_group(
69    device: &wgpu::Device,
70    texture_atlas: &Texture,
71    texture_bind_group_layout: &wgpu::BindGroupLayout,
72) -> wgpu::BindGroup {
73    device.create_bind_group(&wgpu::BindGroupDescriptor {
74        layout: texture_bind_group_layout,
75        entries: &[
76            wgpu::BindGroupEntry {
77                binding: 0,
78                resource: wgpu::BindingResource::TextureView(&texture_atlas.view),
79            },
80            wgpu::BindGroupEntry {
81                binding: 1,
82                resource: wgpu::BindingResource::Sampler(texture_atlas.sampler.as_ref().unwrap()),
83            },
84        ],
85        label: Some("diffuse_bind_group"),
86    })
87}
88
89pub fn mk_screen_size_bind_group_layout(device: &wgpu::Device) -> wgpu::BindGroupLayout {
90    device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
91        entries: &[wgpu::BindGroupLayoutEntry {
92            binding: 0,
93            visibility: wgpu::ShaderStages::VERTEX,
94            ty: wgpu::BindingType::Buffer {
95                ty: wgpu::BufferBindingType::Uniform,
96                has_dynamic_offset: false,
97                min_binding_size: None,
98            },
99            count: None,
100        }],
101        label: Some("screen_size_bind_group_layout"),
102    })
103}
104
105pub fn mk_screen_size_bind_group(
106    device: &wgpu::Device,
107    buffer: &wgpu::Buffer,
108    layout: &wgpu::BindGroupLayout,
109) -> wgpu::BindGroup {
110    device.create_bind_group(&wgpu::BindGroupDescriptor {
111        layout,
112        entries: &[wgpu::BindGroupEntry {
113            binding: 0,
114            resource: buffer.as_entire_binding(),
115        }],
116        label: Some("screen_size_bind_group"),
117    })
118}
119
120fn mk_pipeline_layout(
121    device: &wgpu::Device,
122    texture_bind_group_layout: wgpu::BindGroupLayout,
123    screen_size_bind_group_layout: &wgpu::BindGroupLayout,
124) -> wgpu::PipelineLayout {
125    device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
126        label: Some("Menu Render Pipeline Layout"),
127        bind_group_layouts: &[&texture_bind_group_layout, screen_size_bind_group_layout],
128        ..Default::default()
129    })
130}
131
132fn mk_texture_bind_group_layout(device: &wgpu::Device) -> wgpu::BindGroupLayout {
133    device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
134        entries: &[
135            wgpu::BindGroupLayoutEntry {
136                binding: 0,
137                visibility: wgpu::ShaderStages::FRAGMENT,
138                ty: wgpu::BindingType::Texture {
139                    multisampled: false,
140                    view_dimension: wgpu::TextureViewDimension::D2,
141                    sample_type: wgpu::TextureSampleType::Float { filterable: true },
142                },
143                count: None,
144            },
145            wgpu::BindGroupLayoutEntry {
146                binding: 1,
147                visibility: wgpu::ShaderStages::FRAGMENT,
148                ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
149                count: None,
150            },
151        ],
152        label: Some("Menu texture_bind_group_layout"),
153    })
154}
155
156fn mk_render_pipeline(
157    device: &wgpu::Device,
158    config: &wgpu::SurfaceConfiguration,
159    render_pipeline_layout: &wgpu::PipelineLayout,
160    shader: &wgpu::ShaderModule,
161    sample_count: u32,
162) -> wgpu::RenderPipeline {
163    device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
164        label: Some("Menu Render Pipeline"),
165        layout: Some(&render_pipeline_layout),
166        vertex: wgpu::VertexState {
167            module: shader,
168            entry_point: Some("vs_main"),
169            buffers: &[Vertex::desc()],
170            compilation_options: Default::default(),
171        },
172        fragment: Some(wgpu::FragmentState {
173            module: shader,
174            entry_point: Some("fs_main"),
175            targets: &[Some(wgpu::ColorTargetState {
176                format: config.format,
177                blend: Some(wgpu::BlendState {
178                    color: wgpu::BlendComponent::OVER,
179                    alpha: wgpu::BlendComponent::OVER,
180                }),
181                write_mask: wgpu::ColorWrites::ALL,
182            })],
183            compilation_options: Default::default(),
184        }),
185        primitive: wgpu::PrimitiveState {
186            topology: wgpu::PrimitiveTopology::TriangleList,
187            strip_index_format: None,
188            front_face: wgpu::FrontFace::Ccw,
189            cull_mode: Some(wgpu::Face::Back),
190            polygon_mode: wgpu::PolygonMode::Fill,
191            unclipped_depth: false,
192            conservative: false,
193        },
194        depth_stencil: Some(wgpu::DepthStencilState {
195            format: texture::Texture::DEPTH_FORMAT,
196            depth_write_enabled: true,
197            depth_compare: wgpu::CompareFunction::LessEqual,
198            stencil: wgpu::StencilState::default(),
199            bias: wgpu::DepthBiasState::default(),
200        }),
201        multisample: wgpu::MultisampleState {
202            count: sample_count,
203            mask: !0,
204            alpha_to_coverage_enabled: false,
205        },
206        multiview_mask: None,
207        // Useful for optimizing shader compilation on Android
208        cache: None,
209    })
210}
211
212pub fn mk_gui_pipeline(device: &wgpu::Device, config: &wgpu::SurfaceConfiguration, screen_size_layout: &wgpu::BindGroupLayout, sample_count: u32) -> wgpu::RenderPipeline {
213    let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
214        label: Some("Shader"),
215        source: wgpu::ShaderSource::Wgsl(include_str!("icon.wgsl").into()),
216    });
217    let texture_bind_group_layout = mk_texture_bind_group_layout(device);
218    let render_pipeline_layout = &mk_pipeline_layout(device, texture_bind_group_layout, screen_size_layout);
219    mk_render_pipeline(device, config, render_pipeline_layout, &shader, sample_count)
220}