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