egui_baseview/renderer/opengl/
renderer.rs1use baseview::{PhySize, Window, gl::GlConfig};
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 gl_config: GlConfig,
11
12 pub dithering: bool,
20
21 pub shader_version: Option<egui_glow::ShaderVersion>,
26}
27
28impl Default for GraphicsConfig {
29 fn default() -> Self {
30 Self {
31 gl_config: GlConfig::default(),
32 shader_version: None,
33 dithering: true,
34 }
35 }
36}
37
38pub struct Renderer {
39 glow_context: Arc<egui_glow::glow::Context>,
40 painter: Painter,
41}
42
43impl Renderer {
44 pub fn new(window: &Window, config: GraphicsConfig) -> Result<Self, OpenGlError> {
45 let context = window.gl_context().ok_or(OpenGlError::NoContext)?;
46 unsafe {
47 context.make_current();
48 }
49
50 #[allow(clippy::arc_with_non_send_sync)]
51 let glow_context = Arc::new(unsafe {
52 egui_glow::glow::Context::from_loader_function(|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: &Window,
80 bg_color: egui::Rgba,
81 physical_size: PhySize,
82 pixels_per_point: f32,
83 egui_ctx: &mut egui::Context,
84 full_output: &mut FullOutput,
85 ) {
86 let PhySize {
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();
99 }
100
101 unsafe {
102 use egui_glow::glow::HasContext as _;
103 self.glow_context
104 .clear_color(bg_color.r(), bg_color.g(), bg_color.b(), bg_color.a());
105 self.glow_context.clear(egui_glow::glow::COLOR_BUFFER_BIT);
106 }
107
108 for (id, image_delta) in &textures_delta.set {
109 self.painter.set_texture(*id, image_delta);
110 }
111
112 let clipped_primitives = egui_ctx.tessellate(shapes, pixels_per_point);
113 let dimensions: [u32; 2] = [canvas_width, canvas_height];
114
115 self.painter
116 .paint_primitives(dimensions, pixels_per_point, &clipped_primitives);
117
118 for id in textures_delta.free.drain(..) {
119 self.painter.free_texture(id);
120 }
121
122 unsafe {
123 context.swap_buffers();
124 context.make_not_current();
125 }
126 }
127}
128
129impl Drop for Renderer {
130 fn drop(&mut self) {
131 self.painter.destroy()
132 }
133}