From 4a7a2d643047a0960736e6762fac543a8baa8ebb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20R=C3=B6ssler?= Date: Sun, 29 May 2022 20:33:04 +0200 Subject: [PATCH] eframe::App::post_rendering (#1591) --- Cargo.lock | 9 +++ Cargo.toml | 1 + eframe/src/epi.rs | 5 ++ eframe/src/native/epi_integration.rs | 7 ++ eframe/src/native/run.rs | 2 + examples/screenshot/Cargo.toml | 14 ++++ examples/screenshot/README.md | 3 + examples/screenshot/src/main.rs | 102 +++++++++++++++++++++++++++ 8 files changed, 143 insertions(+) create mode 100644 examples/screenshot/Cargo.toml create mode 100644 examples/screenshot/README.md create mode 100644 examples/screenshot/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 3d6a8ae5d..780a7ed2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3151,6 +3151,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "screenshot" +version = "0.1.0" +dependencies = [ + "eframe", + "egui_extras", + "itertools", +] + [[package]] name = "sct" version = "0.7.0" diff --git a/Cargo.toml b/Cargo.toml index fc26b0625..b05a4925b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ members = [ "examples/hello_world", "examples/puffin_profiler", "examples/retained_image", + "examples/screenshot", "examples/svg", ] diff --git a/eframe/src/epi.rs b/eframe/src/epi.rs index d7cac24c2..0142f734e 100644 --- a/eframe/src/epi.rs +++ b/eframe/src/epi.rs @@ -141,6 +141,11 @@ pub trait App { fn warm_up_enabled(&self) -> bool { false } + + /// Called each time after the rendering the UI. + /// + /// Can be used to access pixel data with `get_pixels` + fn post_rendering(&mut self, _window_size_px: [u32; 2], _frame: &Frame) {} } /// Options controlling the behavior of a native window. diff --git a/eframe/src/native/epi_integration.rs b/eframe/src/native/epi_integration.rs index 69d665de4..0365d1683 100644 --- a/eframe/src/native/epi_integration.rs +++ b/eframe/src/native/epi_integration.rs @@ -299,6 +299,13 @@ impl EpiIntegration { full_output } + pub fn post_rendering(&mut self, app: &mut dyn epi::App, window: &winit::window::Window) { + let inner_size = window.inner_size(); + let window_size_px = [inner_size.width, inner_size.height]; + + app.post_rendering(window_size_px, &self.frame); + } + pub fn handle_platform_output( &mut self, window: &winit::window::Window, diff --git a/eframe/src/native/run.rs b/eframe/src/native/run.rs index 606d85d1b..74155254e 100644 --- a/eframe/src/native/run.rs +++ b/eframe/src/native/run.rs @@ -126,6 +126,8 @@ pub fn run_glow( &textures_delta, ); + integration.post_rendering(app.as_mut(), window); + { crate::profile_scope!("swap_buffers"); gl_window.swap_buffers().unwrap(); diff --git a/examples/screenshot/Cargo.toml b/examples/screenshot/Cargo.toml new file mode 100644 index 000000000..aab4e6565 --- /dev/null +++ b/examples/screenshot/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "screenshot" +version = "0.1.0" +authors = ["René Rössler "] +license = "MIT OR Apache-2.0" +edition = "2021" +rust-version = "1.60" +publish = false + + +[dependencies] +eframe = { path = "../../eframe" } +egui_extras = { path = "../../egui_extras", features = ["image"] } +itertools = "0.10.3" diff --git a/examples/screenshot/README.md b/examples/screenshot/README.md new file mode 100644 index 000000000..416c8bbad --- /dev/null +++ b/examples/screenshot/README.md @@ -0,0 +1,3 @@ +```sh +cargo run -p screenshot +``` diff --git a/examples/screenshot/src/main.rs b/examples/screenshot/src/main.rs new file mode 100644 index 000000000..4594f3b15 --- /dev/null +++ b/examples/screenshot/src/main.rs @@ -0,0 +1,102 @@ +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release + +use eframe::{ + egui::{self, ColorImage}, + glow::{self, HasContext}, +}; +use itertools::Itertools; + +fn main() { + let options = eframe::NativeOptions::default(); + eframe::run_native( + "Take screenshots and display with eframe/egui", + options, + Box::new(|_cc| Box::new(MyApp::default())), + ); +} + +#[derive(Default)] +struct MyApp { + continuously_take_screenshots: bool, + take_screenshot: bool, + texture: Option, + screenshot: Option, +} + +impl eframe::App for MyApp { + fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { + egui::CentralPanel::default().show(ctx, |ui| { + if let Some(screenshot) = self.screenshot.take() { + self.texture = Some(ui.ctx().load_texture("screenshot", screenshot)); + } + + ui.horizontal(|ui| { + ui.checkbox( + &mut self.continuously_take_screenshots, + "continuously take screenshots", + ); + + ui.with_layout(egui::Layout::top_down(egui::Align::RIGHT), |ui| { + if self.continuously_take_screenshots { + if ui + .add(egui::Label::new("hover me!").sense(egui::Sense::hover())) + .hovered() + { + ctx.set_visuals(egui::Visuals::dark()); + } else { + ctx.set_visuals(egui::Visuals::light()); + }; + } else if ui.button("take screenshot!").clicked() { + self.take_screenshot = true; + } + }); + }); + + if let Some(texture) = self.texture.as_ref() { + ui.image(texture, ui.available_size()); + } else { + ui.spinner(); + } + + ctx.request_repaint(); + }); + } + + #[allow(unsafe_code)] + fn post_rendering(&mut self, screen_size_px: [u32; 2], frame: &eframe::Frame) { + if !self.take_screenshot && !self.continuously_take_screenshots { + return; + } + + self.take_screenshot = false; + if let Some(gl) = frame.gl() { + let mut buf = vec![0u8; screen_size_px[0] as usize * screen_size_px[1] as usize * 4]; + let pixels = glow::PixelPackData::Slice(&mut buf[..]); + unsafe { + gl.read_pixels( + 0, + 0, + screen_size_px[0] as i32, + screen_size_px[1] as i32, + glow::RGBA, + glow::UNSIGNED_BYTE, + pixels, + ); + } + + let mut rows: Vec> = buf + .into_iter() + .chunks(screen_size_px[0] as usize * 4) + .into_iter() + .map(|chunk| chunk.collect()) + .collect(); + rows.reverse(); + let buf: Vec = rows.into_iter().flatten().collect(); + + self.screenshot = Some(ColorImage::from_rgba_unmultiplied( + [screen_size_px[0] as usize, screen_size_px[1] as usize], + &buf[..], + )); + } + } +}