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;
39#[cfg(feature = "canvas-backend")]
40pub mod painter;
41pub mod state;
42
43#[cfg(feature = "canvas-backend")]
44pub use canvas::*;
45#[cfg(feature = "glow-backend")]
46pub use glow::*;
47#[cfg(feature = "canvas-backend")]
48pub use painter::*;
49pub use state::*;
50
51#[cfg(any(feature = "glow-backend", feature = "canvas-backend"))]
52struct EguiBackend {
53    pub ctx: egui::Context,
54
55    // output from the last run:
56    shapes: Vec<egui::epaint::ClippedShape>,
57    pixels_per_point: f32,
58    textures_delta: egui::TexturesDelta,
59}
60
61#[cfg(any(feature = "glow-backend", feature = "canvas-backend"))]
62impl EguiBackend {
63    pub fn new(ctx: egui::Context) -> Self {
64        Self {
65            ctx,
66            shapes: Default::default(),
67            pixels_per_point: 1.0,
68            textures_delta: Default::default(),
69        }
70    }
71
72    #[inline]
73    pub fn run(&mut self, state: &mut State, run_ui: impl FnMut(&egui::Context)) {
74        let raw_input = state.take_egui_input();
75        let egui::FullOutput {
76            platform_output,
77            viewport_output: _,
78            textures_delta,
79            shapes,
80            pixels_per_point,
81        } = self.ctx.run(raw_input, run_ui);
82        state.handle_platform_output(platform_output);
83
84        self.shapes = shapes;
85        self.textures_delta.append(textures_delta);
86        self.pixels_per_point = pixels_per_point;
87    }
88
89    #[inline]
90    pub fn paint(&mut self, state: &State, painter: &mut impl PainterTrait) {
91        let mut textures_delta = std::mem::take(&mut self.textures_delta);
92
93        for (id, image_delta) in textures_delta.set {
94            painter.set_texture(id, &image_delta);
95        }
96
97        let pixels_per_point = self.pixels_per_point;
98        let shapes = std::mem::take(&mut self.shapes);
99        let clipped_primitives = self.ctx.tessellate(shapes, pixels_per_point);
100        let size = state.get_window_size();
101        painter.paint_primitives(size.into(), pixels_per_point, clipped_primitives);
102
103        for id in textures_delta.free.drain(..) {
104            painter.free_texture(id);
105        }
106    }
107}
108
109#[cfg(any(feature = "glow-backend", feature = "canvas-backend"))]
110trait PainterTrait {
111    fn paint_primitives(
112        &mut self,
113        screen_size_px: [u32; 2],
114        pixels_per_point: f32,
115        clipped_primitives: Vec<egui::ClippedPrimitive>,
116    );
117    fn set_texture(&mut self, tex_id: egui::TextureId, delta: &egui::epaint::ImageDelta);
118    fn free_texture(&mut self, tex_id: egui::TextureId);
119}