Skip to main content

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 let RainOcclusionMap::Enabled(ref rain_occlusion_renderer) = self.borrow.shadow?.rain_map
242        {
243            let mut render_pass = self.encoder.scoped_render_pass(
244                "rain_occlusion_pass",
245                wgpu::RenderPassDescriptor {
246                    label: Some("rain occlusion pass"),
247                    color_attachments: &[],
248                    depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
249                        view: &rain_occlusion_renderer.depth.view,
250                        depth_ops: Some(wgpu::Operations {
251                            load: wgpu::LoadOp::Clear(1.0),
252                            store: wgpu::StoreOp::Store,
253                        }),
254                        stencil_ops: None,
255                    }),
256                    timestamp_writes: None,
257                    occlusion_query_set: None,
258                },
259            );
260
261            render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
262
263            Some(RainOcclusionPassDrawer {
264                render_pass,
265                borrow: &self.borrow,
266                rain_occlusion_renderer,
267            })
268        } else {
269            None
270        }
271    }
272
273    /// Returns None if the shadow renderer is not enabled at some level or the
274    /// pipelines are not available yet
275    pub fn shadow_pass(&mut self) -> Option<ShadowPassDrawer<'_>> {
276        if !self.borrow.pipeline_modes.shadow.is_map() {
277            return None;
278        }
279
280        if let ShadowMap::Enabled(ref shadow_renderer) = self.borrow.shadow?.map {
281            let mut render_pass =
282                self.encoder
283                    .scoped_render_pass("shadow_pass", wgpu::RenderPassDescriptor {
284                        label: Some("shadow pass"),
285                        color_attachments: &[],
286                        depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
287                            view: &shadow_renderer.directed_depth.view,
288                            depth_ops: Some(wgpu::Operations {
289                                load: wgpu::LoadOp::Clear(1.0),
290                                store: wgpu::StoreOp::Store,
291                            }),
292                            stencil_ops: None,
293                        }),
294                        timestamp_writes: None,
295                        occlusion_query_set: None,
296                    });
297
298            render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
299
300            Some(ShadowPassDrawer {
301                render_pass,
302                borrow: &self.borrow,
303                shadow_renderer,
304            })
305        } else {
306            None
307        }
308    }
309
310    /// Returns None if all the pipelines are not available
311    pub fn first_pass(&mut self) -> Option<FirstPassDrawer<'_>> {
312        let pipelines = self.borrow.pipelines.all()?;
313        // Note: this becomes Some once pipeline creation is complete even if shadows
314        // are not enabled
315        let shadow = self.borrow.shadow?;
316
317        let mut render_pass =
318            self.encoder
319                .scoped_render_pass("first_pass", wgpu::RenderPassDescriptor {
320                    label: Some("first pass"),
321                    color_attachments: &[
322                        Some(wgpu::RenderPassColorAttachment {
323                            view: &self.borrow.views.tgt_color,
324                            depth_slice: None,
325                            resolve_target: None,
326                            ops: wgpu::Operations {
327                                load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
328                                store: wgpu::StoreOp::Store,
329                            },
330                        }),
331                        Some(wgpu::RenderPassColorAttachment {
332                            view: &self.borrow.views.tgt_mat,
333                            depth_slice: None,
334                            resolve_target: None,
335                            ops: wgpu::Operations {
336                                load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
337                                store: wgpu::StoreOp::Store,
338                            },
339                        }),
340                    ],
341                    depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
342                        view: &self.borrow.views.tgt_depth,
343                        depth_ops: Some(wgpu::Operations {
344                            load: wgpu::LoadOp::Clear(0.0),
345                            store: wgpu::StoreOp::Store,
346                        }),
347                        stencil_ops: None,
348                    }),
349                    timestamp_writes: None,
350                    occlusion_query_set: None,
351                });
352
353        render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
354        render_pass.set_bind_group(1, &shadow.bind.bind_group, &[]);
355
356        Some(FirstPassDrawer {
357            render_pass,
358            borrow: &self.borrow,
359            pipelines,
360            globals: self.globals,
361        })
362    }
363
364    /// Returns None if the volumetrics pipeline is not available
365    pub fn volumetric_pass(&mut self) -> Option<VolumetricPassDrawer<'_>> {
366        let pipelines = &self.borrow.pipelines.all()?;
367        let shadow = self.borrow.shadow?;
368
369        let mut render_pass =
370            self.encoder
371                .scoped_render_pass("volumetric_pass", wgpu::RenderPassDescriptor {
372                    label: Some("volumetric pass (clouds)"),
373                    color_attachments: &[Some(wgpu::RenderPassColorAttachment {
374                        view: &self.borrow.views.tgt_color_pp,
375                        depth_slice: None,
376                        resolve_target: None,
377                        ops: wgpu::Operations {
378                            load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
379                            store: wgpu::StoreOp::Store,
380                        },
381                    })],
382                    depth_stencil_attachment: None,
383                    timestamp_writes: None,
384                    occlusion_query_set: None,
385                });
386
387        render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
388        render_pass.set_bind_group(1, &shadow.bind.bind_group, &[]);
389
390        Some(VolumetricPassDrawer {
391            render_pass,
392            borrow: &self.borrow,
393            clouds_pipeline: &pipelines.clouds,
394        })
395    }
396
397    /// Returns None if the trail pipeline is not available
398    pub fn transparent_pass(&mut self) -> Option<TransparentPassDrawer<'_>> {
399        let pipelines = &self.borrow.pipelines.all()?;
400        let shadow = self.borrow.shadow?;
401
402        let mut render_pass =
403            self.encoder
404                .scoped_render_pass("transparent_pass", wgpu::RenderPassDescriptor {
405                    label: Some("transparent pass (trails)"),
406                    color_attachments: &[Some(wgpu::RenderPassColorAttachment {
407                        view: &self.borrow.views.tgt_color_pp,
408                        depth_slice: None,
409                        resolve_target: None,
410                        ops: wgpu::Operations {
411                            load: wgpu::LoadOp::Load,
412                            store: wgpu::StoreOp::Store,
413                        },
414                    })],
415                    depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
416                        view: &self.borrow.views.tgt_depth,
417                        depth_ops: Some(wgpu::Operations {
418                            load: wgpu::LoadOp::Load,
419                            store: wgpu::StoreOp::Store,
420                        }),
421                        stencil_ops: None,
422                    }),
423                    timestamp_writes: None,
424                    occlusion_query_set: None,
425                });
426
427        render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
428        render_pass.set_bind_group(1, &shadow.bind.bind_group, &[]);
429
430        Some(TransparentPassDrawer {
431            render_pass,
432            borrow: &self.borrow,
433            trail_pipeline: &pipelines.trail,
434        })
435    }
436
437    /// To be ran between the second pass and the third pass
438    /// does nothing if the ingame pipelines are not yet ready
439    /// does nothing if bloom is disabled
440    pub fn run_bloom_passes(&mut self) {
441        let locals = &self.borrow.locals;
442        let views = &self.borrow.views;
443
444        let bloom_pipelines = match self.borrow.pipelines.all() {
445            Some(super::Pipelines { bloom: Some(p), .. }) => p,
446            _ => return,
447        };
448
449        // TODO: consider consolidating optional bloom bind groups and optional pipeline
450        // into a single structure?
451        let (bloom_tgts, bloom_binds) =
452            match views.bloom_tgts.as_ref().zip(locals.bloom_binds.as_ref()) {
453                Some((t, b)) => (t, b),
454                None => return,
455            };
456
457        let mut encoder = self.encoder.scope("bloom");
458
459        let mut run_bloom_pass = |bind, view, label: String, pipeline, load| {
460            let pass_label = format!("bloom {} pass", label);
461            let mut render_pass = encoder.scoped_render_pass(&label, wgpu::RenderPassDescriptor {
462                label: Some(&pass_label),
463                color_attachments: &[Some(wgpu::RenderPassColorAttachment {
464                    depth_slice: None,
465                    resolve_target: None,
466                    view,
467                    ops: wgpu::Operations {
468                        store: wgpu::StoreOp::Store,
469                        load,
470                    },
471                })],
472                depth_stencil_attachment: None,
473                timestamp_writes: None,
474                occlusion_query_set: None,
475            });
476
477            render_pass.set_bind_group(0, bind, &[]);
478            render_pass.set_pipeline(pipeline);
479            render_pass.draw(0..3, 0..1);
480        };
481
482        // Downsample filter passes
483        (0..bloom::NUM_SIZES - 1).for_each(|index| {
484            let bind = &bloom_binds[index].bind_group;
485            let view = &bloom_tgts[index + 1];
486            // Do filtering during the first downsample
487            // NOTE: We currently blur all things without filtering by brightness.
488            // This is left in for those that might want to experminent with filtering by
489            // brightness, and it is used to filter out NaNs/Infs that would infect all the
490            // pixels they are blurred with.
491            let (label, pipeline) = if index == 0 {
492                (
493                    format!("downsample filtered {}", index + 1),
494                    &bloom_pipelines.downsample_filtered,
495                )
496            } else {
497                (
498                    format!("downsample {}", index + 1),
499                    &bloom_pipelines.downsample,
500                )
501            };
502            run_bloom_pass(
503                bind,
504                view,
505                label,
506                pipeline,
507                wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
508            );
509        });
510
511        // Upsample filter passes
512        (0..bloom::NUM_SIZES - 1).for_each(|index| {
513            let bind = &bloom_binds[bloom::NUM_SIZES - 1 - index].bind_group;
514            let view = &bloom_tgts[bloom::NUM_SIZES - 2 - index];
515            let label = format!("upsample {}", index + 1);
516            run_bloom_pass(
517                bind,
518                view,
519                label,
520                &bloom_pipelines.upsample,
521                if index + 2 == bloom::NUM_SIZES {
522                    // Clear for the final image since that is just stuff from the previous frame.
523                    wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT)
524                } else {
525                    // Add to less blurred images to get gradient of blur instead of a smudge>
526                    // https://catlikecoding.com/unity/tutorials/advanced-rendering/bloom/
527                    wgpu::LoadOp::Load
528                },
529            );
530        });
531    }
532
533    /// Runs render passes with alpha premultiplication pipeline to complete any
534    /// pending uploads.
535    fn run_ui_premultiply_passes(&mut self) {
536        prof_span!("run_ui_premultiply_passes");
537        let Some(premultiply_alpha) = self.borrow.pipelines.premultiply_alpha() else {
538            return;
539        };
540
541        let targets = self.borrow.ui_premultiply_uploads.take();
542
543        for (i, (target_texture, uploads)) in targets.into_iter().enumerate() {
544            prof_span!("ui premultiply pass");
545            let profile_name = format!("{UI_PREMULTIPLY_PASS} {i}");
546            let label = format!("ui premultiply pass {i}");
547            let mut render_pass =
548                self.encoder
549                    .scoped_render_pass(&profile_name, wgpu::RenderPassDescriptor {
550                        label: Some(&label),
551                        color_attachments: &[Some(wgpu::RenderPassColorAttachment {
552                            view: &target_texture.view,
553                            depth_slice: None,
554                            resolve_target: None,
555                            ops: wgpu::Operations {
556                                load: wgpu::LoadOp::Load,
557                                store: wgpu::StoreOp::Store,
558                            },
559                        })],
560                        depth_stencil_attachment: None,
561                        timestamp_writes: None,
562                        occlusion_query_set: None,
563                    });
564            render_pass.set_pipeline(&premultiply_alpha.pipeline);
565            for upload in &uploads {
566                let (source_bind_group, push_constant_data) = upload.draw_data(&target_texture);
567                let bytes = bytemuck::bytes_of(&push_constant_data);
568                render_pass.set_bind_group(0, source_bind_group, &[]);
569                render_pass.set_push_constants(wgpu::ShaderStages::VERTEX, 0, bytes);
570                render_pass.draw(0..6, 0..1);
571            }
572        }
573    }
574
575    /// Prepares the third pass drawer to be used.
576    ///
577    /// Note, this automatically calls the internal `run_ui_premultiply_passes`
578    /// to complete any pending image uploads for the UI.
579    pub fn third_pass(&mut self) -> ThirdPassDrawer<'_> {
580        self.run_ui_premultiply_passes();
581
582        let mut render_pass =
583            self.encoder
584                .scoped_render_pass("third_pass", wgpu::RenderPassDescriptor {
585                    label: Some("third pass (postprocess + ui)"),
586                    color_attachments: &[Some(wgpu::RenderPassColorAttachment {
587                        // If a screenshot was requested render to that as an intermediate texture
588                        // instead
589                        view: self
590                            .taking_screenshot
591                            .as_ref()
592                            .map_or(&self.surface_view, |s| s.texture_view()),
593                        depth_slice: None,
594                        resolve_target: None,
595                        ops: wgpu::Operations {
596                            load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
597                            store: wgpu::StoreOp::Store,
598                        },
599                    })],
600                    depth_stencil_attachment: None,
601                    timestamp_writes: None,
602                    occlusion_query_set: None,
603                });
604
605        render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
606
607        ThirdPassDrawer {
608            render_pass,
609            borrow: &self.borrow,
610        }
611    }
612
613    #[cfg(feature = "egui-ui")]
614    pub fn draw_egui(
615        &mut self,
616        state: &mut egui_winit::State,
617        scale_factor: f32,
618    ) -> egui::PlatformOutput {
619        span!(guard, "Draw egui");
620
621        let output = state.egui_ctx().end_pass();
622
623        let paint_jobs = state.egui_ctx().tessellate(output.shapes, scale_factor);
624
625        let screen_descriptor = ScreenDescriptor {
626            size_in_pixels: [
627                self.borrow.surface_config.width,
628                self.borrow.surface_config.height,
629            ],
630            pixels_per_point: scale_factor,
631        };
632
633        for (id, delta) in output.textures_delta.set.iter() {
634            self.borrow.egui_renderer.update_texture(
635                self.borrow.device,
636                self.borrow.queue,
637                *id,
638                delta,
639            );
640        }
641
642        // PaintCallback is not used to my knowledge so this should always be empty
643        // Couldn't figure out a nice way to get it into Drawer's Drop impl, anyway
644        let _ = self.borrow.egui_renderer.update_buffers(
645            self.borrow.device,
646            self.borrow.queue,
647            self.encoder.encoder(),
648            &paint_jobs,
649            &screen_descriptor,
650        );
651
652        let mut render_pass = self
653            .encoder
654            .encoder()
655            .begin_render_pass(&wgpu::RenderPassDescriptor {
656                label: Some("egui pass"),
657                color_attachments: &[Some(wgpu::RenderPassColorAttachment {
658                    view: self
659                        .taking_screenshot
660                        .as_ref()
661                        .map_or(&self.surface_view, |s| s.texture_view()),
662                    depth_slice: None,
663                    resolve_target: None,
664                    ops: wgpu::Operations {
665                        load: wgpu::LoadOp::Load,
666                        store: wgpu::StoreOp::Store,
667                    },
668                })],
669                depth_stencil_attachment: None,
670                timestamp_writes: None,
671                occlusion_query_set: None,
672            })
673            .forget_lifetime();
674
675        self.borrow
676            .egui_renderer
677            .render(&mut render_pass, &paint_jobs, &screen_descriptor);
678
679        for id in output.textures_delta.free.iter() {
680            self.borrow.egui_renderer.free_texture(id);
681        }
682
683        drop(guard);
684        output.platform_output
685    }
686
687    /// Does nothing if the shadow pipelines are not available or shadow map
688    /// rendering is disabled
689    pub fn draw_point_shadows<'data>(
690        &mut self,
691        matrices: &[shadow::PointLightMatrix; 126],
692        chunks: impl Clone
693        + Iterator<Item = (&'data Model<terrain::Vertex>, &'data terrain::BoundLocals)>,
694    ) {
695        if !self.borrow.pipeline_modes.shadow.is_map() {
696            return;
697        }
698
699        if let Some(ShadowMap::Enabled(shadow_renderer)) = self.borrow.shadow.map(|s| &s.map) {
700            let mut encoder = self.encoder.scope("point shadows");
701            const STRIDE: usize = std::mem::size_of::<shadow::PointLightMatrix>();
702            let data = bytemuck::cast_slice(matrices);
703
704            for face in 0..6 {
705                // TODO: view creation cost?
706                let view =
707                    shadow_renderer
708                        .point_depth
709                        .tex
710                        .create_view(&wgpu::TextureViewDescriptor {
711                            label: Some("Point shadow cubemap face"),
712                            format: None,
713                            dimension: Some(wgpu::TextureViewDimension::D2),
714                            usage: None,
715                            aspect: wgpu::TextureAspect::DepthOnly,
716                            base_mip_level: 0,
717                            mip_level_count: None,
718                            base_array_layer: face,
719                            array_layer_count: Some(1),
720                        });
721
722                let label = format!("point shadow face-{} pass", face);
723                let mut render_pass =
724                    encoder.scoped_render_pass(&label, wgpu::RenderPassDescriptor {
725                        label: Some(&label),
726                        color_attachments: &[],
727                        depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
728                            view: &view,
729                            depth_ops: Some(wgpu::Operations {
730                                load: wgpu::LoadOp::Clear(1.0),
731                                store: wgpu::StoreOp::Store,
732                            }),
733                            stencil_ops: None,
734                        }),
735                        timestamp_writes: None,
736                        occlusion_query_set: None,
737                    });
738
739                render_pass.set_pipeline(&shadow_renderer.point_pipeline.pipeline);
740                set_quad_index_buffer::<terrain::Vertex>(&mut render_pass, &self.borrow);
741                render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
742
743                (0../*20*/1).for_each(|point_light| {
744                    render_pass.set_push_constants(
745                        wgpu::ShaderStages::VERTEX_FRAGMENT,
746                        0,
747                        &data[(6 * (point_light + 1) * STRIDE + face as usize * STRIDE)
748                            ..(6 * (point_light + 1) * STRIDE + (face + 1) as usize * STRIDE)],
749                    );
750                    chunks.clone().for_each(|(model, locals)| {
751                        render_pass.set_bind_group(1, &locals.bind_group, &[]);
752                        render_pass.set_vertex_buffer(0, model.buf().slice(..));
753                        render_pass.draw_indexed(0..model.len() as u32 / 4 * 6, 0, 0..1);
754                    });
755                });
756            }
757        }
758    }
759
760    /// Clear all the shadow textures, useful if directed shadows (shadow_pass)
761    /// and point light shadows (draw_point_shadows) are unused and thus the
762    /// textures will otherwise not be cleared after either their
763    /// initialization or their last use
764    /// NOTE: could simply use the above passes except `draw_point_shadows`
765    /// requires an array of matrices that could be a pain to construct
766    /// simply for clearing
767    ///
768    /// Does nothing if the shadow pipelines are not available (although they
769    /// aren't used here they are needed for the ShadowMap to exist)
770    pub fn clear_shadows(&mut self) {
771        if let Some(ShadowMap::Enabled(shadow_renderer)) = self.borrow.shadow.map(|s| &s.map) {
772            let _ = self.encoder.scoped_render_pass(
773                "clear_directed_shadow",
774                wgpu::RenderPassDescriptor {
775                    label: Some("clear directed shadow pass"),
776                    color_attachments: &[],
777                    depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
778                        view: &shadow_renderer.directed_depth.view,
779                        depth_ops: Some(wgpu::Operations {
780                            load: wgpu::LoadOp::Clear(1.0),
781                            store: wgpu::StoreOp::Store,
782                        }),
783                        stencil_ops: None,
784                    }),
785                    timestamp_writes: None,
786                    occlusion_query_set: None,
787                },
788            );
789
790            for face in 0..6 {
791                // TODO: view creation cost?
792                let view =
793                    shadow_renderer
794                        .point_depth
795                        .tex
796                        .create_view(&wgpu::TextureViewDescriptor {
797                            label: Some("Point shadow cubemap face"),
798                            format: None,
799                            dimension: Some(wgpu::TextureViewDimension::D2),
800                            usage: None,
801                            aspect: wgpu::TextureAspect::DepthOnly,
802                            base_mip_level: 0,
803                            mip_level_count: None,
804                            base_array_layer: face,
805                            array_layer_count: Some(1),
806                        });
807
808                let label = format!("clear point shadow face-{} pass", face);
809                let _ = self
810                    .encoder
811                    .scoped_render_pass(&label, wgpu::RenderPassDescriptor {
812                        label: Some(&label),
813                        color_attachments: &[],
814                        depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
815                            view: &view,
816                            depth_ops: Some(wgpu::Operations {
817                                load: wgpu::LoadOp::Clear(1.0),
818                                store: wgpu::StoreOp::Store,
819                            }),
820                            stencil_ops: None,
821                        }),
822                        timestamp_writes: None,
823                        occlusion_query_set: None,
824                    });
825            }
826        }
827    }
828}
829
830impl Drop for Drawer<'_> {
831    fn drop(&mut self) {
832        // If taking a screenshot and the blit pipeline is available
833        // NOTE: blit pipeline should always be available for now so we don't report an
834        // error if it isn't
835        let download_and_handle_screenshot = self
836            .taking_screenshot
837            .take()
838            .zip(self.borrow.pipelines.blit())
839            .map(|(screenshot, blit)| {
840                // Image needs to be copied from the screenshot texture to the swapchain texture
841                let mut render_pass = self.encoder.scoped_render_pass(
842                    "screenshot blit",
843                    wgpu::RenderPassDescriptor {
844                        label: Some("Blit screenshot pass"),
845                        color_attachments: &[Some(wgpu::RenderPassColorAttachment {
846                            view: &self.surface_view,
847                            depth_slice: None,
848                            resolve_target: None,
849                            ops: wgpu::Operations {
850                                load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
851                                store: wgpu::StoreOp::Store,
852                            },
853                        })],
854                        depth_stencil_attachment: None,
855                        timestamp_writes: None,
856                        occlusion_query_set: None,
857                    },
858                );
859                render_pass.set_pipeline(&blit.pipeline);
860                render_pass.set_bind_group(0, screenshot.bind_group(), &[]);
861                render_pass.draw(0..3, 0..1);
862                drop(render_pass);
863                // Issues a command to copy from the texture to a buffer and returns a closure
864                // that will send the buffer off to another thread to be mapped
865                // and processed.
866                screenshot.copy_to_buffer(self.encoder.encoder())
867            });
868
869        let (profiler, mut encoder) = self.encoder.end_query();
870        profiler.resolve_queries(&mut encoder);
871
872        // It is recommended to only do one submit per frame
873        self.borrow.queue.submit(std::iter::once(encoder.finish()));
874        // Need to call this after submit so the async mapping doesn't occur before
875        // copying the screenshot to the buffer which will be mapped.
876        if let Some(f) = download_and_handle_screenshot {
877            f();
878        }
879        self.surface_texture.take().unwrap().present();
880
881        profiler
882            .end_frame()
883            .expect("Gpu profiler error! Maybe there was an unclosed scope?");
884    }
885}
886
887// Shadow pass
888#[must_use]
889pub struct ShadowPassDrawer<'pass> {
890    render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
891    borrow: &'pass RendererBorrow<'pass>,
892    shadow_renderer: &'pass ShadowMapRenderer,
893}
894
895impl<'pass> ShadowPassDrawer<'pass> {
896    pub fn draw_figure_shadows(&mut self) -> FigureShadowDrawer<'_, 'pass> {
897        let mut render_pass = self.render_pass.scope("directed_figure_shadows");
898
899        render_pass.set_pipeline(&self.shadow_renderer.figure_directed_pipeline.pipeline);
900        set_quad_index_buffer::<terrain::Vertex>(&mut render_pass, self.borrow);
901
902        FigureShadowDrawer { render_pass }
903    }
904
905    pub fn draw_terrain_shadows(&mut self) -> TerrainShadowDrawer<'_, 'pass> {
906        let mut render_pass = self.render_pass.scope("directed_terrain_shadows");
907
908        render_pass.set_pipeline(&self.shadow_renderer.terrain_directed_pipeline.pipeline);
909        set_quad_index_buffer::<terrain::Vertex>(&mut render_pass, self.borrow);
910
911        TerrainShadowDrawer { render_pass }
912    }
913
914    pub fn draw_debug_shadows(&mut self) -> DebugShadowDrawer<'_, 'pass> {
915        let mut render_pass = self.render_pass.scope("directed_debug_shadows");
916
917        render_pass.set_pipeline(&self.shadow_renderer.debug_directed_pipeline.pipeline);
918        set_quad_index_buffer::<debug::Vertex>(&mut render_pass, self.borrow);
919
920        DebugShadowDrawer { render_pass }
921    }
922}
923
924#[must_use]
925pub struct RainOcclusionPassDrawer<'pass> {
926    render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
927    borrow: &'pass RendererBorrow<'pass>,
928    rain_occlusion_renderer: &'pass RainOcclusionMapRenderer,
929}
930
931impl<'pass> RainOcclusionPassDrawer<'pass> {
932    pub fn draw_figure_shadows(&mut self) -> FigureShadowDrawer<'_, 'pass> {
933        let mut render_pass = self.render_pass.scope("directed_figure_rain_occlusion");
934
935        render_pass.set_pipeline(&self.rain_occlusion_renderer.figure_pipeline.pipeline);
936        set_quad_index_buffer::<terrain::Vertex>(&mut render_pass, self.borrow);
937
938        FigureShadowDrawer { render_pass }
939    }
940
941    pub fn draw_terrain_shadows(&mut self) -> TerrainShadowDrawer<'_, 'pass> {
942        let mut render_pass = self.render_pass.scope("directed_terrain_rain_occlusion");
943
944        render_pass.set_pipeline(&self.rain_occlusion_renderer.terrain_pipeline.pipeline);
945        set_quad_index_buffer::<terrain::Vertex>(&mut render_pass, self.borrow);
946
947        TerrainShadowDrawer { render_pass }
948    }
949}
950
951#[must_use]
952pub struct FigureShadowDrawer<'pass_ref, 'pass: 'pass_ref> {
953    render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
954}
955
956impl<'pass_ref, 'pass: 'pass_ref> FigureShadowDrawer<'pass_ref, 'pass> {
957    pub fn draw<'data: 'pass>(
958        &mut self,
959        model: SubModel<'data, terrain::Vertex>,
960        locals: &'data figure::BoundLocals,
961    ) {
962        self.render_pass.set_bind_group(1, &locals.bind_group, &[]);
963        self.render_pass.set_vertex_buffer(0, model.buf());
964        self.render_pass
965            .draw_indexed(0..model.len() / 4 * 6, 0, 0..1);
966    }
967}
968
969#[must_use]
970pub struct TerrainShadowDrawer<'pass_ref, 'pass: 'pass_ref> {
971    render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
972}
973
974impl<'pass_ref, 'pass: 'pass_ref> TerrainShadowDrawer<'pass_ref, 'pass> {
975    pub fn draw<'data: 'pass>(
976        &mut self,
977        model: &'data Model<terrain::Vertex>,
978        locals: &'data terrain::BoundLocals,
979        alt_indices: &'data AltIndices,
980        culling_mode: CullingMode,
981    ) {
982        let index_range = match culling_mode {
983            // Don't bother rendering shadows when underground
984            // TODO: Does this break point shadows in certain cases?
985            CullingMode::Underground => return, //0..alt_indices.underground_end as u32,
986            CullingMode::Surface => alt_indices.deep_end as u32..model.len() as u32,
987            CullingMode::None => 0..model.len() as u32,
988        };
989
990        // Don't render anything if there's nothing to render!
991        if index_range.is_empty() {
992            return;
993        }
994
995        let submodel = model.submodel(index_range);
996
997        self.render_pass.set_bind_group(1, &locals.bind_group, &[]);
998        self.render_pass.set_vertex_buffer(0, submodel.buf());
999        self.render_pass
1000            .draw_indexed(0..submodel.len() / 4 * 6, 0, 0..1);
1001    }
1002}
1003
1004#[must_use]
1005pub struct DebugShadowDrawer<'pass_ref, 'pass: 'pass_ref> {
1006    render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1007}
1008
1009impl<'pass_ref, 'pass: 'pass_ref> DebugShadowDrawer<'pass_ref, 'pass> {
1010    pub fn draw<'data: 'pass>(
1011        &mut self,
1012        model: &'data Model<debug::Vertex>,
1013        locals: &'data debug::BoundLocals,
1014    ) {
1015        self.render_pass.set_bind_group(1, &locals.bind_group, &[]);
1016        self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
1017        self.render_pass.draw(0..model.len() as u32, 0..1);
1018    }
1019}
1020
1021// First pass
1022#[must_use]
1023pub struct FirstPassDrawer<'pass> {
1024    pub(super) render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
1025    borrow: &'pass RendererBorrow<'pass>,
1026    pipelines: &'pass super::Pipelines,
1027    globals: &'pass GlobalsBindGroup,
1028}
1029
1030impl<'pass> FirstPassDrawer<'pass> {
1031    pub fn draw_skybox<'data: 'pass>(&mut self, model: &'data Model<skybox::Vertex>) {
1032        let mut render_pass = self.render_pass.scope("skybox");
1033
1034        render_pass.set_pipeline(&self.pipelines.skybox.pipeline);
1035        set_quad_index_buffer::<skybox::Vertex>(&mut render_pass, self.borrow);
1036        render_pass.set_vertex_buffer(0, model.buf().slice(..));
1037        render_pass.draw(0..model.len() as u32, 0..1);
1038    }
1039
1040    pub fn draw_debug(&mut self) -> DebugDrawer<'_, 'pass> {
1041        let mut render_pass = self.render_pass.scope("debug");
1042
1043        render_pass.set_pipeline(&self.pipelines.debug.pipeline);
1044        set_quad_index_buffer::<debug::Vertex>(&mut render_pass, self.borrow);
1045
1046        DebugDrawer { render_pass }
1047    }
1048
1049    pub fn draw_lod_terrain<'data: 'pass>(&mut self, model: &'data Model<lod_terrain::Vertex>) {
1050        let mut render_pass = self.render_pass.scope("lod_terrain");
1051
1052        render_pass.set_pipeline(&self.pipelines.lod_terrain.pipeline);
1053        set_quad_index_buffer::<lod_terrain::Vertex>(&mut render_pass, self.borrow);
1054        render_pass.set_vertex_buffer(0, model.buf().slice(..));
1055        render_pass.draw_indexed(0..model.len() as u32 / 4 * 6, 0, 0..1);
1056    }
1057
1058    pub fn draw_figures(&mut self) -> FigureDrawer<'_, 'pass> {
1059        let mut render_pass = self.render_pass.scope("figures");
1060
1061        render_pass.set_pipeline(&self.pipelines.figure.pipeline);
1062        // Note: figures use the same vertex type as the terrain
1063        set_quad_index_buffer::<terrain::Vertex>(&mut render_pass, self.borrow);
1064
1065        FigureDrawer { render_pass }
1066    }
1067
1068    pub fn draw_terrain(&mut self) -> TerrainDrawer<'_, 'pass> {
1069        let mut render_pass = self.render_pass.scope("terrain");
1070
1071        render_pass.set_pipeline(&self.pipelines.terrain.pipeline);
1072        set_quad_index_buffer::<terrain::Vertex>(&mut render_pass, self.borrow);
1073
1074        TerrainDrawer {
1075            render_pass,
1076            atlas_textures: None,
1077        }
1078    }
1079
1080    pub fn draw_particles(&mut self) -> ParticleDrawer<'_, 'pass> {
1081        let mut render_pass = self.render_pass.scope("particles");
1082
1083        render_pass.set_pipeline(&self.pipelines.particle.pipeline);
1084        set_quad_index_buffer::<particle::Vertex>(&mut render_pass, self.borrow);
1085
1086        ParticleDrawer { render_pass }
1087    }
1088
1089    pub fn draw_ropes(&mut self) -> RopeDrawer<'_, 'pass> {
1090        let mut render_pass = self.render_pass.scope("ropes");
1091
1092        render_pass.set_pipeline(&self.pipelines.rope.pipeline);
1093        set_quad_index_buffer::<rope::Vertex>(&mut render_pass, self.borrow);
1094
1095        RopeDrawer { render_pass }
1096    }
1097
1098    pub fn draw_sprites<'data: 'pass>(
1099        &mut self,
1100        globals: &'data sprite::SpriteGlobalsBindGroup,
1101        atlas_textures: &'data AtlasTextures<sprite::Locals, FigureSpriteAtlasData>,
1102    ) -> SpriteDrawer<'_, 'pass> {
1103        let mut render_pass = self.render_pass.scope("sprites");
1104
1105        render_pass.set_pipeline(&self.pipelines.sprite.pipeline);
1106        set_quad_index_buffer::<sprite::Vertex>(&mut render_pass, self.borrow);
1107        render_pass.set_bind_group(0, &globals.bind_group, &[]);
1108        render_pass.set_bind_group(2, &atlas_textures.bind_group, &[]);
1109
1110        SpriteDrawer {
1111            render_pass,
1112            globals: self.globals,
1113        }
1114    }
1115
1116    pub fn draw_lod_objects(&mut self) -> LodObjectDrawer<'_, 'pass> {
1117        let mut render_pass = self.render_pass.scope("lod objects");
1118
1119        render_pass.set_pipeline(&self.pipelines.lod_object.pipeline);
1120        set_quad_index_buffer::<lod_object::Vertex>(&mut render_pass, self.borrow);
1121
1122        LodObjectDrawer { render_pass }
1123    }
1124
1125    pub fn draw_fluid(&mut self) -> FluidDrawer<'_, 'pass> {
1126        let mut render_pass = self.render_pass.scope("fluid");
1127
1128        render_pass.set_pipeline(&self.pipelines.fluid.pipeline);
1129        set_quad_index_buffer::<fluid::Vertex>(&mut render_pass, self.borrow);
1130
1131        FluidDrawer { render_pass }
1132    }
1133}
1134
1135#[must_use]
1136pub struct DebugDrawer<'pass_ref, 'pass: 'pass_ref> {
1137    render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1138}
1139
1140impl<'pass_ref, 'pass: 'pass_ref> DebugDrawer<'pass_ref, 'pass> {
1141    pub fn draw<'data: 'pass>(
1142        &mut self,
1143        model: &'data Model<debug::Vertex>,
1144        locals: &'data debug::BoundLocals,
1145    ) {
1146        self.render_pass.set_bind_group(2, &locals.bind_group, &[]);
1147        self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
1148        self.render_pass.draw(0..model.len() as u32, 0..1);
1149    }
1150}
1151
1152#[must_use]
1153pub struct FigureDrawer<'pass_ref, 'pass: 'pass_ref> {
1154    render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1155}
1156
1157impl<'pass_ref, 'pass: 'pass_ref> FigureDrawer<'pass_ref, 'pass> {
1158    pub fn draw<'data: 'pass>(
1159        &mut self,
1160        model: SubModel<'data, terrain::Vertex>,
1161        locals: &'data figure::BoundLocals,
1162        // TODO: don't rebind this every time once they are shared between figures
1163        atlas_textures: &'data AtlasTextures<figure::Locals, FigureSpriteAtlasData>,
1164    ) {
1165        self.render_pass
1166            .set_bind_group(2, &atlas_textures.bind_group, &[]);
1167        self.render_pass.set_bind_group(3, &locals.bind_group, &[]);
1168        self.render_pass.set_vertex_buffer(0, model.buf());
1169        self.render_pass
1170            .draw_indexed(0..model.len() / 4 * 6, 0, 0..1);
1171    }
1172}
1173
1174#[must_use]
1175pub struct TerrainDrawer<'pass_ref, 'pass: 'pass_ref> {
1176    render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1177    atlas_textures: Option<&'pass_ref Arc<AtlasTextures<terrain::Locals, TerrainAtlasData>>>,
1178}
1179
1180impl<'pass_ref, 'pass: 'pass_ref> TerrainDrawer<'pass_ref, 'pass> {
1181    pub fn draw<'data: 'pass>(
1182        &mut self,
1183        model: &'data Model<terrain::Vertex>,
1184        atlas_textures: &'data Arc<AtlasTextures<terrain::Locals, TerrainAtlasData>>,
1185        locals: &'data terrain::BoundLocals,
1186        alt_indices: &'data AltIndices,
1187        culling_mode: CullingMode,
1188    ) {
1189        let index_range = match culling_mode {
1190            CullingMode::Underground => 0..alt_indices.underground_end as u32,
1191            CullingMode::Surface => alt_indices.deep_end as u32..model.len() as u32,
1192            CullingMode::None => 0..model.len() as u32,
1193        };
1194
1195        // Don't render anything if there's nothing to render!
1196        if index_range.is_empty() {
1197            return;
1198        }
1199
1200        let submodel = model.submodel(index_range);
1201
1202        if self.atlas_textures
1203            // Check if we are still using the same atlas texture as the previous drawn
1204            // chunk
1205            .filter(|current_atlas_textures| Arc::ptr_eq(current_atlas_textures, atlas_textures))
1206            .is_none()
1207        {
1208            self.render_pass
1209                .set_bind_group(2, &atlas_textures.bind_group, &[]);
1210            self.atlas_textures = Some(atlas_textures);
1211        };
1212
1213        self.render_pass.set_bind_group(3, &locals.bind_group, &[]);
1214
1215        self.render_pass.set_vertex_buffer(0, submodel.buf());
1216        self.render_pass
1217            .draw_indexed(0..submodel.len() / 4 * 6, 0, 0..1);
1218    }
1219}
1220
1221#[must_use]
1222pub struct ParticleDrawer<'pass_ref, 'pass: 'pass_ref> {
1223    render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1224}
1225
1226impl<'pass_ref, 'pass: 'pass_ref> ParticleDrawer<'pass_ref, 'pass> {
1227    // Note: if we ever need to draw less than the whole model, these APIs can be
1228    // changed
1229    pub fn draw<'data: 'pass>(
1230        &mut self,
1231        model: &'data Model<particle::Vertex>,
1232        instances: &'data Instances<particle::Instance>,
1233    ) {
1234        if instances.count() != 0 {
1235            self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
1236            self.render_pass
1237                .set_vertex_buffer(1, instances.buf().slice(..));
1238            self.render_pass
1239            // TODO: since we cast to u32 maybe this should returned by the len/count functions?
1240            .draw_indexed(0..model.len() as u32 / 4 * 6, 0, 0..instances.count() as u32);
1241        }
1242    }
1243}
1244
1245#[must_use]
1246pub struct RopeDrawer<'pass_ref, 'pass: 'pass_ref> {
1247    render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1248}
1249
1250impl<'pass_ref, 'pass: 'pass_ref> RopeDrawer<'pass_ref, 'pass> {
1251    // Note: if we ever need to draw less than the whole model, these APIs can be
1252    // changed
1253    pub fn draw<'data: 'pass>(
1254        &mut self,
1255        model: &'data Model<rope::Vertex>,
1256        locals: &'data rope::BoundLocals,
1257    ) {
1258        self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
1259        self.render_pass.set_bind_group(2, &locals.bind_group, &[]);
1260        // TODO: since we cast to u32 maybe this should returned by the len/count
1261        // functions?
1262        self.render_pass
1263            .draw_indexed(0..model.len() as u32 / 4 * 6, 0, 0..1);
1264    }
1265}
1266
1267#[must_use]
1268pub struct SpriteDrawer<'pass_ref, 'pass: 'pass_ref> {
1269    render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1270    globals: &'pass GlobalsBindGroup,
1271}
1272
1273impl<'pass_ref, 'pass: 'pass_ref> SpriteDrawer<'pass_ref, 'pass> {
1274    pub fn draw<'data: 'pass, T>(
1275        &mut self,
1276        terrain_locals: &'data Bound<T>,
1277        instances: &'data Instances<sprite::Instance>,
1278        alt_indices: &'data AltIndices,
1279        culling_mode: CullingMode,
1280    ) {
1281        let instance_range = match culling_mode {
1282            CullingMode::Underground => 0..alt_indices.underground_end as u32,
1283            CullingMode::Surface => alt_indices.deep_end as u32..instances.count() as u32,
1284            CullingMode::None => 0..instances.count() as u32,
1285        };
1286
1287        // Don't render anything if there's nothing to render!
1288        if instance_range.is_empty() {
1289            return;
1290        }
1291
1292        self.render_pass
1293            .set_bind_group(3, &terrain_locals.bind_group, &[]);
1294
1295        let subinstances = instances.subinstances(instance_range);
1296
1297        self.render_pass.set_vertex_buffer(0, subinstances.buf());
1298        self.render_pass.draw_indexed(
1299            0..sprite::VERT_PAGE_SIZE / 4 * 6,
1300            0,
1301            0..subinstances.count(),
1302        );
1303    }
1304}
1305
1306impl<'pass_ref, 'pass: 'pass_ref> Drop for SpriteDrawer<'pass_ref, 'pass> {
1307    fn drop(&mut self) {
1308        // Reset to regular globals
1309        self.render_pass
1310            .set_bind_group(0, &self.globals.bind_group, &[]);
1311    }
1312}
1313
1314#[must_use]
1315pub struct LodObjectDrawer<'pass_ref, 'pass: 'pass_ref> {
1316    render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1317}
1318
1319impl<'pass_ref, 'pass: 'pass_ref> LodObjectDrawer<'pass_ref, 'pass> {
1320    pub fn draw<'data: 'pass>(
1321        &mut self,
1322        model: &'data Model<lod_object::Vertex>,
1323        instances: &'data Instances<lod_object::Instance>,
1324    ) {
1325        self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
1326        self.render_pass
1327            .set_vertex_buffer(1, instances.buf().slice(..));
1328        self.render_pass
1329            .draw(0..model.len() as u32, 0..instances.count() as u32);
1330    }
1331}
1332
1333#[must_use]
1334pub struct FluidDrawer<'pass_ref, 'pass: 'pass_ref> {
1335    render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1336}
1337
1338impl<'pass_ref, 'pass: 'pass_ref> FluidDrawer<'pass_ref, 'pass> {
1339    pub fn draw<'data: 'pass>(
1340        &mut self,
1341        model: &'data Model<fluid::Vertex>,
1342        locals: &'data terrain::BoundLocals,
1343    ) {
1344        self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
1345        self.render_pass.set_bind_group(2, &locals.bind_group, &[]);
1346        self.render_pass
1347            .draw_indexed(0..model.len() as u32 / 4 * 6, 0, 0..1);
1348    }
1349}
1350
1351// Second pass: volumetrics
1352#[must_use]
1353pub struct VolumetricPassDrawer<'pass> {
1354    render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
1355    borrow: &'pass RendererBorrow<'pass>,
1356    clouds_pipeline: &'pass clouds::CloudsPipeline,
1357}
1358
1359impl VolumetricPassDrawer<'_> {
1360    pub fn draw_clouds(&mut self) {
1361        self.render_pass
1362            .set_pipeline(&self.clouds_pipeline.pipeline);
1363        self.render_pass
1364            .set_bind_group(2, &self.borrow.locals.clouds_bind.bind_group, &[]);
1365        self.render_pass.draw(0..3, 0..1);
1366    }
1367}
1368
1369// Third pass: transparents
1370#[must_use]
1371pub struct TransparentPassDrawer<'pass> {
1372    render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
1373    borrow: &'pass RendererBorrow<'pass>,
1374    trail_pipeline: &'pass trail::TrailPipeline,
1375}
1376
1377impl<'pass> TransparentPassDrawer<'pass> {
1378    pub fn draw_trails(&mut self) -> Option<TrailDrawer<'_, 'pass>> {
1379        let shadow = &self.borrow.shadow?;
1380
1381        let mut render_pass = self.render_pass.scope("trails");
1382
1383        render_pass.set_pipeline(&self.trail_pipeline.pipeline);
1384        set_quad_index_buffer::<trail::Vertex>(&mut render_pass, self.borrow);
1385
1386        render_pass.set_bind_group(1, &shadow.bind.bind_group, &[]);
1387
1388        Some(TrailDrawer { render_pass })
1389    }
1390}
1391
1392#[must_use]
1393pub struct TrailDrawer<'pass_ref, 'pass: 'pass_ref> {
1394    render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1395}
1396
1397impl<'pass_ref, 'pass: 'pass_ref> TrailDrawer<'pass_ref, 'pass> {
1398    pub fn draw(&mut self, submodel: SubModel<'pass, trail::Vertex>) {
1399        self.render_pass.set_vertex_buffer(0, submodel.buf());
1400        self.render_pass
1401            .draw_indexed(0..submodel.len() / 4 * 6, 0, 0..1);
1402    }
1403}
1404
1405/// Third pass: postprocess + ui
1406#[must_use]
1407pub struct ThirdPassDrawer<'pass> {
1408    render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
1409    borrow: &'pass RendererBorrow<'pass>,
1410}
1411
1412impl<'pass> ThirdPassDrawer<'pass> {
1413    /// Does nothing if the postprocess pipeline is not available
1414    pub fn draw_postprocess(&mut self) {
1415        let postprocess = match self.borrow.pipelines.all() {
1416            Some(p) => &p.postprocess,
1417            None => return,
1418        };
1419
1420        let mut render_pass = self.render_pass.scope("postprocess");
1421        render_pass.set_pipeline(&postprocess.pipeline);
1422        render_pass.set_bind_group(1, &self.borrow.locals.postprocess_bind.bind_group, &[]);
1423        render_pass.draw(0..3, 0..1);
1424    }
1425
1426    /// Returns None if the UI pipeline is not available (note: this should
1427    /// never be the case for now)
1428    pub fn draw_ui(&mut self) -> Option<UiDrawer<'_, 'pass>> {
1429        let ui = self.borrow.pipelines.ui()?;
1430
1431        let mut render_pass = self.render_pass.scope("ui");
1432        render_pass.set_pipeline(&ui.pipeline);
1433        set_quad_index_buffer::<ui::Vertex>(&mut render_pass, self.borrow);
1434
1435        Some(UiDrawer { render_pass })
1436    }
1437}
1438
1439#[must_use]
1440pub struct UiDrawer<'pass_ref, 'pass: 'pass_ref> {
1441    render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
1442}
1443
1444#[must_use]
1445pub struct PreparedUiDrawer<'pass_ref, 'pass: 'pass_ref> {
1446    render_pass: &'pass_ref mut wgpu::RenderPass<'pass>,
1447}
1448
1449impl<'pass_ref, 'pass: 'pass_ref> UiDrawer<'pass_ref, 'pass> {
1450    /// Set vertex buffer, initial scissor, and locals
1451    /// These can be changed later but this ensures that they don't have to be
1452    /// set with every draw call
1453    pub fn prepare<'data: 'pass>(
1454        &mut self,
1455        locals: &'data ui::BoundLocals,
1456        buf: &'data DynamicModel<ui::Vertex>,
1457        scissor: Aabr<u16>,
1458    ) -> PreparedUiDrawer<'_, 'pass> {
1459        // Note: not actually prepared yet
1460        // we do this to avoid having to write extra code for the set functions
1461        let mut prepared = PreparedUiDrawer {
1462            render_pass: &mut self.render_pass,
1463        };
1464        // Prepare
1465        prepared.set_locals(locals);
1466        prepared.set_model(buf);
1467        prepared.set_scissor(scissor);
1468
1469        prepared
1470    }
1471}
1472
1473impl<'pass_ref, 'pass: 'pass_ref> PreparedUiDrawer<'pass_ref, 'pass> {
1474    pub fn set_locals<'data: 'pass>(&mut self, locals: &'data ui::BoundLocals) {
1475        self.render_pass.set_bind_group(1, &locals.bind_group, &[]);
1476    }
1477
1478    pub fn set_model<'data: 'pass>(&mut self, model: &'data DynamicModel<ui::Vertex>) {
1479        self.render_pass.set_vertex_buffer(0, model.buf().slice(..))
1480    }
1481
1482    pub fn set_scissor(&mut self, scissor: Aabr<u16>) {
1483        let Aabr { min, max } = scissor;
1484        self.render_pass.set_scissor_rect(
1485            min.x as u32,
1486            min.y as u32,
1487            (max.x - min.x) as u32,
1488            (max.y - min.y) as u32,
1489        );
1490    }
1491
1492    pub fn draw<'data: 'pass>(&mut self, texture: &'data ui::TextureBindGroup, verts: Range<u32>) {
1493        self.render_pass.set_bind_group(2, &texture.bind_group, &[]);
1494        self.render_pass.draw(verts, 0..1);
1495    }
1496}
1497
1498fn set_quad_index_buffer<'a, V: super::Vertex>(
1499    pass: &mut wgpu::RenderPass<'a>,
1500    borrow: &RendererBorrow<'a>,
1501) {
1502    if let Some(format) = V::QUADS_INDEX {
1503        let slice = match format {
1504            wgpu::IndexFormat::Uint16 => borrow.quad_index_buffer_u16.buf.slice(..),
1505            wgpu::IndexFormat::Uint32 => borrow.quad_index_buffer_u32.buf.slice(..),
1506        };
1507
1508        pass.set_index_buffer(slice, format);
1509    }
1510}