egui_sdl2/wgpu/
mod.rs

1//! Integration between [`egui`] and [`wgpu`](https://docs.rs/wgpu) API.
2//!
3//! This module provides [`EguiWgpu`], a convenience wrapper that bundles
4//! together:
5//! - [`egui::Context`] for running your UI
6//! - [`crate::State`] for event and input handling
7//! - [`Painter`] for rendering using [`wgpu`](https://docs.rs/wgpu)
8
9//! # Usage
10//! Typical usage is to:
11//! 1. Create an [`EguiWgpu`] for your SDL2 window
12//! 2. Pass SDL2 events to [`EguiWgpu::on_event`]
13//! 3. Call [`EguiWgpu::run`] providing our UI function
14//! 4. Paint egui output via [`EguiWgpu::paint`]
15//!
16
17use std::num::NonZeroU32;
18pub mod painter;
19pub use painter::*;
20
21/// Integration between [`egui`] and [`wgpu`](https://docs.rs/wgpu) for app based on [`sdl2`].
22pub struct EguiWgpu {
23    run_output: crate::EguiRunOutput,
24    viewport_id: egui::ViewportId,
25    pub ctx: egui::Context,
26    pub state: crate::State,
27    pub painter: painter::Painter,
28    pub window: sdl2::video::Window,
29}
30
31impl EguiWgpu {
32    pub async fn new(window: sdl2::video::Window) -> Self {
33        let ctx = egui::Context::default();
34        let viewport_id = egui::ViewportId::ROOT;
35        let state = crate::State::new(&window, ctx.clone(), viewport_id);
36        let run_output = crate::EguiRunOutput::default();
37        let config = egui_wgpu::WgpuConfiguration::default();
38        let mut painter = painter::Painter::new(ctx.clone(), config, 1, None, true, false).await;
39        // SAFETY:
40        // Window lives as long as self
41        unsafe {
42            painter.set_window(viewport_id, &window).await.unwrap();
43        }
44
45        Self {
46            window,
47            ctx,
48            painter,
49            state,
50            run_output,
51            viewport_id,
52        }
53    }
54
55    #[inline]
56    pub fn on_event(&mut self, event: &sdl2::event::Event) -> crate::EventResponse {
57        match event {
58            sdl2::event::Event::Window {
59                window_id,
60                win_event:
61                    sdl2::event::WindowEvent::Resized(w, h)
62                    | sdl2::event::WindowEvent::SizeChanged(w, h),
63                ..
64            } if *window_id == self.window.id() && *w > 0 && *h > 0 => {
65                let w = NonZeroU32::new(*w as u32).unwrap();
66                let h = NonZeroU32::new(*h as u32).unwrap();
67                self.painter.on_window_resized(self.viewport_id, w, h);
68            }
69            _ => {}
70        }
71
72        self.state.on_event(&self.window, event)
73    }
74
75    /// Call [`Self::paint`] later to paint.
76    #[inline]
77    pub fn run(&mut self, run_ui: impl FnMut(&egui::Context)) {
78        self.run_output.update(&self.ctx, &mut self.state, run_ui);
79    }
80
81    /// Paint the results of the last call to [`Self::run`].
82    pub fn paint(&mut self, clear_color: [f32; 4]) {
83        let pixels_per_point = self.run_output.pixels_per_point;
84        let (textures_delta, shapes) = self.run_output.take();
85        let clipped_primitives = self.ctx.tessellate(shapes, pixels_per_point);
86        self.painter.paint_and_update_textures(
87            self.viewport_id,
88            pixels_per_point,
89            clear_color,
90            &clipped_primitives,
91            &textures_delta,
92            Vec::with_capacity(0),
93        );
94    }
95}