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