vsvg_viewer/painters/
point_painter.rs1use crate::engine::EngineRenderObjects;
2use crate::painters::Painter;
3use std::mem;
4use wgpu::util::DeviceExt;
5use wgpu::{
6 include_wgsl, vertex_attr_array, Buffer, ColorTargetState, PrimitiveTopology, RenderPass,
7 RenderPipeline,
8};
9
10#[repr(C)]
11#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
12pub(super) struct PointVertex {
13 pub(crate) position: [f32; 2],
14 pub(crate) color: u32,
15 pub(crate) size: f32,
16}
17
18pub(crate) struct PointPainterData {
19 instance_buffer: Buffer,
20 instance_count: u32,
21}
22
23impl PointPainterData {
24 pub fn new(
25 render_objects: &EngineRenderObjects,
26 vertices: impl IntoIterator<Item = [f32; 2]>,
27 color: u32,
28 size: f32,
29 ) -> Self {
30 vsvg::trace_function!();
31
32 let instances = vertices
33 .into_iter()
34 .map(|v| PointVertex {
35 position: v,
36 color,
37 size,
38 })
39 .collect::<Vec<_>>();
40
41 let instance_buffer =
42 render_objects
43 .device
44 .create_buffer_init(&wgpu::util::BufferInitDescriptor {
45 label: Some("PointPainter instance buffer"),
46 contents: bytemuck::cast_slice(instances.as_slice()),
47 usage: wgpu::BufferUsages::VERTEX,
48 });
49
50 #[allow(clippy::cast_possible_truncation)]
51 Self {
52 instance_buffer,
53 instance_count: instances.len() as u32,
54 }
55 }
56}
57
58pub(crate) struct PointPainter {
59 render_pipeline: RenderPipeline,
60}
61
62impl PointPainter {
63 pub(crate) fn new(render_objects: &EngineRenderObjects) -> Self {
64 let vertex_buffer_layout = wgpu::VertexBufferLayout {
65 array_stride: mem::size_of::<PointVertex>() as wgpu::BufferAddress,
66 step_mode: wgpu::VertexStepMode::Instance,
67 attributes: &vertex_attr_array![
68 0 => Float32x2,
69 1 => Uint32,
70 2 => Float32,
71 ],
72 };
73
74 let shader = render_objects
75 .device
76 .create_shader_module(include_wgsl!("../shaders/point.wgsl"));
77
78 let pipeline_layout =
79 render_objects
80 .device
81 .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
82 label: None,
83 bind_group_layouts: &[&render_objects.camera_bind_group_layout],
84 push_constant_ranges: &[],
85 });
86
87 let target = ColorTargetState {
89 format: render_objects.target_format,
90 blend: Some(wgpu::BlendState {
91 color: wgpu::BlendComponent {
92 src_factor: wgpu::BlendFactor::SrcAlpha,
93 dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
94 operation: wgpu::BlendOperation::Add,
95 },
96 alpha: wgpu::BlendComponent {
97 src_factor: wgpu::BlendFactor::OneMinusDstAlpha,
98 dst_factor: wgpu::BlendFactor::DstAlpha,
99 operation: wgpu::BlendOperation::Add,
100 },
101 }),
102 write_mask: wgpu::ColorWrites::ALL,
103 };
104
105 let render_pipeline =
106 render_objects
107 .device
108 .create_render_pipeline(&wgpu::RenderPipelineDescriptor {
109 label: Some("PointPainter pipeline"),
110 layout: Some(&pipeline_layout),
111 vertex: wgpu::VertexState {
112 module: &shader,
113 entry_point: "vs_main",
114 buffers: &[vertex_buffer_layout],
115 },
116 fragment: Some(wgpu::FragmentState {
117 module: &shader,
118 entry_point: "fs_main",
119 targets: &[Some(target)],
120 }),
121 primitive: wgpu::PrimitiveState {
122 topology: PrimitiveTopology::TriangleStrip,
123 ..Default::default()
124 },
125 depth_stencil: None,
126 multisample: wgpu::MultisampleState::default(),
127 multiview: None,
128 });
129
130 Self { render_pipeline }
131 }
132}
133
134impl Painter for PointPainter {
135 type Data = PointPainterData;
136
137 fn draw<'a>(
138 &'a self,
139 rpass: &mut RenderPass<'a>,
140 camera_bind_group: &'a wgpu::BindGroup,
141 data: &'a Self::Data,
142 ) {
143 rpass.set_pipeline(&self.render_pipeline);
144 rpass.set_bind_group(0, camera_bind_group, &[]);
145 rpass.set_vertex_buffer(0, data.instance_buffer.slice(..));
146 rpass.draw(0..4, 0..data.instance_count);
147 }
148}