Skip to main content

veloren_voxygen/render/pipelines/
fluid.rs

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