egui_sdl2/
lib.rs

1//! # egui-sdl2
2//!
3//! Integration between [`egui`](https://github.com/emilk/egui) and
4//! [`sdl2`](https://github.com/Rust-SDL2/rust-sdl2).
5//!
6//! ## Features
7//! - Translate SDL2 events into [`egui`] events.
8//! - Handle [`egui::PlatformOutput`] (clipboard, cursor updates, links).
9//! - Render with OpenGL via [`glow`] (`glow-backend` feature).
10//! - Render with the SDL2 software renderer via [`sdl2::render::Canvas`] (`canvas-backend` feature).
11//!
12//! ## Usage
13//! ```no_run
14//! // Create SDL2 window:
15//! let sdl = sdl2::init().unwrap();
16//! let video = sdl.video().unwrap();
17//! let window = video.window("Egui SDL2 Canvas", 800, 600).build().unwrap();
18//! let mut event_pump = sdl.event_pump().unwrap();
19//! // Create egui renderer:
20//! let mut egui = egui_sdl2::EguiCanvas::new(window);
21//! // Feed SDL2 events into egui:
22//! let window = egui.painter.canvas.window();
23//! let event = event_pump.wait_event();
24//! egui.state.on_event(window, &event);
25//! // Call `run` + `paint` each frame:
26//! egui.run(|ctx: &egui::Context| {});
27//! egui.paint();
28//! ```
29
30pub use egui;
31#[cfg(feature = "glow-backend")]
32pub use egui_glow;
33pub use sdl2;
34
35#[cfg(feature = "canvas-backend")]
36pub mod canvas;
37#[cfg(feature = "glow-backend")]
38pub mod glow;
39pub mod painter;
40pub mod state;
41
42#[cfg(feature = "canvas-backend")]
43pub use canvas::*;
44#[cfg(feature = "glow-backend")]
45pub use glow::*;
46pub use state::*;
47
48struct EguiBackend {
49    pub ctx: egui::Context,
50
51    // output from the last run:
52    shapes: Vec<egui::epaint::ClippedShape>,
53    pixels_per_point: f32,
54    textures_delta: egui::TexturesDelta,
55}
56
57impl EguiBackend {
58    pub fn new(ctx: egui::Context) -> Self {
59        Self {
60            ctx,
61            shapes: Default::default(),
62            pixels_per_point: 1.0,
63            textures_delta: Default::default(),
64        }
65    }
66
67    #[inline]
68    pub fn run(&mut self, state: &mut State, run_ui: impl FnMut(&egui::Context)) {
69        let raw_input = state.take_egui_input();
70        let egui::FullOutput {
71            platform_output,
72            viewport_output: _,
73            textures_delta,
74            shapes,
75            pixels_per_point,
76        } = self.ctx.run(raw_input, run_ui);
77        state.handle_platform_output(platform_output);
78
79        self.shapes = shapes;
80        self.textures_delta.append(textures_delta);
81        self.pixels_per_point = pixels_per_point;
82    }
83
84    #[inline]
85    pub fn paint(&mut self, state: &State, painter: &mut impl PainterTrait) {
86        let mut textures_delta = std::mem::take(&mut self.textures_delta);
87
88        for (id, image_delta) in textures_delta.set {
89            painter.set_texture(id, &image_delta);
90        }
91
92        let pixels_per_point = self.pixels_per_point;
93        let shapes = std::mem::take(&mut self.shapes);
94        let clipped_primitives = self.ctx.tessellate(shapes, pixels_per_point);
95        let size = state.get_window_size();
96        painter.paint_primitives(size.into(), pixels_per_point, clipped_primitives);
97
98        for id in textures_delta.free.drain(..) {
99            painter.free_texture(id);
100        }
101    }
102}
103
104trait PainterTrait {
105    fn paint_primitives(
106        &mut self,
107        screen_size_px: [u32; 2],
108        pixels_per_point: f32,
109        clipped_primitives: Vec<egui::ClippedPrimitive>,
110    );
111    fn set_texture(&mut self, tex_id: egui::TextureId, delta: &egui::epaint::ImageDelta);
112    fn free_texture(&mut self, tex_id: egui::TextureId);
113}