1
- use crate :: { ContentSize , FixedMeasure , Measure , Node , NodeMeasure , UiScale } ;
1
+ use crate :: {
2
+ ContentSize , DefaultUiCamera , FixedMeasure , Measure , Node , NodeMeasure , TargetCamera , UiScale ,
3
+ } ;
2
4
use bevy_asset:: Assets ;
3
5
use bevy_ecs:: {
6
+ entity:: { Entity , EntityHashMap } ,
4
7
prelude:: { Component , DetectChanges } ,
5
8
query:: With ,
6
9
reflect:: ReflectComponent ,
@@ -9,13 +12,13 @@ use bevy_ecs::{
9
12
} ;
10
13
use bevy_math:: Vec2 ;
11
14
use bevy_reflect:: { std_traits:: ReflectDefault , Reflect } ;
12
- use bevy_render:: texture:: Image ;
15
+ use bevy_render:: { camera :: Camera , texture:: Image } ;
13
16
use bevy_sprite:: TextureAtlasLayout ;
14
17
use bevy_text:: {
15
18
scale_value, BreakLineOn , Font , FontAtlasSets , Text , TextError , TextLayoutInfo ,
16
19
TextMeasureInfo , TextPipeline , TextSettings , YAxisOrientation ,
17
20
} ;
18
- use bevy_window :: { PrimaryWindow , Window } ;
21
+ use bevy_utils :: Entry ;
19
22
use taffy:: style:: AvailableSpace ;
20
23
21
24
/// Text system flags
@@ -112,41 +115,54 @@ fn create_text_measure(
112
115
/// A `Measure` is used by the UI's layout algorithm to determine the appropriate amount of space
113
116
/// to provide for the text given the fonts, the text itself and the constraints of the layout.
114
117
///
115
- /// * All measures are regenerated if the primary window 's scale factor or [`UiScale`] is changed.
118
+ /// * Measures are regenerated if the target camera 's scale factor (or primary window if no specific target) or [`UiScale`] is changed.
116
119
/// * Changes that only modify the colors of a `Text` do not require a new `Measure`. This system
117
120
/// is only able to detect that a `Text` component has changed and will regenerate the `Measure` on
118
121
/// 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)
119
122
/// method should be called when only changing the `Text`'s colors.
120
123
pub fn measure_text_system (
121
- mut last_scale_factor : Local < f32 > ,
124
+ mut last_scale_factors : Local < EntityHashMap < f32 > > ,
122
125
fonts : Res < Assets < Font > > ,
123
- windows : Query < & Window , With < PrimaryWindow > > ,
126
+ camera_query : Query < ( Entity , & Camera ) > ,
127
+ default_ui_camera : DefaultUiCamera ,
124
128
ui_scale : Res < UiScale > ,
125
- mut text_query : Query < ( Ref < Text > , & mut ContentSize , & mut TextFlags ) , With < Node > > ,
129
+ mut text_query : Query <
130
+ (
131
+ Ref < Text > ,
132
+ & mut ContentSize ,
133
+ & mut TextFlags ,
134
+ Option < & TargetCamera > ,
135
+ ) ,
136
+ With < Node > ,
137
+ > ,
126
138
) {
127
- let window_scale_factor = windows
128
- . get_single ( )
129
- . map ( |window| window. resolution . scale_factor ( ) )
130
- . unwrap_or ( 1. ) ;
131
-
132
- let scale_factor = ui_scale. 0 * window_scale_factor;
133
-
134
- #[ allow( clippy:: float_cmp) ]
135
- if * last_scale_factor == scale_factor {
136
- // scale factor unchanged, only create new measure funcs for modified text
137
- for ( text, content_size, text_flags) in & mut text_query {
138
- if text. is_changed ( ) || text_flags. needs_new_measure_func || content_size. is_added ( ) {
139
- create_text_measure ( & fonts, scale_factor, text, content_size, text_flags) ;
140
- }
141
- }
142
- } else {
143
- // scale factor changed, create new measure funcs for all text
144
- * last_scale_factor = scale_factor;
139
+ let mut scale_factors: EntityHashMap < f32 > = EntityHashMap :: default ( ) ;
145
140
146
- for ( text, content_size, text_flags) in & mut text_query {
141
+ for ( text, content_size, text_flags, camera) in & mut text_query {
142
+ let Some ( camera_entity) = camera. map ( TargetCamera :: entity) . or ( default_ui_camera. get ( ) )
143
+ else {
144
+ continue ;
145
+ } ;
146
+ let scale_factor = match scale_factors. entry ( camera_entity) {
147
+ Entry :: Occupied ( entry) => * entry. get ( ) ,
148
+ Entry :: Vacant ( entry) => * entry. insert (
149
+ camera_query
150
+ . get ( camera_entity)
151
+ . ok ( )
152
+ . and_then ( |( _, c) | c. target_scaling_factor ( ) )
153
+ . unwrap_or ( 1.0 )
154
+ * ui_scale. 0 ,
155
+ ) ,
156
+ } ;
157
+ if last_scale_factors. get ( & camera_entity) != Some ( & scale_factor)
158
+ || text. is_changed ( )
159
+ || text_flags. needs_new_measure_func
160
+ || content_size. is_added ( )
161
+ {
147
162
create_text_measure ( & fonts, scale_factor, text, content_size, text_flags) ;
148
163
}
149
164
}
165
+ * last_scale_factors = scale_factors;
150
166
}
151
167
152
168
#[ allow( clippy:: too_many_arguments) ]
@@ -219,49 +235,47 @@ fn queue_text(
219
235
#[ allow( clippy:: too_many_arguments) ]
220
236
pub fn text_system (
221
237
mut textures : ResMut < Assets < Image > > ,
222
- mut last_scale_factor : Local < f32 > ,
238
+ mut last_scale_factors : Local < EntityHashMap < f32 > > ,
223
239
fonts : Res < Assets < Font > > ,
224
- windows : Query < & Window , With < PrimaryWindow > > ,
240
+ camera_query : Query < ( Entity , & Camera ) > ,
241
+ default_ui_camera : DefaultUiCamera ,
225
242
text_settings : Res < TextSettings > ,
226
243
ui_scale : Res < UiScale > ,
227
244
mut texture_atlases : ResMut < Assets < TextureAtlasLayout > > ,
228
245
mut font_atlas_sets : ResMut < FontAtlasSets > ,
229
246
mut text_pipeline : ResMut < TextPipeline > ,
230
- mut text_query : Query < ( Ref < Node > , & Text , & mut TextLayoutInfo , & mut TextFlags ) > ,
247
+ mut text_query : Query < (
248
+ Ref < Node > ,
249
+ & Text ,
250
+ & mut TextLayoutInfo ,
251
+ & mut TextFlags ,
252
+ Option < & TargetCamera > ,
253
+ ) > ,
231
254
) {
232
- // TODO: Support window-independent scaling: https://github.com/bevyengine/bevy/issues/5621
233
- let window_scale_factor = windows
234
- . get_single ( )
235
- . map ( |window| window. resolution . scale_factor ( ) )
236
- . unwrap_or ( 1. ) ;
255
+ let mut scale_factors: EntityHashMap < f32 > = EntityHashMap :: default ( ) ;
237
256
238
- let scale_factor = ui_scale. 0 * window_scale_factor;
239
- let inverse_scale_factor = scale_factor. recip ( ) ;
240
- if * last_scale_factor == scale_factor {
241
- // Scale factor unchanged, only recompute text for modified text nodes
242
- for ( node, text, text_layout_info, text_flags) in & mut text_query {
243
- if node. is_changed ( ) || text_flags. needs_recompute {
244
- queue_text (
245
- & fonts,
246
- & mut text_pipeline,
247
- & mut font_atlas_sets,
248
- & mut texture_atlases,
249
- & mut textures,
250
- & text_settings,
251
- scale_factor,
252
- inverse_scale_factor,
253
- text,
254
- node,
255
- text_flags,
256
- text_layout_info,
257
- ) ;
258
- }
259
- }
260
- } else {
261
- // Scale factor changed, recompute text for all text nodes
262
- * last_scale_factor = scale_factor;
257
+ for ( node, text, text_layout_info, text_flags, camera) in & mut text_query {
258
+ let Some ( camera_entity) = camera. map ( TargetCamera :: entity) . or ( default_ui_camera. get ( ) )
259
+ else {
260
+ continue ;
261
+ } ;
262
+ let scale_factor = match scale_factors. entry ( camera_entity) {
263
+ Entry :: Occupied ( entry) => * entry. get ( ) ,
264
+ Entry :: Vacant ( entry) => * entry. insert (
265
+ camera_query
266
+ . get ( camera_entity)
267
+ . ok ( )
268
+ . and_then ( |( _, c) | c. target_scaling_factor ( ) )
269
+ . unwrap_or ( 1.0 )
270
+ * ui_scale. 0 ,
271
+ ) ,
272
+ } ;
273
+ let inverse_scale_factor = scale_factor. recip ( ) ;
263
274
264
- for ( node, text, text_layout_info, text_flags) in & mut text_query {
275
+ if last_scale_factors. get ( & camera_entity) != Some ( & scale_factor)
276
+ || node. is_changed ( )
277
+ || text_flags. needs_recompute
278
+ {
265
279
queue_text (
266
280
& fonts,
267
281
& mut text_pipeline,
@@ -278,4 +292,5 @@ pub fn text_system(
278
292
) ;
279
293
}
280
294
}
295
+ * last_scale_factors = scale_factors;
281
296
}
0 commit comments