loam_render/passes/
sky_ground.rs1use 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}