summaryrefslogtreecommitdiff
path: root/client/src/scene_render.rs
blob: f80f6c20e4f1d5247126fabd711c7e7ea7fd4ff6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use std::collections::{HashMap, HashSet};
use weareshared::{packets::Resource, tree::SceneTree};
use wgpu::{
    BindGroup, BindGroupDescriptor, BindGroupLayoutDescriptor, BlendState, Color, ColorTargetState,
    ColorWrites, CommandEncoder, Device, FragmentState, FrontFace, IndexFormat, LoadOp,
    MultisampleState, Operations, PipelineCompilationOptions, PipelineLayoutDescriptor,
    PolygonMode, PrimitiveState, PrimitiveTopology, RenderPassColorAttachment,
    RenderPassDescriptor, RenderPipeline, RenderPipelineDescriptor, StoreOp, TextureFormat,
    TextureView, VertexAttribute, VertexBufferLayout, VertexFormat, VertexState, VertexStepMode,
    include_wgsl,
};

use crate::scene_prepare::RPrefab;

pub struct ScenePipeline {
    pipeline: RenderPipeline,
    bind_group: BindGroup,
    prefabs: HashMap<Resource, RPrefab>,
    prefabs_needed: HashSet<Resource>,
}

impl ScenePipeline {
    pub fn new(device: &Device, format: TextureFormat) -> Self {
        let module = device.create_shader_module(include_wgsl!("shader.wgsl"));

        let bind_group_layout = device.create_bind_group_layout(&BindGroupLayoutDescriptor {
            entries: &[],
            label: None,
        });
        let bind_group = device.create_bind_group(&BindGroupDescriptor {
            label: None,
            layout: &bind_group_layout,
            entries: &[],
        });
        let pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor {
            label: None,
            bind_group_layouts: &[&bind_group_layout],
            push_constant_ranges: &[],
        });
        let pipeline = device.create_render_pipeline(&RenderPipelineDescriptor {
            label: None,
            layout: Some(&pipeline_layout),
            fragment: Some(FragmentState {
                module: &module,
                entry_point: Some("fs_main"),
                targets: &[Some(ColorTargetState {
                    blend: Some(BlendState::PREMULTIPLIED_ALPHA_BLENDING),
                    format,
                    write_mask: ColorWrites::all(),
                })],
                compilation_options: PipelineCompilationOptions::default(),
            }),
            vertex: VertexState {
                module: &module,
                entry_point: Some("vs_main"),
                buffers: &[VertexBufferLayout {
                    step_mode: VertexStepMode::Vertex,
                    array_stride: 2 * 4 * 3,
                    attributes: &[
                        VertexAttribute {
                            format: VertexFormat::Float32x3,
                            offset: 0,
                            shader_location: 0,
                        },
                        VertexAttribute {
                            format: VertexFormat::Float32x3,
                            offset: 3 * 4,
                            shader_location: 1,
                        },
                    ],
                }],
                compilation_options: PipelineCompilationOptions::default(),
            },
            primitive: PrimitiveState {
                topology: PrimitiveTopology::TriangleList,
                front_face: FrontFace::Ccw,
                cull_mode: None, //Some(Face::Back),
                polygon_mode: PolygonMode::Fill,
                ..Default::default()
            },
            depth_stencil: Default::default(),
            multisample: MultisampleState::default(),
            multiview: None,
            cache: None,
        });
        Self {
            bind_group,
            pipeline,
            prefabs_needed: HashSet::new(),
            prefabs: HashMap::new(),
        }
    }
    pub fn draw(&mut self, commands: &mut CommandEncoder, target: &TextureView, scene: &SceneTree) {
        let mut rpass = commands.begin_render_pass(&RenderPassDescriptor {
            label: None,
            color_attachments: &[Some(RenderPassColorAttachment {
                view: target,
                resolve_target: None,
                ops: Operations {
                    store: StoreOp::Store,
                    load: LoadOp::Clear(Color {
                        r: 0.1,
                        g: 0.1,
                        b: 0.1,
                        a: 1.,
                    }),
                },
            })],
            ..Default::default()
        });
        rpass.set_bind_group(0, &self.bind_group, &[]);
        rpass.set_pipeline(&self.pipeline);

        for ob in scene.objects.values() {
            if let Some(prefab) = self.prefabs.get(&ob.res) {
                for part in &prefab.0 {
                    rpass.set_index_buffer(part.index.slice(..), IndexFormat::Uint16);
                    rpass.set_vertex_buffer(0, part.positions.slice(..));
                    rpass.set_vertex_buffer(1, part.normals.slice(..));
                    rpass.draw_indexed(0..part.index_count, 0, 0..1);
                }
            } else {
                self.prefabs_needed.insert(ob.res);
            }
        }
    }
}