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
40#[allow(dead_code)]
41fn mk_bind_group_layout(device: &wgpu::Device) -> wgpu::BindGroupLayout {
42    device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
43        entries: &[
44            wgpu::BindGroupLayoutEntry {
45                binding: 0,
46                visibility: wgpu::ShaderStages::FRAGMENT,
47                ty: wgpu::BindingType::Texture {
48                    multisampled: false,
49                    view_dimension: wgpu::TextureViewDimension::D2,
50                    sample_type: wgpu::TextureSampleType::Float { filterable: true },
51                },
52                count: None,
53            },
54            wgpu::BindGroupLayoutEntry {
55                binding: 1,
56                visibility: wgpu::ShaderStages::FRAGMENT,
57                ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
58                count: None,
59            },
60        ],
61        label: Some("Menu texture_bind_group_layout"),
62    })
63}
64
65/**
66 * Warning: make sure the texture atlas is smaller than 2048x2048 bytes as not all browsers
67 * support graphics APIs that can handle larger images.
68 */
69#[allow(dead_code)]
70fn mk_bind_group(
71    device: &wgpu::Device,
72    texture_atlas: Texture,
73    texture_bind_group_layout: &wgpu::BindGroupLayout,
74) -> wgpu::BindGroup {
75    device.create_bind_group(&wgpu::BindGroupDescriptor {
76        layout: texture_bind_group_layout,
77        entries: &[
78            wgpu::BindGroupEntry {
79                binding: 0,
80                resource: wgpu::BindingResource::TextureView(&texture_atlas.view),
81            },
82            wgpu::BindGroupEntry {
83                binding: 1,
84                resource: wgpu::BindingResource::Sampler(&texture_atlas.sampler.unwrap()),
85            },
86        ],
87        label: Some("diffuse_bind_group"),
88    })
89}
90
91fn mk_pipeline_layout(
92    device: &wgpu::Device,
93    texture_bind_group_layout: wgpu::BindGroupLayout,
94) -> wgpu::PipelineLayout {
95    device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
96        label: Some("Menu Render Pipeline Layout"),
97        bind_group_layouts: &[&texture_bind_group_layout],
98        push_constant_ranges: &[],
99    })
100}
101
102fn mk_texture_bind_group_layout(device: &wgpu::Device) -> wgpu::BindGroupLayout {
103    device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
104        entries: &[
105            wgpu::BindGroupLayoutEntry {
106                binding: 0,
107                visibility: wgpu::ShaderStages::FRAGMENT,
108                ty: wgpu::BindingType::Texture {
109                    multisampled: false,
110                    view_dimension: wgpu::TextureViewDimension::D2,
111                    sample_type: wgpu::TextureSampleType::Float { filterable: true },
112                },
113                count: None,
114            },
115            wgpu::BindGroupLayoutEntry {
116                binding: 1,
117                visibility: wgpu::ShaderStages::FRAGMENT,
118                ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
119                count: None,
120            },
121        ],
122        label: Some("Menu texture_bind_group_layout"),
123    })
124}
125
126fn mk_render_pipeline(
127    device: &wgpu::Device,
128    config: &wgpu::SurfaceConfiguration,
129    render_pipeline_layout: &wgpu::PipelineLayout,
130    shader: &wgpu::ShaderModule,
131) -> wgpu::RenderPipeline {
132    device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
133        label: Some("Menu Render Pipeline"),
134        layout: Some(&render_pipeline_layout),
135        vertex: wgpu::VertexState {
136            module: shader,
137            entry_point: Some("vs_main"),
138            buffers: &[Vertex::desc()],
139            compilation_options: Default::default(),
140        },
141        fragment: Some(wgpu::FragmentState {
142            module: shader,
143            entry_point: Some("fs_main"),
144            targets: &[Some(wgpu::ColorTargetState {
145                format: config.format,
146                blend: Some(wgpu::BlendState {
147                    color: wgpu::BlendComponent::OVER,
148                    alpha: wgpu::BlendComponent::OVER,
149                }),
150                write_mask: wgpu::ColorWrites::ALL,
151            })],
152            compilation_options: Default::default(),
153        }),
154        primitive: wgpu::PrimitiveState {
155            topology: wgpu::PrimitiveTopology::TriangleList,
156            strip_index_format: None,
157            front_face: wgpu::FrontFace::Ccw,
158            cull_mode: Some(wgpu::Face::Back),
159            polygon_mode: wgpu::PolygonMode::Fill,
160            unclipped_depth: false,
161            conservative: false,
162        },
163        depth_stencil: Some(wgpu::DepthStencilState {
164            format: texture::Texture::DEPTH_FORMAT,
165            depth_write_enabled: true,
166            depth_compare: wgpu::CompareFunction::Less,
167            stencil: wgpu::StencilState::default(),
168            bias: wgpu::DepthBiasState::default(),
169        }),
170        multisample: wgpu::MultisampleState {
171            count: 1,
172            mask: !0,
173            alpha_to_coverage_enabled: false,
174        },
175        multiview: None,
176        // Useful for optimizing shader compilation on Android
177        cache: None,
178    })
179}
180
181pub fn mk_gui_pipeline(device: &wgpu::Device, config: &wgpu::SurfaceConfiguration) -> wgpu::RenderPipeline {
182    let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
183        label: Some("Shader"),
184        source: wgpu::ShaderSource::Wgsl(include_str!("icon.wgsl").into()),
185    });
186    let texture_bind_group_layout = mk_texture_bind_group_layout(device);
187    let render_pipeline_layout = &mk_pipeline_layout(device, texture_bind_group_layout);
188    mk_render_pipeline(device, config, render_pipeline_layout, &shader)
189}