use std::sync::Arc;
use crate::backend::{FramebufferSize, PlayerState};
use eframe::egui;
use eframe::glow::HasContext as _;
use tracing::error;
pub struct SharkPlayer<'a> {
backend: &'a mut PlayerState,
}
impl<'a> SharkPlayer<'a> {
pub fn new(backend: &'a mut PlayerState) -> Self { Self { backend } }
}
impl<'a> egui::Widget for SharkPlayer<'a> {
fn ui(self, ui: &mut egui::Ui) -> egui::Response {
let (rect, response) = ui.allocate_exact_size(ui.available_size(), egui::Sense::click());
if response.clicked()
&& let Err(e) = self.backend.toggle_pause()
{
error!("Failed to toggle playback: {e}");
}
let (fb, fb_size) = match self.backend.get_current_framebuffer(FramebufferSize {
width: rect.width() as i32,
height: rect.height() as i32,
}) {
Ok((fb, fb_sz)) => (fb, fb_sz),
Err(e) if cfg!(debug_assertions) => {
error!("Failed to get current framebuffer: {e}");
return response;
}
Err(_) => return response,
};
let cb = eframe::egui_glow::CallbackFn::new(move |info, painter| {
let gl = painter.gl();
unsafe {
let prev_read_fb = gl.get_parameter_i32(eframe::glow::READ_FRAMEBUFFER_BINDING);
gl.bind_framebuffer(eframe::glow::READ_FRAMEBUFFER, Some(fb));
let p_per_point = info.pixels_per_point;
let screen_h = info.screen_size_px[1] as f32;
gl.blit_framebuffer(
0,
0,
fb_size.width,
fb_size.height,
(rect.min.x * p_per_point) as i32,
(screen_h - rect.max.y * p_per_point) as i32,
(rect.max.x * p_per_point) as i32,
(screen_h - rect.min.y * p_per_point) as i32,
eframe::glow::COLOR_BUFFER_BIT,
eframe::glow::LINEAR,
);
let prev_fb =
std::num::NonZeroU32::new(prev_read_fb as u32).map(eframe::glow::NativeFramebuffer);
gl.bind_framebuffer(eframe::glow::READ_FRAMEBUFFER, prev_fb);
}
});
ui.painter().add(egui::PaintCallback {
rect,
callback: Arc::new(cb),
});
response
}
}