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 glow_context: Arc<egui_glow::glow::Context>,
41 painter: Painter,
42 pub window: WindowContext,
43}
44
45impl Renderer {
46 pub fn new(window: WindowContext, config: GraphicsConfig) -> Result<Self, OpenGlError> {
47 let context = window.gl_context().ok_or(OpenGlError::NoContext)?;
48 unsafe {
49 context.make_current();
50 }
51
52 let glow_context = Arc::new(unsafe {
53 egui_glow::glow::Context::from_loader_function(|s| context.get_proc_address(s))
54 });
55
56 let painter = egui_glow::Painter::new(
57 Arc::clone(&glow_context),
58 "",
59 config.shader_version,
60 config.dithering,
61 )
62 .map_err(OpenGlError::CreatePainter)?;
63
64 unsafe {
65 context.make_not_current();
66 }
67
68 Ok(Self {
69 window,
70 glow_context,
71 painter,
72 })
73 }
74
75 pub fn max_texture_side(&self) -> usize {
76 self.painter.max_texture_side()
77 }
78
79 pub fn render(
80 &mut self,
81 _window: &WindowContext,
82 clear_color: egui::Rgba,
83 physical_size: PhysicalSize<u32>,
84 pixels_per_point: f32,
85 egui_ctx: &mut egui::Context,
86 full_output: &mut FullOutput,
87 ) {
88 let PhysicalSize {
89 width: canvas_width,
90 height: canvas_height,
91 } = physical_size;
92
93 let shapes = std::mem::take(&mut full_output.shapes);
94 let textures_delta = &mut full_output.textures_delta;
95
96 let context = self
97 .window
98 .gl_context()
99 .expect("failed to get baseview gl context");
100 unsafe {
101 context.make_current();
102 }
103
104 unsafe {
105 use egui_glow::glow::HasContext as _;
106 self.glow_context.clear_color(
107 clear_color.r(),
108 clear_color.g(),
109 clear_color.b(),
110 clear_color.a(),
111 );
112 self.glow_context.clear(egui_glow::glow::COLOR_BUFFER_BIT);
113 }
114
115 for (id, image_delta) in &textures_delta.set {
116 self.painter.set_texture(*id, image_delta);
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 for id in textures_delta.free.drain(..) {
126 self.painter.free_texture(id);
127 }
128
129 unsafe {
130 context.swap_buffers();
131 context.make_not_current();
132 }
133 }
134}
135
136impl Drop for Renderer {
137 fn drop(&mut self) {
138 self.painter.destroy()
139 }
140}