rend3_egui/
lib.rs

1//! Render routine integrating egui into a rend3 rendergraph.
2//!
3//! Call [`EguiRenderRoutine::add_to_graph`] to add it to the graph.
4
5use rend3::{
6    graph::{RenderGraph, RenderPassTarget, RenderPassTargets, RenderTargetHandle},
7    types::SampleCount,
8    Renderer,
9};
10use wgpu::{Color, TextureFormat};
11
12pub struct EguiRenderRoutine {
13    pub internal: egui_wgpu_backend::RenderPass,
14    screen_descriptor: egui_wgpu_backend::ScreenDescriptor,
15}
16
17impl EguiRenderRoutine {
18    /// Creates a new render routine to render a egui UI.
19    ///
20    /// Egui will always output gamma-encoded color. It will determine if to do
21    /// this in the shader manually based on the output format.
22    pub fn new(
23        renderer: &Renderer,
24        surface_format: TextureFormat,
25        samples: SampleCount,
26        width: u32,
27        height: u32,
28        scale_factor: f32,
29    ) -> Self {
30        let rpass = egui_wgpu_backend::RenderPass::new(&renderer.device, surface_format, samples as _);
31
32        Self {
33            internal: rpass,
34            screen_descriptor: egui_wgpu_backend::ScreenDescriptor {
35                physical_height: height,
36                physical_width: width,
37                scale_factor,
38            },
39        }
40    }
41
42    pub fn resize(&mut self, new_width: u32, new_height: u32, new_scale_factor: f32) {
43        self.screen_descriptor = egui_wgpu_backend::ScreenDescriptor {
44            physical_height: new_height,
45            physical_width: new_width,
46            scale_factor: new_scale_factor,
47        };
48    }
49
50    pub fn add_to_graph<'node>(
51        &'node mut self,
52        graph: &mut RenderGraph<'node>,
53        input: Input<'node>,
54        output: RenderTargetHandle,
55    ) {
56        let mut builder = graph.add_node("egui");
57
58        let output_handle = builder.add_render_target_output(output);
59
60        let rpass_handle = builder.add_renderpass(RenderPassTargets {
61            targets: vec![RenderPassTarget {
62                color: output_handle,
63                clear: Color::BLACK,
64                resolve: None,
65            }],
66            depth_stencil: None,
67        });
68
69        let pt_handle = builder.passthrough_ref_mut(self);
70
71        builder.build(move |pt, renderer, encoder_or_pass, _temps, _ready, _graph_data| {
72            let this = pt.get_mut(pt_handle);
73            let rpass = encoder_or_pass.get_rpass(rpass_handle);
74
75            this.internal
76                .update_texture(&renderer.device, &renderer.queue, &input.context.font_image());
77            this.internal.update_user_textures(&renderer.device, &renderer.queue);
78            this.internal.update_buffers(
79                &renderer.device,
80                &renderer.queue,
81                input.clipped_meshes,
82                &this.screen_descriptor,
83            );
84
85            this.internal
86                .execute_with_renderpass(rpass, input.clipped_meshes, &this.screen_descriptor)
87                .unwrap();
88        });
89    }
90}
91
92pub struct Input<'a> {
93    pub clipped_meshes: &'a Vec<egui::ClippedMesh>,
94    pub context: egui::CtxRef,
95}