From 66bbed345f7a2e53a66dd1ae4d8572dc1c80df7a Mon Sep 17 00:00:00 2001 From: DGriffin91 <33357138+DGriffin91@users.noreply.github.com> Date: Sat, 30 Jul 2022 10:48:40 -0700 Subject: [PATCH] Update to Bevy 0.8 (#111) * update to work with bevy main * update to latest bevy main * Refactor the side_panel example, fix linters * dont run EguiNode when there is no window * add bevy_asset feature as it is now optional * Update to the released version Co-authored-by: mvlabat --- Cargo.toml | 4 ++-- examples/side_panel.rs | 11 +++++++---- examples/two_windows.rs | 11 ++--------- examples/ui.rs | 8 +------- src/egui.wgsl | 34 +++++++++++++++++----------------- src/egui_node.rs | 38 ++++++++++++++++++++++---------------- src/lib.rs | 4 ++-- src/render_systems.rs | 27 ++++++++++++++------------- src/systems.rs | 15 +++++++-------- 9 files changed, 74 insertions(+), 78 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 032eedd67..9cdfb2261 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ manage_clipboard = ["arboard", "thread_local"] open_url = ["webbrowser"] [dependencies] -bevy = { version = "0.7", default-features = false, features = ["bevy_render", "bevy_core_pipeline"] } +bevy = { version = "0.8", default-features = false, features = ["bevy_render", "bevy_core_pipeline", "bevy_asset"] } egui = { version = "0.18", features = ["bytemuck"] } webbrowser = { version = "0.7", optional = true } @@ -31,7 +31,7 @@ thread_local = { version = "1.1.0", optional = true } [dev-dependencies] once_cell = "1.9.0" version-sync = "0.9.2" -bevy = { version = "0.7", default-features = false, features = [ +bevy = { version = "0.8", default-features = false, features = [ "x11", "png", "bevy_pbr", diff --git a/examples/side_panel.rs b/examples/side_panel.rs index fc463b30d..946ceb04e 100644 --- a/examples/side_panel.rs +++ b/examples/side_panel.rs @@ -1,4 +1,4 @@ -use bevy::{prelude::*, window::PresentMode, winit::WinitSettings}; +use bevy::{prelude::*, render::camera::Projection, window::PresentMode, winit::WinitSettings}; use bevy_egui::{egui, EguiContext, EguiPlugin}; #[derive(Default)] @@ -99,7 +99,7 @@ fn setup_system( Transform::from_translation(camera_pos).looking_at(CAMERA_TARGET, Vec3::Y); commands.insert_resource(OriginalCameraTransform(camera_transform)); - commands.spawn_bundle(PerspectiveCameraBundle { + commands.spawn_bundle(Camera3dBundle { transform: camera_transform, ..Default::default() }); @@ -109,9 +109,12 @@ fn update_camera_transform_system( occupied_screen_space: Res, original_camera_transform: Res, windows: Res, - mut camera_query: Query<(&PerspectiveProjection, &mut Transform)>, + mut camera_query: Query<(&Projection, &mut Transform)>, ) { - let (camera_projection, mut transform) = camera_query.get_single_mut().unwrap(); + let (camera_projection, mut transform) = match camera_query.get_single_mut() { + Ok((Projection::Perspective(projection), transform)) => (projection, transform), + _ => unreachable!(), + }; let distance_to_target = (CAMERA_TARGET - original_camera_transform.0.translation).length(); let frustum_height = 2.0 * distance_to_target * (camera_projection.fov * 0.5).tan(); diff --git a/examples/two_windows.rs b/examples/two_windows.rs index d72aa5ffd..6d9c0e91f 100644 --- a/examples/two_windows.rs +++ b/examples/two_windows.rs @@ -2,7 +2,6 @@ use bevy::{ prelude::*, render::{camera::RenderTarget, render_graph::RenderGraph, RenderApp}, window::{CreateWindow, PresentMode, WindowId}, - winit::WinitSettings, }; use bevy_egui::{EguiContext, EguiPlugin}; use once_cell::sync::Lazy; @@ -16,12 +15,6 @@ struct Images { fn main() { let mut app = App::new(); app.add_plugins(DefaultPlugins) - // Optimal power saving and present mode settings for desktop apps. - .insert_resource(WinitSettings::desktop_app()) - .insert_resource(WindowDescriptor { - present_mode: PresentMode::Mailbox, - ..Default::default() - }) .add_plugin(EguiPlugin) .init_resource::() .add_startup_system(load_assets) @@ -52,13 +45,13 @@ fn create_new_window(mut create_window_events: EventWriter, mut co descriptor: WindowDescriptor { width: 800., height: 600., - present_mode: PresentMode::Mailbox, + present_mode: PresentMode::AutoVsync, title: "Second window".to_string(), ..Default::default() }, }); // second window camera - commands.spawn_bundle(PerspectiveCameraBundle { + commands.spawn_bundle(Camera3dBundle { camera: Camera { target: RenderTarget::Window(*SECOND_WINDOW_ID), ..Default::default() diff --git a/examples/ui.rs b/examples/ui.rs index 4d320523e..22f3fb3b7 100644 --- a/examples/ui.rs +++ b/examples/ui.rs @@ -1,4 +1,4 @@ -use bevy::{prelude::*, window::PresentMode, winit::WinitSettings}; +use bevy::prelude::*; use bevy_egui::{egui, EguiContext, EguiPlugin, EguiSettings}; struct Images { @@ -24,12 +24,6 @@ fn main() { App::new() .insert_resource(ClearColor(Color::rgb(0.0, 0.0, 0.0))) .insert_resource(Msaa { samples: 4 }) - // Optimal power saving and present mode settings for desktop apps. - .insert_resource(WinitSettings::desktop_app()) - .insert_resource(WindowDescriptor { - present_mode: PresentMode::Mailbox, - ..Default::default() - }) .init_resource::() .add_plugins(DefaultPlugins) .add_plugin(EguiPlugin) diff --git a/src/egui.wgsl b/src/egui.wgsl index 06c4b1415..230670ef2 100644 --- a/src/egui.wgsl +++ b/src/egui.wgsl @@ -1,23 +1,23 @@ struct Transform { - scale: vec2; - translation: vec2; -}; + scale: vec2, + translation: vec2, +} struct VertexInput { - [[location(0)]] position: vec2; - [[location(1)]] uv: vec2; - [[location(2)]] color: vec4; -}; + @location(0) position: vec2, + @location(1) uv: vec2, + @location(2) color: vec4, +} struct VertexOutput { - [[builtin(position)]] position: vec4; - [[location(0)]] color: vec4; - [[location(1)]] uv: vec2; -}; + @builtin(position) position: vec4, + @location(0) color: vec4, + @location(1) uv: vec2, +} -[[group(0), binding(0)]] var transform: Transform; -[[group(1), binding(0)]] var image_texture: texture_2d; -[[group(1), binding(1)]] var image_sampler: sampler; +@group(0) @binding(0) var transform: Transform; +@group(1) @binding(0) var image_texture: texture_2d; +@group(1) @binding(1) var image_sampler: sampler; fn linear_from_srgb(srgb: vec3) -> vec3 { let cutoff = srgb < vec3(0.04045); @@ -26,15 +26,15 @@ fn linear_from_srgb(srgb: vec3) -> vec3 { return select(higher, lower, cutoff); } -[[stage(vertex)]] +@vertex fn vs_main(in: VertexInput) -> VertexOutput { let position = in.position * transform.scale + transform.translation; let color = vec4(linear_from_srgb(in.color.rgb), in.color.a); return VertexOutput(vec4(position, 0.0, 1.0), color, in.uv); } -[[stage(fragment)]] -fn fs_main(in: VertexOutput) -> [[location(0)]] vec4 { +@fragment +fn fs_main(in: VertexOutput) -> @location(0) vec4 { let texture_color = textureSample(image_texture, image_sampler, in.uv); // This assumes that texture images are not premultiplied. let color = in.color * vec4(texture_color.rgb * texture_color.a, texture_color.a); diff --git a/src/egui_node.rs b/src/egui_node.rs index 96f454ea3..372f48fe3 100644 --- a/src/egui_node.rs +++ b/src/egui_node.rs @@ -4,12 +4,12 @@ use bevy::{ render::{ render_graph::{Node, NodeRunError, RenderGraphContext}, render_resource::{ - std140::AsStd140, BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, - BindingType, BlendComponent, BlendFactor, BlendOperation, BlendState, Buffer, - BufferAddress, BufferBindingType, BufferDescriptor, BufferSize, BufferUsages, - ColorTargetState, ColorWrites, Extent3d, FrontFace, IndexFormat, LoadOp, - MultisampleState, Operations, PipelineLayoutDescriptor, PrimitiveState, - RawFragmentState, RawRenderPipelineDescriptor, RawVertexBufferLayout, RawVertexState, + BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType, + BlendComponent, BlendFactor, BlendOperation, BlendState, Buffer, BufferAddress, + BufferBindingType, BufferDescriptor, BufferUsages, ColorTargetState, ColorWrites, + Extent3d, FrontFace, IndexFormat, LoadOp, MultisampleState, Operations, + PipelineLayoutDescriptor, PrimitiveState, RawFragmentState, + RawRenderPipelineDescriptor, RawVertexBufferLayout, RawVertexState, RenderPassColorAttachment, RenderPassDescriptor, RenderPipeline, SamplerBindingType, ShaderModuleDescriptor, ShaderSource, ShaderStages, TextureDimension, TextureFormat, TextureSampleType, TextureViewDimension, VertexAttribute, VertexFormat, VertexStepMode, @@ -21,6 +21,8 @@ use bevy::{ window::WindowId, }; +use bevy::render::render_resource::ShaderType; + use crate::render_systems::{ EguiTexture, EguiTextureBindGroups, EguiTransform, EguiTransforms, ExtractedEguiContext, ExtractedEguiSettings, ExtractedRenderOutput, ExtractedWindowSizes, @@ -38,7 +40,7 @@ impl FromWorld for EguiPipeline { let render_device = world.get_resource::().unwrap(); let shader_source = ShaderSource::Wgsl(include_str!("egui.wgsl").into()); - let shader_module = render_device.create_shader_module(&ShaderModuleDescriptor { + let shader_module = render_device.create_shader_module(ShaderModuleDescriptor { label: Some("egui shader"), source: shader_source, }); @@ -52,9 +54,7 @@ impl FromWorld for EguiPipeline { ty: BindingType::Buffer { ty: BufferBindingType::Uniform, has_dynamic_offset: true, - min_binding_size: Some( - BufferSize::new(EguiTransform::std140_size_static() as u64).unwrap(), - ), + min_binding_size: Some(EguiTransform::min_size()), }, count: None, }], @@ -119,7 +119,7 @@ impl FromWorld for EguiPipeline { fragment: Some(RawFragmentState { module: &shader_module, entry_point: "fs_main", - targets: &[ColorTargetState { + targets: &[Some(ColorTargetState { format: TextureFormat::bevy_default(), blend: Some(BlendState { color: BlendComponent { @@ -134,7 +134,7 @@ impl FromWorld for EguiPipeline { }, }), write_mask: ColorWrites::ALL, - }], + })], }), primitive: PrimitiveState { front_face: FrontFace::Cw, @@ -306,6 +306,14 @@ impl Node for EguiNode { render_context: &mut RenderContext, world: &World, ) -> Result<(), NodeRunError> { + let extracted_windows = &world.get_resource::().unwrap().windows; + let extracted_window = + if let Some(extracted_window) = extracted_windows.get(&self.window_id) { + extracted_window + } else { + return Ok(()); // No window + }; + let egui_shaders = world.get_resource::().unwrap(); let render_queue = world.get_resource::().unwrap(); @@ -324,8 +332,6 @@ impl Node for EguiNode { let egui_transforms = world.get_resource::().unwrap(); - let extracted_window = - &world.get_resource::().unwrap().windows[&self.window_id]; let swap_chain_texture = extracted_window.swap_chain_texture.as_ref().unwrap(); let mut render_pass = @@ -333,14 +339,14 @@ impl Node for EguiNode { .command_encoder .begin_render_pass(&RenderPassDescriptor { label: Some("egui render pass"), - color_attachments: &[RenderPassColorAttachment { + color_attachments: &[Some(RenderPassColorAttachment { view: swap_chain_texture, resolve_target: None, ops: Operations { load: LoadOp::Load, store: true, }, - }], + })], depth_stencil_attachment: None, }); diff --git a/src/lib.rs b/src/lib.rs index 00e25a46e..9dfb0a1d1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -486,7 +486,7 @@ impl Plugin for EguiPlugin { .add_system_to_stage(RenderStage::Queue, render_systems::queue_bind_groups); let mut render_graph = render_app.world.get_resource_mut::().unwrap(); - setup_pipeline(&mut *render_graph, RenderGraphConfig::default()); + setup_pipeline(&mut render_graph, RenderGraphConfig::default()); } } } @@ -604,7 +604,7 @@ pub fn setup_pipeline(render_graph: &mut RenderGraph, config: RenderGraphConfig) render_graph .add_node_edge( - bevy::core_pipeline::node::MAIN_PASS_DRIVER, + bevy::render::main_graph::node::CAMERA_DRIVER, config.egui_pass, ) .unwrap(); diff --git a/src/render_systems.rs b/src/render_systems.rs index d08cfd748..5c1afee28 100644 --- a/src/render_systems.rs +++ b/src/render_systems.rs @@ -8,11 +8,12 @@ use bevy::{ render::{ render_asset::RenderAssets, render_resource::{ - std140::AsStd140, BindGroup, BindGroupDescriptor, BindGroupEntry, BindingResource, - BufferId, DynamicUniformVec, + BindGroup, BindGroupDescriptor, BindGroupEntry, BindingResource, BufferId, + DynamicUniformBuffer, ShaderType, }, renderer::{RenderDevice, RenderQueue}, texture::Image, + Extract, }, utils::HashMap, window::WindowId, @@ -53,13 +54,12 @@ impl ExtractedEguiTextures { pub(crate) fn extract_egui_render_data( mut commands: Commands, - mut egui_render_output: ResMut>, - window_sizes: ResMut>, - egui_settings: Res, - egui_context: Res, + egui_render_output: Extract>>, + window_sizes: Extract>>, + egui_settings: Extract>, + egui_context: Extract>, ) { - let render_output = std::mem::take(&mut *egui_render_output); - commands.insert_resource(ExtractedRenderOutput(render_output)); + commands.insert_resource(ExtractedRenderOutput(egui_render_output.clone())); commands.insert_resource(ExtractedEguiSettings(egui_settings.clone())); commands.insert_resource(ExtractedEguiContext(egui_context.ctx.clone())); commands.insert_resource(ExtractedWindowSizes(window_sizes.clone())); @@ -67,8 +67,8 @@ pub(crate) fn extract_egui_render_data( pub(crate) fn extract_egui_textures( mut commands: Commands, - egui_context: Res, - egui_managed_textures: ResMut, + egui_context: Extract>, + egui_managed_textures: Extract>, ) { commands.insert_resource(ExtractedEguiTextures { egui_textures: egui_managed_textures @@ -84,16 +84,17 @@ pub(crate) fn extract_egui_textures( #[derive(Default)] pub(crate) struct EguiTransforms { - pub buffer: DynamicUniformVec, + pub buffer: DynamicUniformBuffer, pub offsets: HashMap, pub bind_group: Option<(BufferId, BindGroup)>, } -#[derive(AsStd140)] +#[derive(ShaderType, Default)] pub(crate) struct EguiTransform { scale: Vec2, translation: Vec2, } + impl EguiTransform { fn new(window_size: WindowSize, egui_settings: &EguiSettings) -> Self { EguiTransform { @@ -130,7 +131,7 @@ pub(crate) fn prepare_egui_transforms( .buffer .write_buffer(&render_device, &render_queue); - if let Some(buffer) = egui_transforms.buffer.uniform_buffer() { + if let Some(buffer) = egui_transforms.buffer.buffer() { match egui_transforms.bind_group { Some((id, _)) if buffer.id() == id => {} _ => { diff --git a/src/systems.rs b/src/systems.rs index e48439738..5ea001281 100644 --- a/src/systems.rs +++ b/src/systems.rs @@ -4,7 +4,6 @@ use crate::{EguiContext, EguiInput, EguiOutput, EguiRenderOutput, EguiSettings, #[cfg(feature = "open_url")] use bevy::log; use bevy::{ - core::Time, ecs::{ event::EventWriter, system::{Local, Res, ResMut, SystemParam}, @@ -12,9 +11,9 @@ use bevy::{ input::{ keyboard::{KeyCode, KeyboardInput}, mouse::{MouseButton, MouseButtonInput, MouseScrollUnit, MouseWheel}, - ElementState, Input, + ButtonState, Input, }, - prelude::EventReader, + prelude::{EventReader, Time}, utils::HashMap, window::{ CursorEntered, CursorLeft, CursorMoved, ReceivedCharacter, RequestRedraw, WindowCreated, @@ -172,8 +171,8 @@ pub fn process_input( _ => None, }; let pressed = match mouse_button_event.state { - ElementState::Pressed => true, - ElementState::Released => false, + ButtonState::Pressed => true, + ButtonState::Released => false, }; if let Some(button) = button { events.push(egui::Event::PointerButton { @@ -233,8 +232,8 @@ pub fn process_input( for ev in input_events.ev_keyboard_input.iter() { if let Some(key) = ev.key_code.and_then(bevy_to_egui_key) { let pressed = match ev.state { - ElementState::Pressed => true, - ElementState::Released => false, + ButtonState::Pressed => true, + ButtonState::Released => false, }; let egui_event = egui::Event::Key { key, @@ -243,7 +242,7 @@ pub fn process_input( }; focused_input.raw_input.events.push(egui_event); - // We also check that it's an `ElementState::Pressed` event, as we don't want to + // We also check that it's an `ButtonState::Pressed` event, as we don't want to // copy, cut or paste on the key release. #[cfg(feature = "manage_clipboard")] if command && pressed {