wgpu_3dgs_viewer/selection/
viewport_texture_rectangle.rs1use crate::{
2 CameraBuffer, RendererCreateError,
3 core::BufferWrapper,
4 selection::{ViewportTexture, ViewportTexturePosBuffer},
5 wesl_utils,
6};
7
8#[derive(Debug)]
10pub struct ViewportTextureRectangleRenderer<B = wgpu::BindGroup> {
11 #[allow(dead_code)]
13 bind_group_layout: wgpu::BindGroupLayout,
14 bind_group: B,
16 pipeline: wgpu::RenderPipeline,
18}
19
20impl<B> ViewportTextureRectangleRenderer<B> {
21 pub fn create_bind_group(
23 &self,
24 device: &wgpu::Device,
25 camera: &CameraBuffer,
26 top_left: &ViewportTexturePosBuffer,
27 bottom_right: &ViewportTexturePosBuffer,
28 ) -> wgpu::BindGroup {
29 ViewportTextureRectangleRenderer::create_bind_group_static(
30 device,
31 &self.bind_group_layout,
32 camera,
33 top_left,
34 bottom_right,
35 )
36 }
37}
38
39impl ViewportTextureRectangleRenderer {
40 pub const BIND_GROUP_LAYOUT_DESCRIPTOR: wgpu::BindGroupLayoutDescriptor<'static> =
42 wgpu::BindGroupLayoutDescriptor {
43 label: Some("Viewport Selection Texture Rectangle Renderer Bind Group Layout"),
44 entries: &[
45 wgpu::BindGroupLayoutEntry {
47 binding: 0,
48 visibility: wgpu::ShaderStages::VERTEX,
49 ty: wgpu::BindingType::Buffer {
50 ty: wgpu::BufferBindingType::Uniform,
51 has_dynamic_offset: false,
52 min_binding_size: None,
53 },
54 count: None,
55 },
56 wgpu::BindGroupLayoutEntry {
58 binding: 1,
59 visibility: wgpu::ShaderStages::VERTEX,
60 ty: wgpu::BindingType::Buffer {
61 ty: wgpu::BufferBindingType::Uniform,
62 has_dynamic_offset: false,
63 min_binding_size: None,
64 },
65 count: None,
66 },
67 wgpu::BindGroupLayoutEntry {
69 binding: 2,
70 visibility: wgpu::ShaderStages::VERTEX,
71 ty: wgpu::BindingType::Buffer {
72 ty: wgpu::BufferBindingType::Uniform,
73 has_dynamic_offset: false,
74 min_binding_size: None,
75 },
76 count: None,
77 },
78 ],
79 };
80
81 pub fn new(
83 device: &wgpu::Device,
84 texture: &ViewportTexture,
85 camera: &CameraBuffer,
86 top_left: &ViewportTexturePosBuffer,
87 bottom_right: &ViewportTexturePosBuffer,
88 ) -> Result<Self, RendererCreateError> {
89 let this = ViewportTextureRectangleRenderer::new_without_bind_group(device, texture)?;
90
91 log::debug!("Creating viewport texture rectangle renderer bind group");
92 let bind_group = this.create_bind_group(device, camera, top_left, bottom_right);
93
94 Ok(Self {
95 bind_group_layout: this.bind_group_layout,
96 bind_group,
97 pipeline: this.pipeline,
98 })
99 }
100
101 pub fn render(&self, encoder: &mut wgpu::CommandEncoder, texture: &ViewportTexture) {
103 let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
104 label: Some("Viewport Texture Rectangle Renderer Render Pass"),
105 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
106 view: texture.view(),
107 resolve_target: None,
108 ops: wgpu::Operations {
109 load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
110 store: wgpu::StoreOp::Store,
111 },
112 depth_slice: None,
113 })],
114 ..Default::default()
115 });
116
117 self.render_with_pass(&mut render_pass);
118 }
119
120 pub fn render_with_pass(&self, pass: &mut wgpu::RenderPass<'_>) {
122 pass.set_pipeline(&self.pipeline);
123 pass.set_bind_group(0, &self.bind_group, &[]);
124 pass.draw(0..6, 0..1);
125 }
126
127 fn create_bind_group_static(
129 device: &wgpu::Device,
130 bind_group_layout: &wgpu::BindGroupLayout,
131 camera: &CameraBuffer,
132 top_left: &ViewportTexturePosBuffer,
133 bottom_right: &ViewportTexturePosBuffer,
134 ) -> wgpu::BindGroup {
135 device.create_bind_group(&wgpu::BindGroupDescriptor {
136 label: Some("Viewport Texture Rectangle Renderer Bind Group"),
137 layout: bind_group_layout,
138 entries: &[
139 wgpu::BindGroupEntry {
141 binding: 0,
142 resource: camera.buffer().as_entire_binding(),
143 },
144 wgpu::BindGroupEntry {
146 binding: 1,
147 resource: top_left.buffer().as_entire_binding(),
148 },
149 wgpu::BindGroupEntry {
151 binding: 2,
152 resource: bottom_right.buffer().as_entire_binding(),
153 },
154 ],
155 })
156 }
157}
158
159impl ViewportTextureRectangleRenderer<()> {
160 pub fn new_without_bind_group(
165 device: &wgpu::Device,
166 texture: &ViewportTexture,
167 ) -> Result<Self, RendererCreateError> {
168 log::debug!("Creating viewport texture rectangle renderer bind group layout");
169 let bind_group_layout = device.create_bind_group_layout(
170 &ViewportTextureRectangleRenderer::BIND_GROUP_LAYOUT_DESCRIPTOR,
171 );
172
173 log::debug!("Creating viewport texture rectangle renderer pipeline layout");
174 let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
175 label: Some("Viewport Texture Rectangle Renderer Pipeline Layout"),
176 bind_group_layouts: &[&bind_group_layout],
177 ..Default::default()
178 });
179
180 log::debug!("Creating viewport texture rectangle renderer shader");
181 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
182 label: Some("Viewport Texture Rectangle Renderer Shader"),
183 source: wgpu::ShaderSource::Wgsl(
184 wesl::compile_sourcemap(
185 &"wgpu_3dgs_viewer::selection::viewport_texture_rectangle"
186 .parse()
187 .expect("selection::viewport_texture_rectangle module path"),
188 &wesl_utils::resolver(),
189 &wesl::NoMangler,
190 &wesl::CompileOptions::default(),
191 )?
192 .to_string()
193 .into(),
194 ),
195 });
196
197 log::debug!("Creating viewport texture rectangle renderer pipeline");
198 let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
199 label: Some("Viewport Texture Rectangle Renderer Pipeline"),
200 layout: Some(&pipeline_layout),
201 vertex: wgpu::VertexState {
202 module: &shader,
203 entry_point: Some("vert_main"),
204 buffers: &[],
205 compilation_options: wgpu::PipelineCompilationOptions::default(),
206 },
207 fragment: Some(wgpu::FragmentState {
208 module: &shader,
209 entry_point: Some("frag_main"),
210 targets: &[Some(wgpu::ColorTargetState {
211 format: texture.texture().format(),
212 blend: None,
213 write_mask: wgpu::ColorWrites::ALL,
214 })],
215 compilation_options: wgpu::PipelineCompilationOptions::default(),
216 }),
217 primitive: wgpu::PrimitiveState::default(),
218 depth_stencil: None,
219 multisample: wgpu::MultisampleState::default(),
220 multiview_mask: None,
221 cache: None,
222 });
223
224 log::info!("Viewport texture rectangle renderer created");
225
226 Ok(Self {
227 bind_group_layout,
228 bind_group: (),
229 pipeline,
230 })
231 }
232
233 pub fn render(
235 &self,
236 encoder: &mut wgpu::CommandEncoder,
237 texture: &ViewportTexture,
238 bind_group: &wgpu::BindGroup,
239 ) {
240 let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
241 label: Some("Viewport Texture Rectangle Renderer Render Pass"),
242 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
243 view: texture.view(),
244 resolve_target: None,
245 ops: wgpu::Operations {
246 load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
247 store: wgpu::StoreOp::Store,
248 },
249 depth_slice: None,
250 })],
251 ..Default::default()
252 });
253
254 self.render_with_pass(&mut render_pass, bind_group);
255 }
256
257 pub fn render_with_pass(&self, pass: &mut wgpu::RenderPass<'_>, bind_group: &wgpu::BindGroup) {
259 pass.set_pipeline(&self.pipeline);
260 pass.set_bind_group(0, bind_group, &[]);
261 pass.draw(0..6, 0..1);
262 }
263}