Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 37 additions & 32 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "bevy_egui"
version = "0.38.1"
rust-version = "1.88.0"
version = "0.39.0"
rust-version = "1.89.0"
authors = ["vladbat00 <[email protected]>"]
description = "A plugin for Egui integration into Bevy"
license = "MIT"
Expand Down Expand Up @@ -77,27 +77,27 @@ name = "ui"
required-features = ["render"]
[[example]]
name = "render_egui_to_image"
required-features = ["picking", "render", "bevy/bevy_gizmos"]
required-features = ["picking", "render", "bevy/bevy_gizmos", "bevy/bevy_gizmos_render"]
[[example]]
name = "file_browse"
required-features = ["render"]

[dependencies]
egui = { version = "0.33", default-features = false }
bevy_a11y = { version = "0.17.0", optional = true }
bevy_app = { version = "0.17.0" }
bevy_camera = { version = "0.17.0" }
bevy_derive = { version = "0.17.0" }
bevy_ecs = { version = "0.17.0" }
bevy_input = { version = "0.17.0" }
bevy_log = { version = "0.17.0" }
bevy_math = { version = "0.17.0" }
bevy_platform = { version = "0.17.0" }
bevy_reflect = { version = "0.17.0" }
bevy_time = { version = "0.17.0" }
bevy_window = { version = "0.17.0" }
bevy_winit = { version = "0.17.0" }
bevy_utils = { version = "0.17.0", features = ["debug"] }
bevy_a11y = { version = "0.18.0-rc.1", optional = true }
bevy_app = { version = "0.18.0-rc.1" }
bevy_camera = { version = "0.18.0-rc.1" }
bevy_derive = { version = "0.18.0-rc.1" }
bevy_ecs = { version = "0.18.0-rc.1" }
bevy_input = { version = "0.18.0-rc.1", features = ["gamepad"] }
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like an issue on the Bevy end that the import isn't feature-gated:

error[E0432]: unresolved import `bevy_input::gamepad`
  --> /home/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bevy_input_focus-0.18.0-rc.1/src/lib.rs:37:18
   |
37 | use bevy_input::{gamepad::GamepadButtonChangedEvent, keyboard::KeyboardInput, mouse::MouseWheel};
   |                  ^^^^^^^ could not find `gamepad` in `bevy_input`
   |
note: found an item that was configured out
  --> /home/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bevy_input-0.18.0-rc.1/src/lib.rs:26:9
   |
25 | #[cfg(feature = "gamepad")]
   |       ------------------- the item is gated behind the `gamepad` feature
26 | pub mod gamepad;
   |         ^^^^^^^

Aaaand it's already fixed here: bevyengine/bevy#22177
So let's remove the gamepad feature requirement once the next version is available.

bevy_log = { version = "0.18.0-rc.1" }
bevy_math = { version = "0.18.0-rc.1" }
bevy_platform = { version = "0.18.0-rc.1" }
bevy_reflect = { version = "0.18.0-rc.1" }
bevy_time = { version = "0.18.0-rc.1" }
bevy_window = { version = "0.18.0-rc.1" }
bevy_winit = { version = "0.18.0-rc.1" }
bevy_utils = { version = "0.18.0-rc.1", features = ["debug"] }
winit = { version = "0.30", default-features = false }

# `open_url` feature
Expand All @@ -106,23 +106,23 @@ webbrowser = { version = "1.0.1", optional = true }
# `render` feature
bytemuck = { version = "1", optional = true }

bevy_asset = { version = "0.17.0", optional = true }
bevy_core_pipeline = { version = "0.17.0", optional = true }
bevy_image = { version = "0.17.0", features = ["zstd_rust"], optional = true }
bevy_mesh = { version = "0.17.0", optional = true }
bevy_render = { version = "0.17.0", optional = true }
bevy_color = { version = "0.17.0", optional = true }
bevy_shader = { version = "0.17.0", optional = true }
bevy_transform = { version = "0.17.0", optional = true }
encase = { version = "0.11", optional = true }
bevy_asset = { version = "0.18.0-rc.1", optional = true }
bevy_core_pipeline = { version = "0.18.0-rc.1", optional = true }
bevy_image = { version = "0.18.0-rc.1", features = ["zstd_rust"], optional = true }
bevy_mesh = { version = "0.18.0-rc.1", optional = true }
bevy_render = { version = "0.18.0-rc.1", optional = true }
bevy_color = { version = "0.18.0-rc.1", optional = true }
bevy_shader = { version = "0.18.0-rc.1", optional = true }
bevy_transform = { version = "0.18.0-rc.1", optional = true }
encase = { version = "0.12", optional = true }
itertools = { version = "0.14", optional = true }
wgpu-types = { version = "26.0", optional = true }
wgpu-types = { version = "27.0", optional = true }

