mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 20:53:53 +00:00
make UI text rendering camera driven (#13697)
# Objective - Fixes #13687 ## Solution - Text rendering in UI is still dependent on the `PrimaryWIndow` - implements #10559 for text rendering There are other parts of UI that are still `PrimaryWindow` dependent, if the changes here are OK I'll apply them everywhere. I'm not a fan of the `EntityHashMap` here to hold the scale factors, but it seems the quick and easy fix ## Testing - Run example `multiple_windows` on a screen with a scale factor different than 1, close the primary window
This commit is contained in:
parent
52215ce072
commit
3d9b1e4025
1 changed files with 75 additions and 60 deletions
|
@ -1,6 +1,9 @@
|
|||
use crate::{ContentSize, FixedMeasure, Measure, Node, NodeMeasure, UiScale};
|
||||
use crate::{
|
||||
ContentSize, DefaultUiCamera, FixedMeasure, Measure, Node, NodeMeasure, TargetCamera, UiScale,
|
||||
};
|
||||
use bevy_asset::Assets;
|
||||
use bevy_ecs::{
|
||||
entity::{Entity, EntityHashMap},
|
||||
prelude::{Component, DetectChanges},
|
||||
query::With,
|
||||
reflect::ReflectComponent,
|
||||
|
@ -9,13 +12,13 @@ use bevy_ecs::{
|
|||
};
|
||||
use bevy_math::Vec2;
|
||||
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
|
||||
use bevy_render::texture::Image;
|
||||
use bevy_render::{camera::Camera, texture::Image};
|
||||
use bevy_sprite::TextureAtlasLayout;
|
||||
use bevy_text::{
|
||||
scale_value, BreakLineOn, Font, FontAtlasSets, Text, TextError, TextLayoutInfo,
|
||||
TextMeasureInfo, TextPipeline, TextSettings, YAxisOrientation,
|
||||
};
|
||||
use bevy_window::{PrimaryWindow, Window};
|
||||
use bevy_utils::Entry;
|
||||
use taffy::style::AvailableSpace;
|
||||
|
||||
/// Text system flags
|
||||
|
@ -112,41 +115,54 @@ fn create_text_measure(
|
|||
/// A `Measure` is used by the UI's layout algorithm to determine the appropriate amount of space
|
||||
/// to provide for the text given the fonts, the text itself and the constraints of the layout.
|
||||
///
|
||||
/// * All measures are regenerated if the primary window's scale factor or [`UiScale`] is changed.
|
||||
/// * Measures are regenerated if the target camera's scale factor (or primary window if no specific target) or [`UiScale`] is changed.
|
||||
/// * Changes that only modify the colors of a `Text` do not require a new `Measure`. This system
|
||||
/// is only able to detect that a `Text` component has changed and will regenerate the `Measure` on
|
||||
/// color changes. This can be expensive, particularly for large blocks of text, and the [`bypass_change_detection`](bevy_ecs::change_detection::DetectChangesMut::bypass_change_detection)
|
||||
/// method should be called when only changing the `Text`'s colors.
|
||||
pub fn measure_text_system(
|
||||
mut last_scale_factor: Local<f32>,
|
||||
mut last_scale_factors: Local<EntityHashMap<f32>>,
|
||||
fonts: Res<Assets<Font>>,
|
||||
windows: Query<&Window, With<PrimaryWindow>>,
|
||||
camera_query: Query<(Entity, &Camera)>,
|
||||
default_ui_camera: DefaultUiCamera,
|
||||
ui_scale: Res<UiScale>,
|
||||
mut text_query: Query<(Ref<Text>, &mut ContentSize, &mut TextFlags), With<Node>>,
|
||||
mut text_query: Query<
|
||||
(
|
||||
Ref<Text>,
|
||||
&mut ContentSize,
|
||||
&mut TextFlags,
|
||||
Option<&TargetCamera>,
|
||||
),
|
||||
With<Node>,
|
||||
>,
|
||||
) {
|
||||
let window_scale_factor = windows
|
||||
.get_single()
|
||||
.map(|window| window.resolution.scale_factor())
|
||||
.unwrap_or(1.);
|
||||
let mut scale_factors: EntityHashMap<f32> = EntityHashMap::default();
|
||||
|
||||
let scale_factor = ui_scale.0 * window_scale_factor;
|
||||
|
||||
#[allow(clippy::float_cmp)]
|
||||
if *last_scale_factor == scale_factor {
|
||||
// scale factor unchanged, only create new measure funcs for modified text
|
||||
for (text, content_size, text_flags) in &mut text_query {
|
||||
if text.is_changed() || text_flags.needs_new_measure_func || content_size.is_added() {
|
||||
create_text_measure(&fonts, scale_factor, text, content_size, text_flags);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// scale factor changed, create new measure funcs for all text
|
||||
*last_scale_factor = scale_factor;
|
||||
|
||||
for (text, content_size, text_flags) in &mut text_query {
|
||||
for (text, content_size, text_flags, camera) in &mut text_query {
|
||||
let Some(camera_entity) = camera.map(TargetCamera::entity).or(default_ui_camera.get())
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
let scale_factor = match scale_factors.entry(camera_entity) {
|
||||
Entry::Occupied(entry) => *entry.get(),
|
||||
Entry::Vacant(entry) => *entry.insert(
|
||||
camera_query
|
||||
.get(camera_entity)
|
||||
.ok()
|
||||
.and_then(|(_, c)| c.target_scaling_factor())
|
||||
.unwrap_or(1.0)
|
||||
* ui_scale.0,
|
||||
),
|
||||
};
|
||||
if last_scale_factors.get(&camera_entity) != Some(&scale_factor)
|
||||
|| text.is_changed()
|
||||
|| text_flags.needs_new_measure_func
|
||||
|| content_size.is_added()
|
||||
{
|
||||
create_text_measure(&fonts, scale_factor, text, content_size, text_flags);
|
||||
}
|
||||
}
|
||||
*last_scale_factors = scale_factors;
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
|
@ -219,49 +235,47 @@ fn queue_text(
|
|||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn text_system(
|
||||
mut textures: ResMut<Assets<Image>>,
|
||||
mut last_scale_factor: Local<f32>,
|
||||
mut last_scale_factors: Local<EntityHashMap<f32>>,
|
||||
fonts: Res<Assets<Font>>,
|
||||
windows: Query<&Window, With<PrimaryWindow>>,
|
||||
camera_query: Query<(Entity, &Camera)>,
|
||||
default_ui_camera: DefaultUiCamera,
|
||||
text_settings: Res<TextSettings>,
|
||||
ui_scale: Res<UiScale>,
|
||||
mut texture_atlases: ResMut<Assets<TextureAtlasLayout>>,
|
||||
mut font_atlas_sets: ResMut<FontAtlasSets>,
|
||||
mut text_pipeline: ResMut<TextPipeline>,
|
||||
mut text_query: Query<(Ref<Node>, &Text, &mut TextLayoutInfo, &mut TextFlags)>,
|
||||
mut text_query: Query<(
|
||||
Ref<Node>,
|
||||
&Text,
|
||||
&mut TextLayoutInfo,
|
||||
&mut TextFlags,
|
||||
Option<&TargetCamera>,
|
||||
)>,
|
||||
) {
|
||||
// TODO: Support window-independent scaling: https://github.com/bevyengine/bevy/issues/5621
|
||||
let window_scale_factor = windows
|
||||
.get_single()
|
||||
.map(|window| window.resolution.scale_factor())
|
||||
.unwrap_or(1.);
|
||||
let mut scale_factors: EntityHashMap<f32> = EntityHashMap::default();
|
||||
|
||||
let scale_factor = ui_scale.0 * window_scale_factor;
|
||||
let inverse_scale_factor = scale_factor.recip();
|
||||
if *last_scale_factor == scale_factor {
|
||||
// Scale factor unchanged, only recompute text for modified text nodes
|
||||
for (node, text, text_layout_info, text_flags) in &mut text_query {
|
||||
if node.is_changed() || text_flags.needs_recompute {
|
||||
queue_text(
|
||||
&fonts,
|
||||
&mut text_pipeline,
|
||||
&mut font_atlas_sets,
|
||||
&mut texture_atlases,
|
||||
&mut textures,
|
||||
&text_settings,
|
||||
scale_factor,
|
||||
inverse_scale_factor,
|
||||
text,
|
||||
node,
|
||||
text_flags,
|
||||
text_layout_info,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Scale factor changed, recompute text for all text nodes
|
||||
*last_scale_factor = scale_factor;
|
||||
for (node, text, text_layout_info, text_flags, camera) in &mut text_query {
|
||||
let Some(camera_entity) = camera.map(TargetCamera::entity).or(default_ui_camera.get())
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
let scale_factor = match scale_factors.entry(camera_entity) {
|
||||
Entry::Occupied(entry) => *entry.get(),
|
||||
Entry::Vacant(entry) => *entry.insert(
|
||||
camera_query
|
||||
.get(camera_entity)
|
||||
.ok()
|
||||
.and_then(|(_, c)| c.target_scaling_factor())
|
||||
.unwrap_or(1.0)
|
||||
* ui_scale.0,
|
||||
),
|
||||
};
|
||||
let inverse_scale_factor = scale_factor.recip();
|
||||
|
||||
for (node, text, text_layout_info, text_flags) in &mut text_query {
|
||||
if last_scale_factors.get(&camera_entity) != Some(&scale_factor)
|
||||
|| node.is_changed()
|
||||
|| text_flags.needs_recompute
|
||||
{
|
||||
queue_text(
|
||||
&fonts,
|
||||
&mut text_pipeline,
|
||||
|
@ -278,4 +292,5 @@ pub fn text_system(
|
|||
);
|
||||
}
|
||||
}
|
||||
*last_scale_factors = scale_factors;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue