Skip to main content

loam_render/passes/
raymarch.rs

1use std::cell::RefCell;
2use std::rc::Rc;
3
4use wgpu::{CommandEncoder, Queue};
5
6use crate::device::GpuContext;
7use crate::pass::{ColorLoad, FrameFormat, FramePass, FrameTarget, PassStage};
8use crate::raymarch::{RayMarchNode, RayMarchUniforms};
9use crate::Viewport;
10
11struct State {
12    source: String,
13    uniforms: RayMarchUniforms,
14    node: Option<RayMarchNode>,
15    queue: Option<Queue>,
16}
17
18#[derive(Clone)]
19pub struct RaymarchPass {
20    shared: Rc<RefCell<State>>,
21}
22
23impl RaymarchPass {
24    pub fn new(source: String) -> Self {
25        Self {
26            shared: Rc::new(RefCell::new(State {
27                source,
28                uniforms: RayMarchUniforms::default(),
29                node: None,
30                queue: None,
31            })),
32        }
33    }
34
35    pub fn publish(&self, uniforms: RayMarchUniforms) {
36        self.shared.borrow_mut().uniforms = uniforms;
37    }
38}
39
40impl FramePass for RaymarchPass {
41    fn name(&self) -> &'static str {
42        "raymarch"
43    }
44
45    fn stage(&self) -> PassStage {
46        PassStage::Background
47    }
48
49    fn color_load(&self) -> ColorLoad {
50        ColorLoad::Clear
51    }
52
53    fn record(
54        &mut self,
55        encoder: &mut CommandEncoder,
56        target: &FrameTarget<'_>,
57    ) -> anyhow::Result<()> {
58        let mut state = self.shared.borrow_mut();
59        let State {
60            uniforms,
61            node,
62            queue,
63            ..
64        } = &mut *state;
65        let (Some(node), Some(queue)) = (node.as_mut(), queue.as_ref()) else {
66            return Ok(());
67        };
68        uniforms.resolution = [target.size.0 as f32, target.size.1 as f32];
69        *node.uniforms_mut() = *uniforms;
70        node.flush_uniforms(queue);
71        node.record(
72            encoder,
73            target.color,
74            None,
75            Viewport::full([target.size.0, target.size.1]),
76        );
77        Ok(())
78    }
79
80    fn attach(&mut self, gpu: &GpuContext, frame: FrameFormat) -> anyhow::Result<()> {
81        let mut state = self.shared.borrow_mut();
82        crate::shader::validate_raymarch_wgsl(&state.source)?;
83        let module = gpu
84            .device
85            .create_shader_module(wgpu::ShaderModuleDescriptor {
86                label: Some("loam-render::passes::raymarch"),
87                source: wgpu::ShaderSource::Wgsl(state.source.clone().into()),
88            });
89        state.node = Some(RayMarchNode::new(&gpu.device, frame.color, &module));
90        state.queue = Some(gpu.queue.clone());
91        Ok(())
92    }
93}