veloren_voxygen/render/pipelines/
fluid.rs

1use super::super::{AaMode, GlobalsLayouts, TerrainLayout, Vertex as VertexTrait};
2use bytemuck::{Pod, Zeroable};
3use std::mem;
4use vek::*;
5
6#[repr(C)]
7#[derive(Copy, Clone, Debug, Zeroable, Pod)]
8pub struct Vertex {
9    pos_norm: u32,
10    vel: u32,
11}
12
13impl Vertex {
14    pub fn new(pos: Vec3<f32>, norm: Vec3<f32>, river_velocity: Vec2<f32>) -> Self {
15        let (norm_axis, norm_dir) = norm
16            .as_slice()
17            .iter()
18            .enumerate()
19            .find(|(_i, e)| **e != 0.0)
20            .unwrap_or((0, &1.0));
21        let norm_bits = ((norm_axis << 1) | usize::from(*norm_dir > 0.0)) as u32;
22
23        const EXTRA_NEG_Z: f32 = 65536.0;
24
25        Self {
26            pos_norm: 0
27                | (((pos.x as u32) & 0x003F) << 0)
28                | (((pos.y as u32) & 0x003F) << 6)
29                | ((((pos.z + EXTRA_NEG_Z).clamp(0.0, (1 << 17) as f32) as u32) & 0x1FFFF) << 12)
30                | ((norm_bits & 0x7) << 29),
31            vel: river_velocity
32                .map2(Vec2::new(0, 16), |e, off| {
33                    ((e * 1000.0 + 32768.9) as u16 as u32) << off
34                })
35                .reduce_bitor(),
36        }
37    }
38
39    fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
40        const ATTRIBUTES: [wgpu::VertexAttribute; 2] = wgpu::vertex_attr_array![
41            0 => Uint32,
42            1 => Uint32,
43        ];
44        wgpu::VertexBufferLayout {
45            array_stride: Self::STRIDE,
46            step_mode: wgpu::VertexStepMode::Vertex,
47            attributes: &ATTRIBUTES,
48        }
49    }
50}
51
52impl VertexTrait for Vertex {
53    const QUADS_INDEX: Option<wgpu::IndexFormat> = Some(wgpu::IndexFormat::Uint16);
54    const STRIDE: wgpu::BufferAddress = mem::size_of::<Self>() as wgpu::BufferAddress;
55}
56
57pub struct FluidPipeline {
58    pub pipeline: wgpu::RenderPipeline,
59}
60
61impl FluidPipeline {
62    pub fn new(
63        device: &wgpu::Device,
64        vs_module: &wgpu::ShaderModule,
65        fs_module: &wgpu::ShaderModule,
66        global_layout: &GlobalsLayouts,
67        terrain_layout: &TerrainLayout,
68        aa_mode: AaMode,
69        format: wgpu::TextureFormat,
70    ) -> Self {
71        common_base::span!(_guard, "FluidPipeline::new");
72        let render_pipeline_layout =
73            device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
74                label: Some("Fluid pipeline layout"),
75                push_constant_ranges: &[],
76                bind_group_layouts: &[
77                    &global_layout.globals,
78                    &global_layout.shadow_textures,
79                    &terrain_layout.locals,
80                ],
81            });
82
83        let samples = aa_mode.samples();
84
85        let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
86            label: Some("Fluid pipeline"),
87            layout: Some(&render_pipeline_layout),
88            vertex: wgpu::VertexState {
89                module: vs_module,
90                entry_point: "main",
91                buffers: &[Vertex::desc()],
92            },
93            primitive: wgpu::PrimitiveState {
94                topology: wgpu::PrimitiveTopology::TriangleList,
95                strip_index_format: None,
96                front_face: wgpu::FrontFace::Ccw,
97                cull_mode: None,
98                unclipped_depth: false,
99                polygon_mode: wgpu::PolygonMode::Fill,
100                conservative: false,
101            },
102            depth_stencil: Some(wgpu::DepthStencilState {
103                format: wgpu::TextureFormat::Depth32Float,
104                depth_write_enabled: true,
105                depth_compare: wgpu::CompareFunction::GreaterEqual,
106                stencil: wgpu::StencilState {
107                    front: wgpu::StencilFaceState::IGNORE,
108                    back: wgpu::StencilFaceState::IGNORE,
109                    read_mask: !0,
110                    write_mask: 0,
111                },
112                bias: wgpu::DepthBiasState {
113                    constant: 0,
114                    slope_scale: 0.0,
115                    clamp: 0.0,
116                },
117            }),
118            multisample: wgpu::MultisampleState {
119                count: samples,
120                mask: !0,
121                alpha_to_coverage_enabled: false,
122            },
123            fragment: Some(wgpu::FragmentState {
124                module: fs_module,
125                entry_point: "main",
126                targets: &[
127                    Some(wgpu::ColorTargetState {
128                        format,
129                        blend: Some(wgpu::BlendState {
130                            color: wgpu::BlendComponent {
131                                src_factor: wgpu::BlendFactor::SrcAlpha,
132                                dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
133                                operation: wgpu::BlendOperation::Add,
134                            },
135                            alpha: wgpu::BlendComponent {
136                                src_factor: wgpu::BlendFactor::One,
137                                dst_factor: wgpu::BlendFactor::One,
138                                operation: wgpu::BlendOperation::Min,
139                            },
140                        }),
141                        write_mask: wgpu::ColorWrites::ALL,
142                    }),
143                    Some(wgpu::ColorTargetState {
144                        format: wgpu::TextureFormat::Rgba8Uint,
145                        blend: None,
146                        write_mask: wgpu::ColorWrites::ALL,
147                    }),
148                ],
149            }),
150            multiview: None,
151        });
152
153        Self {
154            pipeline: render_pipeline,
155        }
156    }
157}