Skip to main content

loam_render/passes/
sky_ground.rs

1use std::cell::RefCell;
2use std::rc::Rc;
3
4use loam_runtime::Eye;
5use wgpu::{Color, CommandEncoder, Queue, RenderPass};
6
7use crate::device::GpuContext;
8use crate::pass::{ColorLoad, FrameFormat, FramePass, FrameTarget, PassStage};
9use crate::sky_ground::{Ground, Sky, SkyGroundNode, SkyGroundUniforms, DEFAULT_SKY};
10use crate::{DepthConvention, Viewport};
11
12struct State {
13    eye: Eye,
14    sky: Sky,
15    ground: Ground,
16    node: Option<SkyGroundNode>,
17    queue: Option<Queue>,
18}
19
20#[derive(Clone)]
21pub struct SkyGroundPass {
22    shared: Rc<RefCell<State>>,
23}
24
25impl SkyGroundPass {
26    pub fn new(ground: Ground) -> Self {
27        Self {
28            shared: Rc::new(RefCell::new(State {
29                eye: Eye::default(),
30                sky: DEFAULT_SKY,
31                ground,
32                node: None,
33                queue: None,
34            })),
35        }
36    }
37
38    pub fn publish(&self, eye: &Eye, sky: Sky, ground: Ground) {
39        let mut state = self.shared.borrow_mut();
40        state.eye = *eye;
41        state.sky = sky;
42        state.ground = ground;
43    }
44}
45
46impl FramePass for SkyGroundPass {
47    fn name(&self) -> &'static str {
48        "sky-ground"
49    }
50
51    fn stage(&self) -> PassStage {
52        PassStage::Background
53    }
54
55    fn color_load(&self) -> ColorLoad {
56        ColorLoad::Clear
57    }
58
59    fn depth_convention(&self) -> Option<DepthConvention> {
60        Some(DepthConvention::ReversedZ)
61    }
62
63    fn shares_pass(&self) -> bool {
64        true
65    }
66
67    fn clear_color(&self) -> Color {
68        self.shared.borrow().sky.horizon()
69    }
70
71    fn prepare(
72        &mut self,
73        _encoder: &mut CommandEncoder,
74        target: &FrameTarget<'_>,
75    ) -> anyhow::Result<()> {
76        let state = &mut *self.shared.borrow_mut();
77        let (Some(node), Some(queue)) = (state.node.as_mut(), state.queue.as_ref()) else {
78            return Ok(());
79        };
80        node.set_uniforms(
81            queue,
82            &SkyGroundUniforms::new(
83                crate::view::root_view_projection(&state.eye),
84                Viewport::full([target.size.0, target.size.1]),
85                state.sky,
86                state.ground,
87            ),
88        );
89        Ok(())
90    }
91
92    fn draw(&mut self, pass: &mut RenderPass<'_>, target: &FrameTarget<'_>) -> anyhow::Result<()> {
93        if let Some(node) = self.shared.borrow().node.as_ref() {
94            node.draw(pass, Some(&Viewport::full([target.size.0, target.size.1])));
95        }
96        Ok(())
97    }
98
99    fn record(
100        &mut self,
101        encoder: &mut CommandEncoder,
102        target: &FrameTarget<'_>,
103    ) -> anyhow::Result<()> {
104        let Some(depth) = target.depth else {
105            return Ok(());
106        };
107        self.prepare(encoder, target)?;
108        if let Some(node) = self.shared.borrow().node.as_ref() {
109            node.record(
110                encoder,
111                target.color,
112                depth,
113                Some(&Viewport::full([target.size.0, target.size.1])),
114            );
115        }
116        Ok(())
117    }
118
119    fn attach(&mut self, gpu: &GpuContext, frame: FrameFormat) -> anyhow::Result<()> {
120        let mut state = self.shared.borrow_mut();
121        state.node = Some(SkyGroundNode::new(
122            &gpu.device,
123            frame.color,
124            frame.depth,
125            DepthConvention::ReversedZ,
126        ));
127        state.queue = Some(gpu.queue.clone());
128        Ok(())
129    }
130}