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
use super::{
    super::{
        consts::Consts,
        pipelines::{bloom, clouds, postprocess},
    },
    Layouts,
};

pub struct BloomParams<'a> {
    pub locals: [Consts<bloom::Locals>; bloom::NUM_SIZES],
    pub src_views: [&'a wgpu::TextureView; bloom::NUM_SIZES],
    pub final_tgt_view: &'a wgpu::TextureView,
}

pub struct Locals {
    pub clouds: Consts<clouds::Locals>,
    pub clouds_bind: clouds::BindGroup,

    pub bloom_binds: Option<[bloom::BindGroup; bloom::NUM_SIZES]>,

    pub postprocess: Consts<postprocess::Locals>,
    pub postprocess_bind: postprocess::BindGroup,
}

fn arr_zip_map<const N: usize, A, B, C>(a: [A; N], b: [B; N], f: impl Fn(A, B) -> C) -> [C; N] {
    let mut b = b.into_iter();
    a.map(|a| f(a, b.next().unwrap()))
}

impl Locals {
    pub(super) fn new(
        device: &wgpu::Device,
        layouts: &Layouts,
        clouds_locals: Consts<clouds::Locals>,
        postprocess_locals: Consts<postprocess::Locals>,
        tgt_color_view: &wgpu::TextureView,
        tgt_mat_view: &wgpu::TextureView,
        tgt_depth_view: &wgpu::TextureView,
        bloom: Option<BloomParams>,
        tgt_color_pp_view: &wgpu::TextureView,
        sampler: &wgpu::Sampler,
        depth_sampler: &wgpu::Sampler,
    ) -> Self {
        let clouds_bind = layouts.clouds.bind(
            device,
            tgt_color_view,
            tgt_mat_view,
            tgt_depth_view,
            sampler,
            depth_sampler,
            &clouds_locals,
        );

        let postprocess_bind = layouts.postprocess.bind(
            device,
            tgt_color_pp_view,
            tgt_depth_view,
            tgt_mat_view,
            bloom.as_ref().map(|b| b.final_tgt_view),
            sampler,
            depth_sampler,
            &postprocess_locals,
        );

        let bloom_binds = bloom.map(|bloom| {
            arr_zip_map(bloom.src_views, bloom.locals, |view, locals| {
                layouts.bloom.bind(device, view, sampler, locals)
            })
        });

        Self {
            clouds: clouds_locals,
            clouds_bind,
            bloom_binds,
            postprocess: postprocess_locals,
            postprocess_bind,
        }
    }

    pub(super) fn rebind(
        &mut self,
        device: &wgpu::Device,
        layouts: &Layouts,
        // Call when these are recreated and need to be rebound
        // e.g. resizing
        tgt_color_view: &wgpu::TextureView,
        tgt_mat_view: &wgpu::TextureView,
        tgt_depth_view: &wgpu::TextureView,
        bloom: Option<BloomParams>,
        tgt_color_pp_view: &wgpu::TextureView,
        sampler: &wgpu::Sampler,
        depth_sampler: &wgpu::Sampler,
    ) {
        self.clouds_bind = layouts.clouds.bind(
            device,
            tgt_color_view,
            tgt_mat_view,
            tgt_depth_view,
            sampler,
            depth_sampler,
            &self.clouds,
        );
        self.postprocess_bind = layouts.postprocess.bind(
            device,
            tgt_color_pp_view,
            tgt_depth_view,
            tgt_mat_view,
            bloom.as_ref().map(|b| b.final_tgt_view),
            sampler,
            depth_sampler,
            &self.postprocess,
        );
        self.bloom_binds = bloom.map(|bloom| {
            arr_zip_map(bloom.src_views, bloom.locals, |view, locals| {
                layouts.bloom.bind(device, view, sampler, locals)
            })
        });
    }
}