veloren_voxygen/render/renderer/
drawer.rs

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::ScreenDescriptor};
25
26/// Gpu timing label prefix associated with the UI alpha premultiplication pass.
27pub const UI_PREMULTIPLY_PASS: &str = "ui_premultiply_pass";
28
29// Currently available pipelines
30enum Pipelines<'frame> {
31    Interface(&'frame super::InterfacePipelines),
32    All(&'frame super::Pipelines),
33    // Should never be in this state for now but we need this to account for super::State::Nothing
34    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
142// Borrow the fields we need from the renderer so that the GpuProfiler can be
143// disjointedly borrowed mutably
144struct 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_renderer: &'frame mut egui_wgpu::Renderer,
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    // Texture and other info for taking a screenshot
169    // Writes to this instead in the third pass if it is present
170    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_renderer: &mut renderer.egui_renderer,
213        };
214
215        let encoder = ManualScope::start("frame", &mut renderer.profiler, encoder);
216
217        // Create a view to the surface texture.
218        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    /// Get the pipeline modes.
236    pub fn pipeline_modes(&self) -> &super::PipelineModes { self.borrow.pipeline_modes }
237
238    /// Returns None if the rain occlusion renderer is not enabled at some
239    /// level, the pipelines are not available yet or clouds are disabled.
240    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    /// Returns None if the shadow renderer is not enabled at some level or the
278    /// pipelines are not available yet
279    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    /// Returns None if all the pipelines are not available
315    pub fn first_pass(&mut self) -> Option<FirstPassDrawer<'_>> {
316        let pipelines = self.borrow.pipelines.all()?;
317        // Note: this becomes Some once pipeline creation is complete even if shadows
318        // are not enabled
319        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    /// Returns None if the volumetrics pipeline is not available
369    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    /// Returns None if the trail pipeline is not available
402    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    /// To be ran between the second pass and the third pass
442    /// does nothing if the ingame pipelines are not yet ready
443    /// does nothing if bloom is disabled
444    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        // TODO: consider consolidating optional bloom bind groups and optional pipeline
454        // into a single structure?
455        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        // Downsample filter passes
487        (0..bloom::NUM_SIZES - 1).for_each(|index| {
488            let bind = &bloom_binds[index].bind_group;
489            let view = &bloom_tgts[index + 1];
490            // Do filtering during the first downsample
491            // NOTE: We currently blur all things without filtering by brightness.
492            // This is left in for those that might want to experminent with filtering by
493            // brightness, and it is used to filter out NaNs/Infs that would infect all the
494            // pixels they are blurred with.
495            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        // Upsample filter passes
516        (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                    // Clear for the final image since that is just stuff from the previous frame.
527                    wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT)
528                } else {
529                    // Add to less blurred images to get gradient of blur instead of a smudge>
530                    // https://catlikecoding.com/unity/tutorials/advanced-rendering/bloom/
531                    wgpu::LoadOp::Load
532                },
533            );
534        });
535    }
536
537    /// Runs render passes with alpha premultiplication pipeline to complete any
538    /// pending uploads.
539    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    /// Prepares the third pass drawer to be used.
580    ///
581    /// Note, this automatically calls the internal `run_ui_premultiply_passes`
582    /// to complete any pending image uploads for the UI.
583    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                        // If a screenshot was requested render to that as an intermediate texture
592                        // instead
593                        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(
619        &mut self,
620        state: &mut egui_winit::State,
621        scale_factor: f32,
622    ) -> egui::PlatformOutput {
623        span!(guard, "Draw egui");
624
625        let output = state.egui_ctx().end_pass();
626
627        let paint_jobs = state.egui_ctx().tessellate(output.shapes, scale_factor);
628
629        let screen_descriptor = ScreenDescriptor {
630            size_in_pixels: [
631                self.borrow.surface_config.width,
632                self.borrow.surface_config.height,
633            ],
634            pixels_per_point: scale_factor,
635        };
636
637        for (id, delta) in output.textures_delta.set.iter() {
638            self.borrow.egui_renderer.update_texture(
639                self.borrow.device,
640                self.borrow.queue,
641                *id,
642                delta,
643            );
644        }
645
646        // PaintCallback is not used to my knowledge so this should always be empty
647        // Couldn't figure out a nice way to get it into Drawer's Drop impl, anyway
648        let _ = self.borrow.egui_renderer.update_buffers(
649            self.borrow.device,
650            self.borrow.queue,
651            self.encoder.encoder(),
652            &paint_jobs,
653            &screen_descriptor,
654        );
655
656        let mut render_pass = self
657            .encoder
658            .encoder()
659            .begin_render_pass(&wgpu::RenderPassDescriptor {
660                label: Some("egui pass"),
661                color_attachments: &[Some(wgpu::RenderPassColorAttachment {
662                    view: self
663                        .taking_screenshot
664                        .as_ref()
665                        .map_or(&self.surface_view, |s| s.texture_view()),
666                    depth_slice: None,
667                    resolve_target: None,
668                    ops: wgpu::Operations {
669                        load: wgpu::LoadOp::Load,
670                        store: wgpu::StoreOp::Store,
671                    },
672                })],
673                depth_stencil_attachment: None,
674                timestamp_writes: None,
675                occlusion_query_set: None,
676            })
677            .forget_lifetime();
678
679        self.borrow
680            .egui_renderer
681            .render(&mut render_pass, &paint_jobs, &screen_descriptor);
682
683        for id in output.textures_delta.free.iter() {
684            self.borrow.egui_renderer.free_texture(id);
685        }
686
687        drop(guard);
688        output.platform_output
689    }
690
691    /// Does nothing if the shadow pipelines are not available or shadow map
692    /// rendering is disabled
693    pub fn draw_point_shadows<'data>(
694        &mut self,
695        matrices: &[shadow::PointLightMatrix; 126],
696        chunks: impl Clone
697        + Iterator<Item = (&'data Model<terrain::Vertex>, &'data terrain::BoundLocals)>,
698    ) {
699        if !self.borrow.pipeline_modes.shadow.is_map() {
700            return;
701        }
702
703        if let Some(ShadowMap::Enabled(shadow_renderer)) = self.borrow.shadow.map(|s| &s.map) {
704            let mut encoder = self.encoder.scope("point shadows");
705            const STRIDE: usize = std::mem::size_of::<shadow::PointLightMatrix>();
706            let data = bytemuck::cast_slice(matrices);
707
708            for face in 0..6 {
709                // TODO: view creation cost?
710                let view =
711                    shadow_renderer
712                        .point_depth
713                        .tex
714                        .create_view(&wgpu::TextureViewDescriptor {
715                            label: Some("Point shadow cubemap face"),
716                            format: None,
717                            dimension: Some(wgpu::TextureViewDimension::D2),
718                            usage: None,
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!("point shadow face-{} pass", face);
727                let mut render_pass =
728                    encoder.scoped_render_pass(&label, wgpu::RenderPassDescriptor {
729                        label: Some(&label),
730                        color_attachments: &[],
731                        depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
732                            view: &view,
733                            depth_ops: Some(wgpu::Operations {
734                                load: wgpu::LoadOp::Clear(1.0),
735                                store: wgpu::StoreOp::Store,
736                            }),
737                            stencil_ops: None,
738                        }),
739                        timestamp_writes: None,
740                        occlusion_query_set: None,
741                    });
742
743                render_pass.set_pipeline(&shadow_renderer.point_pipeline.pipeline);
744                set_quad_index_buffer::<terrain::Vertex>(&mut render_pass, &self.borrow);
745                render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
746
747                (0../*20*/1).for_each(|point_light| {
748                    render_pass.set_push_constants(
749                        wgpu::ShaderStages::VERTEX_FRAGMENT,
750                        0,
751                        &data[(6 * (point_light + 1) * STRIDE + face as usize * STRIDE)
752                            ..(6 * (point_light + 1) * STRIDE + (face + 1) as usize * STRIDE)],
753                    );
754                    chunks.clone().for_each(|(model, locals)| {
755                        render_pass.set_bind_group(1, &locals.bind_group, &[]);
756                        render_pass.set_vertex_buffer(0, model.buf().slice(..));
757                        render_pass.draw_indexed(0..model.len() as u32 / 4 * 6, 0, 0..1);
758                    });
759                });
760            }
761        }
762    }
763
764    /// Clear all the shadow textures, useful if directed shadows (shadow_pass)
765    /// and point light shadows (draw_point_shadows) are unused and thus the
766    /// textures will otherwise not be cleared after either their
767    /// initialization or their last use
768    /// NOTE: could simply use the above passes except `draw_point_shadows`
769    /// requires an array of matrices that could be a pain to construct
770    /// simply for clearing
771    ///
772    /// Does nothing if the shadow pipelines are not available (although they
773    /// aren't used here they are needed for the ShadowMap to exist)
774    pub fn clear_shadows(&mut self) {
775        if let Some(ShadowMap::Enabled(shadow_renderer)) = self.borrow.shadow.map(|s| &s.map) {
776            let _ = self.encoder.scoped_render_pass(
777                "clear_directed_shadow",
778                wgpu::RenderPassDescriptor {
779                    label: Some("clear directed shadow pass"),
780                    color_attachments: &[],
781                    depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
782                        view: &shadow_renderer.directed_depth.view,
783                        depth_ops: Some(wgpu::Operations {
784                            load: wgpu::LoadOp::Clear(1.0),
785                            store: wgpu::StoreOp::Store,
786                        }),
787                        stencil_ops: None,
788                    }),
789                    timestamp_writes: None,
790                    occlusion_query_set: None,
791                },
792            );
793
794            for face in 0..6 {
795                // TODO: view creation cost?
796                let view =
797                    shadow_renderer
798                        .point_depth
799                        .tex
800                        .create_view(&wgpu::TextureViewDescriptor {
801                            label: Some("Point shadow cubemap face"),
802                            format: None,
803                            dimension: Some(wgpu::TextureViewDimension::D2),
804                            usage: None,
805                            aspect: wgpu::TextureAspect::DepthOnly,
806                            base_mip_level: 0,
807                            mip_level_count: None,
808                            base_array_layer: face,
809                            array_layer_count: Some(1),
810                        });
811
812                let label = format!("clear point shadow face-{} pass", face);
813                let _ = self
814                    .encoder
815                    .scoped_render_pass(&label, wgpu::RenderPassDescriptor {
816                        label: Some(&label),
817                        color_attachments: &[],
818                        depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
819                            view: &view,
820                            depth_ops: Some(wgpu::Operations {
821                                load: wgpu::LoadOp::Clear(1.0),
822                                store: wgpu::StoreOp::Store,
823                            }),
824                            stencil_ops: None,
825                        }),
826                        timestamp_writes: None,
827                        occlusion_query_set: None,
828                    });
829            }
830        }
831    }
832}
833
834impl Drop for Drawer<'_> {
835    fn drop(&mut self) {
836        // If taking a screenshot and the blit pipeline is available
837        // NOTE: blit pipeline should always be available for now so we don't report an
838        // error if it isn't
839        let download_and_handle_screenshot = self
840            .taking_screenshot
841            .take()
842            .zip(self.borrow.pipelines.blit())
843            .map(|(screenshot, blit)| {
844                // Image needs to be copied from the screenshot texture to the swapchain texture
845                let mut render_pass = self.encoder.scoped_render_pass(
846                    "screenshot blit",
847                    wgpu::RenderPassDescriptor {
848                        label: Some("Blit screenshot pass"),
849                        color_attachments: &[Some(wgpu::RenderPassColorAttachment {
850                            view: &self.surface_view,
851                            depth_slice: None,
852                            resolve_target: None,
853                            ops: wgpu::Operations {
854                                load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
855                                store: wgpu::StoreOp::Store,
856                            },
857                        })],
858                        depth_stencil_attachment: None,
859                        timestamp_writes: None,
860                        occlusion_query_set: None,
861                    },
862                );
863                render_pass.set_pipeline(&blit.pipeline);
864                render_pass.set_bind_group(0, screenshot.bind_group(), &[]);
865                render_pass.draw(0..3, 0..1);
866                drop(render_pass);
867                // Issues a command to copy from the texture to a buffer and returns a closure
868                // that will send the buffer off to another thread to be mapped
869                // and processed.
870                screenshot.copy_to_buffer(self.encoder.encoder())
871            });
872
873        let (profiler, mut encoder) = self.encoder.end_query();
874        profiler.resolve_queries(&mut encoder);
875
876        // It is recommended to only do one submit per frame
877        self.borrow.queue.submit(std::iter::once(encoder.finish()));
878        // Need to call this after submit so the async mapping doesn't occur before
879        // copying the screenshot to the buffer which will be mapped.
880        if let Some(f) = download_and_handle_screenshot {
881            f();
882        }
883        self.surface_texture.take().unwrap().present();
884
885        profiler
886            .end_frame()
887            .expect("Gpu profiler error! Maybe there was an unclosed scope?");
888    }
889}
890
891// Shadow pass
892#[must_use]
893pub struct ShadowPassDrawer<'pass> {
894    render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
895    borrow: &'pass RendererBorrow<'pass>,
896    shadow_renderer: &'pass ShadowMapRenderer,
897}
898
899impl<'pass> ShadowPassDrawer<'pass> {
900    pub fn draw_figure_shadows(&mut self) -> FigureShadowDrawer<'_, 'pass> {
901        let mut render_pass = self.render_pass.scope("directed_figure_shadows");
902
903        render_pass.set_pipeline(&self.shadow_renderer.figure_directed_pipeline.pipeline);
904        set_quad_index_buffer::<terrain::Vertex>(&mut render_pass, self.borrow);
905
906        FigureShadowDrawer { render_pass }
907    }
908
909    pub fn draw_terrain_shadows(&mut self) -> TerrainShadowDrawer<'_, 'pass> {
910        let mut render_pass = self.render_pass.scope("directed_terrain_shadows");
911
912        render_pass.set_pipeline(&self.shadow_renderer.terrain_directed_pipeline.pipeline);
913        set_quad_index_buffer::<terrain::Vertex>(&mut render_pass, self.borrow);
914
915        TerrainShadowDrawer { render_pass }
916    }
917
918    pub fn draw_debug_shadows(&mut self) -> DebugShadowDrawer<'_, 'pass> {
919        let mut render_pass = self.render_pass.scope("directed_debug_shadows");
920
921        render_pass.set_pipeline(&self.shadow_renderer.debug_directed_pipeline.pipeline);
922        set_quad_index_buffer::<debug::Vertex>(&mut render_pass, self.borrow);
923
924        DebugShadowDrawer { render_pass }
925    }
926}
927
928#[must_use]
929pub struct RainOcclusionPassDrawer<'pass> {
930    render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
931    borrow: &'pass RendererBorrow<'pass>,
932    rain_occlusion_renderer: &'pass RainOcclusionMapRenderer,
933}
934
935impl<'pass> RainOcclusionPassDrawer<'pass> {
936    pub fn draw_figure_shadows(&mut self) -> FigureShadowDrawer<'_, 'pass> {
937        let mut render_pass = self.render_pass.scope("directed_figure_rain_occlusion");
938
939        render_pass.set_pipeline(&self.rain_occlusion_renderer.figure_pipeline.pipeline);
940        set_quad_index_buffer::<terrain::Vertex>(&mut render_pass, self.borrow);
941
942        FigureShadowDrawer { render_pass }
943    }
944
945    pub fn draw_terrain_shadows(&mut self) -> TerrainShadowDrawer<'_, 'pass> {
946        let mut render_pass = self.render_pass.scope("directed_terrain_rain_occlusion");
947
948        render_pass.set_pipeline(&self.rain_occlusion_renderer.terrain_pipeline.pipeline);
949        set_quad_index_buffer::<terrain::Vertex>(&mut render_pass, self.borrow);
950
951        TerrainShadowDrawer { render_pass }
952    }
953}
954
955#[must_use]
956pub struct FigureShadowDrawer<'pass_ref, 'pass: 'pass_ref> {
957    render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
958}
959
960impl<'pass_ref, 'pass: 'pass_ref> FigureShadowDrawer<'pass_ref, 'pass> {
961    pub fn draw<'data: 'pass>(
962        &mut self,
963        model: SubModel<'data, terrain::Vertex>,
964        locals: &'data figure::BoundLocals,
965    ) {
966        self.render_pass.set_bind_group(1, &locals.bind_group, &[]);
967        self.render_pass.set_vertex_buffer(0, model.buf());
968        self.render_pass
969            .draw_indexed(0..model.len() / 4 * 6, 0, 0..1);
970    }
971}
972
973#[must_use]
974pub struct TerrainShadowDrawer<'pass_ref, 'pass: 'pass_ref> {
975    render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
976}
977
978impl<'pass_ref, 'pass: 'pass_ref> TerrainShadowDrawer<'pass_ref, 'pass> {
979    pub fn draw<'data: 'pass>(
980        &mut self,
981        model: &'data Model<terrain::Vertex>,
982        locals: &'data terrain::BoundLocals,
983        alt_indices: &'data AltIndices,
984        culling_mode: CullingMode,
985    ) {
986        let index_range = match culling_mode {
987            // Don't bother rendering shadows when underground
988            // TODO: Does this break point shadows in certain cases?
989            CullingMode::Underground => return, //0..alt_indices.underground_end as u32,
990            CullingMode::Surface => alt_indices.deep_end as u32..model.len() as u32,
991            CullingMode::None => 0..model.len() as u32,
992        };
993
994        // Don't render anything if there's nothing to render!
995        if index_range.is_empty() {
996            return;
997        }
998
999        let submodel = model.submodel(index_range);
1000
1001        self.render_pass.set_bind_group(1, &locals.bind_group, &[]);
1002        self.render_pass.set_vertex_buffer(0, submodel.buf());
1003        self.render_pass
1004            .draw_indexed(0..submodel.len() / 4 * 6, 0, 0..1);
1005    }
1006}
1007
1008#[must_use]
1009pub struct DebugShadowDrawer<'pass_ref, 'pass: 'pass_ref> {
1010    render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1011}
1012
1013impl<'pass_ref, 'pass: 'pass_ref> DebugShadowDrawer<'pass_ref, 'pass> {
1014    pub fn draw<'data: 'pass>(
1015        &mut self,
1016        model: &'data Model<debug::Vertex>,
1017        locals: &'data debug::BoundLocals,
1018    ) {
1019        self.render_pass.set_bind_group(1, &locals.bind_group, &[]);
1020        self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
1021        self.render_pass.draw(0..model.len() as u32, 0..1);
1022    }
1023}
1024
1025// First pass
1026#[must_use]
1027pub struct FirstPassDrawer<'pass> {
1028    pub(super) render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
1029    borrow: &'pass RendererBorrow<'pass>,
1030    pipelines: &'pass super::Pipelines,
1031    globals: &'pass GlobalsBindGroup,
1032}
1033
1034impl<'pass> FirstPassDrawer<'pass> {
1035    pub fn draw_skybox<'data: 'pass>(&mut self, model: &'data Model<skybox::Vertex>) {
1036        let mut render_pass = self.render_pass.scope("skybox");
1037
1038        render_pass.set_pipeline(&self.pipelines.skybox.pipeline);
1039        set_quad_index_buffer::<skybox::Vertex>(&mut render_pass, self.borrow);
1040        render_pass.set_vertex_buffer(0, model.buf().slice(..));
1041        render_pass.draw(0..model.len() as u32, 0..1);
1042    }
1043
1044    pub fn draw_debug(&mut self) -> DebugDrawer<'_, 'pass> {
1045        let mut render_pass = self.render_pass.scope("debug");
1046
1047        render_pass.set_pipeline(&self.pipelines.debug.pipeline);
1048        set_quad_index_buffer::<debug::Vertex>(&mut render_pass, self.borrow);
1049
1050        DebugDrawer { render_pass }
1051    }
1052
1053    pub fn draw_lod_terrain<'data: 'pass>(&mut self, model: &'data Model<lod_terrain::Vertex>) {
1054        let mut render_pass = self.render_pass.scope("lod_terrain");
1055
1056        render_pass.set_pipeline(&self.pipelines.lod_terrain.pipeline);
1057        set_quad_index_buffer::<lod_terrain::Vertex>(&mut render_pass, self.borrow);
1058        render_pass.set_vertex_buffer(0, model.buf().slice(..));
1059        render_pass.draw_indexed(0..model.len() as u32 / 4 * 6, 0, 0..1);
1060    }
1061
1062    pub fn draw_figures(&mut self) -> FigureDrawer<'_, 'pass> {
1063        let mut render_pass = self.render_pass.scope("figures");
1064
1065        render_pass.set_pipeline(&self.pipelines.figure.pipeline);
1066        // Note: figures use the same vertex type as the terrain
1067        set_quad_index_buffer::<terrain::Vertex>(&mut render_pass, self.borrow);
1068
1069        FigureDrawer { render_pass }
1070    }
1071
1072    pub fn draw_terrain(&mut self) -> TerrainDrawer<'_, 'pass> {
1073        let mut render_pass = self.render_pass.scope("terrain");
1074
1075        render_pass.set_pipeline(&self.pipelines.terrain.pipeline);
1076        set_quad_index_buffer::<terrain::Vertex>(&mut render_pass, self.borrow);
1077
1078        TerrainDrawer {
1079            render_pass,
1080            atlas_textures: None,
1081        }
1082    }
1083
1084    pub fn draw_particles(&mut self) -> ParticleDrawer<'_, 'pass> {
1085        let mut render_pass = self.render_pass.scope("particles");
1086
1087        render_pass.set_pipeline(&self.pipelines.particle.pipeline);
1088        set_quad_index_buffer::<particle::Vertex>(&mut render_pass, self.borrow);
1089
1090        ParticleDrawer { render_pass }
1091    }
1092
1093    pub fn draw_ropes(&mut self) -> RopeDrawer<'_, 'pass> {
1094        let mut render_pass = self.render_pass.scope("ropes");
1095
1096        render_pass.set_pipeline(&self.pipelines.rope.pipeline);
1097        set_quad_index_buffer::<rope::Vertex>(&mut render_pass, self.borrow);
1098
1099        RopeDrawer { render_pass }
1100    }
1101
1102    pub fn draw_sprites<'data: 'pass>(
1103        &mut self,
1104        globals: &'data sprite::SpriteGlobalsBindGroup,
1105        atlas_textures: &'data AtlasTextures<sprite::Locals, FigureSpriteAtlasData>,
1106    ) -> SpriteDrawer<'_, 'pass> {
1107        let mut render_pass = self.render_pass.scope("sprites");
1108
1109        render_pass.set_pipeline(&self.pipelines.sprite.pipeline);
1110        set_quad_index_buffer::<sprite::Vertex>(&mut render_pass, self.borrow);
1111        render_pass.set_bind_group(0, &globals.bind_group, &[]);
1112        render_pass.set_bind_group(2, &atlas_textures.bind_group, &[]);
1113
1114        SpriteDrawer {
1115            render_pass,
1116            globals: self.globals,
1117        }
1118    }
1119
1120    pub fn draw_lod_objects(&mut self) -> LodObjectDrawer<'_, 'pass> {
1121        let mut render_pass = self.render_pass.scope("lod objects");
1122
1123        render_pass.set_pipeline(&self.pipelines.lod_object.pipeline);
1124        set_quad_index_buffer::<lod_object::Vertex>(&mut render_pass, self.borrow);
1125
1126        LodObjectDrawer { render_pass }
1127    }
1128
1129    pub fn draw_fluid(&mut self) -> FluidDrawer<'_, 'pass> {
1130        let mut render_pass = self.render_pass.scope("fluid");
1131
1132        render_pass.set_pipeline(&self.pipelines.fluid.pipeline);
1133        set_quad_index_buffer::<fluid::Vertex>(&mut render_pass, self.borrow);
1134
1135        FluidDrawer { render_pass }
1136    }
1137}
1138
1139#[must_use]
1140pub struct DebugDrawer<'pass_ref, 'pass: 'pass_ref> {
1141    render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1142}
1143
1144impl<'pass_ref, 'pass: 'pass_ref> DebugDrawer<'pass_ref, 'pass> {
1145    pub fn draw<'data: 'pass>(
1146        &mut self,
1147        model: &'data Model<debug::Vertex>,
1148        locals: &'data debug::BoundLocals,
1149    ) {
1150        self.render_pass.set_bind_group(2, &locals.bind_group, &[]);
1151        self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
1152        self.render_pass.draw(0..model.len() as u32, 0..1);
1153    }
1154}
1155
1156#[must_use]
1157pub struct FigureDrawer<'pass_ref, 'pass: 'pass_ref> {
1158    render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1159}
1160
1161impl<'pass_ref, 'pass: 'pass_ref> FigureDrawer<'pass_ref, 'pass> {
1162    pub fn draw<'data: 'pass>(
1163        &mut self,
1164        model: SubModel<'data, terrain::Vertex>,
1165        locals: &'data figure::BoundLocals,
1166        // TODO: don't rebind this every time once they are shared between figures
1167        atlas_textures: &'data AtlasTextures<figure::Locals, FigureSpriteAtlasData>,
1168    ) {
1169        self.render_pass
1170            .set_bind_group(2, &atlas_textures.bind_group, &[]);
1171        self.render_pass.set_bind_group(3, &locals.bind_group, &[]);
1172        self.render_pass.set_vertex_buffer(0, model.buf());
1173        self.render_pass
1174            .draw_indexed(0..model.len() / 4 * 6, 0, 0..1);
1175    }
1176}
1177
1178#[must_use]
1179pub struct TerrainDrawer<'pass_ref, 'pass: 'pass_ref> {
1180    render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1181    atlas_textures: Option<&'pass_ref Arc<AtlasTextures<terrain::Locals, TerrainAtlasData>>>,
1182}
1183
1184impl<'pass_ref, 'pass: 'pass_ref> TerrainDrawer<'pass_ref, 'pass> {
1185    pub fn draw<'data: 'pass>(
1186        &mut self,
1187        model: &'data Model<terrain::Vertex>,
1188        atlas_textures: &'data Arc<AtlasTextures<terrain::Locals, TerrainAtlasData>>,
1189        locals: &'data terrain::BoundLocals,
1190        alt_indices: &'data AltIndices,
1191        culling_mode: CullingMode,
1192    ) {
1193        let index_range = match culling_mode {
1194            CullingMode::Underground => 0..alt_indices.underground_end as u32,
1195            CullingMode::Surface => alt_indices.deep_end as u32..model.len() as u32,
1196            CullingMode::None => 0..model.len() as u32,
1197        };
1198
1199        // Don't render anything if there's nothing to render!
1200        if index_range.is_empty() {
1201            return;
1202        }
1203
1204        let submodel = model.submodel(index_range);
1205
1206        if self.atlas_textures
1207            // Check if we are still using the same atlas texture as the previous drawn
1208            // chunk
1209            .filter(|current_atlas_textures| Arc::ptr_eq(current_atlas_textures, atlas_textures))
1210            .is_none()
1211        {
1212            self.render_pass
1213                .set_bind_group(2, &atlas_textures.bind_group, &[]);
1214            self.atlas_textures = Some(atlas_textures);
1215        };
1216
1217        self.render_pass.set_bind_group(3, &locals.bind_group, &[]);
1218
1219        self.render_pass.set_vertex_buffer(0, submodel.buf());
1220        self.render_pass
1221            .draw_indexed(0..submodel.len() / 4 * 6, 0, 0..1);
1222    }
1223}
1224
1225#[must_use]
1226pub struct ParticleDrawer<'pass_ref, 'pass: 'pass_ref> {
1227    render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1228}
1229
1230impl<'pass_ref, 'pass: 'pass_ref> ParticleDrawer<'pass_ref, 'pass> {
1231    // Note: if we ever need to draw less than the whole model, these APIs can be
1232    // changed
1233    pub fn draw<'data: 'pass>(
1234        &mut self,
1235        model: &'data Model<particle::Vertex>,
1236        instances: &'data Instances<particle::Instance>,
1237    ) {
1238        if instances.count() != 0 {
1239            self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
1240            self.render_pass
1241                .set_vertex_buffer(1, instances.buf().slice(..));
1242            self.render_pass
1243            // TODO: since we cast to u32 maybe this should returned by the len/count functions?
1244            .draw_indexed(0..model.len() as u32 / 4 * 6, 0, 0..instances.count() as u32);
1245        }
1246    }
1247}
1248
1249#[must_use]
1250pub struct RopeDrawer<'pass_ref, 'pass: 'pass_ref> {
1251    render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1252}
1253
1254impl<'pass_ref, 'pass: 'pass_ref> RopeDrawer<'pass_ref, 'pass> {
1255    // Note: if we ever need to draw less than the whole model, these APIs can be
1256    // changed
1257    pub fn draw<'data: 'pass>(
1258        &mut self,
1259        model: &'data Model<rope::Vertex>,
1260        locals: &'data rope::BoundLocals,
1261    ) {
1262        self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
1263        self.render_pass.set_bind_group(2, &locals.bind_group, &[]);
1264        // TODO: since we cast to u32 maybe this should returned by the len/count
1265        // functions?
1266        self.render_pass
1267            .draw_indexed(0..model.len() as u32 / 4 * 6, 0, 0..1);
1268    }
1269}
1270
1271#[must_use]
1272pub struct SpriteDrawer<'pass_ref, 'pass: 'pass_ref> {
1273    render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1274    globals: &'pass GlobalsBindGroup,
1275}
1276
1277impl<'pass_ref, 'pass: 'pass_ref> SpriteDrawer<'pass_ref, 'pass> {
1278    pub fn draw<'data: 'pass, T>(
1279        &mut self,
1280        terrain_locals: &'data Bound<T>,
1281        instances: &'data Instances<sprite::Instance>,
1282        alt_indices: &'data AltIndices,
1283        culling_mode: CullingMode,
1284    ) {
1285        let instance_range = match culling_mode {
1286            CullingMode::Underground => 0..alt_indices.underground_end as u32,
1287            CullingMode::Surface => alt_indices.deep_end as u32..instances.count() as u32,
1288            CullingMode::None => 0..instances.count() as u32,
1289        };
1290
1291        // Don't render anything if there's nothing to render!
1292        if instance_range.is_empty() {
1293            return;
1294        }
1295
1296        self.render_pass
1297            .set_bind_group(3, &terrain_locals.bind_group, &[]);
1298
1299        let subinstances = instances.subinstances(instance_range);
1300
1301        self.render_pass.set_vertex_buffer(0, subinstances.buf());
1302        self.render_pass.draw_indexed(
1303            0..sprite::VERT_PAGE_SIZE / 4 * 6,
1304            0,
1305            0..subinstances.count(),
1306        );
1307    }
1308}
1309
1310impl<'pass_ref, 'pass: 'pass_ref> Drop for SpriteDrawer<'pass_ref, 'pass> {
1311    fn drop(&mut self) {
1312        // Reset to regular globals
1313        self.render_pass
1314            .set_bind_group(0, &self.globals.bind_group, &[]);
1315    }
1316}
1317
1318#[must_use]
1319pub struct LodObjectDrawer<'pass_ref, 'pass: 'pass_ref> {
1320    render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1321}
1322
1323impl<'pass_ref, 'pass: 'pass_ref> LodObjectDrawer<'pass_ref, 'pass> {
1324    pub fn draw<'data: 'pass>(
1325        &mut self,
1326        model: &'data Model<lod_object::Vertex>,
1327        instances: &'data Instances<lod_object::Instance>,
1328    ) {
1329        self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
1330        self.render_pass
1331            .set_vertex_buffer(1, instances.buf().slice(..));
1332        self.render_pass
1333            .draw(0..model.len() as u32, 0..instances.count() as u32);
1334    }
1335}
1336
1337#[must_use]
1338pub struct FluidDrawer<'pass_ref, 'pass: 'pass_ref> {
1339    render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1340}
1341
1342impl<'pass_ref, 'pass: 'pass_ref> FluidDrawer<'pass_ref, 'pass> {
1343    pub fn draw<'data: 'pass>(
1344        &mut self,
1345        model: &'data Model<fluid::Vertex>,
1346        locals: &'data terrain::BoundLocals,
1347    ) {
1348        self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
1349        self.render_pass.set_bind_group(2, &locals.bind_group, &[]);
1350        self.render_pass
1351            .draw_indexed(0..model.len() as u32 / 4 * 6, 0, 0..1);
1352    }
1353}
1354
1355// Second pass: volumetrics
1356#[must_use]
1357pub struct VolumetricPassDrawer<'pass> {
1358    render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
1359    borrow: &'pass RendererBorrow<'pass>,
1360    clouds_pipeline: &'pass clouds::CloudsPipeline,
1361}
1362
1363impl VolumetricPassDrawer<'_> {
1364    pub fn draw_clouds(&mut self) {
1365        self.render_pass
1366            .set_pipeline(&self.clouds_pipeline.pipeline);
1367        self.render_pass
1368            .set_bind_group(2, &self.borrow.locals.clouds_bind.bind_group, &[]);
1369        self.render_pass.draw(0..3, 0..1);
1370    }
1371}
1372
1373// Third pass: transparents
1374#[must_use]
1375pub struct TransparentPassDrawer<'pass> {
1376    render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
1377    borrow: &'pass RendererBorrow<'pass>,
1378    trail_pipeline: &'pass trail::TrailPipeline,
1379}
1380
1381impl<'pass> TransparentPassDrawer<'pass> {
1382    pub fn draw_trails(&mut self) -> Option<TrailDrawer<'_, 'pass>> {
1383        let shadow = &self.borrow.shadow?;
1384
1385        let mut render_pass = self.render_pass.scope("trails");
1386
1387        render_pass.set_pipeline(&self.trail_pipeline.pipeline);
1388        set_quad_index_buffer::<trail::Vertex>(&mut render_pass, self.borrow);
1389
1390        render_pass.set_bind_group(1, &shadow.bind.bind_group, &[]);
1391
1392        Some(TrailDrawer { render_pass })
1393    }
1394}
1395
1396#[must_use]
1397pub struct TrailDrawer<'pass_ref, 'pass: 'pass_ref> {
1398    render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1399}
1400
1401impl<'pass_ref, 'pass: 'pass_ref> TrailDrawer<'pass_ref, 'pass> {
1402    pub fn draw(&mut self, submodel: SubModel<'pass, trail::Vertex>) {
1403        self.render_pass.set_vertex_buffer(0, submodel.buf());
1404        self.render_pass
1405            .draw_indexed(0..submodel.len() / 4 * 6, 0, 0..1);
1406    }
1407}
1408
1409/// Third pass: postprocess + ui
1410#[must_use]
1411pub struct ThirdPassDrawer<'pass> {
1412    render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
1413    borrow: &'pass RendererBorrow<'pass>,
1414}
1415
1416impl<'pass> ThirdPassDrawer<'pass> {
1417    /// Does nothing if the postprocess pipeline is not available
1418    pub fn draw_postprocess(&mut self) {
1419        let postprocess = match self.borrow.pipelines.all() {
1420            Some(p) => &p.postprocess,
1421            None => return,
1422        };
1423
1424        let mut render_pass = self.render_pass.scope("postprocess");
1425        render_pass.set_pipeline(&postprocess.pipeline);
1426        render_pass.set_bind_group(1, &self.borrow.locals.postprocess_bind.bind_group, &[]);
1427        render_pass.draw(0..3, 0..1);
1428    }
1429
1430    /// Returns None if the UI pipeline is not available (note: this should
1431    /// never be the case for now)
1432    pub fn draw_ui(&mut self) -> Option<UiDrawer<'_, 'pass>> {
1433        let ui = self.borrow.pipelines.ui()?;
1434
1435        let mut render_pass = self.render_pass.scope("ui");
1436        render_pass.set_pipeline(&ui.pipeline);
1437        set_quad_index_buffer::<ui::Vertex>(&mut render_pass, self.borrow);
1438
1439        Some(UiDrawer { render_pass })
1440    }
1441}
1442
1443#[must_use]
1444pub struct UiDrawer<'pass_ref, 'pass: 'pass_ref> {
1445    render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1446}
1447
1448#[must_use]
1449pub struct PreparedUiDrawer<'pass_ref, 'pass: 'pass_ref> {
1450    render_pass: &'pass_ref mut wgpu::RenderPass<'pass>,
1451}
1452
1453impl<'pass_ref, 'pass: 'pass_ref> UiDrawer<'pass_ref, 'pass> {
1454    /// Set vertex buffer, initial scissor, and locals
1455    /// These can be changed later but this ensures that they don't have to be
1456    /// set with every draw call
1457    pub fn prepare<'data: 'pass>(
1458        &mut self,
1459        locals: &'data ui::BoundLocals,
1460        buf: &'data DynamicModel<ui::Vertex>,
1461        scissor: Aabr<u16>,
1462    ) -> PreparedUiDrawer<'_, 'pass> {
1463        // Note: not actually prepared yet
1464        // we do this to avoid having to write extra code for the set functions
1465        let mut prepared = PreparedUiDrawer {
1466            render_pass: &mut self.render_pass,
1467        };
1468        // Prepare
1469        prepared.set_locals(locals);
1470        prepared.set_model(buf);
1471        prepared.set_scissor(scissor);
1472
1473        prepared
1474    }
1475}
1476
1477impl<'pass_ref, 'pass: 'pass_ref> PreparedUiDrawer<'pass_ref, 'pass> {
1478    pub fn set_locals<'data: 'pass>(&mut self, locals: &'data ui::BoundLocals) {
1479        self.render_pass.set_bind_group(1, &locals.bind_group, &[]);
1480    }
1481
1482    pub fn set_model<'data: 'pass>(&mut self, model: &'data DynamicModel<ui::Vertex>) {
1483        self.render_pass.set_vertex_buffer(0, model.buf().slice(..))
1484    }
1485
1486    pub fn set_scissor(&mut self, scissor: Aabr<u16>) {
1487        let Aabr { min, max } = scissor;
1488        self.render_pass.set_scissor_rect(
1489            min.x as u32,
1490            min.y as u32,
1491            (max.x - min.x) as u32,
1492            (max.y - min.y) as u32,
1493        );
1494    }
1495
1496    pub fn draw<'data: 'pass>(&mut self, texture: &'data ui::TextureBindGroup, verts: Range<u32>) {
1497        self.render_pass.set_bind_group(2, &texture.bind_group, &[]);
1498        self.render_pass.draw(verts, 0..1);
1499    }
1500}
1501
1502fn set_quad_index_buffer<'a, V: super::Vertex>(
1503    pass: &mut wgpu::RenderPass<'a>,
1504    borrow: &RendererBorrow<'a>,
1505) {
1506    if let Some(format) = V::QUADS_INDEX {
1507        let slice = match format {
1508            wgpu::IndexFormat::Uint16 => borrow.quad_index_buffer_u16.buf.slice(..),
1509            wgpu::IndexFormat::Uint32 => borrow.quad_index_buffer_u32.buf.slice(..),
1510        };
1511
1512        pass.set_index_buffer(slice, format);
1513    }
1514}