diff options
Diffstat (limited to 'client/src/render/scene/pipelines.rs')
-rw-r--r-- | client/src/render/scene/pipelines.rs | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/client/src/render/scene/pipelines.rs b/client/src/render/scene/pipelines.rs new file mode 100644 index 0000000..3b6758e --- /dev/null +++ b/client/src/render/scene/pipelines.rs @@ -0,0 +1,196 @@ +/* + wearechat - generic multiplayer game with voip + Copyright (C) 2025 metamuffin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, version 3 of the License only. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ +use wgpu::{ + BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType, BlendState, + BufferBindingType, ColorTargetState, ColorWrites, CompareFunction, DepthBiasState, + DepthStencilState, Device, Face, FragmentState, FrontFace, MultisampleState, + PipelineCompilationOptions, PipelineLayoutDescriptor, PolygonMode, PrimitiveState, + PrimitiveTopology, PushConstantRange, RenderPipeline, RenderPipelineDescriptor, + SamplerBindingType, ShaderStages, StencilState, TextureFormat, TextureSampleType, + TextureViewDimension, VertexAttribute, VertexBufferLayout, VertexFormat, VertexState, + VertexStepMode, +}; + +use crate::shaders::SceneShaders; + +use super::PipelineSpec; + +pub struct SceneBgLayouts { + pub texture: BindGroupLayout, + pub material: BindGroupLayout, + pub joints: BindGroupLayout, +} + +impl SceneBgLayouts { + pub fn load(device: &Device) -> Self { + Self { + texture: device.create_bind_group_layout(&BindGroupLayoutDescriptor { + entries: &[ + BindGroupLayoutEntry { + binding: 0, + count: None, + visibility: ShaderStages::FRAGMENT, + ty: BindingType::Texture { + sample_type: TextureSampleType::Float { filterable: true }, + view_dimension: TextureViewDimension::D2, + multisampled: false, + }, + }, + BindGroupLayoutEntry { + binding: 1, + count: None, + visibility: ShaderStages::FRAGMENT, + ty: BindingType::Sampler(SamplerBindingType::Filtering), + }, + ], + label: None, + }), + material: device.create_bind_group_layout(&BindGroupLayoutDescriptor { + entries: &[BindGroupLayoutEntry { + binding: 0, + count: None, + visibility: ShaderStages::FRAGMENT, + ty: BindingType::Buffer { + ty: BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + }], + label: None, + }), + joints: device.create_bind_group_layout(&BindGroupLayoutDescriptor { + entries: &[BindGroupLayoutEntry { + binding: 0, + count: None, + visibility: ShaderStages::VERTEX, + ty: BindingType::Buffer { + ty: BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + }], + label: None, + }), + } + } +} + +impl PipelineSpec { + pub fn create( + &self, + device: &Device, + layouts: &SceneBgLayouts, + shaders: &SceneShaders, + ) -> RenderPipeline { + let pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor { + label: None, + bind_group_layouts: &[&layouts.texture, &layouts.texture, &layouts.material], + push_constant_ranges: &[PushConstantRange { + // 4x4 view projections + // 3x3(+1 pad) model basis + range: 0..((4 * 4 + 3 * 4) * size_of::<f32>() as u32), + stages: ShaderStages::VERTEX, + }], + }); + device.create_render_pipeline(&RenderPipelineDescriptor { + label: None, + layout: Some(&pipeline_layout), + fragment: Some(FragmentState { + module: &shaders.fragment_pbr, + entry_point: Some("main"), + targets: &[Some(ColorTargetState { + blend: Some(BlendState::PREMULTIPLIED_ALPHA_BLENDING), + format: self.format, + write_mask: ColorWrites::all(), + })], + compilation_options: PipelineCompilationOptions::default(), + }), + vertex: VertexState { + module: if self.skin { + &shaders.vertex_world_skin + } else { + &shaders.vertex_world + }, + entry_point: Some("main"), + buffers: &[ + // position + VertexBufferLayout { + step_mode: VertexStepMode::Vertex, + array_stride: 3 * size_of::<f32>() as u64, + attributes: &[VertexAttribute { + format: VertexFormat::Float32x3, + offset: 0, + shader_location: 0, + }], + }, + // normal + VertexBufferLayout { + step_mode: VertexStepMode::Vertex, + array_stride: 3 * size_of::<f32>() as u64, + attributes: &[VertexAttribute { + format: VertexFormat::Float32x3, + offset: 0, + shader_location: 1, + }], + }, + // tangent + VertexBufferLayout { + step_mode: VertexStepMode::Vertex, + array_stride: 3 * size_of::<f32>() as u64, + attributes: &[VertexAttribute { + format: VertexFormat::Float32x3, + offset: 0, + shader_location: 2, + }], + }, + // texcoord + VertexBufferLayout { + step_mode: VertexStepMode::Vertex, + array_stride: 2 * size_of::<f32>() as u64, + attributes: &[VertexAttribute { + format: VertexFormat::Float32x2, + offset: 0, + shader_location: 3, + }], + }, + ], + compilation_options: PipelineCompilationOptions::default(), + }, + primitive: PrimitiveState { + topology: PrimitiveTopology::TriangleList, + front_face: FrontFace::Ccw, + cull_mode: if self.backface_culling { + Some(Face::Back) + } else { + None + }, + polygon_mode: PolygonMode::Fill, + ..Default::default() + }, + depth_stencil: Some(DepthStencilState { + depth_write_enabled: true, + depth_compare: CompareFunction::Less, + format: TextureFormat::Depth32Float, + bias: DepthBiasState::default(), + stencil: StencilState::default(), + }), + multisample: MultisampleState::default(), + multiview: None, + cache: None, + }) + } +} |