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