1mod camera;
2mod edges;
3mod halo;
4mod hit;
5mod labels;
6mod nodes;
7mod surface;
8pub use camera::{grow_to_min_extent, Camera, CameraUniform};
9pub use hit::{contains, pick, HitTarget};
10pub use labels::{LabelAnchor, LabelDraw};
11pub use surface::fit_within_max_dimension;
12
13use edges::EdgePipeline;
14use halo::HaloPipeline;
15use labels::Labels;
16use nodes::NodePipeline;
17use wgpu::util::DeviceExt;
18
19#[derive(Debug, Clone, Copy, PartialEq)]
21pub struct NodeInstanceData {
22 pub pos: [f32; 2],
23 pub radius: f32,
24 pub opacity: f32,
25 pub shape: u32, pub color: [f32; 4],
27}
28
29#[derive(Clone)]
31pub struct EdgeLineData {
32 pub a: [f32; 2],
33 pub b: [f32; 2],
34 pub color: [f32; 4],
35 pub width: f32,
36 pub opacity: f32,
37}
38
39#[derive(Clone)]
41pub struct HaloInstanceData {
42 pub pos: [f32; 2],
43 pub radius: f32,
44 pub color: [f32; 4],
45 pub softness: f32,
46 pub phase: f32,
49}
50
51pub struct Renderer {
52 device: wgpu::Device,
53 queue: wgpu::Queue,
54 camera: Camera,
55 camera_buf: wgpu::Buffer,
56 camera_bind_group: wgpu::BindGroup,
57 nodes: NodePipeline,
58 node_bounds: Option<([f32; 2], [f32; 2])>,
62 edges: EdgePipeline,
63 halos: HaloPipeline,
64 labels: Labels,
65}
66
67impl Renderer {
68 pub fn new(device: wgpu::Device, queue: wgpu::Queue, format: wgpu::TextureFormat, width: u32, height: u32) -> Self {
69 let camera = Camera::new(width as f32, height as f32);
70 let camera_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
71 label: Some("camera"),
72 contents: bytemuck::bytes_of(&camera.uniform()),
73 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
74 });
75 let camera_bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
76 label: Some("camera-bgl"),
77 entries: &[wgpu::BindGroupLayoutEntry {
78 binding: 0,
79 visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
80 ty: wgpu::BindingType::Buffer {
81 ty: wgpu::BufferBindingType::Uniform,
82 has_dynamic_offset: false,
83 min_binding_size: None,
84 },
85 count: None,
86 }],
87 });
88 let camera_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
89 label: Some("camera-bg"),
90 layout: &camera_bgl,
91 entries: &[wgpu::BindGroupEntry { binding: 0, resource: camera_buf.as_entire_binding() }],
92 });
93
94 let nodes = NodePipeline::new(&device, format, &camera_bgl);
95 let edges = EdgePipeline::new(&device, format, &camera_bgl);
96 let halos = HaloPipeline::new(&device, format, &camera_bgl);
97 let labels = Labels::new(&device, &queue, format);
98
99 Self {
100 device,
101 queue,
102 camera,
103 camera_buf,
104 camera_bind_group,
105 nodes,
106 node_bounds: None,
107 edges,
108 halos,
109 labels,
110 }
111 }
112
113 pub fn resize(&mut self, width: u32, height: u32) {
114 self.camera.viewport = [width as f32, height as f32];
115 }
116
117 pub fn camera_mut(&mut self) -> &mut Camera { &mut self.camera }
118 pub fn camera_ref(&self) -> &Camera { &self.camera }
119
120 pub fn set_fade(&mut self, fade: f32) {
121 self.camera.fade = fade.clamp(0.0, 1.0);
122 }
123
124 pub fn configure_surface(&self, surface: &wgpu::Surface, config: &wgpu::SurfaceConfiguration) {
129 surface.configure(&self.device, config);
130 }
131
132 pub fn max_surface_dimension(&self) -> u32 {
136 self.device.limits().max_texture_dimension_2d
137 }
138
139 pub fn set_nodes(&mut self, nodes: &[NodeInstanceData]) {
140 self.nodes.upload(&self.device, &self.queue, nodes);
141 self.node_bounds = if nodes.is_empty() {
144 None
145 } else {
146 let mut min = [f32::MAX, f32::MAX];
147 let mut max = [f32::MIN, f32::MIN];
148 for n in nodes {
149 min[0] = min[0].min(n.pos[0] - n.radius);
150 min[1] = min[1].min(n.pos[1] - n.radius);
151 max[0] = max[0].max(n.pos[0] + n.radius);
152 max[1] = max[1].max(n.pos[1] + n.radius);
153 }
154 Some((min, max))
155 };
156 }
157
158 pub fn set_labels(&mut self, labels: &[LabelDraw]) {
161 self.labels.set_labels(labels, self.camera.pixel_ratio);
162 }
163
164 pub fn set_pixel_ratio(&mut self, ratio: f32) {
171 self.camera.set_pixel_ratio(ratio);
172 }
173
174 pub fn pixel_ratio(&self) -> f32 { self.camera.pixel_ratio }
175
176 pub fn set_edges(&mut self, edges: &[EdgeLineData]) {
177 self.edges.upload(&self.device, &self.queue, edges);
178 }
179
180 pub fn set_halos(&mut self, halos: &[HaloInstanceData]) {
181 self.halos.upload(&self.device, &self.queue, halos);
182 }
183
184 pub fn tick(&mut self, dt_ms: f32, dur_ms: f32) {
186 self.camera.tick(dt_ms, dur_ms);
187 }
188
189 pub fn glide_bounds(&mut self, min: [f32; 2], max: [f32; 2]) {
191 self.camera.glide_bounds(min, max);
192 }
193
194 pub fn fit_view(&mut self) {
201 if let Some((min, max)) = self.node_bounds {
202 self.camera.fit_bounds(min, max);
203 }
204 }
205
206 pub fn fit_view_at_least(&mut self, min_extent: f32) {
209 if let Some((min, max)) = self.node_bounds {
210 self.camera.fit_bounds_at_least(min, max, min_extent);
211 }
212 }
213
214 fn upload_camera(&self) {
215 self.queue.write_buffer(&self.camera_buf, 0, bytemuck::bytes_of(&self.camera.uniform()));
216 }
217
218 pub fn render(&mut self, view: &wgpu::TextureView) -> Result<(), String> {
220 self.upload_camera();
221 self.labels.prepare(&self.device, &self.queue, &self.camera)?;
222 let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: Some("frame") });
223 let label_res;
224 {
225 let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
226 label: Some("main-pass"),
227 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
228 view,
229 resolve_target: None,
230 ops: wgpu::Operations {
231 load: wgpu::LoadOp::Clear(wgpu::Color { r: 0.05, g: 0.06, b: 0.09, a: 1.0 }),
232 store: wgpu::StoreOp::Store,
233 },
234 })],
235 depth_stencil_attachment: None,
236 timestamp_writes: None,
237 occlusion_query_set: None,
238 });
239 self.edges.draw(&mut rpass, &self.camera_bind_group);
240 self.halos.draw(&mut rpass, &self.camera_bind_group);
241 self.nodes.draw(&mut rpass, &self.camera_bind_group);
242 label_res = self.labels.draw(&mut rpass);
243 }
244 label_res?;
245 self.queue.submit(Some(encoder.finish()));
246 Ok(())
247 }
248}