From 6f844f0c604098b7f7eaf2be3f8ab50b342cb5b6 Mon Sep 17 00:00:00 2001 From: Vladyslav Batyrenko Date: Sun, 7 Jan 2024 17:46:44 +0200 Subject: [PATCH] Custom render (#243) * Add render feature * Fix clippy * Add the tonemapping_luts feature to dev-dependencies * Fix broken imports, specify required features for examples * Expand the CI workflow to cover the render feature --------- Co-authored-by: BeastLe9enD --- .github/workflows/check.yml | 22 +++++++--- Cargo.toml | 21 ++++++++- src/lib.rs | 86 +++++++++++++++++++++++++++++-------- 3 files changed, 103 insertions(+), 26 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index afcb6f2a4..29101b799 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -25,8 +25,14 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] - features: - ["", "manage_clipboard", "open_url", "manage_clipboard,open_url"] + features: [ + "", + "immutable_ctx", + "manage_clipboard", + "open_url", + "render", + "manage_clipboard,open_url,render", + ] steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@master @@ -56,10 +62,12 @@ jobs: matrix: features: [ + "", "immutable_ctx", "manage_clipboard", "open_url", - "manage_clipboard,open_url", + "render", + "manage_clipboard,open_url,render", ] env: RUSTFLAGS: --cfg=web_sys_unstable_apis @@ -90,10 +98,12 @@ jobs: matrix: features: [ + "", "immutable_ctx", "manage_clipboard", "open_url", - "manage_clipboard,open_url", + "render", + "manage_clipboard,open_url,render", ] steps: - uses: actions/checkout@v3 @@ -125,10 +135,12 @@ jobs: matrix: features: [ + "", "immutable_ctx", "manage_clipboard", "open_url", - "manage_clipboard,open_url", + "render", + "manage_clipboard,open_url,render", ] steps: - uses: actions/checkout@v3 diff --git a/Cargo.toml b/Cargo.toml index f7bc39a0c..fce483f3f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,16 +14,32 @@ all-features = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -default = ["manage_clipboard", "open_url", "default_fonts"] +default = ["manage_clipboard", "open_url", "default_fonts", "render"] immutable_ctx = [] manage_clipboard = ["arboard", "thread_local"] open_url = ["webbrowser"] default_fonts = ["egui/default_fonts"] +render = ["bevy/bevy_render"] serde = ["egui/serde"] +[[example]] +name = "render_to_image_widget" +required-features = ["render"] +[[example]] +name = "side_panel" +required-features = ["render"] +[[example]] +name = "simple" +required-features = ["render"] +[[example]] +name = "two_windows" +required-features = ["render"] +[[example]] +name = "ui" +required-features = ["render"] + [dependencies] bevy = { version = "0.12", default-features = false, features = [ - "bevy_render", "bevy_asset", ] } egui = { version = "0.24.0", default-features = false, features = ["bytemuck"] } @@ -41,4 +57,5 @@ bevy = { version = "0.12", default-features = false, features = [ "png", "bevy_pbr", "bevy_core_pipeline", + "tonemapping_luts", ] } diff --git a/src/lib.rs b/src/lib.rs index 3cd3df899..4a7a3948e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,41 +51,39 @@ //! - [`bevy-inspector-egui`](https://github.com/jakobhellermann/bevy-inspector-egui) /// Plugin systems for the render app. +#[cfg(feature = "render")] pub mod render_systems; /// Plugin systems. pub mod systems; /// Egui render node. +#[cfg(feature = "render")] pub mod egui_node; pub use egui; +use crate::systems::*; +#[cfg(feature = "render")] use crate::{ egui_node::{EguiPipeline, EGUI_SHADER_HANDLE}, render_systems::{EguiTransforms, ExtractedEguiManagedTextures}, - systems::*, }; #[cfg(all( feature = "manage_clipboard", not(any(target_arch = "wasm32", target_os = "android")) ))] use arboard::Clipboard; +#[allow(unused_imports)] +use bevy::log; +#[cfg(feature = "render")] use bevy::{ - app::{App, Last, Plugin, PostUpdate, PreStartup, PreUpdate}, + app::Last, asset::{load_internal_asset, AssetEvent, Assets, Handle}, ecs::{ event::EventReader, - query::{QueryEntityError, WorldQuery}, - schedule::apply_deferred, - system::{Res, ResMut, SystemParam}, + system::{Res, ResMut}, }, - input::InputSystem, - log, - prelude::{ - Added, Commands, Component, Deref, DerefMut, Entity, IntoSystemConfigs, Query, Resource, - Shader, SystemSet, With, Without, - }, - reflect::Reflect, + prelude::Shader, render::{ extract_component::{ExtractComponent, ExtractComponentPlugin}, extract_resource::{ExtractResource, ExtractResourcePlugin}, @@ -94,6 +92,20 @@ use bevy::{ ExtractSchedule, Render, RenderApp, RenderSet, }, utils::HashMap, +}; +use bevy::{ + app::{App, Plugin, PostUpdate, PreStartup, PreUpdate}, + ecs::{ + query::{QueryEntityError, WorldQuery}, + schedule::apply_deferred, + system::SystemParam, + }, + input::InputSystem, + prelude::{ + Added, Commands, Component, Deref, DerefMut, Entity, IntoSystemConfigs, Query, Resource, + SystemSet, With, Without, + }, + reflect::Reflect, window::{PrimaryWindow, Window}, }; use std::borrow::Cow; @@ -112,7 +124,8 @@ use thread_local::ThreadLocal; pub struct EguiPlugin; /// A resource for storing global UI settings. -#[derive(Clone, Debug, Resource, ExtractResource, Reflect)] +#[derive(Clone, Debug, Resource, Reflect)] +#[cfg_attr(feature = "render", derive(ExtractResource))] pub struct EguiSettings { /// Global scale factor for Egui widgets (`1.0` by default). /// @@ -134,21 +147,26 @@ pub struct EguiSettings { pub default_open_url_target: Option, /// Used to change sampler properties /// Defaults to linear and clamped to edge + #[cfg(feature = "render")] #[reflect(ignore)] pub sampler_descriptor: ImageSampler, } // Just to keep the PartialEq impl PartialEq for EguiSettings { + #[allow(clippy::let_and_return)] fn eq(&self, other: &Self) -> bool { let eq = self.scale_factor == other.scale_factor; #[cfg(feature = "open_url")] let eq = eq && self.default_open_url_target == other.default_open_url_target; - eq && compare_descriptors(&self.sampler_descriptor, &other.sampler_descriptor) + #[cfg(feature = "render")] + let eq = eq && compare_descriptors(&self.sampler_descriptor, &other.sampler_descriptor); + eq } } // Since Eq is not implemented for ImageSampler +#[cfg(feature = "render")] fn compare_descriptors(a: &ImageSampler, b: &ImageSampler) -> bool { match (a, b) { (ImageSampler::Default, ImageSampler::Default) => true, @@ -165,6 +183,7 @@ impl Default for EguiSettings { scale_factor: 1.0, #[cfg(feature = "open_url")] default_open_url_target: None, + #[cfg(feature = "render")] sampler_descriptor: ImageSampler::Descriptor(ImageSamplerDescriptor { address_mode_u: ImageAddressMode::ClampToEdge, address_mode_v: ImageAddressMode::ClampToEdge, @@ -176,6 +195,7 @@ impl Default for EguiSettings { impl EguiSettings { /// Use nearest descriptor instead of linear. + #[cfg(feature = "render")] pub fn use_nearest_descriptor(&mut self) { self.sampler_descriptor = ImageSampler::Descriptor(ImageSamplerDescriptor { address_mode_u: ImageAddressMode::ClampToEdge, @@ -184,6 +204,7 @@ impl EguiSettings { }) } /// Use default image sampler, derived from the [`ImagePlugin`](bevy::render::texture::ImagePlugin) setup. + #[cfg(feature = "render")] pub fn use_bevy_descriptor(&mut self) { self.sampler_descriptor = ImageSampler::Default; } @@ -268,7 +289,8 @@ impl EguiClipboard { } /// Is used for storing Egui shapes and textures delta. -#[derive(Component, Clone, Default, Debug, ExtractComponent)] +#[derive(Component, Clone, Default, Debug)] +#[cfg_attr(feature = "render", derive(ExtractComponent))] pub struct EguiRenderOutput { /// Pairs of rectangles and paint commands. /// @@ -287,7 +309,8 @@ pub struct EguiOutput { } /// A component for storing `bevy_egui` context. -#[derive(Clone, Component, Default, ExtractComponent)] +#[derive(Clone, Component, Default)] +#[cfg_attr(feature = "render", derive(ExtractComponent))] pub struct EguiContext(egui::Context); impl EguiContext { @@ -335,6 +358,7 @@ pub struct EguiContexts<'w, 's> { ), With, >, + #[cfg(feature = "render")] user_textures: ResMut<'w, EguiUserTextures>, } @@ -459,17 +483,20 @@ impl<'w, 's> EguiContexts<'w, 's> { /// /// You'll want to pass a strong handle if a texture is used only in Egui and there are no /// handle copies stored anywhere else. + #[cfg(feature = "render")] pub fn add_image(&mut self, image: Handle) -> egui::TextureId { self.user_textures.add_image(image) } /// Removes the image handle and an Egui texture id associated with it. + #[cfg(feature = "render")] #[track_caller] pub fn remove_image(&mut self, image: &Handle) -> Option { self.user_textures.remove_image(image) } /// Returns an associated Egui texture id. + #[cfg(feature = "render")] #[must_use] #[track_caller] pub fn image_id(&self, image: &Handle) -> Option { @@ -483,11 +510,13 @@ pub struct EguiMousePosition(pub Option<(Entity, egui::Vec2)>); /// A resource for storing `bevy_egui` user textures. #[derive(Clone, Resource, Default, ExtractResource)] +#[cfg(feature = "render")] pub struct EguiUserTextures { textures: HashMap, u64>, last_texture_id: u64, } +#[cfg(feature = "render")] impl EguiUserTextures { /// Can accept either a strong or a weak handle. /// @@ -523,7 +552,8 @@ impl EguiUserTextures { } /// Stores physical size and scale factor, is used as a helper to calculate logical size. -#[derive(Component, Debug, Default, Clone, Copy, PartialEq, ExtractComponent)] +#[derive(Component, Debug, Default, Clone, Copy, PartialEq)] +#[cfg_attr(feature = "render", derive(ExtractComponent))] pub struct WindowSize { physical_width: f32, physical_height: f32, @@ -539,13 +569,15 @@ impl WindowSize { } } + /// Returns the width of the window. #[inline] - fn width(&self) -> f32 { + pub fn width(&self) -> f32 { self.physical_width / self.scale_factor } + /// Returns the height of the window. #[inline] - fn height(&self) -> f32 { + pub fn height(&self) -> f32 { self.physical_height / self.scale_factor } } @@ -586,17 +618,25 @@ impl Plugin for EguiPlugin { let world = &mut app.world; world.init_resource::(); + #[cfg(feature = "render")] world.init_resource::(); #[cfg(all(feature = "manage_clipboard", not(target_os = "android")))] world.init_resource::(); + #[cfg(feature = "render")] world.init_resource::(); world.init_resource::(); world.insert_resource(TouchId::default()); + #[cfg(feature = "render")] app.add_plugins(ExtractResourcePlugin::::default()); + #[cfg(feature = "render")] app.add_plugins(ExtractResourcePlugin::::default()); + #[cfg(feature = "render")] app.add_plugins(ExtractResourcePlugin::::default()); + #[cfg(feature = "render")] app.add_plugins(ExtractComponentPlugin::::default()); + #[cfg(feature = "render")] app.add_plugins(ExtractComponentPlugin::::default()); + #[cfg(feature = "render")] app.add_plugins(ExtractComponentPlugin::::default()); app.add_systems( @@ -636,10 +676,12 @@ impl Plugin for EguiPlugin { PostUpdate, process_output_system.in_set(EguiSet::ProcessOutput), ); + #[cfg(feature = "render")] app.add_systems( PostUpdate, update_egui_textures_system.after(EguiSet::ProcessOutput), ); + #[cfg(feature = "render")] app.add_systems(Last, free_egui_textures_system) .add_systems( Render, @@ -654,9 +696,11 @@ impl Plugin for EguiPlugin { render_systems::queue_pipelines_system.in_set(RenderSet::Queue), ); + #[cfg(feature = "render")] load_internal_asset!(app, EGUI_SHADER_HANDLE, "egui.wgsl", Shader::from_wgsl); } + #[cfg(feature = "render")] fn finish(&self, app: &mut App) { if let Ok(render_app) = app.get_sub_app_mut(RenderApp) { render_app @@ -704,10 +748,12 @@ pub struct EguiContextQuery { } /// Contains textures allocated and painted by Egui. +#[cfg(feature = "render")] #[derive(Resource, Deref, DerefMut, Default)] pub struct EguiManagedTextures(pub HashMap<(Entity, u64), EguiManagedTexture>); /// Represents a texture allocated and painted by Egui. +#[cfg(feature = "render")] pub struct EguiManagedTexture { /// Assets store handle. pub handle: Handle, @@ -733,6 +779,7 @@ pub fn setup_new_windows_system( } /// Updates textures painted by Egui. +#[cfg(feature = "render")] pub fn update_egui_textures_system( mut egui_render_output: Query<(Entity, &mut EguiRenderOutput), With>, mut egui_managed_textures: ResMut, @@ -792,6 +839,7 @@ pub fn update_egui_textures_system( } } +#[cfg(feature = "render")] fn free_egui_textures_system( mut egui_user_textures: ResMut, mut egui_render_output: Query<(Entity, &mut EguiRenderOutput), With>,