use crate::ecs::mesh::components::Vertex;
use std::collections::HashMap;
use super::{
CullingUniforms, DrawIndexedIndirect, INITIAL_WATER_BATCHES, INITIAL_WATER_INDEX_BUFFER_SIZE,
INITIAL_WATER_INSTANCES, INITIAL_WATER_MATERIALS, INITIAL_WATER_OBJECTS,
INITIAL_WATER_VERTEX_BUFFER_SIZE, WaterInstance, WaterMaterialData, WaterMeshPass,
WaterObjectData,
};
impl WaterMeshPass {
pub fn new(
device: &wgpu::Device,
color_format: wgpu::TextureFormat,
depth_format: wgpu::TextureFormat,
) -> Self {
let uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Water Mesh Uniform Buffer"),
size: std::mem::size_of::<super::WaterUniforms>() as u64,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let culling_uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Water Mesh Culling Uniform Buffer"),
size: std::mem::size_of::<CullingUniforms>() as u64,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let material_buffer_size = INITIAL_WATER_MATERIALS;
let material_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Water Mesh Material Buffer"),
size: (std::mem::size_of::<WaterMaterialData>() * material_buffer_size) as u64,
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let instance_buffer_size = INITIAL_WATER_INSTANCES;
let instance_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Water Mesh Instance Buffer"),
size: (std::mem::size_of::<WaterInstance>() * instance_buffer_size) as u64,
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let object_buffer_size = INITIAL_WATER_OBJECTS;
let object_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Water Mesh Object Buffer"),
size: (std::mem::size_of::<WaterObjectData>() * object_buffer_size) as u64,
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let mesh_bounds_buffer_size = 64;
let mesh_bounds_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Water Mesh Bounds Buffer"),
size: (std::mem::size_of::<super::MeshBoundsData>() * mesh_bounds_buffer_size) as u64,
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let visible_indices_buffer_size = INITIAL_WATER_INSTANCES;
let visible_indices_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Water Mesh Visible Indices Buffer"),
size: (std::mem::size_of::<u32>() * visible_indices_buffer_size) as u64,
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let indirect_buffer_size = INITIAL_WATER_BATCHES;
let indirect_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Water Mesh Indirect Buffer"),
size: (std::mem::size_of::<DrawIndexedIndirect>() * indirect_buffer_size) as u64,
usage: wgpu::BufferUsages::INDIRECT
| wgpu::BufferUsages::STORAGE
| wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let indirect_reset_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Water Mesh Indirect Reset Buffer"),
size: (std::mem::size_of::<DrawIndexedIndirect>() * indirect_buffer_size) as u64,
usage: wgpu::BufferUsages::COPY_SRC | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let vertex_buffer_size = INITIAL_WATER_VERTEX_BUFFER_SIZE;
let vertex_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Water Mesh Unified Vertex Buffer"),
size: (std::mem::size_of::<Vertex>() * vertex_buffer_size) as u64,
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let index_buffer_size = INITIAL_WATER_INDEX_BUFFER_SIZE;
let index_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Water Mesh Unified Index Buffer"),
size: (std::mem::size_of::<u32>() * index_buffer_size) as u64,
usage: wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let render_bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("Water Mesh Render Bind Group Layout"),
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 2,
visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 3,
visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
],
});
let render_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("Water Mesh Render Bind Group"),
layout: &render_bind_group_layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: uniform_buffer.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 1,
resource: material_buffer.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 2,
resource: instance_buffer.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 3,
resource: visible_indices_buffer.as_entire_binding(),
},
],
});
let culling_bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("Water Mesh Culling Bind Group Layout"),
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 2,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 3,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 4,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: false },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 5,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: false },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 6,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
],
});
let horizontal_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("Water Mesh Horizontal Shader"),
source: wgpu::ShaderSource::Wgsl(
include_str!("../../../shaders/water_mesh.wgsl").into(),
),
});
let vertical_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("Water Mesh Vertical Shader"),
source: wgpu::ShaderSource::Wgsl(
include_str!("../../../shaders/water_mesh_vertical.wgsl").into(),
),
});
let volumetric_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("Water Volume Shader"),
source: wgpu::ShaderSource::Wgsl(
include_str!("../../../shaders/water_volume.wgsl").into(),
),
});
let culling_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("Water Mesh Culling Shader"),
source: wgpu::ShaderSource::Wgsl(
include_str!("../../../shaders/water_mesh_culling.wgsl").into(),
),
});
let render_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Water Mesh Render Pipeline Layout"),
bind_group_layouts: &[Some(&render_bind_group_layout)],
immediate_size: 0,
});
let culling_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Water Mesh Culling Pipeline Layout"),
bind_group_layouts: &[Some(&culling_bind_group_layout)],
immediate_size: 0,
});
let vertex_layout = wgpu::VertexBufferLayout {
array_stride: std::mem::size_of::<Vertex>() as u64,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &[
wgpu::VertexAttribute {
format: wgpu::VertexFormat::Float32x3,
offset: 0,
shader_location: 0,
},
wgpu::VertexAttribute {
format: wgpu::VertexFormat::Float32x3,
offset: 12,
shader_location: 1,
},
wgpu::VertexAttribute {
format: wgpu::VertexFormat::Float32x2,
offset: 24,
shader_location: 2,
},
],
};
let horizontal_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Water Mesh Horizontal Pipeline"),
layout: Some(&render_pipeline_layout),
vertex: wgpu::VertexState {
module: &horizontal_shader,
entry_point: Some("vs_main"),
buffers: std::slice::from_ref(&vertex_layout),
compilation_options: Default::default(),
},
fragment: Some(wgpu::FragmentState {
module: &horizontal_shader,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
format: color_format,
blend: Some(wgpu::BlendState::ALPHA_BLENDING),
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: Default::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
front_face: wgpu::FrontFace::Ccw,
cull_mode: None,
..Default::default()
},
depth_stencil: Some(wgpu::DepthStencilState {
format: depth_format,
depth_write_enabled: Some(true),
depth_compare: Some(wgpu::CompareFunction::GreaterEqual),
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState::default(),
multiview_mask: None,
cache: None,
});
let vertical_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Water Mesh Vertical Pipeline"),
layout: Some(&render_pipeline_layout),
vertex: wgpu::VertexState {
module: &vertical_shader,
entry_point: Some("vs_main"),
buffers: std::slice::from_ref(&vertex_layout),
compilation_options: Default::default(),
},
fragment: Some(wgpu::FragmentState {
module: &vertical_shader,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
format: color_format,
blend: Some(wgpu::BlendState::ALPHA_BLENDING),
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: Default::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
front_face: wgpu::FrontFace::Ccw,
cull_mode: None,
..Default::default()
},
depth_stencil: Some(wgpu::DepthStencilState {
format: depth_format,
depth_write_enabled: Some(true),
depth_compare: Some(wgpu::CompareFunction::GreaterEqual),
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState::default(),
multiview_mask: None,
cache: None,
});
let volumetric_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Water Volume Pipeline"),
layout: Some(&render_pipeline_layout),
vertex: wgpu::VertexState {
module: &volumetric_shader,
entry_point: Some("vs_main"),
buffers: &[vertex_layout],
compilation_options: Default::default(),
},
fragment: Some(wgpu::FragmentState {
module: &volumetric_shader,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
format: color_format,
blend: Some(wgpu::BlendState::ALPHA_BLENDING),
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: Default::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
front_face: wgpu::FrontFace::Ccw,
cull_mode: Some(wgpu::Face::Front),
..Default::default()
},
depth_stencil: Some(wgpu::DepthStencilState {
format: depth_format,
depth_write_enabled: Some(false),
depth_compare: Some(wgpu::CompareFunction::GreaterEqual),
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState::default(),
multiview_mask: None,
cache: None,
});
let culling_pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
label: Some("Water Mesh Culling Pipeline"),
layout: Some(&culling_pipeline_layout),
module: &culling_shader,
entry_point: Some("main"),
compilation_options: Default::default(),
cache: None,
});
Self {
horizontal_pipeline,
vertical_pipeline,
volumetric_pipeline,
culling_pipeline,
uniform_buffer,
culling_uniform_buffer,
render_bind_group_layout,
render_bind_group,
culling_bind_group_layout,
culling_bind_group: None,
material_buffer,
instance_buffer,
object_buffer,
mesh_bounds_buffer,
visible_indices_buffer,
indirect_buffer,
indirect_reset_buffer,
vertex_buffer,
index_buffer,
vertex_buffer_size,
index_buffer_size,
instance_buffer_size,
material_buffer_size,
object_buffer_size,
mesh_bounds_buffer_size,
visible_indices_buffer_size,
indirect_buffer_size,
current_vertex_offset: 0,
current_index_offset: 0,
meshes: HashMap::new(),
next_mesh_id: 0,
horizontal_batches: Vec::new(),
vertical_batches: Vec::new(),
volumetric_batches: Vec::new(),
batch_count: 0,
object_count: 0,
indirect_reset_count: 0,
camera_position: [0.0, 0.0, 0.0],
}
}
}