Update layout/style when scale factor changes too (#4689)

# Objective

- Fix https://github.com/bevyengine/bevy/issues/4688

## Solution

- Fixes https://github.com/bevyengine/bevy/issues/4688
- This raises an interesting question about our change detection system - is filtered queries actually a good UX for this? They're ergonomic in the easy case, but what do we recommend when it's not so.
- In this case, the system should have been migrated similary to https://github.com/bevyengine/bevy/pull/4180 anyway, so I've done that.
This commit is contained in:
Daniel McNab 2022-05-09 14:18:02 +00:00
parent fca1c861d2
commit 33a4df8008
2 changed files with 25 additions and 32 deletions

View File

@ -47,7 +47,10 @@ impl Plugin for TextPlugin {
.register_type::<HorizontalAlign>() .register_type::<HorizontalAlign>()
.init_asset_loader::<FontLoader>() .init_asset_loader::<FontLoader>()
.insert_resource(DefaultTextPipeline::default()) .insert_resource(DefaultTextPipeline::default())
.add_system_to_stage(CoreStage::PostUpdate, text2d_system.after(ModifiesWindows)); .add_system_to_stage(
CoreStage::PostUpdate,
update_text2d_layout.after(ModifiesWindows),
);
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) { if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
render_app.add_system_to_stage( render_app.add_system_to_stage(

View File

@ -3,16 +3,18 @@ use bevy_ecs::{
bundle::Bundle, bundle::Bundle,
component::Component, component::Component,
entity::Entity, entity::Entity,
query::{Changed, With}, event::EventReader,
query::Changed,
reflect::ReflectComponent, reflect::ReflectComponent,
system::{Local, ParamSet, Query, Res, ResMut}, system::{Local, Query, Res, ResMut},
}; };
use bevy_math::{Vec2, Vec3}; use bevy_math::{Vec2, Vec3};
use bevy_reflect::Reflect; use bevy_reflect::Reflect;
use bevy_render::{texture::Image, view::Visibility, RenderWorld}; use bevy_render::{texture::Image, view::Visibility, RenderWorld};
use bevy_sprite::{Anchor, ExtractedSprite, ExtractedSprites, TextureAtlas}; use bevy_sprite::{Anchor, ExtractedSprite, ExtractedSprites, TextureAtlas};
use bevy_transform::prelude::{GlobalTransform, Transform}; use bevy_transform::prelude::{GlobalTransform, Transform};
use bevy_window::{WindowId, Windows}; use bevy_utils::HashSet;
use bevy_window::{WindowId, WindowScaleFactorChanged, Windows};
use crate::{ use crate::{
DefaultTextPipeline, Font, FontAtlasSet, HorizontalAlign, Text, TextError, VerticalAlign, DefaultTextPipeline, Font, FontAtlasSet, HorizontalAlign, Text, TextError, VerticalAlign,
@ -123,44 +125,34 @@ pub fn extract_text2d_sprite(
} }
} }
#[derive(Debug, Default)]
pub struct QueuedText2d {
entities: Vec<Entity>,
}
/// Updates the layout and size information whenever the text or style is changed. /// Updates the layout and size information whenever the text or style is changed.
/// This information is computed by the `TextPipeline` on insertion, then stored. /// This information is computed by the `TextPipeline` on insertion, then stored.
#[allow(clippy::too_many_arguments, clippy::type_complexity)] #[allow(clippy::too_many_arguments, clippy::type_complexity)]
pub fn text2d_system( pub fn update_text2d_layout(
mut queued_text: Local<QueuedText2d>, // Text items which should be reprocessed again, generally when the font hasn't loaded yet.
mut queue: Local<HashSet<Entity>>,
mut textures: ResMut<Assets<Image>>, mut textures: ResMut<Assets<Image>>,
fonts: Res<Assets<Font>>, fonts: Res<Assets<Font>>,
windows: Res<Windows>, windows: Res<Windows>,
mut scale_factor_changed: EventReader<WindowScaleFactorChanged>,
mut texture_atlases: ResMut<Assets<TextureAtlas>>, mut texture_atlases: ResMut<Assets<TextureAtlas>>,
mut font_atlas_set_storage: ResMut<Assets<FontAtlasSet>>, mut font_atlas_set_storage: ResMut<Assets<FontAtlasSet>>,
mut text_pipeline: ResMut<DefaultTextPipeline>, mut text_pipeline: ResMut<DefaultTextPipeline>,
mut text_queries: ParamSet<( mut text_query: Query<(
Query<Entity, (With<Text2dSize>, Changed<Text>)>, Entity,
Query<(&Text, Option<&Text2dBounds>, &mut Text2dSize), With<Text2dSize>>, Changed<Text>,
&Text,
Option<&Text2dBounds>,
&mut Text2dSize,
)>, )>,
) { ) {
// Adds all entities where the text or the style has changed to the local queue // We need to consume the entire iterator, hence `last`
for entity in text_queries.p0().iter_mut() { let factor_changed = scale_factor_changed.iter().last().is_some();
queued_text.entities.push(entity);
}
if queued_text.entities.is_empty() {
return;
}
let scale_factor = windows.scale_factor(WindowId::primary()); let scale_factor = windows.scale_factor(WindowId::primary());
// Computes all text in the local queue for (entity, text_changed, text, maybe_bounds, mut calculated_size) in text_query.iter_mut() {
let mut new_queue = Vec::new(); if factor_changed || text_changed || queue.remove(&entity) {
let mut query = text_queries.p1(); let text_bounds = match maybe_bounds {
for entity in queued_text.entities.drain(..) {
if let Ok((text, bounds, mut calculated_size)) = query.get_mut(entity) {
let text_bounds = match bounds {
Some(bounds) => Vec2::new( Some(bounds) => Vec2::new(
scale_value(bounds.size.x, scale_factor), scale_value(bounds.size.x, scale_factor),
scale_value(bounds.size.y, scale_factor), scale_value(bounds.size.y, scale_factor),
@ -181,7 +173,7 @@ pub fn text2d_system(
Err(TextError::NoSuchFont) => { Err(TextError::NoSuchFont) => {
// There was an error processing the text layout, let's add this entity to the // There was an error processing the text layout, let's add this entity to the
// queue for further processing // queue for further processing
new_queue.push(entity); queue.insert(entity);
} }
Err(e @ TextError::FailedToAddGlyph(_)) => { Err(e @ TextError::FailedToAddGlyph(_)) => {
panic!("Fatal error when processing text: {}.", e); panic!("Fatal error when processing text: {}.", e);
@ -198,8 +190,6 @@ pub fn text2d_system(
} }
} }
} }
queued_text.entities = new_queue;
} }
pub fn scale_value(value: f32, factor: f64) -> f32 { pub fn scale_value(value: f32, factor: f64) -> f32 {