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