veloren_voxygen/render/pipelines/
rope.rs

1use super::super::{AaMode, Bound, Consts, GlobalsLayouts, 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 Locals {
9    pos_a: [f32; 4],
10    pos_b: [f32; 4],
11    rope_length: f32,
12    _padding: [f32; 3],
13}
14
15impl Locals {
16    pub fn new(pos_a: Vec3<f32>, pos_b: Vec3<f32>, rope_length: f32) -> Self {
17        Self {
18            pos_a: pos_a.with_w(0.0).into_array(),
19            pos_b: pos_b.with_w(0.0).into_array(),
20            rope_length,
21            _padding: [0.0; 3],
22        }
23    }
24}
25
26impl Default for Locals {
27    fn default() -> Self { Self::new(Vec3::zero(), Vec3::zero(), 0.0) }
28}
29
30pub type BoundLocals = Bound<Consts<Locals>>;
31
32#[repr(C)]
33#[derive(Copy, Clone, Debug, Zeroable, Pod)]
34pub struct Vertex {
35    pub pos: [f32; 3],
36    pub norm: [f32; 3],
37}
38
39impl Vertex {
40    pub fn new(pos: Vec3<f32>, norm: Vec3<f32>) -> Self {
41        Self {
42            pos: pos.into_array(),
43            norm: norm.into_array(),
44        }
45    }
46
47    fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
48        const ATTRIBUTES: [wgpu::VertexAttribute; 2] =
49            wgpu::vertex_attr_array![0 => Float32x3, 1 => Float32x3];
50        wgpu::VertexBufferLayout {
51            array_stride: Self::STRIDE,
52            step_mode: wgpu::VertexStepMode::Vertex,
53            attributes: &ATTRIBUTES,
54        }
55    }
56}
57
58impl VertexTrait for Vertex {
59    const QUADS_INDEX: Option<wgpu::IndexFormat> = Some(wgpu::IndexFormat::Uint16);
60    const STRIDE: wgpu::BufferAddress = mem::size_of::<Self>() as wgpu::BufferAddress;
61}
62
63pub struct RopeLayout {
64    pub locals: wgpu::BindGroupLayout,
65}
66
67impl RopeLayout {
68    pub fn new(device: &wgpu::Device) -> Self {
69        Self {
70            locals: device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
71                label: None,
72                entries: &[
73                    // locals
74                    wgpu::BindGroupLayoutEntry {
75                        binding: 0,
76                        visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
77                        ty: wgpu::BindingType::Buffer {
78                            ty: wgpu::BufferBindingType::Uniform,
79                            has_dynamic_offset: false,
80                            min_binding_size: None,
81                        },
82                        count: None,
83                    },
84                ],
85            }),
86        }
87    }
88
89    pub fn bind_locals(&self, device: &wgpu::Device, locals: Consts<Locals>) -> BoundLocals {
90        let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
91            label: None,
92            layout: &self.locals,
93            entries: &[wgpu::BindGroupEntry {
94                binding: 0,
95                resource: locals.buf().as_entire_binding(),
96            }],
97        });
98
99        BoundLocals {
100            bind_group,
101            with: locals,
102        }
103    }
104}
105
106pub struct RopePipeline {
107    pub pipeline: wgpu::RenderPipeline,
108}
109
110impl RopePipeline {
111    pub fn new(
112        device: &wgpu::Device,
113        vs_module: &wgpu::ShaderModule,
114        fs_module: &wgpu::ShaderModule,
115        global_layout: &GlobalsLayouts,
116        layout: &RopeLayout,
117        aa_mode: AaMode,
118        format: wgpu::TextureFormat,
119    ) -> Self {
120        common_base::span!(_guard, "RopePipeline::new");
121        let render_pipeline_layout =
122            device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
123                label: Some("Rope pipeline layout"),
124                push_constant_ranges: &[],
125                bind_group_layouts: &[
126                    &global_layout.globals,
127                    &global_layout.shadow_textures,
128                    &layout.locals,
129                ],
130            });
131
132        let samples = aa_mode.samples();
133
134        let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
135            label: Some("Rope pipeline"),
136            layout: Some(&render_pipeline_layout),
137            vertex: wgpu::VertexState {
138                module: vs_module,
139                entry_point: Some("main"),
140                buffers: &[Vertex::desc()],
141                compilation_options: Default::default(),
142            },
143            primitive: wgpu::PrimitiveState {
144                topology: wgpu::PrimitiveTopology::TriangleList,
145                strip_index_format: None,
146                front_face: wgpu::FrontFace::Ccw,
147                cull_mode: Some(wgpu::Face::Back),
148                unclipped_depth: false,
149                polygon_mode: wgpu::PolygonMode::Fill,
150                conservative: false,
151            },
152            depth_stencil: Some(wgpu::DepthStencilState {
153                format: wgpu::TextureFormat::Depth32Float,
154                depth_write_enabled: true,
155                depth_compare: wgpu::CompareFunction::GreaterEqual,
156                stencil: wgpu::StencilState {
157                    front: wgpu::StencilFaceState::IGNORE,
158                    back: wgpu::StencilFaceState::IGNORE,
159                    read_mask: !0,
160                    write_mask: !0,
161                },
162                bias: wgpu::DepthBiasState {
163                    constant: 0,
164                    slope_scale: 0.0,
165                    clamp: 0.0,
166                },
167            }),
168            multisample: wgpu::MultisampleState {
169                count: samples,
170                mask: !0,
171                alpha_to_coverage_enabled: false,
172            },
173            fragment: Some(wgpu::FragmentState {
174                module: fs_module,
175                entry_point: Some("main"),
176                targets: &[
177                    Some(wgpu::ColorTargetState {
178                        format,
179                        blend: Some(wgpu::BlendState {
180                            color: wgpu::BlendComponent {
181                                src_factor: wgpu::BlendFactor::SrcAlpha,
182                                dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
183                                operation: wgpu::BlendOperation::Add,
184                            },
185                            alpha: wgpu::BlendComponent {
186                                src_factor: wgpu::BlendFactor::One,
187                                dst_factor: wgpu::BlendFactor::One,
188                                operation: wgpu::BlendOperation::Add,
189                            },
190                        }),
191                        write_mask: wgpu::ColorWrites::ALL,
192                    }),
193                    Some(wgpu::ColorTargetState {
194                        format: wgpu::TextureFormat::Rgba8Uint,
195                        blend: None,
196                        write_mask: wgpu::ColorWrites::ALL,
197                    }),
198                ],
199                compilation_options: Default::default(),
200            }),
201            multiview: None,
202            cache: None,
203        });
204
205        Self {
206            pipeline: render_pipeline,
207        }
208    }
209}