1use crate::render::Bound;
2
3use super::{
4 super::{
5 AltIndices, CullingMode,
6 buffer::Buffer,
7 instances::Instances,
8 model::{DynamicModel, Model, SubModel},
9 pipelines::{
10 AtlasTextures, FigureSpriteAtlasData, GlobalsBindGroup, TerrainAtlasData, blit, bloom,
11 clouds, debug, figure, fluid, lod_object, lod_terrain, particle, rope, shadow, skybox,
12 sprite, terrain, trail, ui,
13 },
14 },
15 Renderer, ShadowMap, ShadowMapRenderer,
16 rain_occlusion_map::{RainOcclusionMap, RainOcclusionMapRenderer},
17};
18use common_base::prof_span;
19use core::ops::Range;
20use std::sync::Arc;
21use vek::Aabr;
22use wgpu_profiler::scope::{ManualOwningScope, OwningScope, Scope};
23#[cfg(feature = "egui-ui")]
24use {common_base::span, egui_wgpu_backend::ScreenDescriptor, egui_winit_platform::Platform};
25
26pub const UI_PREMULTIPLY_PASS: &str = "ui_premultiply_pass";
28
29enum Pipelines<'frame> {
31 Interface(&'frame super::InterfacePipelines),
32 All(&'frame super::Pipelines),
33 None,
35}
36
37impl Pipelines<'_> {
38 fn ui(&self) -> Option<&ui::UiPipeline> {
39 match self {
40 Pipelines::Interface(pipelines) => Some(&pipelines.ui),
41 Pipelines::All(pipelines) => Some(&pipelines.ui),
42 Pipelines::None => None,
43 }
44 }
45
46 fn premultiply_alpha(&self) -> Option<&ui::PremultiplyAlphaPipeline> {
47 match self {
48 Pipelines::Interface(pipelines) => Some(&pipelines.premultiply_alpha),
49 Pipelines::All(pipelines) => Some(&pipelines.premultiply_alpha),
50 Pipelines::None => None,
51 }
52 }
53
54 fn blit(&self) -> Option<&blit::BlitPipeline> {
55 match self {
56 Pipelines::Interface(pipelines) => Some(&pipelines.blit),
57 Pipelines::All(pipelines) => Some(&pipelines.blit),
58 Pipelines::None => None,
59 }
60 }
61
62 fn all(&self) -> Option<&super::Pipelines> {
63 match self {
64 Pipelines::All(pipelines) => Some(pipelines),
65 Pipelines::Interface(_) | Pipelines::None => None,
66 }
67 }
68}
69
70struct RendererBorrow<'frame> {
73 queue: &'frame wgpu::Queue,
74 device: &'frame wgpu::Device,
75 #[cfg(feature = "egui-ui")]
76 surface_config: &'frame wgpu::SurfaceConfiguration,
77 shadow: Option<&'frame super::Shadow>,
78 pipelines: Pipelines<'frame>,
79 locals: &'frame super::locals::Locals,
80 views: &'frame super::Views,
81 pipeline_modes: &'frame super::PipelineModes,
82 quad_index_buffer_u16: &'frame Buffer<u16>,
83 quad_index_buffer_u32: &'frame Buffer<u32>,
84 ui_premultiply_uploads: &'frame mut ui::BatchedUploads,
85 #[cfg(feature = "egui-ui")]
86 egui_render_pass: &'frame mut egui_wgpu_backend::RenderPass,
87}
88
89pub struct Drawer<'frame> {
90 surface_view: wgpu::TextureView,
91 encoder: Option<ManualOwningScope<'frame, wgpu::CommandEncoder>>,
92 borrow: RendererBorrow<'frame>,
93 surface_texture: Option<wgpu::SurfaceTexture>,
94 globals: &'frame GlobalsBindGroup,
95 taking_screenshot: Option<super::screenshot::TakeScreenshot>,
98}
99
100impl<'frame> Drawer<'frame> {
101 pub fn new(
102 encoder: wgpu::CommandEncoder,
103 renderer: &'frame mut Renderer,
104 surface_texture: wgpu::SurfaceTexture,
105 globals: &'frame GlobalsBindGroup,
106 ) -> Self {
107 let taking_screenshot = renderer.take_screenshot.take().map(|screenshot_fn| {
108 super::screenshot::TakeScreenshot::new(
109 &renderer.device,
110 &renderer.layouts.blit,
111 &renderer.sampler,
112 &renderer.surface_config,
113 screenshot_fn,
114 )
115 });
116
117 let (pipelines, shadow) = match &renderer.state {
118 super::State::Interface { pipelines, .. } => (Pipelines::Interface(pipelines), None),
119 super::State::Complete {
120 pipelines, shadow, ..
121 } => (Pipelines::All(pipelines), Some(shadow)),
122 super::State::Nothing => (Pipelines::None, None),
123 };
124
125 let borrow = RendererBorrow {
126 queue: &renderer.queue,
127 device: &renderer.device,
128 #[cfg(feature = "egui-ui")]
129 surface_config: &renderer.surface_config,
130 shadow,
131 pipelines,
132 locals: &renderer.locals,
133 views: &renderer.views,
134 pipeline_modes: &renderer.pipeline_modes,
135 quad_index_buffer_u16: &renderer.quad_index_buffer_u16,
136 quad_index_buffer_u32: &renderer.quad_index_buffer_u32,
137 ui_premultiply_uploads: &mut renderer.ui_premultiply_uploads,
138 #[cfg(feature = "egui-ui")]
139 egui_render_pass: &mut renderer.egui_renderpass,
140 };
141
142 let encoder =
143 ManualOwningScope::start("frame", &mut renderer.profiler, encoder, borrow.device);
144
145 let surface_view = surface_texture
147 .texture
148 .create_view(&wgpu::TextureViewDescriptor {
149 label: Some("Surface texture view"),
150 ..Default::default()
151 });
152
153 Self {
154 surface_view,
155 encoder: Some(encoder),
156 borrow,
157 surface_texture: Some(surface_texture),
158 globals,
159 taking_screenshot,
160 }
161 }
162
163 pub fn pipeline_modes(&self) -> &super::PipelineModes { self.borrow.pipeline_modes }
165
166 pub fn rain_occlusion_pass(&mut self) -> Option<RainOcclusionPassDrawer> {
169 if !self.borrow.pipeline_modes.cloud.is_enabled() {
170 return None;
171 }
172
173 if let RainOcclusionMap::Enabled(ref rain_occlusion_renderer) = self.borrow.shadow?.rain_map
174 {
175 let encoder = self.encoder.as_mut().unwrap();
176 let device = self.borrow.device;
177 let mut render_pass = encoder.scoped_render_pass(
178 "rain_occlusion_pass",
179 device,
180 &wgpu::RenderPassDescriptor {
181 label: Some("rain occlusion pass"),
182 color_attachments: &[],
183 depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
184 view: &rain_occlusion_renderer.depth.view,
185 depth_ops: Some(wgpu::Operations {
186 load: wgpu::LoadOp::Clear(1.0),
187 store: wgpu::StoreOp::Store,
188 }),
189 stencil_ops: None,
190 }),
191 timestamp_writes: None,
192 occlusion_query_set: None,
193 },
194 );
195
196 render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
197
198 Some(RainOcclusionPassDrawer {
199 render_pass,
200 borrow: &self.borrow,
201 rain_occlusion_renderer,
202 })
203 } else {
204 None
205 }
206 }
207
208 pub fn shadow_pass(&mut self) -> Option<ShadowPassDrawer> {
211 if !self.borrow.pipeline_modes.shadow.is_map() {
212 return None;
213 }
214
215 if let ShadowMap::Enabled(ref shadow_renderer) = self.borrow.shadow?.map {
216 let encoder = self.encoder.as_mut().unwrap();
217 let device = self.borrow.device;
218 let mut render_pass =
219 encoder.scoped_render_pass("shadow_pass", device, &wgpu::RenderPassDescriptor {
220 label: Some("shadow pass"),
221 color_attachments: &[],
222 depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
223 view: &shadow_renderer.directed_depth.view,
224 depth_ops: Some(wgpu::Operations {
225 load: wgpu::LoadOp::Clear(1.0),
226 store: wgpu::StoreOp::Store,
227 }),
228 stencil_ops: None,
229 }),
230 timestamp_writes: None,
231 occlusion_query_set: None,
232 });
233
234 render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
235
236 Some(ShadowPassDrawer {
237 render_pass,
238 borrow: &self.borrow,
239 shadow_renderer,
240 })
241 } else {
242 None
243 }
244 }
245
246 pub fn first_pass(&mut self) -> Option<FirstPassDrawer> {
248 let pipelines = self.borrow.pipelines.all()?;
249 let shadow = self.borrow.shadow?;
252
253 let encoder = self.encoder.as_mut().unwrap();
254 let device = self.borrow.device;
255 let mut render_pass =
256 encoder.scoped_render_pass("first_pass", device, &wgpu::RenderPassDescriptor {
257 label: Some("first pass"),
258 color_attachments: &[
259 Some(wgpu::RenderPassColorAttachment {
260 view: &self.borrow.views.tgt_color,
261 resolve_target: None,
262 ops: wgpu::Operations {
263 load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
264 store: wgpu::StoreOp::Store,
265 },
266 }),
267 Some(wgpu::RenderPassColorAttachment {
268 view: &self.borrow.views.tgt_mat,
269 resolve_target: None,
270 ops: wgpu::Operations {
271 load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
272 store: wgpu::StoreOp::Store,
273 },
274 }),
275 ],
276 depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
277 view: &self.borrow.views.tgt_depth,
278 depth_ops: Some(wgpu::Operations {
279 load: wgpu::LoadOp::Clear(0.0),
280 store: wgpu::StoreOp::Store,
281 }),
282 stencil_ops: None,
283 }),
284 timestamp_writes: None,
285 occlusion_query_set: None,
286 });
287
288 render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
289 render_pass.set_bind_group(1, &shadow.bind.bind_group, &[]);
290
291 Some(FirstPassDrawer {
292 render_pass,
293 borrow: &self.borrow,
294 pipelines,
295 globals: self.globals,
296 })
297 }
298
299 pub fn volumetric_pass(&mut self) -> Option<VolumetricPassDrawer> {
301 let pipelines = &self.borrow.pipelines.all()?;
302 let shadow = self.borrow.shadow?;
303
304 let encoder = self.encoder.as_mut().unwrap();
305 let device = self.borrow.device;
306 let mut render_pass =
307 encoder.scoped_render_pass("volumetric_pass", device, &wgpu::RenderPassDescriptor {
308 label: Some("volumetric pass (clouds)"),
309 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
310 view: &self.borrow.views.tgt_color_pp,
311 resolve_target: None,
312 ops: wgpu::Operations {
313 load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
314 store: wgpu::StoreOp::Store,
315 },
316 })],
317 depth_stencil_attachment: None,
318 timestamp_writes: None,
319 occlusion_query_set: None,
320 });
321
322 render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
323 render_pass.set_bind_group(1, &shadow.bind.bind_group, &[]);
324
325 Some(VolumetricPassDrawer {
326 render_pass,
327 borrow: &self.borrow,
328 clouds_pipeline: &pipelines.clouds,
329 })
330 }
331
332 pub fn transparent_pass(&mut self) -> Option<TransparentPassDrawer> {
334 let pipelines = &self.borrow.pipelines.all()?;
335 let shadow = self.borrow.shadow?;
336
337 let encoder = self.encoder.as_mut().unwrap();
338 let device = self.borrow.device;
339 let mut render_pass =
340 encoder.scoped_render_pass("transparent_pass", device, &wgpu::RenderPassDescriptor {
341 label: Some("transparent pass (trails)"),
342 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
343 view: &self.borrow.views.tgt_color_pp,
344 resolve_target: None,
345 ops: wgpu::Operations {
346 load: wgpu::LoadOp::Load,
347 store: wgpu::StoreOp::Store,
348 },
349 })],
350 depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
351 view: &self.borrow.views.tgt_depth,
352 depth_ops: Some(wgpu::Operations {
353 load: wgpu::LoadOp::Load,
354 store: wgpu::StoreOp::Store,
355 }),
356 stencil_ops: None,
357 }),
358 timestamp_writes: None,
359 occlusion_query_set: None,
360 });
361
362 render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
363 render_pass.set_bind_group(1, &shadow.bind.bind_group, &[]);
364
365 Some(TransparentPassDrawer {
366 render_pass,
367 borrow: &self.borrow,
368 trail_pipeline: &pipelines.trail,
369 })
370 }
371
372 pub fn run_bloom_passes(&mut self) {
376 let locals = &self.borrow.locals;
377 let views = &self.borrow.views;
378
379 let bloom_pipelines = match self.borrow.pipelines.all() {
380 Some(super::Pipelines { bloom: Some(p), .. }) => p,
381 _ => return,
382 };
383
384 let (bloom_tgts, bloom_binds) =
387 match views.bloom_tgts.as_ref().zip(locals.bloom_binds.as_ref()) {
388 Some((t, b)) => (t, b),
389 None => return,
390 };
391
392 let device = self.borrow.device;
393 let mut encoder = self.encoder.as_mut().unwrap().scope("bloom", device);
394
395 let mut run_bloom_pass = |bind, view, label: String, pipeline, load| {
396 let pass_label = format!("bloom {} pass", label);
397 let mut render_pass =
398 encoder.scoped_render_pass(&label, device, &wgpu::RenderPassDescriptor {
399 label: Some(&pass_label),
400 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
401 resolve_target: None,
402 view,
403 ops: wgpu::Operations {
404 store: wgpu::StoreOp::Store,
405 load,
406 },
407 })],
408 depth_stencil_attachment: None,
409 timestamp_writes: None,
410 occlusion_query_set: None,
411 });
412
413 render_pass.set_bind_group(0, bind, &[]);
414 render_pass.set_pipeline(pipeline);
415 render_pass.draw(0..3, 0..1);
416 };
417
418 (0..bloom::NUM_SIZES - 1).for_each(|index| {
420 let bind = &bloom_binds[index].bind_group;
421 let view = &bloom_tgts[index + 1];
422 let (label, pipeline) = if index == 0 {
428 (
429 format!("downsample filtered {}", index + 1),
430 &bloom_pipelines.downsample_filtered,
431 )
432 } else {
433 (
434 format!("downsample {}", index + 1),
435 &bloom_pipelines.downsample,
436 )
437 };
438 run_bloom_pass(
439 bind,
440 view,
441 label,
442 pipeline,
443 wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
444 );
445 });
446
447 (0..bloom::NUM_SIZES - 1).for_each(|index| {
449 let bind = &bloom_binds[bloom::NUM_SIZES - 1 - index].bind_group;
450 let view = &bloom_tgts[bloom::NUM_SIZES - 2 - index];
451 let label = format!("upsample {}", index + 1);
452 run_bloom_pass(
453 bind,
454 view,
455 label,
456 &bloom_pipelines.upsample,
457 if index + 2 == bloom::NUM_SIZES {
458 wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT)
460 } else {
461 wgpu::LoadOp::Load
464 },
465 );
466 });
467 }
468
469 fn run_ui_premultiply_passes(&mut self) {
472 prof_span!("run_ui_premultiply_passes");
473 let Some(premultiply_alpha) = self.borrow.pipelines.premultiply_alpha() else {
474 return;
475 };
476 let encoder = self.encoder.as_mut().unwrap();
477 let device = self.borrow.device;
478
479 let targets = self.borrow.ui_premultiply_uploads.take();
480
481 for (i, (target_texture, uploads)) in targets.into_iter().enumerate() {
482 prof_span!("ui premultiply pass");
483 let profile_name = format!("{UI_PREMULTIPLY_PASS} {i}");
484 let label = format!("ui premultiply pass {i}");
485 let mut render_pass =
486 encoder.scoped_render_pass(&profile_name, device, &wgpu::RenderPassDescriptor {
487 label: Some(&label),
488 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
489 view: &target_texture.view,
490 resolve_target: None,
491 ops: wgpu::Operations {
492 load: wgpu::LoadOp::Load,
493 store: wgpu::StoreOp::Store,
494 },
495 })],
496 depth_stencil_attachment: None,
497 timestamp_writes: None,
498 occlusion_query_set: None,
499 });
500 render_pass.set_pipeline(&premultiply_alpha.pipeline);
501 for upload in &uploads {
502 let (source_bind_group, push_constant_data) = upload.draw_data(&target_texture);
503 let bytes = bytemuck::bytes_of(&push_constant_data);
504 render_pass.set_bind_group(0, source_bind_group, &[]);
505 render_pass.set_push_constants(wgpu::ShaderStages::VERTEX, 0, bytes);
506 render_pass.draw(0..6, 0..1);
507 }
508 }
509 }
510
511 pub fn third_pass(&mut self) -> ThirdPassDrawer {
516 self.run_ui_premultiply_passes();
517
518 let encoder = self.encoder.as_mut().unwrap();
519 let device = self.borrow.device;
520 let mut render_pass =
521 encoder.scoped_render_pass("third_pass", device, &wgpu::RenderPassDescriptor {
522 label: Some("third pass (postprocess + ui)"),
523 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
524 view: self
527 .taking_screenshot
528 .as_ref()
529 .map_or(&self.surface_view, |s| s.texture_view()),
530 resolve_target: None,
531 ops: wgpu::Operations {
532 load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
533 store: wgpu::StoreOp::Store,
534 },
535 })],
536 depth_stencil_attachment: None,
537 timestamp_writes: None,
538 occlusion_query_set: None,
539 });
540
541 render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
542
543 ThirdPassDrawer {
544 render_pass,
545 borrow: &self.borrow,
546 }
547 }
548
549 #[cfg(feature = "egui-ui")]
550 pub fn draw_egui(&mut self, platform: &mut Platform, scale_factor: f32) {
551 span!(guard, "Draw egui");
552
553 let output = platform.end_frame(None);
554
555 let paint_jobs = platform.context().tessellate(output.shapes);
556
557 let screen_descriptor = ScreenDescriptor {
558 physical_width: self.borrow.surface_config.width,
559 physical_height: self.borrow.surface_config.height,
560 scale_factor,
561 };
562
563 self.borrow
564 .egui_render_pass
565 .add_textures(
566 self.borrow.device,
567 self.borrow.queue,
568 &output.textures_delta,
569 )
570 .expect("Failed to update egui textures");
571 self.borrow.egui_render_pass.update_buffers(
572 self.borrow.device,
573 self.borrow.queue,
574 &paint_jobs,
575 &screen_descriptor,
576 );
577
578 self.borrow
579 .egui_render_pass
580 .execute(
581 self.encoder.as_mut().unwrap(),
582 self.taking_screenshot
583 .as_ref()
584 .map_or(&self.surface_view, |s| s.texture_view()),
585 &paint_jobs,
586 &screen_descriptor,
587 None,
588 )
589 .expect("Failed to draw egui");
590
591 self.borrow
592 .egui_render_pass
593 .remove_textures(output.textures_delta)
594 .expect("Failed to remove unused egui textures");
595
596 drop(guard);
597 }
598
599 pub fn draw_point_shadows<'data>(
602 &mut self,
603 matrices: &[shadow::PointLightMatrix; 126],
604 chunks: impl Clone
605 + Iterator<Item = (&'data Model<terrain::Vertex>, &'data terrain::BoundLocals)>,
606 ) {
607 if !self.borrow.pipeline_modes.shadow.is_map() {
608 return;
609 }
610
611 if let Some(ShadowMap::Enabled(ref shadow_renderer)) = self.borrow.shadow.map(|s| &s.map) {
612 let device = self.borrow.device;
613 let mut encoder = self
614 .encoder
615 .as_mut()
616 .unwrap()
617 .scope("point shadows", device);
618 const STRIDE: usize = std::mem::size_of::<shadow::PointLightMatrix>();
619 let data = bytemuck::cast_slice(matrices);
620
621 for face in 0..6 {
622 let view =
624 shadow_renderer
625 .point_depth
626 .tex
627 .create_view(&wgpu::TextureViewDescriptor {
628 label: Some("Point shadow cubemap face"),
629 format: None,
630 dimension: Some(wgpu::TextureViewDimension::D2),
631 aspect: wgpu::TextureAspect::DepthOnly,
632 base_mip_level: 0,
633 mip_level_count: None,
634 base_array_layer: face,
635 array_layer_count: Some(1),
636 });
637
638 let label = format!("point shadow face-{} pass", face);
639 let mut render_pass =
640 encoder.scoped_render_pass(&label, device, &wgpu::RenderPassDescriptor {
641 label: Some(&label),
642 color_attachments: &[],
643 depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
644 view: &view,
645 depth_ops: Some(wgpu::Operations {
646 load: wgpu::LoadOp::Clear(1.0),
647 store: wgpu::StoreOp::Store,
648 }),
649 stencil_ops: None,
650 }),
651 timestamp_writes: None,
652 occlusion_query_set: None,
653 });
654
655 render_pass.set_pipeline(&shadow_renderer.point_pipeline.pipeline);
656 set_quad_index_buffer::<terrain::Vertex>(&mut render_pass, &self.borrow);
657 render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
658
659 (0..1).for_each(|point_light| {
660 render_pass.set_push_constants(
661 wgpu::ShaderStages::VERTEX_FRAGMENT,
662 0,
663 &data[(6 * (point_light + 1) * STRIDE + face as usize * STRIDE)
664 ..(6 * (point_light + 1) * STRIDE + (face + 1) as usize * STRIDE)],
665 );
666 chunks.clone().for_each(|(model, locals)| {
667 render_pass.set_bind_group(1, &locals.bind_group, &[]);
668 render_pass.set_vertex_buffer(0, model.buf().slice(..));
669 render_pass.draw_indexed(0..model.len() as u32 / 4 * 6, 0, 0..1);
670 });
671 });
672 }
673 }
674 }
675
676 pub fn clear_shadows(&mut self) {
687 if let Some(ShadowMap::Enabled(ref shadow_renderer)) = self.borrow.shadow.map(|s| &s.map) {
688 let device = self.borrow.device;
689 let encoder = self.encoder.as_mut().unwrap();
690 let _ = encoder.scoped_render_pass(
691 "clear_directed_shadow",
692 device,
693 &wgpu::RenderPassDescriptor {
694 label: Some("clear directed shadow pass"),
695 color_attachments: &[],
696 depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
697 view: &shadow_renderer.directed_depth.view,
698 depth_ops: Some(wgpu::Operations {
699 load: wgpu::LoadOp::Clear(1.0),
700 store: wgpu::StoreOp::Store,
701 }),
702 stencil_ops: None,
703 }),
704 timestamp_writes: None,
705 occlusion_query_set: None,
706 },
707 );
708
709 for face in 0..6 {
710 let view =
712 shadow_renderer
713 .point_depth
714 .tex
715 .create_view(&wgpu::TextureViewDescriptor {
716 label: Some("Point shadow cubemap face"),
717 format: None,
718 dimension: Some(wgpu::TextureViewDimension::D2),
719 aspect: wgpu::TextureAspect::DepthOnly,
720 base_mip_level: 0,
721 mip_level_count: None,
722 base_array_layer: face,
723 array_layer_count: Some(1),
724 });
725
726 let label = format!("clear point shadow face-{} pass", face);
727 let _ = encoder.scoped_render_pass(&label, device, &wgpu::RenderPassDescriptor {
728 label: Some(&label),
729 color_attachments: &[],
730 depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
731 view: &view,
732 depth_ops: Some(wgpu::Operations {
733 load: wgpu::LoadOp::Clear(1.0),
734 store: wgpu::StoreOp::Store,
735 }),
736 stencil_ops: None,
737 }),
738 timestamp_writes: None,
739 occlusion_query_set: None,
740 });
741 }
742 }
743 }
744}
745
746impl Drop for Drawer<'_> {
747 fn drop(&mut self) {
748 let mut encoder = self.encoder.take().unwrap();
749
750 let download_and_handle_screenshot = self
754 .taking_screenshot
755 .take()
756 .zip(self.borrow.pipelines.blit())
757 .map(|(screenshot, blit)| {
758 let mut render_pass = encoder.scoped_render_pass(
760 "screenshot blit",
761 self.borrow.device,
762 &wgpu::RenderPassDescriptor {
763 label: Some("Blit screenshot pass"),
764 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
765 view: &self.surface_view,
766 resolve_target: None,
767 ops: wgpu::Operations {
768 load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
769 store: wgpu::StoreOp::Store,
770 },
771 })],
772 depth_stencil_attachment: None,
773 timestamp_writes: None,
774 occlusion_query_set: None,
775 },
776 );
777 render_pass.set_pipeline(&blit.pipeline);
778 render_pass.set_bind_group(0, screenshot.bind_group(), &[]);
779 render_pass.draw(0..3, 0..1);
780 drop(render_pass);
781 screenshot.copy_to_buffer(&mut encoder)
785 });
786
787 let (mut encoder, profiler) = encoder.end_scope();
788 profiler.resolve_queries(&mut encoder);
789
790 self.borrow.queue.submit(std::iter::once(encoder.finish()));
792 if let Some(f) = download_and_handle_screenshot {
795 f();
796 }
797 self.surface_texture.take().unwrap().present();
798
799 profiler
800 .end_frame()
801 .expect("Gpu profiler error! Maybe there was an unclosed scope?");
802 }
803}
804
805#[must_use]
807pub struct ShadowPassDrawer<'pass> {
808 render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
809 borrow: &'pass RendererBorrow<'pass>,
810 shadow_renderer: &'pass ShadowMapRenderer,
811}
812
813impl<'pass> ShadowPassDrawer<'pass> {
814 pub fn draw_figure_shadows(&mut self) -> FigureShadowDrawer<'_, 'pass> {
815 let mut render_pass = self
816 .render_pass
817 .scope("directed_figure_shadows", self.borrow.device);
818
819 render_pass.set_pipeline(&self.shadow_renderer.figure_directed_pipeline.pipeline);
820 set_quad_index_buffer::<terrain::Vertex>(&mut render_pass, self.borrow);
821
822 FigureShadowDrawer { render_pass }
823 }
824
825 pub fn draw_terrain_shadows(&mut self) -> TerrainShadowDrawer<'_, 'pass> {
826 let mut render_pass = self
827 .render_pass
828 .scope("directed_terrain_shadows", self.borrow.device);
829
830 render_pass.set_pipeline(&self.shadow_renderer.terrain_directed_pipeline.pipeline);
831 set_quad_index_buffer::<terrain::Vertex>(&mut render_pass, self.borrow);
832
833 TerrainShadowDrawer { render_pass }
834 }
835
836 pub fn draw_debug_shadows(&mut self) -> DebugShadowDrawer<'_, 'pass> {
837 let mut render_pass = self
838 .render_pass
839 .scope("directed_debug_shadows", self.borrow.device);
840
841 render_pass.set_pipeline(&self.shadow_renderer.debug_directed_pipeline.pipeline);
842 set_quad_index_buffer::<debug::Vertex>(&mut render_pass, self.borrow);
843
844 DebugShadowDrawer { render_pass }
845 }
846}
847
848#[must_use]
849pub struct RainOcclusionPassDrawer<'pass> {
850 render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
851 borrow: &'pass RendererBorrow<'pass>,
852 rain_occlusion_renderer: &'pass RainOcclusionMapRenderer,
853}
854
855impl<'pass> RainOcclusionPassDrawer<'pass> {
856 pub fn draw_figure_shadows(&mut self) -> FigureShadowDrawer<'_, 'pass> {
857 let mut render_pass = self
858 .render_pass
859 .scope("directed_figure_rain_occlusion", self.borrow.device);
860
861 render_pass.set_pipeline(&self.rain_occlusion_renderer.figure_pipeline.pipeline);
862 set_quad_index_buffer::<terrain::Vertex>(&mut render_pass, self.borrow);
863
864 FigureShadowDrawer { render_pass }
865 }
866
867 pub fn draw_terrain_shadows(&mut self) -> TerrainShadowDrawer<'_, 'pass> {
868 let mut render_pass = self
869 .render_pass
870 .scope("directed_terrain_rain_occlusion", self.borrow.device);
871
872 render_pass.set_pipeline(&self.rain_occlusion_renderer.terrain_pipeline.pipeline);
873 set_quad_index_buffer::<terrain::Vertex>(&mut render_pass, self.borrow);
874
875 TerrainShadowDrawer { render_pass }
876 }
877}
878
879#[must_use]
880pub struct FigureShadowDrawer<'pass_ref, 'pass: 'pass_ref> {
881 render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
882}
883
884impl<'pass_ref, 'pass: 'pass_ref> FigureShadowDrawer<'pass_ref, 'pass> {
885 pub fn draw<'data: 'pass>(
886 &mut self,
887 model: SubModel<'data, terrain::Vertex>,
888 locals: &'data figure::BoundLocals,
889 ) {
890 self.render_pass.set_bind_group(1, &locals.bind_group, &[]);
891 self.render_pass.set_vertex_buffer(0, model.buf());
892 self.render_pass
893 .draw_indexed(0..model.len() / 4 * 6, 0, 0..1);
894 }
895}
896
897#[must_use]
898pub struct TerrainShadowDrawer<'pass_ref, 'pass: 'pass_ref> {
899 render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
900}
901
902impl<'pass_ref, 'pass: 'pass_ref> TerrainShadowDrawer<'pass_ref, 'pass> {
903 pub fn draw<'data: 'pass>(
904 &mut self,
905 model: &'data Model<terrain::Vertex>,
906 locals: &'data terrain::BoundLocals,
907 alt_indices: &'data AltIndices,
908 culling_mode: CullingMode,
909 ) {
910 let index_range = match culling_mode {
911 CullingMode::Underground => return, CullingMode::Surface => alt_indices.deep_end as u32..model.len() as u32,
915 CullingMode::None => 0..model.len() as u32,
916 };
917
918 if index_range.is_empty() {
920 return;
921 }
922
923 let submodel = model.submodel(index_range);
924
925 self.render_pass.set_bind_group(1, &locals.bind_group, &[]);
926 self.render_pass.set_vertex_buffer(0, submodel.buf());
927 self.render_pass
928 .draw_indexed(0..submodel.len() / 4 * 6, 0, 0..1);
929 }
930}
931
932#[must_use]
933pub struct DebugShadowDrawer<'pass_ref, 'pass: 'pass_ref> {
934 render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
935}
936
937impl<'pass_ref, 'pass: 'pass_ref> DebugShadowDrawer<'pass_ref, 'pass> {
938 pub fn draw<'data: 'pass>(
939 &mut self,
940 model: &'data Model<debug::Vertex>,
941 locals: &'data debug::BoundLocals,
942 ) {
943 self.render_pass.set_bind_group(1, &locals.bind_group, &[]);
944 self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
945 self.render_pass.draw(0..model.len() as u32, 0..1);
946 }
947}
948
949#[must_use]
951pub struct FirstPassDrawer<'pass> {
952 pub(super) render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
953 borrow: &'pass RendererBorrow<'pass>,
954 pipelines: &'pass super::Pipelines,
955 globals: &'pass GlobalsBindGroup,
956}
957
958impl<'pass> FirstPassDrawer<'pass> {
959 pub fn draw_skybox<'data: 'pass>(&mut self, model: &'data Model<skybox::Vertex>) {
960 let mut render_pass = self.render_pass.scope("skybox", self.borrow.device);
961
962 render_pass.set_pipeline(&self.pipelines.skybox.pipeline);
963 set_quad_index_buffer::<skybox::Vertex>(&mut render_pass, self.borrow);
964 render_pass.set_vertex_buffer(0, model.buf().slice(..));
965 render_pass.draw(0..model.len() as u32, 0..1);
966 }
967
968 pub fn draw_debug(&mut self) -> DebugDrawer<'_, 'pass> {
969 let mut render_pass = self.render_pass.scope("debug", self.borrow.device);
970
971 render_pass.set_pipeline(&self.pipelines.debug.pipeline);
972 set_quad_index_buffer::<debug::Vertex>(&mut render_pass, self.borrow);
973
974 DebugDrawer { render_pass }
975 }
976
977 pub fn draw_lod_terrain<'data: 'pass>(&mut self, model: &'data Model<lod_terrain::Vertex>) {
978 let mut render_pass = self.render_pass.scope("lod_terrain", self.borrow.device);
979
980 render_pass.set_pipeline(&self.pipelines.lod_terrain.pipeline);
981 set_quad_index_buffer::<lod_terrain::Vertex>(&mut render_pass, self.borrow);
982 render_pass.set_vertex_buffer(0, model.buf().slice(..));
983 render_pass.draw_indexed(0..model.len() as u32 / 4 * 6, 0, 0..1);
984 }
985
986 pub fn draw_figures(&mut self) -> FigureDrawer<'_, 'pass> {
987 let mut render_pass = self.render_pass.scope("figures", self.borrow.device);
988
989 render_pass.set_pipeline(&self.pipelines.figure.pipeline);
990 set_quad_index_buffer::<terrain::Vertex>(&mut render_pass, self.borrow);
992
993 FigureDrawer { render_pass }
994 }
995
996 pub fn draw_terrain(&mut self) -> TerrainDrawer<'_, 'pass> {
997 let mut render_pass = self.render_pass.scope("terrain", self.borrow.device);
998
999 render_pass.set_pipeline(&self.pipelines.terrain.pipeline);
1000 set_quad_index_buffer::<terrain::Vertex>(&mut render_pass, self.borrow);
1001
1002 TerrainDrawer {
1003 render_pass,
1004 atlas_textures: None,
1005 }
1006 }
1007
1008 pub fn draw_particles(&mut self) -> ParticleDrawer<'_, 'pass> {
1009 let mut render_pass = self.render_pass.scope("particles", self.borrow.device);
1010
1011 render_pass.set_pipeline(&self.pipelines.particle.pipeline);
1012 set_quad_index_buffer::<particle::Vertex>(&mut render_pass, self.borrow);
1013
1014 ParticleDrawer { render_pass }
1015 }
1016
1017 pub fn draw_ropes(&mut self) -> RopeDrawer<'_, 'pass> {
1018 let mut render_pass = self.render_pass.scope("ropes", self.borrow.device);
1019
1020 render_pass.set_pipeline(&self.pipelines.rope.pipeline);
1021 set_quad_index_buffer::<rope::Vertex>(&mut render_pass, self.borrow);
1022
1023 RopeDrawer { render_pass }
1024 }
1025
1026 pub fn draw_sprites<'data: 'pass>(
1027 &mut self,
1028 globals: &'data sprite::SpriteGlobalsBindGroup,
1029 atlas_textures: &'data AtlasTextures<sprite::Locals, FigureSpriteAtlasData>,
1030 ) -> SpriteDrawer<'_, 'pass> {
1031 let mut render_pass = self.render_pass.scope("sprites", self.borrow.device);
1032
1033 render_pass.set_pipeline(&self.pipelines.sprite.pipeline);
1034 set_quad_index_buffer::<sprite::Vertex>(&mut render_pass, self.borrow);
1035 render_pass.set_bind_group(0, &globals.bind_group, &[]);
1036 render_pass.set_bind_group(2, &atlas_textures.bind_group, &[]);
1037
1038 SpriteDrawer {
1039 render_pass,
1040 globals: self.globals,
1041 }
1042 }
1043
1044 pub fn draw_lod_objects(&mut self) -> LodObjectDrawer<'_, 'pass> {
1045 let mut render_pass = self.render_pass.scope("lod objects", self.borrow.device);
1046
1047 render_pass.set_pipeline(&self.pipelines.lod_object.pipeline);
1048 set_quad_index_buffer::<lod_object::Vertex>(&mut render_pass, self.borrow);
1049
1050 LodObjectDrawer { render_pass }
1051 }
1052
1053 pub fn draw_fluid(&mut self) -> FluidDrawer<'_, 'pass> {
1054 let mut render_pass = self.render_pass.scope("fluid", self.borrow.device);
1055
1056 render_pass.set_pipeline(&self.pipelines.fluid.pipeline);
1057 set_quad_index_buffer::<fluid::Vertex>(&mut render_pass, self.borrow);
1058
1059 FluidDrawer { render_pass }
1060 }
1061}
1062
1063#[must_use]
1064pub struct DebugDrawer<'pass_ref, 'pass: 'pass_ref> {
1065 render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1066}
1067
1068impl<'pass_ref, 'pass: 'pass_ref> DebugDrawer<'pass_ref, 'pass> {
1069 pub fn draw<'data: 'pass>(
1070 &mut self,
1071 model: &'data Model<debug::Vertex>,
1072 locals: &'data debug::BoundLocals,
1073 ) {
1074 self.render_pass.set_bind_group(2, &locals.bind_group, &[]);
1075 self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
1076 self.render_pass.draw(0..model.len() as u32, 0..1);
1077 }
1078}
1079
1080#[must_use]
1081pub struct FigureDrawer<'pass_ref, 'pass: 'pass_ref> {
1082 render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1083}
1084
1085impl<'pass_ref, 'pass: 'pass_ref> FigureDrawer<'pass_ref, 'pass> {
1086 pub fn draw<'data: 'pass>(
1087 &mut self,
1088 model: SubModel<'data, terrain::Vertex>,
1089 locals: &'data figure::BoundLocals,
1090 atlas_textures: &'data AtlasTextures<figure::Locals, FigureSpriteAtlasData>,
1092 ) {
1093 self.render_pass
1094 .set_bind_group(2, &atlas_textures.bind_group, &[]);
1095 self.render_pass.set_bind_group(3, &locals.bind_group, &[]);
1096 self.render_pass.set_vertex_buffer(0, model.buf());
1097 self.render_pass
1098 .draw_indexed(0..model.len() / 4 * 6, 0, 0..1);
1099 }
1100}
1101
1102#[must_use]
1103pub struct TerrainDrawer<'pass_ref, 'pass: 'pass_ref> {
1104 render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1105 atlas_textures: Option<&'pass_ref Arc<AtlasTextures<terrain::Locals, TerrainAtlasData>>>,
1106}
1107
1108impl<'pass_ref, 'pass: 'pass_ref> TerrainDrawer<'pass_ref, 'pass> {
1109 pub fn draw<'data: 'pass>(
1110 &mut self,
1111 model: &'data Model<terrain::Vertex>,
1112 atlas_textures: &'data Arc<AtlasTextures<terrain::Locals, TerrainAtlasData>>,
1113 locals: &'data terrain::BoundLocals,
1114 alt_indices: &'data AltIndices,
1115 culling_mode: CullingMode,
1116 ) {
1117 let index_range = match culling_mode {
1118 CullingMode::Underground => 0..alt_indices.underground_end as u32,
1119 CullingMode::Surface => alt_indices.deep_end as u32..model.len() as u32,
1120 CullingMode::None => 0..model.len() as u32,
1121 };
1122
1123 if index_range.is_empty() {
1125 return;
1126 }
1127
1128 let submodel = model.submodel(index_range);
1129
1130 if self.atlas_textures
1131 .filter(|current_atlas_textures| Arc::ptr_eq(current_atlas_textures, atlas_textures))
1134 .is_none()
1135 {
1136 self.render_pass
1137 .set_bind_group(2, &atlas_textures.bind_group, &[]);
1138 self.atlas_textures = Some(atlas_textures);
1139 };
1140
1141 self.render_pass.set_bind_group(3, &locals.bind_group, &[]);
1142
1143 self.render_pass.set_vertex_buffer(0, submodel.buf());
1144 self.render_pass
1145 .draw_indexed(0..submodel.len() / 4 * 6, 0, 0..1);
1146 }
1147}
1148
1149#[must_use]
1150pub struct ParticleDrawer<'pass_ref, 'pass: 'pass_ref> {
1151 render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1152}
1153
1154impl<'pass_ref, 'pass: 'pass_ref> ParticleDrawer<'pass_ref, 'pass> {
1155 pub fn draw<'data: 'pass>(
1158 &mut self,
1159 model: &'data Model<particle::Vertex>,
1160 instances: &'data Instances<particle::Instance>,
1161 ) {
1162 self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
1163 self.render_pass
1164 .set_vertex_buffer(1, instances.buf().slice(..));
1165 self.render_pass
1166 .draw_indexed(0..model.len() as u32 / 4 * 6, 0, 0..instances.count() as u32);
1168 }
1169}
1170
1171#[must_use]
1172pub struct RopeDrawer<'pass_ref, 'pass: 'pass_ref> {
1173 render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1174}
1175
1176impl<'pass_ref, 'pass: 'pass_ref> RopeDrawer<'pass_ref, 'pass> {
1177 pub fn draw<'data: 'pass>(
1180 &mut self,
1181 model: &'data Model<rope::Vertex>,
1182 locals: &'data rope::BoundLocals,
1183 ) {
1184 self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
1185 self.render_pass.set_bind_group(2, &locals.bind_group, &[]);
1186 self.render_pass
1189 .draw_indexed(0..model.len() as u32 / 4 * 6, 0, 0..1);
1190 }
1191}
1192
1193#[must_use]
1194pub struct SpriteDrawer<'pass_ref, 'pass: 'pass_ref> {
1195 render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1196 globals: &'pass GlobalsBindGroup,
1197}
1198
1199impl<'pass_ref, 'pass: 'pass_ref> SpriteDrawer<'pass_ref, 'pass> {
1200 pub fn draw<'data: 'pass, T>(
1201 &mut self,
1202 terrain_locals: &'data Bound<T>,
1203 instances: &'data Instances<sprite::Instance>,
1204 alt_indices: &'data AltIndices,
1205 culling_mode: CullingMode,
1206 ) {
1207 let instance_range = match culling_mode {
1208 CullingMode::Underground => 0..alt_indices.underground_end as u32,
1209 CullingMode::Surface => alt_indices.deep_end as u32..instances.count() as u32,
1210 CullingMode::None => 0..instances.count() as u32,
1211 };
1212
1213 if instance_range.is_empty() {
1215 return;
1216 }
1217
1218 self.render_pass
1219 .set_bind_group(3, &terrain_locals.bind_group, &[]);
1220
1221 let subinstances = instances.subinstances(instance_range);
1222
1223 self.render_pass.set_vertex_buffer(0, subinstances.buf());
1224 self.render_pass.draw_indexed(
1225 0..sprite::VERT_PAGE_SIZE / 4 * 6,
1226 0,
1227 0..subinstances.count(),
1228 );
1229 }
1230}
1231
1232impl<'pass_ref, 'pass: 'pass_ref> Drop for SpriteDrawer<'pass_ref, 'pass> {
1233 fn drop(&mut self) {
1234 self.render_pass
1236 .set_bind_group(0, &self.globals.bind_group, &[]);
1237 }
1238}
1239
1240#[must_use]
1241pub struct LodObjectDrawer<'pass_ref, 'pass: 'pass_ref> {
1242 render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1243}
1244
1245impl<'pass_ref, 'pass: 'pass_ref> LodObjectDrawer<'pass_ref, 'pass> {
1246 pub fn draw<'data: 'pass>(
1247 &mut self,
1248 model: &'data Model<lod_object::Vertex>,
1249 instances: &'data Instances<lod_object::Instance>,
1250 ) {
1251 self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
1252 self.render_pass
1253 .set_vertex_buffer(1, instances.buf().slice(..));
1254 self.render_pass
1255 .draw(0..model.len() as u32, 0..instances.count() as u32);
1256 }
1257}
1258
1259#[must_use]
1260pub struct FluidDrawer<'pass_ref, 'pass: 'pass_ref> {
1261 render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1262}
1263
1264impl<'pass_ref, 'pass: 'pass_ref> FluidDrawer<'pass_ref, 'pass> {
1265 pub fn draw<'data: 'pass>(
1266 &mut self,
1267 model: &'data Model<fluid::Vertex>,
1268 locals: &'data terrain::BoundLocals,
1269 ) {
1270 self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
1271 self.render_pass.set_bind_group(2, &locals.bind_group, &[]);
1272 self.render_pass
1273 .draw_indexed(0..model.len() as u32 / 4 * 6, 0, 0..1);
1274 }
1275}
1276
1277#[must_use]
1279pub struct VolumetricPassDrawer<'pass> {
1280 render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
1281 borrow: &'pass RendererBorrow<'pass>,
1282 clouds_pipeline: &'pass clouds::CloudsPipeline,
1283}
1284
1285impl VolumetricPassDrawer<'_> {
1286 pub fn draw_clouds(&mut self) {
1287 self.render_pass
1288 .set_pipeline(&self.clouds_pipeline.pipeline);
1289 self.render_pass
1290 .set_bind_group(2, &self.borrow.locals.clouds_bind.bind_group, &[]);
1291 self.render_pass.draw(0..3, 0..1);
1292 }
1293}
1294
1295#[must_use]
1297pub struct TransparentPassDrawer<'pass> {
1298 render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
1299 borrow: &'pass RendererBorrow<'pass>,
1300 trail_pipeline: &'pass trail::TrailPipeline,
1301}
1302
1303impl<'pass> TransparentPassDrawer<'pass> {
1304 pub fn draw_trails(&mut self) -> Option<TrailDrawer<'_, 'pass>> {
1305 let shadow = &self.borrow.shadow?;
1306
1307 let mut render_pass = self.render_pass.scope("trails", self.borrow.device);
1308
1309 render_pass.set_pipeline(&self.trail_pipeline.pipeline);
1310 set_quad_index_buffer::<trail::Vertex>(&mut render_pass, self.borrow);
1311
1312 render_pass.set_bind_group(1, &shadow.bind.bind_group, &[]);
1313
1314 Some(TrailDrawer { render_pass })
1315 }
1316}
1317
1318#[must_use]
1319pub struct TrailDrawer<'pass_ref, 'pass: 'pass_ref> {
1320 render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1321}
1322
1323impl<'pass_ref, 'pass: 'pass_ref> TrailDrawer<'pass_ref, 'pass> {
1324 pub fn draw(&mut self, submodel: SubModel<'pass, trail::Vertex>) {
1325 self.render_pass.set_vertex_buffer(0, submodel.buf());
1326 self.render_pass
1327 .draw_indexed(0..submodel.len() / 4 * 6, 0, 0..1);
1328 }
1329}
1330
1331#[must_use]
1333pub struct ThirdPassDrawer<'pass> {
1334 render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
1335 borrow: &'pass RendererBorrow<'pass>,
1336}
1337
1338impl<'pass> ThirdPassDrawer<'pass> {
1339 pub fn draw_postprocess(&mut self) {
1341 let postprocess = match self.borrow.pipelines.all() {
1342 Some(p) => &p.postprocess,
1343 None => return,
1344 };
1345
1346 let mut render_pass = self.render_pass.scope("postprocess", self.borrow.device);
1347 render_pass.set_pipeline(&postprocess.pipeline);
1348 render_pass.set_bind_group(1, &self.borrow.locals.postprocess_bind.bind_group, &[]);
1349 render_pass.draw(0..3, 0..1);
1350 }
1351
1352 pub fn draw_ui(&mut self) -> Option<UiDrawer<'_, 'pass>> {
1355 let ui = self.borrow.pipelines.ui()?;
1356
1357 let mut render_pass = self.render_pass.scope("ui", self.borrow.device);
1358 render_pass.set_pipeline(&ui.pipeline);
1359 set_quad_index_buffer::<ui::Vertex>(&mut render_pass, self.borrow);
1360
1361 Some(UiDrawer { render_pass })
1362 }
1363}
1364
1365#[must_use]
1366pub struct UiDrawer<'pass_ref, 'pass: 'pass_ref> {
1367 render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1368}
1369
1370#[must_use]
1371pub struct PreparedUiDrawer<'pass_ref, 'pass: 'pass_ref> {
1372 render_pass: &'pass_ref mut wgpu::RenderPass<'pass>,
1373}
1374
1375impl<'pass_ref, 'pass: 'pass_ref> UiDrawer<'pass_ref, 'pass> {
1376 pub fn prepare<'data: 'pass>(
1380 &mut self,
1381 locals: &'data ui::BoundLocals,
1382 buf: &'data DynamicModel<ui::Vertex>,
1383 scissor: Aabr<u16>,
1384 ) -> PreparedUiDrawer<'_, 'pass> {
1385 let mut prepared = PreparedUiDrawer {
1388 render_pass: &mut self.render_pass,
1389 };
1390 prepared.set_locals(locals);
1392 prepared.set_model(buf);
1393 prepared.set_scissor(scissor);
1394
1395 prepared
1396 }
1397}
1398
1399impl<'pass_ref, 'pass: 'pass_ref> PreparedUiDrawer<'pass_ref, 'pass> {
1400 pub fn set_locals<'data: 'pass>(&mut self, locals: &'data ui::BoundLocals) {
1401 self.render_pass.set_bind_group(1, &locals.bind_group, &[]);
1402 }
1403
1404 pub fn set_model<'data: 'pass>(&mut self, model: &'data DynamicModel<ui::Vertex>) {
1405 self.render_pass.set_vertex_buffer(0, model.buf().slice(..))
1406 }
1407
1408 pub fn set_scissor(&mut self, scissor: Aabr<u16>) {
1409 let Aabr { min, max } = scissor;
1410 self.render_pass.set_scissor_rect(
1411 min.x as u32,
1412 min.y as u32,
1413 (max.x - min.x) as u32,
1414 (max.y - min.y) as u32,
1415 );
1416 }
1417
1418 pub fn draw<'data: 'pass>(&mut self, texture: &'data ui::TextureBindGroup, verts: Range<u32>) {
1419 self.render_pass.set_bind_group(2, &texture.bind_group, &[]);
1420 self.render_pass.draw(verts, 0..1);
1421 }
1422}
1423
1424fn set_quad_index_buffer<'a, V: super::Vertex>(
1425 pass: &mut wgpu::RenderPass<'a>,
1426 borrow: &RendererBorrow<'a>,
1427) {
1428 if let Some(format) = V::QUADS_INDEX {
1429 let slice = match format {
1430 wgpu::IndexFormat::Uint16 => borrow.quad_index_buffer_u16.buf.slice(..),
1431 wgpu::IndexFormat::Uint32 => borrow.quad_index_buffer_u32.buf.slice(..),
1432 };
1433
1434 pass.set_index_buffer(slice, format);
1435 }
1436}