Skip to content

Commit

Permalink
Update the documentation, fix Windows, refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
mvlabat committed Mar 7, 2023
1 parent 48b84ed commit 71f9bd1
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 145 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,21 +44,21 @@ bevy_egui = "0.19"
```

```rust
use bevy::prelude::*;
use bevy::{prelude::*, window::PrimaryWindow};
use bevy_egui::{egui, EguiContext, EguiPlugin};

fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugin(EguiPlugin)
// Systems that create Egui widgets should be run during the `CoreStage::Update` stage,
// or after the `EguiSystem::BeginFrame` system (which belongs to the `CoreStage::PreUpdate` stage).
// Systems that create Egui widgets should be run during the `CoreSet::Update` set,
// or after the `EguiSet::BeginFrame` system (which belongs to the `CoreSet::PreUpdate` set).
.add_system(ui_example_system)
.run();
}

fn ui_example_system(mut egui_context: ResMut<EguiContext>) {
egui::Window::new("Hello").show(egui_context.ctx_mut(), |ui| {
fn ui_example_system(mut egui_ctx: Query<&mut EguiContext, With<PrimaryWindow>>) {
egui::Window::new("Hello").show(egui_ctx.single_mut().get_mut(), |ui| {
ui.label("world");
});
}
Expand Down
4 changes: 2 additions & 2 deletions examples/render_to_image_widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ struct MainPassCube;
struct CubePreviewImage(Handle<Image>);

fn setup(
mut egui_ctx: ResMut<EguiUserTextures>,
mut egui_user_textures: ResMut<EguiUserTextures>,
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
Expand Down Expand Up @@ -68,7 +68,7 @@ fn setup(
image.resize(size);

let image_handle = images.add(image);
egui_ctx.add_image(image_handle.clone());
egui_user_textures.add_image(image_handle.clone());
commands.insert_resource(CubePreviewImage(image_handle.clone()));

let cube_handle = meshes.add(Mesh::from(shape::Cube { size: 4.0 }));
Expand Down
4 changes: 2 additions & 2 deletions examples/side_panel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ fn setup_system(
fn update_camera_transform_system(
occupied_screen_space: Res<OccupiedScreenSpace>,
original_camera_transform: Res<OriginalCameraTransform>,
windows: Query<&Window>,
windows: Query<&Window, With<PrimaryWindow>>,
mut camera_query: Query<(&Projection, &mut Transform)>,
) {
let (camera_projection, mut transform) = match camera_query.get_single_mut() {
Expand All @@ -120,7 +120,7 @@ fn update_camera_transform_system(
let frustum_height = 2.0 * distance_to_target * (camera_projection.fov * 0.5).tan();
let frustum_width = frustum_height * camera_projection.aspect_ratio;

let window = windows.iter().next().unwrap();
let window = windows.single();

let left_taken = occupied_screen_space.left / window.width();
let right_taken = occupied_screen_space.right / window.width();
Expand Down
4 changes: 2 additions & 2 deletions examples/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugin(EguiPlugin)
// Systems that create Egui widgets should be run during the `CoreStage::Update` stage,
// or after the `EguiSystem::BeginFrame` system (which belongs to the `CoreStage::PreUpdate` stage).
// Systems that create Egui widgets should be run during the `CoreSet::Update` set,
// or after the `EguiSet::BeginFrame` system (which belongs to the `CoreSet::PreUpdate` set).
.add_system(ui_example_system)
.run();
}
Expand Down
4 changes: 2 additions & 2 deletions examples/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,12 @@ fn update_ui_scale_factor_system(
keyboard_input: Res<Input<KeyCode>>,
mut toggle_scale_factor: Local<Option<bool>>,
mut egui_settings: ResMut<EguiSettings>,
windows: Query<&Window>,
windows: Query<&Window, With<PrimaryWindow>>,
) {
if keyboard_input.just_pressed(KeyCode::Slash) || toggle_scale_factor.is_none() {
*toggle_scale_factor = Some(!toggle_scale_factor.unwrap_or(true));

if let Some(window) = windows.iter().next() {
if let Ok(window) = windows.get_single() {
let scale_factor = if toggle_scale_factor.unwrap() {
1.0
} else {
Expand Down
23 changes: 8 additions & 15 deletions src/egui_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,10 @@ use bevy::{
BlendComponent, BlendFactor, BlendOperation, BlendState, Buffer, BufferAddress,
BufferBindingType, BufferDescriptor, BufferUsages, ColorTargetState, ColorWrites,
Extent3d, FragmentState, FrontFace, IndexFormat, LoadOp, MultisampleState, Operations,
PipelineCache, PrimitiveState, PushConstantRange, RenderPassColorAttachment,
RenderPassDescriptor, RenderPipelineDescriptor, SamplerBindingType, Shader,
ShaderStages, ShaderType, SpecializedRenderPipeline, TextureDimension, TextureFormat,
TextureSampleType, TextureViewDimension, VertexBufferLayout, VertexFormat, VertexState,
VertexStepMode,
PipelineCache, PrimitiveState, RenderPassColorAttachment, RenderPassDescriptor,
RenderPipelineDescriptor, SamplerBindingType, Shader, ShaderStages, ShaderType,
SpecializedRenderPipeline, TextureDimension, TextureFormat, TextureSampleType,
TextureViewDimension, VertexBufferLayout, VertexFormat, VertexState, VertexStepMode,
},
renderer::{RenderContext, RenderDevice, RenderQueue},
texture::Image,
Expand Down Expand Up @@ -149,10 +148,7 @@ impl SpecializedRenderPipeline for EguiPipeline {
},
depth_stencil: None,
multisample: MultisampleState::default(),
push_constant_ranges: vec![PushConstantRange {
stages: ShaderStages::FRAGMENT,
range: 0..0,
}],
push_constant_ranges: vec![],
}
}
}
Expand Down Expand Up @@ -194,15 +190,12 @@ impl EguiNode {

impl Node for EguiNode {
fn update(&mut self, world: &mut World) {
let mut windows = world.query::<(&mut EguiContext, &mut EguiRenderOutput, &WindowSize)>();
let mut egui_contexts =
world.query::<(&mut EguiContext, &mut EguiRenderOutput, &WindowSize)>();

let Ok(
(mut egui_context, mut render_output, window_size),
) = windows.get_mut(world, self.window_entity) else {
// No egui context
let Ok((mut egui_context, mut render_output, window_size)) = egui_contexts.get_mut(world, self.window_entity) else {
return;
};

let window_size = *window_size;

let shapes = std::mem::take(&mut render_output.shapes);
Expand Down
109 changes: 52 additions & 57 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,21 @@
//! Here's a minimal usage example:
//!
//! ```no_run,rust
//! use bevy::prelude::*;
//! use bevy::{prelude::*, window::PrimaryWindow};
//! use bevy_egui::{egui, EguiContext, EguiPlugin};
//!
//! fn main() {
//! App::new()
//! .add_plugins(DefaultPlugins)
//! .add_plugin(EguiPlugin)
//! // Systems that create Egui widgets should be run during the `CoreStage::Update` stage,
//! // or after the `EguiSystem::BeginFrame` system (which belongs to the `CoreStage::PreUpdate` stage).
//! // Systems that create Egui widgets should be run during the `CoreSet::Update` set,
//! // or after the `EguiSet::BeginFrame` system (which belongs to the `CoreSet::PreUpdate` set).
//! .add_system(ui_example_system)
//! .run();
//! }
//!
//! fn ui_example_system(egui_context: Query<&EguiContext>) {
//! egui::Window::new("Hello").show(egui_context.iter().next().unwrap(), |ui| {
//! fn ui_example_system(mut egui_ctx: Query<&mut EguiContext, With<PrimaryWindow>>) {
//! egui::Window::new("Hello").show(egui_ctx.single_mut().get_mut(), |ui| {
//! ui.label("world");
//! });
//! }
Expand Down Expand Up @@ -70,7 +70,7 @@ use arboard::Clipboard;
use bevy::{
app::{App, Plugin},
asset::{AssetEvent, Assets, Handle},
ecs::{event::EventReader, system::ResMut},
ecs::{event::EventReader, query::WorldQuery, schedule::apply_system_buffers, system::ResMut},
input::InputSystem,
log,
prelude::{
Expand All @@ -84,8 +84,6 @@ use bevy::{
utils::HashMap,
window::Window,
};

use bevy::ecs::query::WorldQuery;
use std::borrow::Cow;
#[cfg(all(feature = "manage_clipboard", not(target_arch = "wasm32")))]
use std::cell::{RefCell, RefMut};
Expand All @@ -102,11 +100,11 @@ pub struct EguiSettings {
///
/// This setting can be used to force the UI to render in physical pixels regardless of DPI as follows:
/// ```rust
/// use bevy::prelude::*;
/// use bevy::{prelude::*, window::PrimaryWindow};
/// use bevy_egui::EguiSettings;
///
/// fn update_ui_scale_factor(mut egui_settings: ResMut<EguiSettings>, windows: Query<&Window>) {
/// if let Some(window) = windows.iter().next() {
/// fn update_ui_scale_factor(mut egui_settings: ResMut<EguiSettings>, windows: Query<&Window, With<PrimaryWindow>>) {
/// if let Ok(window) = windows.get_single() {
/// egui_settings.scale_factor = 1.0 / window.scale_factor();
/// }
/// }
Expand All @@ -130,7 +128,7 @@ impl Default for EguiSettings {

/// Is used for storing the input passed to Egui in the [`EguiRenderInputContainer`] resource.
///
/// It gets reset during the [`EguiSystem::ProcessInput`] system.
/// It gets reset during the [`EguiSet::ProcessInput`] system.
#[derive(Component, Clone, Debug, Default, Deref, DerefMut)]
pub struct EguiInput(pub egui::RawInput);

Expand Down Expand Up @@ -211,7 +209,7 @@ impl EguiClipboard {
pub struct EguiRenderOutput {
/// Pairs of rectangles and paint commands.
///
/// The field gets populated during the [`EguiSystem::ProcessOutput`] system in the [`CoreStage::PostUpdate`] and reset during `EguiNode::update`.
/// The field gets populated during the [`EguiSet::ProcessOutput`] system (belonging to [`CoreІуе::PostUpdate`]) and reset during `EguiNode::update`.
pub shapes: Vec<egui::epaint::ClippedShape>,

/// The change in egui textures since last frame.
Expand All @@ -221,7 +219,7 @@ pub struct EguiRenderOutput {
/// Is used for storing Egui output.
#[derive(Component, Clone, Default)]
pub struct EguiOutput {
/// The field gets updated during the [`EguiSystem::ProcessOutput`] system in the [`CoreStage::PostUpdate`].
/// The field gets updated during the [`EguiSet::ProcessOutput`] system (belonging to [`CoreStage::PostUpdate`]).
pub platform_output: egui::PlatformOutput,
}

Expand Down Expand Up @@ -263,20 +261,13 @@ impl EguiContext {
pub struct EguiMousePosition(pub Option<(Entity, egui::Vec2)>);

/// A resource for storing `bevy_egui` user textures.
#[derive(Clone, Resource)]
#[derive(Clone, Resource, Default)]
pub struct EguiUserTextures {
textures: HashMap<Handle<Image>, u64>,
last_texture_id: u64,
}

impl EguiUserTextures {
fn new() -> Self {
Self {
textures: Default::default(),
last_texture_id: 0,
}
}

/// Can accept either a strong or a weak handle.
///
/// You may want to pass a weak handle if you control removing texture assets in your
Expand Down Expand Up @@ -345,76 +336,76 @@ pub mod node {
}

#[derive(SystemSet, Clone, Hash, Debug, Eq, PartialEq)]
/// The names of `bevy_egui` startup systems.
pub enum EguiStartupSystem {
/// The `bevy_egui` plugin startup system sets.
pub enum EguiStartupSet {
/// Initializes Egui contexts for available windows.
InitContexts,
}

/// The names of egui systems.
/// The `bevy_egui` plugin system sets.
#[derive(SystemSet, Clone, Hash, Debug, Eq, PartialEq)]
pub enum EguiSystem {
pub enum EguiSet {
/// Initializes Egui contexts for newly created windows.
InitContexts,
/// Reads Egui inputs (keyboard, mouse, etc) and writes them into the [`EguiInput`] resource.
///
/// To modify the input, you can hook your system like this:
///
/// `system.after(EguiSystem::ProcessInput).before(EguiSystem::BeginFrame)`.
/// `system.after(EguiSet::ProcessInput).before(EguiSet::BeginFrame)`.
ProcessInput,
/// Begins the `egui` frame
/// Begins the `egui` frame.
BeginFrame,
/// Processes the [`EguiOutput`] resource
/// Processes the [`EguiOutput`] resource.
ProcessOutput,
}

impl Plugin for EguiPlugin {
fn build(&self, app: &mut App) {
let world = &mut app.world;
world.insert_resource(EguiSettings::default());
world.insert_resource(EguiManagedTextures::default());
world.init_resource::<EguiSettings>();
world.init_resource::<EguiManagedTextures>();
#[cfg(feature = "manage_clipboard")]
world.insert_resource(EguiClipboard::default());
world.insert_resource(EguiUserTextures::new());
world.insert_resource(EguiMousePosition::default());

app.add_startup_system(
init_contexts_startup_system
.in_set(EguiStartupSystem::InitContexts)
.in_base_set(StartupSet::PreStartup),
);

// TODO where is the correct place for this?
// Probably shouldn't need both add_startup_system & add_system version.
app.add_startup_system(
setup_new_windows_system
.in_set(EguiStartupSystem::InitContexts)
world.init_resource::<EguiClipboard>();
world.init_resource::<EguiUserTextures>();
world.init_resource::<EguiMousePosition>();

app.add_startup_systems(
(
setup_new_windows_system,
apply_system_buffers,
init_contexts_startup_system,
)
.chain()
.in_set(EguiStartupSet::InitContexts)
.in_base_set(StartupSet::PreStartup),
);
app.add_system(
setup_new_windows_system
.in_set(EguiStartupSystem::InitContexts)
.in_base_set(StartupSet::PreStartup),
app.add_systems(
(setup_new_windows_system, apply_system_buffers)
.chain()
.in_set(EguiSet::InitContexts)
.in_base_set(CoreSet::PreUpdate),
);

app.add_system(
process_input_system
.in_set(EguiSystem::ProcessInput)
.in_set(EguiSet::ProcessInput)
.after(InputSystem)
.after(EguiSet::InitContexts)
.in_base_set(CoreSet::PreUpdate),
);
app.add_system(
begin_frame_system
.in_set(EguiSystem::BeginFrame)
.after(EguiSystem::ProcessInput)
.in_set(EguiSet::BeginFrame)
.after(EguiSet::ProcessInput)
.in_base_set(CoreSet::PreUpdate),
);
app.add_system(
process_output_system
.in_set(EguiSystem::ProcessOutput)
.in_set(EguiSet::ProcessOutput)
.in_base_set(CoreSet::PostUpdate),
);
app.add_system(
update_egui_textures_system
.after(EguiSystem::ProcessOutput)
.after(EguiSet::ProcessOutput)
.in_base_set(CoreSet::PostUpdate),
);
app.add_system(free_egui_textures_system.in_base_set(CoreSet::Last));
Expand Down Expand Up @@ -453,15 +444,19 @@ impl Plugin for EguiPlugin {
#[world_query(mutable)]
pub struct EguiContextQuery {
/// Window entity.
pub window: Entity,
pub window_entity: Entity,
/// Egui context associated with the window.
pub ctx: &'static mut EguiContext,
/// Encapsulates [`egui::RawInput`].
pub egui_input: &'static mut EguiInput,
/// Egui shapes and textures delta.
pub render_output: &'static mut EguiRenderOutput,
/// Encapsulates [`egui::PlatformOutput`].
pub egui_output: &'static mut EguiOutput,
/// Stores physical size of the window and its scale factor.
pub window_size: &'static mut WindowSize,
/// [`Window`] component.
pub window: &'static mut Window,
}

/// Contains textures allocated and painted by Egui.
Expand Down
2 changes: 1 addition & 1 deletion src/render_systems.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ pub fn extract_egui_render_data_system(
) {
commands.insert_resource(ExtractedEguiSettings(egui_settings.clone()));
for context in contexts.iter() {
commands.get_or_spawn(context.window).insert((
commands.get_or_spawn(context.window_entity).insert((
context.ctx.clone(),
context.render_output.clone(),
*context.window_size,
Expand Down
Loading

0 comments on commit 71f9bd1

Please sign in to comment.