shura/graphics/gui/
gui.rs

1use std::ops::{Deref, DerefMut};
2
3use crate::{gui::GuiContext, Gpu, GpuDefaults, RenderEncoder, Vector};
4use egui_wgpu::renderer::{Renderer, ScreenDescriptor};
5use egui_winit::State;
6use instant::Duration;
7use winit::window::Window;
8
9pub struct Gui {
10    state: State,
11    context: GuiContext,
12    renderer: Renderer,
13    screen_descriptor: ScreenDescriptor,
14}
15
16impl Gui {
17    pub(crate) fn new(
18        event_loop: &winit::event_loop::EventLoopWindowTarget<()>,
19        gpu: &Gpu,
20    ) -> Self {
21        let config = &gpu.config;
22        let device = &gpu.device;
23        let renderer = Renderer::new(
24            device,
25            wgpu::TextureFormat::Rgba8UnormSrgb,
26            None,
27            gpu.base.sample_count,
28        );
29        let state = State::new(event_loop);
30        let context = GuiContext::default();
31
32        let screen_descriptor = ScreenDescriptor {
33            size_in_pixels: [config.width, config.height],
34            pixels_per_point: 1.0,
35        };
36        Self {
37            renderer,
38            state,
39            context,
40            screen_descriptor,
41        }
42    }
43
44    pub(crate) fn resize(&mut self, size: &Vector<u32>) {
45        self.screen_descriptor = ScreenDescriptor {
46            size_in_pixels: [size.x, size.y],
47            pixels_per_point: 1.0,
48        };
49    }
50
51    pub(crate) fn handle_event(&mut self, event: &winit::event::WindowEvent) {
52        self.state.on_event(&self.context, event).consumed;
53    }
54
55    pub(crate) fn begin(&mut self, total_time: &Duration, window: &Window) {
56        let mut egui_input = self.state.take_egui_input(window);
57        egui_input.time = Some(total_time.as_secs_f64());
58        self.context.begin_frame(egui_input);
59    }
60
61    pub(crate) fn render(
62        &mut self,
63        gpu: &Gpu,
64        defaults: &GpuDefaults,
65        encoder: &mut RenderEncoder,
66    ) {
67        let output = self.context.end_frame();
68        let paint_jobs = self.context.tessellate(output.shapes);
69
70        for add in &output.textures_delta.set {
71            self.renderer
72                .update_texture(&gpu.device, &gpu.queue, add.0, &add.1);
73        }
74
75        self.renderer.update_buffers(
76            &gpu.device,
77            &gpu.queue,
78            &mut encoder.inner,
79            &paint_jobs,
80            &self.screen_descriptor,
81        );
82
83        {
84            let mut rpass = encoder
85                .inner
86                .begin_render_pass(&wgpu::RenderPassDescriptor {
87                    color_attachments: &[Some(wgpu::RenderPassColorAttachment {
88                        view: defaults.world_target.msaa(),
89                        resolve_target: Some(defaults.world_target.view()),
90                        ops: wgpu::Operations {
91                            load: wgpu::LoadOp::Load,
92                            store: true,
93                        },
94                    })],
95                    depth_stencil_attachment: None,
96                    label: Some("egui main render pass"),
97                });
98
99            self.renderer
100                .render(&mut rpass, &paint_jobs, &self.screen_descriptor);
101        }
102
103        for free in &output.textures_delta.free {
104            self.renderer.free_texture(free);
105        }
106    }
107}
108
109impl Deref for Gui {
110    type Target = GuiContext;
111
112    fn deref(&self) -> &Self::Target {
113        &self.context
114    }
115}
116
117impl DerefMut for Gui {
118    fn deref_mut(&mut self) -> &mut Self::Target {
119        &mut self.context
120    }
121}