egui_sdl2/canvas/
mod.rs

1//! Integration between [`egui`] and SDL2’s [`sdl2::render::Canvas`] API.
2//!
3//! This module provides [`EguiCanvas`], 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 [`sdl2::render::Canvas`]
8//!
9//! # When to use
10//! Use [`EguiCanvas`] if you want to render egui using SDL2’s 2D canvas API
11//! instead of OpenGL.
12//!
13//! # Usage
14//! Typical usage is to:
15//! 1. Create an [`EguiCanvas`] for your SDL2 window and canvas
16//! 2. Pass SDL2 events to [`EguiCanvas::on_event`]
17//! 3. Call [`EguiCanvas::run`] providing our UI function
18//! 4. Paint egui output via [`EguiCanvas::paint`]
19//!
20pub mod painter;
21pub use painter::*;
22
23/// Integration between [`egui`] and [`sdl2::render::Canvas`] for app based on [`sdl2`].
24pub struct EguiCanvas {
25    run_output: crate::EguiRunOutput,
26    pub ctx: egui::Context,
27    pub state: crate::State,
28    pub painter: Painter,
29}
30
31impl EguiCanvas {
32    pub fn new(window: sdl2::video::Window) -> Self {
33        let ctx = egui::Context::default();
34        let state = crate::State::new(&window, ctx.clone(), egui::ViewportId::ROOT);
35        let run_output = crate::EguiRunOutput::default();
36        let painter = Painter::new(window);
37
38        Self {
39            ctx,
40            painter,
41            state,
42            run_output,
43        }
44    }
45
46    #[inline]
47    pub fn on_event(&mut self, event: &sdl2::event::Event) -> crate::EventResponse {
48        self.state.on_event(self.painter.canvas.window(), event)
49    }
50
51    /// Call [`Self::paint`] later to paint.
52    #[inline]
53    pub fn run(&mut self, run_ui: impl FnMut(&egui::Context)) {
54        self.run_output.update(&self.ctx, &mut self.state, run_ui);
55    }
56
57    /// Paint the results of the last call to [`Self::run`].
58    pub fn paint(&mut self) {
59        let pixels_per_point = self.run_output.pixels_per_point;
60        let (textures_delta, shapes) = self.run_output.take();
61        let clipped_primitives = self.ctx.tessellate(shapes, pixels_per_point);
62        if let Err(e) = self.painter.paint_and_update_textures(
63            pixels_per_point,
64            &textures_delta,
65            clipped_primitives,
66        ) {
67            log::error!("Failed to paint: {e}");
68        }
69    }
70
71    #[inline]
72    pub fn clear(&mut self, color: [u8; 4]) {
73        let color = sdl2::pixels::Color::RGBA(color[0], color[1], color[2], color[3]);
74        self.painter.canvas.set_draw_color(color);
75        self.painter.canvas.clear();
76    }
77
78    #[inline]
79    pub fn present(&mut self) {
80        self.painter.canvas.present();
81    }
82
83    /// Call to release the allocated graphics resources.
84    pub fn destroy(&mut self) {
85        self.painter.destroy();
86    }
87}