# `bevy_ui` feature
bevy_ui_render = { version = "0.17.0", optional = true }
bevy_ui_render = { version = "0.18.0-rc.1", optional = true }

# `picking` feature
bevy_picking = { version = "0.17.0", optional = true, features = ["bevy_mesh_picking_backend"] }
bevy_picking = { version = "0.18.0-rc.1", optional = true, features = ["mesh_picking"] }

# `manage_clipboard` feature
[target.'cfg(not(any(target_arch = "wasm32", target_os = "android")))'.dependencies]
Expand All @@ -131,17 +131,22 @@ thread_local = { version = "1.1.0", optional = true }

[dev-dependencies]
version-sync = "0.9.5"
bevy = { version = "0.17.0", default-features = false, features = [
bevy = { version = "0.18.0-rc.1", default-features = false, features = [
"bevy_log",
"bevy_asset",
"bevy_core_pipeline",
"bevy_pbr",
"bevy_mesh_picking_backend",
"mesh_picking",
"bevy_sprite",
"bevy_sprite_render",
"bevy_text",
"bevy_window",
"bevy_winit",
"mouse",
"keyboard",
"gamepad",
"touch",
"gestures",
"android-game-activity",
"png",
"std",
Expand All @@ -153,7 +158,7 @@ bevy = { version = "0.17.0", default-features = false, features = [
egui = { version = "0.33", default-features = false, features = ["bytemuck"] }

[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
bevy = { version = "0.17.0", default-features = false, features = ["accesskit_unix"] }
bevy = { version = "0.18.0-rc.1", default-features = false, features = ["accesskit_unix"] }

[target.'cfg(not(any(target_os = "android", target_os = "ios", target_arch = "wasm32")))'.dev-dependencies]
rfd = "0.15"
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ Here's a minimal usage example:
```toml
# Cargo.toml
[dependencies]
bevy = "0.17.0"
bevy_egui = "0.38.1"
bevy = "0.18.0-rc.1"
bevy_egui = "0.39.0"
```

```rust
Expand Down
10 changes: 5 additions & 5 deletions examples/color_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,9 @@ fn setup_system(
Camera2d,
Camera {
order: 1,
target: RenderTarget::Image(mesh_image_handle.clone().into()),
..default()
},
RenderTarget::Image(mesh_image_handle.clone().into()),
MeshImageEguiContext,
EguiMultipassSchedule::new(RenderToMeshImageContextPass),
));
Expand All @@ -122,9 +122,9 @@ fn setup_system(
Camera2d,
Camera {
order: 2,
target: RenderTarget::Image(egui_texture_image_handle.clone().into()),
..default()
},
RenderTarget::Image(egui_texture_image_handle.clone().into()),
EguiTextureImageEguiContext,
EguiMultipassSchedule::new(RenderToEguiTextureImageContextPass),
));
Expand All @@ -142,7 +142,7 @@ fn update_image_size_system(
mut images: ResMut<Assets<bevy::image::Image>>,
mut meshes: ResMut<Assets<bevy::prelude::Mesh>>,
mut materials: ResMut<Assets<ColorMaterial>>,
egui_camera_query: Query<&Camera, With<EguiContext>>,
egui_render_target_query: Query<&RenderTarget, With<EguiContext>>,
egui_mesh: Single<(&Mesh2d, &MeshMaterial2d<ColorMaterial>, &mut Transform)>,
) {
if *prev_window_size == window.physical_size()
Expand All @@ -156,8 +156,8 @@ fn update_image_size_system(

let new_height = window.physical_height() - app_state.top_panel_height;

for egui_camera in egui_camera_query.iter() {
let Some(image_handle) = egui_camera.target.as_image() else {
for egui_render_target in egui_render_target_query.iter() {
let Some(image_handle) = egui_render_target.as_image() else {
continue;
};

Expand Down
2 changes: 1 addition & 1 deletion examples/paint_callback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,9 +243,9 @@ fn setup_worldspace_system(
.spawn(Camera2d)
.insert(Camera {
order: 1,
target: RenderTarget::Image(output_texture.into()),
..default()
})
.insert(RenderTarget::Image(output_texture.into()))
.insert(EguiMultipassSchedule::new(WorldspaceContextPass));
}

Expand Down
6 changes: 2 additions & 4 deletions examples/render_egui_to_image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,8 @@ fn setup_system(
.spawn((
Camera3d::default(),
RenderLayers::none(),
Camera {
target: RenderTarget::Image(image.clone().into()),
..default()
},
Camera::default(),
RenderTarget::Image(image.clone().into()),
EguiMultipassSchedule::new(WorldspaceContextPass),
))
.id();
Expand Down
2 changes: 1 addition & 1 deletion examples/render_to_image_widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,10 @@ fn setup_system(
Camera {
// render before the "main pass" camera
order: -1,
target: RenderTarget::Image(image_handle.into()),
clear_color: ClearColorConfig::Custom(Color::srgba(1.0, 1.0, 1.0, 0.0)),
..default()
},
RenderTarget::Image(image_handle.into()),
Transform::from_translation(Vec3::new(0.0, 0.0, 15.0))
.looking_at(Vec3::default(), Vec3::Y),
))
Expand Down
6 changes: 2 additions & 4 deletions examples/two_windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,8 @@ fn create_new_window_system(
.id();
commands.spawn((
Camera3d::default(),
Camera {
target: RenderTarget::Window(WindowRef::Entity(second_window_id)),
..Default::default()
},
Camera::default(),
RenderTarget::Window(WindowRef::Entity(second_window_id)),
EguiMultipassSchedule::new(SecondWindowContextPass),
Transform::from_xyz(6.0, 0.0, 0.0).looking_at(Vec3::ZERO, Vec3::Y),
));
Expand Down
4 changes: 2 additions & 2 deletions src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ impl<'w, D: QueryData, F: QueryFilter> QueryHelper<'w> for Query<'_, 'w, D, F> {
fn get_some(&self, entity: Entity) -> Option<ROQueryItem<'_, 'w, Self::QueryData>> {
match self.get(entity) {
Ok(item) => Some(item),
Err(QueryEntityError::EntityDoesNotExist(_)) => None,
Err(QueryEntityError::NotSpawned(_)) => None,
err => {
err.unwrap();
unreachable!()
Expand All @@ -267,7 +267,7 @@ impl<'w, D: QueryData, F: QueryFilter> QueryHelper<'w> for Query<'_, 'w, D, F> {
fn get_some_mut(&mut self, entity: Entity) -> Option<QueryItem<'_, 'w, Self::QueryData>> {
match self.get_mut(entity) {
Ok(item) => Some(item),
Err(QueryEntityError::EntityDoesNotExist(_)) => None,
Err(QueryEntityError::NotSpawned(_)) => None,
err => {
err.unwrap();
unreachable!()
Expand Down
14 changes: 9 additions & 5 deletions src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use bevy_input::{
use bevy_log::{self as log};
use bevy_time::{Real, Time};
use bevy_window::{CursorMoved, FileDragAndDrop, Ime, Window};
use bevy_winit::WinitUserEvent;
use egui::Modifiers;

/// Cached pointer position, used to populate [`egui::Event::PointerButton`] messages.
Expand Down Expand Up @@ -169,12 +170,15 @@ impl WindowToEguiContextMap {
/// Adds a context to the map on creation.
pub fn on_egui_context_added_system(
mut res: ResMut<Self>,
added_contexts: Query<(Entity, &bevy_camera::Camera, &mut EguiContext), Added<EguiContext>>,
added_contexts: Query<
(Entity, &bevy_camera::RenderTarget, &mut EguiContext),
Added<EguiContext>,
>,
primary_window: Query<Entity, With<bevy_window::PrimaryWindow>>,
event_loop_proxy: Res<bevy_winit::EventLoopProxyWrapper<bevy_winit::WakeUp>>,
event_loop_proxy: Res<bevy_winit::EventLoopProxyWrapper>,
) {
for (egui_context_entity, camera, mut egui_context) in added_contexts {
if let bevy_camera::RenderTarget::Window(window_ref) = camera.target
for (egui_context_entity, render_target, mut egui_context) in added_contexts {
if let bevy_camera::RenderTarget::Window(window_ref) = render_target
&& let Some(window_ref) = window_ref.normalize(primary_window.single().ok())
{
res.window_to_contexts
Expand All @@ -193,7 +197,7 @@ impl WindowToEguiContextMap {
// to support non-zero wake-ups as well.
if repaint_info.delay.is_zero() {
log::trace!("Sending the WakeUp message");
let _ = message_loop_proxy.send_event(bevy_winit::WakeUp);
let _ = message_loop_proxy.send_event(WinitUserEvent::WakeUp);
}
});
}
Expand Down
6 changes: 2 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,10 +284,8 @@ pub struct EguiPlugin {
/// commands.spawn((
/// EguiMultipassSchedule::new(SecondWindowContextPass),
/// Camera3d::default(),
/// Camera {
/// target: RenderTarget::Window(WindowRef::Entity(second_window_id)),
/// ..Default::default()
/// },
/// Camera::default(),
/// RenderTarget::Window(WindowRef::Entity(second_window_id)),
/// ));
/// }
///
Expand Down
13 changes: 8 additions & 5 deletions src/picking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{
input::{EguiContextPointerPosition, HoveredNonWindowEguiContext},
};
use bevy_asset::Assets;
use bevy_camera::{Camera, NormalizedRenderTarget};
use bevy_camera::{Camera, NormalizedRenderTarget, RenderTarget};
use bevy_ecs::{
change_detection::Res,
component::Component,
Expand Down Expand Up @@ -35,7 +35,7 @@ pub fn handle_move_system(
event: On<Pointer<Move>>,
mut mesh_ray_cast: MeshRayCast,
mut egui_pointers: Query<&mut EguiContextPointerPosition>,
egui_contexts: Query<(&Camera, &GlobalTransform), With<EguiContext>>,
egui_contexts: Query<(&Camera, &GlobalTransform, &RenderTarget), With<EguiContext>>,
pickable_egui_context_query: Query<(&PickableEguiContext, AnyOf<(&Mesh2d, &Mesh3d)>)>,
primary_window_query: Query<Entity, With<PrimaryWindow>>,
meshes: Res<Assets<Mesh>>,
Expand All @@ -46,7 +46,8 @@ pub fn handle_move_system(

// Ray-cast attempting to find the context again.
// TODO: track https://github.com/bevyengine/bevy/issues/19883 - once it's fixed, we can avoid the double-work with ray-casting again.
let Ok((context_camera, global_transform)) = egui_contexts.get(event.hit.camera) else {
let Ok((context_camera, global_transform, render_target)) = egui_contexts.get(event.hit.camera)
else {
return Ok(());
};
let settings = MeshRayCastSettings {
Expand All @@ -58,6 +59,7 @@ pub fn handle_move_system(
&primary_window_query,
context_camera,
global_transform,
render_target,
&bevy_picking::pointer::PointerLocation {
location: Some(event.pointer_location.clone()),
},
Expand All @@ -80,7 +82,7 @@ pub fn handle_move_system(

// At this point, we expect that the context exists, since we checked that with the ray cast filter.
let (&PickableEguiContext(context), mesh) = pickable_egui_context_query.get(hit_entity)?;
let (egui_mesh_camera, _) = egui_contexts.get(context)?;
let (egui_mesh_camera, _, _) = egui_contexts.get(context)?;

// Read triangle indices and the respective UVs of the mesh.
let handle = match mesh {
Expand Down Expand Up @@ -179,10 +181,11 @@ fn make_ray(
primary_window_entity: &Query<Entity, With<PrimaryWindow>>,
camera: &Camera,
camera_tfm: &GlobalTransform,
render_target: &RenderTarget,
pointer_loc: &bevy_picking::pointer::PointerLocation,
) -> Option<Ray3d> {
let pointer_loc = pointer_loc.location()?;
if !pointer_loc.is_in_viewport(camera, primary_window_entity) {
if !pointer_loc.is_in_viewport(camera, render_target, primary_window_entity) {
return None;
}
let mut viewport_pos = pointer_loc.position;
Expand Down
Loading