egui_baseview/renderer/opengl/
renderer.rs1use super::OpenGlError;
2use baseview::WindowContext;
3use baseview::dpi::PhysicalSize;
4use baseview::gl::GlConfig;
5use egui::FullOutput;
6use egui_glow::Painter;
7use std::sync::Arc;
8
9#[derive(Debug, Clone, PartialEq)]
10pub struct GraphicsConfig {
11 pub gl_config: GlConfig,
12
13 pub dithering: bool,
21
22 pub shader_version: Option<egui_glow::ShaderVersion>,
27}
28
29impl Default for GraphicsConfig {
30 fn default() -> Self {
31 Self {
32 gl_config: GlConfig::default(),
33 shader_version: None,
34 dithering: true,
35 }
36 }
37}
38
39pub struct Renderer {
40 pub glow_context: Arc<egui_glow::glow::Context>,
41 painter: Painter,
42}
43
44impl Renderer {
45 pub fn new(window: WindowContext, config: GraphicsConfig) -> Result<Self, OpenGlError> {
46 let context = window.gl_context().ok_or(OpenGlError::NoContext)?;
47 unsafe {
48 context.make_current()?;
49 }
50
51 let glow_context = Arc::new(unsafe {
52 egui_glow::glow::Context::from_loader_function_cstr(|s| context.get_proc_address(s))
53 });
54
55 let painter = egui_glow::Painter::new(
56 Arc::clone(&glow_context),
57 "",
58 config.shader_version,
59 config.dithering,
60 )
61 .map_err(OpenGlError::CreatePainter)?;
62
63 unsafe {
64 context.make_not_current()?;
65 }
66
67 Ok(Self {
68 glow_context,
69 painter,
70 })
71 }
72
73 pub fn max_texture_side(&self) -> usize {
74 self.painter.max_texture_side()
75 }
76
77 pub fn render(
78 &mut self,
79 window: &WindowContext,
80 clear_color: egui::Rgba,
81 physical_size: PhysicalSize<u32>,
82 pixels_per_point: f32,
83 egui_ctx: &mut egui::Context,
84 full_output: &mut FullOutput,
85 ) {
86 let PhysicalSize {
87 width: canvas_width,
88 height: canvas_height,
89 } = physical_size;
90
91 let shapes = std::mem::take(&mut full_output.shapes);
92 let textures_delta = &mut full_output.textures_delta;
93
94 let context = window
95 .gl_context()
96 .expect("failed to get baseview gl context");
97 unsafe {
98 context.make_current().unwrap();
99 }
100
101 unsafe {
102 use egui_glow::glow::HasContext as _;
103 self.glow_context.clear_color(
104 clear_color.r(),
105 clear_color.g(),
106 clear_color.b(),
107 clear_color.a(),
108 );
109 self.glow_context.clear(egui_glow::glow::COLOR_BUFFER_BIT);
110 }
111
112 #[expect(clippy::iter_over_hash_type)] for (id, image_deltas) in textures_delta.set.drain() {
114 for image_delta in image_deltas {
115 self.painter.set_texture(id, &image_delta);
116 }
117 }
118
119 let clipped_primitives = egui_ctx.tessellate(shapes, pixels_per_point);
120 let dimensions: [u32; 2] = [canvas_width, canvas_height];
121
122 self.painter
123 .paint_primitives(dimensions, pixels_per_point, &clipped_primitives);
124
125 #[expect(clippy::iter_over_hash_type)] for id in textures_delta.free.drain() {
127 self.painter.free_texture(id);
128 }
129
130 unsafe {
131 context.swap_buffers().unwrap();
132 context.make_not_current().unwrap();
133 }
134 }
135}
136
137impl Drop for Renderer {
138 fn drop(&mut self) {
139 self.painter.destroy()
140 }
141}