From bd317ea364f5a74e265223cd16a3723a9f28c02e Mon Sep 17 00:00:00 2001 From: Marc-Stefan Cassola Date: Tue, 16 Aug 2022 20:46:44 +0000 Subject: [PATCH 1/6] register `Cow<'static, str>` for reflection (#5664) # Objective Fixes #5597 ## Solution Registered type at suggested place. --- crates/bevy_core/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/bevy_core/src/lib.rs b/crates/bevy_core/src/lib.rs index 41b8e02d4935e..527332ab97def 100644 --- a/crates/bevy_core/src/lib.rs +++ b/crates/bevy_core/src/lib.rs @@ -17,6 +17,7 @@ pub mod prelude { use bevy_app::prelude::*; use bevy_ecs::entity::Entity; use bevy_utils::HashSet; +use std::borrow::Cow; use std::ops::Range; /// Adds core functionality to Apps. @@ -43,7 +44,8 @@ fn register_rust_types(app: &mut App) { app.register_type::>() .register_type::() .register_type::>() - .register_type::>(); + .register_type::>() + .register_type::>(); } fn register_math_types(app: &mut App) { From 110831150e8228ab96dce8a73123d9f1a1a56a90 Mon Sep 17 00:00:00 2001 From: Jonas Wagner Date: Tue, 16 Aug 2022 20:46:45 +0000 Subject: [PATCH 2/6] Make vertex colors work without textures in bevy_sprite (#5685) # Objective This PR changes it possible to use vertex colors without a texture using the bevy_sprite ColorMaterial. Fixes #5679 ## Solution - Made multiplication of the output color independent of the COLOR_MATERIAL_FLAGS_TEXTURE_BIT bit - Extended mesh2d_vertex_color_texture example to show off both vertex colors and tinting Not sure if extending the existing example was the right call but it seems to be reasonable to me. I couldn't find any tests for the shaders and I think adding shader testing would be beyond the scope of this PR. So no tests in this PR. :grimacing: Co-authored-by: Jonas Wagner --- .../src/mesh2d/color_material.wgsl | 7 +++-- examples/2d/mesh2d_vertex_color_texture.rs | 26 ++++++++++++++++--- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/crates/bevy_sprite/src/mesh2d/color_material.wgsl b/crates/bevy_sprite/src/mesh2d/color_material.wgsl index 3b6a2b5217176..3b5893d4ce285 100644 --- a/crates/bevy_sprite/src/mesh2d/color_material.wgsl +++ b/crates/bevy_sprite/src/mesh2d/color_material.wgsl @@ -26,12 +26,11 @@ struct FragmentInput { @fragment fn fragment(in: FragmentInput) -> @location(0) vec4 { var output_color: vec4 = material.color; - if ((material.flags & COLOR_MATERIAL_FLAGS_TEXTURE_BIT) != 0u) { #ifdef VERTEX_COLORS - output_color = output_color * textureSample(texture, texture_sampler, in.uv) * in.color; -#else - output_color = output_color * textureSample(texture, texture_sampler, in.uv); + output_color = output_color * in.color; #endif + if ((material.flags & COLOR_MATERIAL_FLAGS_TEXTURE_BIT) != 0u) { + output_color = output_color * textureSample(texture, texture_sampler, in.uv); } return output_color; } diff --git a/examples/2d/mesh2d_vertex_color_texture.rs b/examples/2d/mesh2d_vertex_color_texture.rs index de3ec5c4491a1..1633c2f736c3f 100644 --- a/examples/2d/mesh2d_vertex_color_texture.rs +++ b/examples/2d/mesh2d_vertex_color_texture.rs @@ -1,7 +1,10 @@ //! Shows how to render a polygonal [`Mesh`], generated from a [`Quad`] primitive, in a 2D scene. //! Adds a texture and colored vertices, giving per-vertex tinting. -use bevy::{prelude::*, sprite::MaterialMesh2dBundle}; +use bevy::{ + prelude::*, + sprite::{MaterialMesh2dBundle, Mesh2dHandle}, +}; fn main() { App::new() @@ -29,11 +32,26 @@ fn setup( ]; // Insert the vertex colors as an attribute mesh.insert_attribute(Mesh::ATTRIBUTE_COLOR, vertex_colors); - // Spawn + + let mesh_handle: Mesh2dHandle = meshes.add(mesh).into(); + + // Spawn camera commands.spawn_bundle(Camera2dBundle::default()); + + // Spawn the quad with vertex colors + commands.spawn_bundle(MaterialMesh2dBundle { + mesh: mesh_handle.clone(), + transform: Transform::from_translation(Vec3::new(-96., 0., 0.)) + .with_scale(Vec3::splat(128.)), + material: materials.add(ColorMaterial::default()), + ..default() + }); + + // Spawning the quad with vertex colors and a texture results in tinting commands.spawn_bundle(MaterialMesh2dBundle { - mesh: meshes.add(mesh).into(), - transform: Transform::default().with_scale(Vec3::splat(128.)), + mesh: mesh_handle, + transform: Transform::from_translation(Vec3::new(96., 0., 0.)) + .with_scale(Vec3::splat(128.)), material: materials.add(ColorMaterial::from(texture_handle)), ..default() }); From f20c9ee0f5223189c8f3ca49e9bde2d7a17e7fa6 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 16 Aug 2022 20:46:46 +0000 Subject: [PATCH 3/6] fix: grammar and typo fixes in rendergraph docs (#5710) # Objective - fix a typo on RendGraph Docs ## Solution - fixed typo --- Co-authored-by: Carter Anderson --- crates/bevy_render/src/render_graph/graph.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_render/src/render_graph/graph.rs b/crates/bevy_render/src/render_graph/graph.rs index 0633cb342a353..39d76120a4aa9 100644 --- a/crates/bevy_render/src/render_graph/graph.rs +++ b/crates/bevy_render/src/render_graph/graph.rs @@ -12,7 +12,7 @@ use std::{borrow::Cow, fmt::Debug}; use super::EdgeExistence; /// The render graph configures the modular, parallel and re-usable render logic. -/// It is a retained and stateless (nodes themselves may have internal state) structure, +/// It is a retained and stateless (nodes themselves may have their own internal state) structure, /// which can not be modified while it is executed by the graph runner. /// /// The `RenderGraphRunner` is responsible for executing the entire graph each frame. From f9104b73a2980717a0745c108d47c1ea573ddf2d Mon Sep 17 00:00:00 2001 From: Tomasz Galkowski Date: Tue, 16 Aug 2022 23:18:54 +0000 Subject: [PATCH 4/6] Use circle for breakout example (#5657) # Objective - Replace the square with a circle in the breakout example. - Fixes #4324, adopted from #4682 by @shaderduck. ## Solution - Uses the Mesh2D APIs to draw a circle. The collision still uses the AABB algorithm, but it seems to be working fine, and I haven't seen any odd looking cases. --- examples/games/breakout.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/games/breakout.rs b/examples/games/breakout.rs index 5677a4bf90337..c2d592b4c7e3c 100644 --- a/examples/games/breakout.rs +++ b/examples/games/breakout.rs @@ -3,6 +3,7 @@ use bevy::{ prelude::*, sprite::collide_aabb::{collide, Collision}, + sprite::MaterialMesh2dBundle, time::FixedTimestep, }; @@ -171,7 +172,12 @@ struct Scoreboard { } // Add the game's entities to our world -fn setup(mut commands: Commands, asset_server: Res) { +fn setup( + mut commands: Commands, + mut meshes: ResMut>, + mut materials: ResMut>, + asset_server: Res, +) { // Camera commands.spawn_bundle(Camera2dBundle::default()); @@ -203,16 +209,10 @@ fn setup(mut commands: Commands, asset_server: Res) { commands .spawn() .insert(Ball) - .insert_bundle(SpriteBundle { - transform: Transform { - scale: BALL_SIZE, - translation: BALL_STARTING_POSITION, - ..default() - }, - sprite: Sprite { - color: BALL_COLOR, - ..default() - }, + .insert_bundle(MaterialMesh2dBundle { + mesh: meshes.add(shape::Circle::default().into()).into(), + material: materials.add(ColorMaterial::from(BALL_COLOR)), + transform: Transform::from_translation(BALL_STARTING_POSITION).with_scale(BALL_SIZE), ..default() }) .insert(Velocity(INITIAL_BALL_DIRECTION.normalize() * BALL_SPEED)); From 3221e569e059eaf133fb3d46c0b45725eca96d77 Mon Sep 17 00:00:00 2001 From: JoJoJet Date: Tue, 16 Aug 2022 23:40:24 +0000 Subject: [PATCH 5/6] Remove an outdated workaround for `impl Trait` (#5659) # Objective Rust 1.63 resolved [an issue](https://github.com/rust-lang/rust/issues/83701) that prevents you from combining explicit generic arguments with `impl Trait` arguments. Now, we no longer need to use dynamic dispatch to work around this. ## Migration Guide The methods `Schedule::get_stage` and `get_stage_mut` now accept `impl StageLabel` instead of `&dyn StageLabel`. ### Before ```rust let stage = schedule.get_stage_mut::(&MyLabel)?; ``` ### After ```rust let stage = schedule.get_stage_mut::(MyLabel)?; ``` --- crates/bevy_ecs/src/schedule/mod.rs | 29 +++++++++++++++-------------- crates/bevy_render/src/lib.rs | 12 ++++++------ 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/crates/bevy_ecs/src/schedule/mod.rs b/crates/bevy_ecs/src/schedule/mod.rs index 2e1bd167caedf..0ac1e8702d685 100644 --- a/crates/bevy_ecs/src/schedule/mod.rs +++ b/crates/bevy_ecs/src/schedule/mod.rs @@ -211,9 +211,10 @@ impl Schedule { ) } + let label = stage_label.as_label(); let stage = self - .get_stage_mut::(&stage_label) - .unwrap_or_else(move || stage_not_found(&stage_label.as_label())); + .get_stage_mut::(label) + .unwrap_or_else(move || stage_not_found(&label)); stage.add_system(system); self } @@ -278,14 +279,12 @@ impl Schedule { /// Panics if `label` refers to a non-existing stage, or if it's not of type `T`. pub fn stage &mut T>( &mut self, - label: impl StageLabel, + stage_label: impl StageLabel, func: F, ) -> &mut Self { - let stage = self.get_stage_mut::(&label).unwrap_or_else(move || { - panic!( - "stage '{:?}' does not exist or is the wrong type", - label.as_label() - ) + let label = stage_label.as_label(); + let stage = self.get_stage_mut::(label).unwrap_or_else(move || { + panic!("stage '{label:?}' does not exist or is the wrong type",) }); func(stage); self @@ -304,11 +303,12 @@ impl Schedule { /// # let mut schedule = Schedule::default(); /// # schedule.add_stage("my_stage", SystemStage::parallel()); /// # - /// let stage = schedule.get_stage::(&"my_stage").unwrap(); + /// let stage = schedule.get_stage::("my_stage").unwrap(); /// ``` - pub fn get_stage(&self, label: &dyn StageLabel) -> Option<&T> { + pub fn get_stage(&self, stage_label: impl StageLabel) -> Option<&T> { + let label = stage_label.as_label(); self.stages - .get(&label.as_label()) + .get(&label) .and_then(|stage| stage.downcast_ref::()) } @@ -325,11 +325,12 @@ impl Schedule { /// # let mut schedule = Schedule::default(); /// # schedule.add_stage("my_stage", SystemStage::parallel()); /// # - /// let stage = schedule.get_stage_mut::(&"my_stage").unwrap(); + /// let stage = schedule.get_stage_mut::("my_stage").unwrap(); /// ``` - pub fn get_stage_mut(&mut self, label: &dyn StageLabel) -> Option<&mut T> { + pub fn get_stage_mut(&mut self, stage_label: impl StageLabel) -> Option<&mut T> { + let label = stage_label.as_label(); self.stages - .get_mut(&label.as_label()) + .get_mut(&label) .and_then(|stage| stage.downcast_mut::()) } diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index 5efbb5ba9c03a..fbe5f14923970 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -249,7 +249,7 @@ impl Plugin for RenderPlugin { // prepare let prepare = render_app .schedule - .get_stage_mut::(&RenderStage::Prepare) + .get_stage_mut::(RenderStage::Prepare) .unwrap(); prepare.run(&mut render_app.world); } @@ -262,7 +262,7 @@ impl Plugin for RenderPlugin { // queue let queue = render_app .schedule - .get_stage_mut::(&RenderStage::Queue) + .get_stage_mut::(RenderStage::Queue) .unwrap(); queue.run(&mut render_app.world); } @@ -275,7 +275,7 @@ impl Plugin for RenderPlugin { // phase sort let phase_sort = render_app .schedule - .get_stage_mut::(&RenderStage::PhaseSort) + .get_stage_mut::(RenderStage::PhaseSort) .unwrap(); phase_sort.run(&mut render_app.world); } @@ -288,7 +288,7 @@ impl Plugin for RenderPlugin { // render let render = render_app .schedule - .get_stage_mut::(&RenderStage::Render) + .get_stage_mut::(RenderStage::Render) .unwrap(); render.run(&mut render_app.world); } @@ -301,7 +301,7 @@ impl Plugin for RenderPlugin { // cleanup let cleanup = render_app .schedule - .get_stage_mut::(&RenderStage::Cleanup) + .get_stage_mut::(RenderStage::Cleanup) .unwrap(); cleanup.run(&mut render_app.world); } @@ -335,7 +335,7 @@ struct ScratchMainWorld(World); fn extract(app_world: &mut World, render_app: &mut App) { let extract = render_app .schedule - .get_stage_mut::(&RenderStage::Extract) + .get_stage_mut::(RenderStage::Extract) .unwrap(); // temporarily add the app world to the render world as a resource From aed3232e38e2d700cbb06b782ed7242d0684c244 Mon Sep 17 00:00:00 2001 From: Gino Valente Date: Wed, 17 Aug 2022 00:21:15 +0000 Subject: [PATCH 6/6] bevy_reflect: Relax bounds on `Option` (#5658) # Objective The reflection impls on `Option` have the bound `T: Reflect + Clone`. This means that using `FromReflect` requires `Clone` even though we can normally get away with just `FromReflect`. ## Solution Update the bounds on `Option` to match that of `Vec`, where `T: FromReflect`. This helps remove a `Clone` implementation that may be undesired but added for the sole purpose of getting the code to compile. --- ## Changelog * Reflection on `Option` now has `T` bound by `FromReflect` rather than `Reflect + Clone` * Added a `FromReflect` impl for `Instant` ## Migration Guide If using `Option` with Bevy's reflection API, `T` now needs to implement `FromReflect` rather than just `Clone`. This can be achieved easily by simply deriving `FromReflect`: ```rust // OLD #[derive(Reflect, Clone)] struct Foo; let reflected: Box = Box::new(Some(Foo)); // NEW #[derive(Reflect, FromReflect)] struct Foo; let reflected: Box = Box::new(Some(Foo)); ``` > Note: You can still derive `Clone`, but it's not required in order to compile. --- crates/bevy_reflect/src/impls/std.rs | 39 +++++++++++++++++++------ crates/bevy_render/src/camera/camera.rs | 5 ++-- crates/bevy_time/src/time.rs | 4 +-- 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/crates/bevy_reflect/src/impls/std.rs b/crates/bevy_reflect/src/impls/std.rs index 7b66aba360249..90fa58dc372ec 100644 --- a/crates/bevy_reflect/src/impls/std.rs +++ b/crates/bevy_reflect/src/impls/std.rs @@ -76,6 +76,7 @@ impl_from_reflect_value!(String); impl_from_reflect_value!(HashSet); impl_from_reflect_value!(Range); impl_from_reflect_value!(Duration); +impl_from_reflect_value!(Instant); impl_from_reflect_value!(NonZeroI128); impl_from_reflect_value!(NonZeroU128); impl_from_reflect_value!(NonZeroIsize); @@ -585,13 +586,13 @@ impl Reflect for Cow<'static, str> { } } -impl GetTypeRegistration for Option { +impl GetTypeRegistration for Option { fn get_type_registration() -> TypeRegistration { TypeRegistration::of::>() } } -impl Enum for Option { +impl Enum for Option { fn field(&self, _name: &str) -> Option<&dyn Reflect> { None } @@ -655,7 +656,7 @@ impl Enum for Option { } } -impl Reflect for Option { +impl Reflect for Option { #[inline] fn type_name(&self) -> &str { std::any::type_name::() @@ -741,7 +742,7 @@ impl Reflect for Option { #[inline] fn clone_value(&self) -> Box { - Box::new(self.clone()) + Box::new(Enum::clone_dynamic(self)) } fn reflect_hash(&self) -> Option { @@ -753,7 +754,7 @@ impl Reflect for Option { } } -impl FromReflect for Option { +impl FromReflect for Option { fn from_reflect(reflect: &dyn Reflect) -> Option { if let ReflectRef::Enum(dyn_enum) = reflect.reflect_ref() { match dyn_enum.variant_name() { @@ -762,7 +763,7 @@ impl FromReflect for Option { .field_at(0) .expect("Field at index 0 should exist") .clone_value(); - let field = field.take::().unwrap_or_else(|_| { + let field = T::from_reflect(field.as_ref()).unwrap_or_else(|| { panic!( "Field at index 0 should be of type {}", std::any::type_name::() @@ -783,7 +784,7 @@ impl FromReflect for Option { } } -impl Typed for Option { +impl Typed for Option { fn type_info() -> &'static TypeInfo { static CELL: GenericTypeInfoCell = GenericTypeInfoCell::new(); CELL.get_or_insert::(|| { @@ -827,10 +828,12 @@ impl FromReflect for Cow<'static, str> { #[cfg(test)] mod tests { + use crate as bevy_reflect; use crate::{ - Enum, Reflect, ReflectSerialize, TypeInfo, TypeRegistry, Typed, VariantInfo, VariantType, + Enum, FromReflect, Reflect, ReflectSerialize, TypeInfo, TypeRegistry, Typed, VariantInfo, + VariantType, }; - use bevy_utils::HashMap; + use bevy_utils::{HashMap, Instant}; use std::f32::consts::{PI, TAU}; #[test] @@ -939,6 +942,17 @@ mod tests { assert_eq!(Some(321), value); } + #[test] + fn option_should_from_reflect() { + #[derive(Reflect, FromReflect, PartialEq, Debug)] + struct Foo(usize); + + let expected = Some(Foo(123)); + let output = as FromReflect>::from_reflect(&expected).unwrap(); + + assert_eq!(expected, output); + } + #[test] fn option_should_impl_typed() { type MyOption = Option; @@ -979,4 +993,11 @@ mod tests { let forty_two: std::num::NonZeroUsize = crate::FromReflect::from_reflect(a).unwrap(); assert_eq!(forty_two, std::num::NonZeroUsize::new(42).unwrap()); } + + #[test] + fn instant_should_from_reflect() { + let expected = Instant::now(); + let output = ::from_reflect(&expected).unwrap(); + assert_eq!(expected, output); + } } diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index f81c5b6ad1aed..0bfd3c5a7de03 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -19,6 +19,7 @@ use bevy_ecs::{ }; use bevy_math::{Mat4, UVec2, Vec2, Vec3}; use bevy_reflect::prelude::*; +use bevy_reflect::FromReflect; use bevy_transform::components::GlobalTransform; use bevy_utils::HashSet; use bevy_window::{WindowCreated, WindowId, WindowResized, Windows}; @@ -32,7 +33,7 @@ use wgpu::Extent3d; /// You can overlay multiple cameras in a single window using viewports to create effects like /// split screen, minimaps, and character viewers. // TODO: remove reflect_value when possible -#[derive(Reflect, Debug, Clone, Serialize, Deserialize)] +#[derive(Reflect, FromReflect, Debug, Clone, Serialize, Deserialize)] #[reflect_value(Default, Serialize, Deserialize)] pub struct Viewport { /// The physical position to render this viewport to within the [`RenderTarget`] of this [`Camera`]. @@ -71,7 +72,7 @@ pub struct ComputedCameraValues { target_info: Option, } -#[derive(Component, Debug, Reflect, Clone)] +#[derive(Component, Debug, Reflect, FromReflect, Clone)] #[reflect(Component)] pub struct Camera { /// If set, this camera will render to the given [`Viewport`] rectangle within the configured [`RenderTarget`]. diff --git a/crates/bevy_time/src/time.rs b/crates/bevy_time/src/time.rs index 8cb864882f25e..1835f841c93a7 100644 --- a/crates/bevy_time/src/time.rs +++ b/crates/bevy_time/src/time.rs @@ -1,9 +1,9 @@ use bevy_ecs::{reflect::ReflectResource, system::Resource}; -use bevy_reflect::Reflect; +use bevy_reflect::{FromReflect, Reflect}; use bevy_utils::{Duration, Instant}; /// Tracks elapsed time since the last update and since the App has started -#[derive(Resource, Reflect, Debug, Clone)] +#[derive(Resource, Reflect, FromReflect, Debug, Clone)] #[reflect(Resource)] pub struct Time { delta: Duration,