summaryrefslogtreecommitdiff
path: root/client/src/render/scene/draw.rs
blob: bdbcb50508a070c39224e9ee8776bb71f7019cba (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
/*
    wearechat - generic multiplayer game with voip
    Copyright (C) 2025 metamuffin

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, version 3 of the License only.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/
use super::{DemandMap, RPrefab};
use glam::{EulerRot, Mat3, Mat4};
use std::sync::Arc;
use weareshared::{packets::Resource, resources::Prefab, tree::SceneTree};
use wgpu::{
    Color, CommandEncoder, IndexFormat, LoadOp, Operations, RenderPassColorAttachment,
    RenderPassDepthStencilAttachment, RenderPassDescriptor, ShaderStages, StoreOp, TextureView,
};

pub struct ScenePipeline;

impl ScenePipeline {
    pub fn draw(
        &mut self,
        commands: &mut CommandEncoder,
        target: &TextureView,
        depth: &TextureView,
        scene: &SceneTree,
        prefabs: &DemandMap<Resource<Prefab>, Arc<RPrefab>>,
        view: Mat4,
        project: Mat4,
    ) {
        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.01,
                        g: 0.01,
                        b: 0.01,
                        a: 1.,
                    }),
                },
            })],
            depth_stencil_attachment: Some(RenderPassDepthStencilAttachment {
                view: &depth,
                depth_ops: Some(Operations {
                    load: LoadOp::Clear(1.),
                    store: StoreOp::Store,
                }),
                stencil_ops: None,
            }),
            ..Default::default()
        });

        for ob in scene.objects.values() {
            let prefab_modelview = view
                * Mat4::from_translation(ob.pos.into())
                * Mat4::from_mat3(Mat3::from_euler(
                    EulerRot::YXZ,
                    ob.rot.x,
                    ob.rot.y,
                    ob.rot.z,
                ));
            if let Some(prefab) = prefabs.try_get(ob.res.clone()) {
                for (affine, part) in &prefab.0 {
                    let modelview = prefab_modelview
                        * Mat4::from_translation(affine.translation.into())
                        * Mat4::from_mat3a(affine.matrix3);
                    let modelviewp = project * modelview;
                    // let light = modelview * vec4(5., 5., 5., 1.);

                    // let light = light.to_array().map(|v| v.to_le_bytes());
                    let modelview = modelview.to_cols_array().map(|v| v.to_le_bytes());
                    let modelviewp = modelviewp.to_cols_array().map(|v| v.to_le_bytes());

                    rpass.set_pipeline(&part.pipeline);
                    rpass.set_bind_group(0, &*part.tex_albedo, &[]);
                    rpass.set_bind_group(1, &*part.tex_normal, &[]);
                    rpass.set_bind_group(2, &*part.material, &[]);
                    rpass.set_push_constants(ShaderStages::VERTEX, 0, modelviewp.as_flattened());
                    rpass.set_push_constants(ShaderStages::VERTEX, 64, modelview.as_flattened());
                    // rpass.set_push_constants(ShaderStages::FRAGMENT, 128, light.as_flattened());
                    rpass.set_index_buffer(part.index.slice(..), IndexFormat::Uint32);
                    rpass.set_vertex_buffer(0, part.va_position.slice(..));
                    rpass.set_vertex_buffer(1, part.va_normal.slice(..));
                    rpass.set_vertex_buffer(2, part.va_tangent.slice(..));
                    rpass.set_vertex_buffer(3, part.va_texcoord.slice(..));
                    rpass.draw_indexed(0..part.index_count, 0, 0..1);
                }
            }
        }
    }
}