From c0fbadbc4cd613a61a7ec0baf5c22416c25c0082 Mon Sep 17 00:00:00 2001 From: ickshonpe Date: Wed, 13 Nov 2024 21:22:20 +0000 Subject: [PATCH] Text2d scalefactor change detection fix (#16264) # Objective Text2d doesn't respond to changes to the window scalefactor. Fixes #16223 ## Solution In `update_text2d_layout` store the previous scale factor in a `Local` instead and check against the current scale factor to detect changes. It seems like previously the text wasn't updated because of a bug with the `WindowScaleFactorChanged` event and it isn't emitted after changes to the scale factor. That needs to be looked into, but this will work for now. ## Testing Really simple app that draws a big message in the middle of the window: ``` use bevy::prelude::*; fn main() { App::new() .add_plugins(DefaultPlugins) .add_systems(Startup, setup) .run(); } fn setup(mut commands: Commands) { commands.spawn(Camera2d); commands.spawn(( Text2d::new("Hello"), TextFont { font_size: 400., ..Default::default() }, )); } ``` Looks fine: hello1 On main, after changing the monitor's scale factor: hello2 With this PR the text maintains the same size and position after the scale factor is changed. --- crates/bevy_text/src/text2d.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/crates/bevy_text/src/text2d.rs b/crates/bevy_text/src/text2d.rs index 36448baab7..03dd84d073 100644 --- a/crates/bevy_text/src/text2d.rs +++ b/crates/bevy_text/src/text2d.rs @@ -11,7 +11,6 @@ use bevy_ecs::component::Component; use bevy_ecs::{ change_detection::{DetectChanges, Ref}, entity::Entity, - event::EventReader, prelude::{ReflectComponent, With}, query::{Changed, Without}, system::{Commands, Local, Query, Res, ResMut}, @@ -30,7 +29,7 @@ use bevy_sprite::{Anchor, ExtractedSprite, ExtractedSprites, SpriteSource, Textu use bevy_transform::components::Transform; use bevy_transform::prelude::GlobalTransform; use bevy_utils::HashSet; -use bevy_window::{PrimaryWindow, Window, WindowScaleFactorChanged}; +use bevy_window::{PrimaryWindow, Window}; /// [`Text2dBundle`] was removed in favor of required components. /// The core component is now [`Text2d`] which can contain a single text segment. @@ -235,12 +234,12 @@ pub fn extract_text2d_sprite( /// It does not modify or observe existing ones. #[allow(clippy::too_many_arguments)] pub fn update_text2d_layout( + mut last_scale_factor: Local, // Text items which should be reprocessed again, generally when the font hasn't loaded yet. mut queue: Local>, mut textures: ResMut>, fonts: Res>, windows: Query<&Window, With>, - mut scale_factor_changed: EventReader, mut texture_atlases: ResMut>, mut font_atlas_sets: ResMut, mut text_pipeline: ResMut, @@ -255,9 +254,6 @@ pub fn update_text2d_layout( mut font_system: ResMut, mut swash_cache: ResMut, ) { - // We need to consume the entire iterator, hence `last` - let factor_changed = scale_factor_changed.read().last().is_some(); - // TODO: Support window-independent scaling: https://github.com/bevyengine/bevy/issues/5621 let scale_factor = windows .get_single() @@ -266,6 +262,9 @@ pub fn update_text2d_layout( let inverse_scale_factor = scale_factor.recip(); + let factor_changed = *last_scale_factor != scale_factor; + *last_scale_factor = scale_factor; + for (entity, block, bounds, text_layout_info, mut computed) in &mut text_query { if factor_changed || computed.needs_rerender() @@ -359,7 +358,7 @@ mod tests { use bevy_app::{App, Update}; use bevy_asset::{load_internal_binary_asset, Handle}; - use bevy_ecs::{event::Events, schedule::IntoSystemConfigs}; + use bevy_ecs::schedule::IntoSystemConfigs; use crate::{detect_text_needs_rerender, TextIterScratch}; @@ -374,7 +373,6 @@ mod tests { .init_resource::>() .init_resource::>() .init_resource::() - .init_resource::>() .init_resource::() .init_resource::() .init_resource::()