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: "main",
140                buffers: &[Vertex::desc()],
141            },
142            primitive: wgpu::PrimitiveState {
143                topology: wgpu::PrimitiveTopology::TriangleList,
144                strip_index_format: None,
145                front_face: wgpu::FrontFace::Ccw,
146                cull_mode: Some(wgpu::Face::Back),
147                unclipped_depth: false,
148                polygon_mode: wgpu::PolygonMode::Fill,
149                conservative: false,
150            },
151            depth_stencil: Some(wgpu::DepthStencilState {
152                format: wgpu::TextureFormat::Depth32Float,
153                depth_write_enabled: true,
154                depth_compare: wgpu::CompareFunction::GreaterEqual,
155                stencil: wgpu::StencilState {
156                    front: wgpu::StencilFaceState::IGNORE,
157                    back: wgpu::StencilFaceState::IGNORE,
158                    read_mask: !0,
159                    write_mask: !0,
160                },
161                bias: wgpu::DepthBiasState {
162                    constant: 0,
163                    slope_scale: 0.0,
164                    clamp: 0.0,
165                },
166            }),
167            multisample: wgpu::MultisampleState {
168                count: samples,
169                mask: !0,
170                alpha_to_coverage_enabled: false,
171            },
172            fragment: Some(wgpu::FragmentState {
173                module: fs_module,
174                entry_point: "main",
175                targets: &[
176                    Some(wgpu::ColorTargetState {
177                        format,
178                        blend: Some(wgpu::BlendState {
179                            color: wgpu::BlendComponent {
180                                src_factor: wgpu::BlendFactor::SrcAlpha,
181                                dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
182                                operation: wgpu::BlendOperation::Add,
183                            },
184                            alpha: wgpu::BlendComponent {
185                                src_factor: wgpu::BlendFactor::One,
186                                dst_factor: wgpu::BlendFactor::One,
187                                operation: wgpu::BlendOperation::Add,
188                            },
189                        }),
190                        write_mask: wgpu::ColorWrites::ALL,
191                    }),
192                    Some(wgpu::ColorTargetState {
193                        format: wgpu::TextureFormat::Rgba8Uint,
194                        blend: None,
195                        write_mask: wgpu::ColorWrites::ALL,
196                    }),
197                ],
198            }),
199            multiview: None,
200        });
201
202        Self {
203            pipeline: render_pipeline,
204        }
205    }
206}