From 37c9f116bfb717243e70ecbc48f2d2280106a51d Mon Sep 17 00:00:00 2001 From: Jake Shadle Date: Mon, 7 Mar 2022 10:48:40 +0100 Subject: [PATCH] Fix egui_glow when targeting `wasm32-unknown-unknown` (#1303) * Gate winit/glow and epi correctly * Add check to CI * Fix epi cfg --- .github/workflows/rust.yml | 14 +++++ egui_glow/src/lib.rs | 117 +++++-------------------------------- egui_glow/src/winit.rs | 92 +++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+), 102 deletions(-) create mode 100644 egui_glow/src/winit.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index ee60bdc49..a4a0c7794 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -56,6 +56,20 @@ jobs: command: check args: -p egui_demo_app --lib --target wasm32-unknown-unknown + check_wasm_eframe_with_features: + name: cargo check wasm eframe + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: 1.56.0 + override: true + - run: rustup target add wasm32-unknown-unknown + - name: check + run: cargo check -p eframe --lib --no-default-features --features egui_glow,persistence --target wasm32-unknown-unknown + check_web_all_features: name: cargo check web --all-features runs-on: ubuntu-latest diff --git a/egui_glow/src/lib.rs b/egui_glow/src/lib.rs index c65147443..6889e9cdf 100644 --- a/egui_glow/src/lib.rs +++ b/egui_glow/src/lib.rs @@ -88,114 +88,27 @@ #![allow(clippy::manual_range_contains)] pub mod painter; -#[cfg(feature = "winit")] -use egui_winit::winit; pub use glow; pub use painter::Painter; -#[cfg(feature = "winit")] -mod epi_backend; mod misc_util; mod post_process; mod shader_version; mod vao_emulate; -#[cfg(not(target_arch = "wasm32"))] -#[cfg(feature = "egui_winit")] -pub use egui_winit; +#[cfg(all(not(target_arch = "wasm32"), feature = "winit"))] +pub mod winit; +#[cfg(all(not(target_arch = "wasm32"), feature = "winit"))] +pub use winit::*; -#[cfg(all(feature = "epi", feature = "winit"))] +#[cfg(all( + not(target_arch = "wasm32"), + feature = "persistence", + feature = "winit" +))] +mod epi_backend; +#[cfg(all( + not(target_arch = "wasm32"), + feature = "persistence", + feature = "winit" +))] pub use epi_backend::{run, NativeOptions}; - -// ---------------------------------------------------------------------------- - -/// Use [`egui`] from a [`glow`] app. -#[cfg(feature = "winit")] -pub struct EguiGlow { - pub egui_ctx: egui::Context, - pub egui_winit: egui_winit::State, - pub painter: crate::Painter, - - shapes: Vec, - textures_delta: egui::TexturesDelta, -} - -#[cfg(feature = "winit")] -impl EguiGlow { - pub fn new(window: &winit::window::Window, gl: &glow::Context) -> Self { - let painter = crate::Painter::new(gl, None, "") - .map_err(|error| { - tracing::error!("error occurred in initializing painter:\n{}", error); - }) - .unwrap(); - - Self { - egui_ctx: Default::default(), - egui_winit: egui_winit::State::new(painter.max_texture_side(), window), - painter, - shapes: Default::default(), - textures_delta: Default::default(), - } - } - - /// Returns `true` if egui wants exclusive use of this event - /// (e.g. a mouse click on an egui window, or entering text into a text field). - /// For instance, if you use egui for a game, you want to first call this - /// and only when this returns `false` pass on the events to your game. - /// - /// Note that egui uses `tab` to move focus between elements, so this will always return `true` for tabs. - pub fn on_event(&mut self, event: &winit::event::WindowEvent<'_>) -> bool { - self.egui_winit.on_event(&self.egui_ctx, event) - } - - /// Returns `true` if egui requests a repaint. - /// - /// Call [`Self::paint`] later to paint. - pub fn run( - &mut self, - window: &winit::window::Window, - run_ui: impl FnMut(&egui::Context), - ) -> bool { - let raw_input = self.egui_winit.take_egui_input(window); - let egui::FullOutput { - platform_output, - needs_repaint, - textures_delta, - shapes, - } = self.egui_ctx.run(raw_input, run_ui); - - self.egui_winit - .handle_platform_output(window, &self.egui_ctx, platform_output); - - self.shapes = shapes; - self.textures_delta.append(textures_delta); - needs_repaint - } - - /// Paint the results of the last call to [`Self::run`]. - pub fn paint(&mut self, window: &winit::window::Window, gl: &glow::Context) { - let shapes = std::mem::take(&mut self.shapes); - let mut textures_delta = std::mem::take(&mut self.textures_delta); - - for (id, image_delta) in textures_delta.set { - self.painter.set_texture(gl, id, &image_delta); - } - - let clipped_meshes = self.egui_ctx.tessellate(shapes); - let dimensions: [u32; 2] = window.inner_size().into(); - self.painter.paint_meshes( - gl, - dimensions, - self.egui_ctx.pixels_per_point(), - clipped_meshes, - ); - - for id in textures_delta.free.drain(..) { - self.painter.free_texture(gl, id); - } - } - - /// Call to release the allocated graphics resources. - pub fn destroy(&mut self, gl: &glow::Context) { - self.painter.destroy(gl); - } -} diff --git a/egui_glow/src/winit.rs b/egui_glow/src/winit.rs new file mode 100644 index 000000000..8be08c881 --- /dev/null +++ b/egui_glow/src/winit.rs @@ -0,0 +1,92 @@ +pub use egui_winit; +use egui_winit::winit; + +/// Use [`egui`] from a [`glow`] app. +pub struct EguiGlow { + pub egui_ctx: egui::Context, + pub egui_winit: egui_winit::State, + pub painter: crate::Painter, + + shapes: Vec, + textures_delta: egui::TexturesDelta, +} + +impl EguiGlow { + pub fn new(window: &winit::window::Window, gl: &glow::Context) -> Self { + let painter = crate::Painter::new(gl, None, "") + .map_err(|error| { + tracing::error!("error occurred in initializing painter:\n{}", error); + }) + .unwrap(); + + Self { + egui_ctx: Default::default(), + egui_winit: egui_winit::State::new(painter.max_texture_side(), window), + painter, + shapes: Default::default(), + textures_delta: Default::default(), + } + } + + /// Returns `true` if egui wants exclusive use of this event + /// (e.g. a mouse click on an egui window, or entering text into a text field). + /// For instance, if you use egui for a game, you want to first call this + /// and only when this returns `false` pass on the events to your game. + /// + /// Note that egui uses `tab` to move focus between elements, so this will always return `true` for tabs. + pub fn on_event(&mut self, event: &winit::event::WindowEvent<'_>) -> bool { + self.egui_winit.on_event(&self.egui_ctx, event) + } + + /// Returns `true` if egui requests a repaint. + /// + /// Call [`Self::paint`] later to paint. + pub fn run( + &mut self, + window: &winit::window::Window, + run_ui: impl FnMut(&egui::Context), + ) -> bool { + let raw_input = self.egui_winit.take_egui_input(window); + let egui::FullOutput { + platform_output, + needs_repaint, + textures_delta, + shapes, + } = self.egui_ctx.run(raw_input, run_ui); + + self.egui_winit + .handle_platform_output(window, &self.egui_ctx, platform_output); + + self.shapes = shapes; + self.textures_delta.append(textures_delta); + needs_repaint + } + + /// Paint the results of the last call to [`Self::run`]. + pub fn paint(&mut self, window: &winit::window::Window, gl: &glow::Context) { + let shapes = std::mem::take(&mut self.shapes); + let mut textures_delta = std::mem::take(&mut self.textures_delta); + + for (id, image_delta) in textures_delta.set { + self.painter.set_texture(gl, id, &image_delta); + } + + let clipped_meshes = self.egui_ctx.tessellate(shapes); + let dimensions: [u32; 2] = window.inner_size().into(); + self.painter.paint_meshes( + gl, + dimensions, + self.egui_ctx.pixels_per_point(), + clipped_meshes, + ); + + for id in textures_delta.free.drain(..) { + self.painter.free_texture(gl, id); + } + } + + /// Call to release the allocated graphics resources. + pub fn destroy(&mut self, gl: &glow::Context) { + self.painter.destroy(gl); + } +}