1use std::sync::Arc;
2
3use libdqg::renderer::Renderer;
4
5pub struct EguiLayer {
9 window: Option<Arc<winit::window::Window>>,
10 ctx: egui::Context,
11 state: Option<egui_winit::State>,
12 renderer: Option<egui_wgpu::Renderer>,
13 pending_output: Option<egui::FullOutput>,
14}
15
16impl EguiLayer {
17 pub fn new() -> Self {
18 Self {
19 window: None,
20 ctx: egui::Context::default(),
21 state: None,
22 renderer: None,
23 pending_output: None,
24 }
25 }
26
27 fn ensure_init(&mut self, renderer: &Renderer) {
28 if self.window.is_some() {
29 return;
30 }
31
32 let window = renderer.window();
33 self.state = Some(egui_winit::State::new(
34 self.ctx.clone(),
35 egui::ViewportId::ROOT,
36 window.as_ref(),
37 Some(window.scale_factor() as f32),
38 None,
39 None,
40 ));
41 self.renderer = Some(egui_wgpu::Renderer::new(
42 renderer.device(),
43 renderer.wgpu_surface_format(),
44 egui_wgpu::RendererOptions::default(),
45 ));
46 self.window = Some(window);
47 }
48
49 pub fn run(&mut self, renderer: &Renderer, run_ui: impl FnMut(&mut egui::Ui)) {
52 self.ensure_init(renderer);
53
54 let window = self.window.clone().unwrap();
55 let state = self.state.as_mut().unwrap();
56 let raw_input = state.take_egui_input(&window);
57 let full_output = self.ctx.run_ui(raw_input, run_ui);
58 state.handle_platform_output(&window, full_output.platform_output.clone());
59 self.pending_output = Some(full_output);
60 }
61
62 pub fn wants_pointer_input(&self) -> bool {
63 self.ctx.egui_wants_pointer_input()
64 }
65
66 pub fn on_window_event(&mut self, event: &winit::event::WindowEvent) {
67 if let (Some(window), Some(state)) = (self.window.as_ref(), self.state.as_mut()) {
68 let _ = state.on_window_event(window, event);
69 }
70 }
71
72 pub fn render_overlay(
73 &mut self,
74 device: &wgpu::Device,
75 queue: &wgpu::Queue,
76 encoder: &mut wgpu::CommandEncoder,
77 view: &wgpu::TextureView,
78 ) {
79 let (Some(mut full_output), Some(egui_renderer), Some(window)) =
80 (self.pending_output.take(), self.renderer.as_mut(), self.window.as_ref())
81 else {
82 return;
83 };
84
85 let pixels_per_point = full_output.pixels_per_point;
86 let paint_jobs = self.ctx.tessellate(std::mem::take(&mut full_output.shapes), pixels_per_point);
87
88 for (id, image_deltas) in full_output.textures_delta.set.drain() {
91 for image_delta in &image_deltas {
92 egui_renderer.update_texture(device, queue, id, image_delta);
93 }
94 }
95
96 let size = window.inner_size();
97 let screen_descriptor = egui_wgpu::ScreenDescriptor {
98 size_in_pixels: [size.width, size.height],
99 pixels_per_point,
100 };
101
102 egui_renderer.update_buffers(device, queue, encoder, &paint_jobs, &screen_descriptor);
103
104 let mut rpass = encoder
105 .begin_render_pass(&wgpu::RenderPassDescriptor {
106 label: Some("egui overlay pass"),
107 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
108 view,
109 resolve_target: None,
110 ops: wgpu::Operations {
111 load: wgpu::LoadOp::Load,
112 store: wgpu::StoreOp::Store,
113 },
114 depth_slice: None,
115 })],
116 depth_stencil_attachment: None,
117 timestamp_writes: None,
118 occlusion_query_set: None,
119 multiview_mask: None,
120 })
121 .forget_lifetime();
122
123 egui_renderer.render(&mut rpass, &paint_jobs, &screen_descriptor);
124 drop(rpass);
125
126 for id in full_output.textures_delta.free.drain() {
127 egui_renderer.free_texture(&id);
128 }
129 }
130}