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