Skip to main content

loam_render/passes/
line.rs

1use std::cell::RefCell;
2use std::rc::Rc;
3
4use glam::Vec2;
5use loam_runtime::{Eye, SegmentRecord};
6use wgpu::{CommandEncoder, Device, Queue, RenderPass};
7
8use crate::device::GpuContext;
9use crate::pass::{FrameFormat, FramePass, FrameTarget, PassStage};
10use crate::{DepthConvention, DepthMode, LineRasterNode};
11
12struct State {
13    eye: Eye,
14    segments: Vec<SegmentRecord>,
15    uploaded: bool,
16    node: Option<LineRasterNode>,
17    device: Option<Device>,
18    queue: Option<Queue>,
19}
20
21#[derive(Clone)]
22pub struct LinePass {
23    name: &'static str,
24    shared: Rc<RefCell<State>>,
25}
26
27impl LinePass {
28    pub fn new(name: &'static str) -> Self {
29        Self {
30            name,
31            shared: Rc::new(RefCell::new(State {
32                eye: Eye::default(),
33                segments: Vec::new(),
34                uploaded: false,
35                node: None,
36                device: None,
37                queue: None,
38            })),
39        }
40    }
41
42    pub fn publish(&self, eye: &Eye, segments: &[SegmentRecord]) {
43        let mut state = self.shared.borrow_mut();
44        state.eye = *eye;
45        state.uploaded &= state.segments == segments;
46        state.segments.clear();
47        state.segments.extend_from_slice(segments);
48    }
49
50    pub fn segment_count(&self) -> usize {
51        self.shared.borrow().segments.len()
52    }
53}
54
55impl FramePass for LinePass {
56    fn name(&self) -> &'static str {
57        self.name
58    }
59
60    fn stage(&self) -> PassStage {
61        PassStage::Scene
62    }
63
64    fn depth_read(&self) -> Option<DepthConvention> {
65        Some(DepthConvention::ReversedZ)
66    }
67
68    fn shares_pass(&self) -> bool {
69        true
70    }
71
72    fn prepare(
73        &mut self,
74        _encoder: &mut CommandEncoder,
75        target: &FrameTarget<'_>,
76    ) -> anyhow::Result<()> {
77        let mut state = self.shared.borrow_mut();
78        let State {
79            eye,
80            segments,
81            uploaded,
82            node,
83            device,
84            queue,
85            ..
86        } = &mut *state;
87        let (Some(node), Some(device), Some(queue)) =
88            (node.as_mut(), device.as_ref(), queue.as_ref())
89        else {
90            return Ok(());
91        };
92        node.set_camera(
93            queue,
94            crate::view::root_view_projection(eye),
95            Vec2::new(target.size.0 as f32, target.size.1 as f32),
96        );
97        if !*uploaded {
98            node.upload_segments(device, queue, segments);
99            *uploaded = true;
100        }
101        Ok(())
102    }
103
104    fn draw(&mut self, pass: &mut RenderPass<'_>, _target: &FrameTarget<'_>) -> anyhow::Result<()> {
105        if let Some(node) = self.shared.borrow().node.as_ref() {
106            node.draw(pass, None);
107        }
108        Ok(())
109    }
110
111    fn record(
112        &mut self,
113        encoder: &mut CommandEncoder,
114        target: &FrameTarget<'_>,
115    ) -> anyhow::Result<()> {
116        let Some(depth) = target.depth else {
117            return Ok(());
118        };
119        self.prepare(encoder, target)?;
120        if let Some(node) = self.shared.borrow().node.as_ref() {
121            node.record(encoder, target.color, Some(depth), None);
122        }
123        Ok(())
124    }
125
126    fn attach(&mut self, gpu: &GpuContext, frame: FrameFormat) -> anyhow::Result<()> {
127        let mut state = self.shared.borrow_mut();
128        state.node = Some(LineRasterNode::new(
129            &gpu.device,
130            frame.color,
131            DepthMode::ReadOnly {
132                format: frame.depth,
133            },
134            DepthConvention::ReversedZ,
135        ));
136        state.device = Some(gpu.device.clone());
137        state.queue = Some(gpu.queue.clone());
138        state.uploaded = false;
139        Ok(())
140    }
141}