From fb6cfaa24bf9f5d46b380cf675dbade641862556 Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Sat, 25 Feb 2023 13:25:16 +0000 Subject: [PATCH 01/22] move transform scaling calculations for text out of the inner loop --- crates/bevy_text/src/text2d.rs | 11 ++++------- crates/bevy_ui/src/render/mod.rs | 12 +++++------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/crates/bevy_text/src/text2d.rs b/crates/bevy_text/src/text2d.rs index 26ecf5796ac2d..35e09e84ba54c 100644 --- a/crates/bevy_text/src/text2d.rs +++ b/crates/bevy_text/src/text2d.rs @@ -95,7 +95,7 @@ pub fn extract_text2d_sprite( .map(|window| window.resolution.scale_factor() as f32) .unwrap_or(1.0); - for (entity, computed_visibility, text, text_layout_info, anchor, text_transform) in + for (entity, computed_visibility, text, text_layout_info, anchor, global_transform) in text2d_query.iter() { if !computed_visibility.is_visible() { @@ -107,6 +107,7 @@ pub fn extract_text2d_sprite( let alignment_offset = text_layout_info.size * text_anchor; let mut color = Color::WHITE; let mut current_section = usize::MAX; + let transform = *global_transform * Transform::from_scale(Vec3::splat(scale_factor)); for text_glyph in text_glyphs { if text_glyph.section_index != current_section { color = text.sections[text_glyph.section_index] @@ -122,12 +123,8 @@ pub fn extract_text2d_sprite( let index = text_glyph.atlas_info.glyph_index; let rect = Some(atlas.textures[index]); - let glyph_transform = - Transform::from_translation((alignment_offset + text_glyph.position).extend(0.)); - - let transform = *text_transform - * GlobalTransform::from_scale(Vec3::splat(scale_factor.recip())) - * glyph_transform; + let transform = transform + * Transform::from_translation((alignment_offset + text_glyph.position).extend(0.)); extracted_sprites.sprites.push(ExtractedSprite { entity, diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 2cfa098d28bb1..dba573e743328 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -328,10 +328,12 @@ pub fn extract_text_uinodes( continue; } let text_glyphs = &text_layout_info.glyphs; - let alignment_offset = (uinode.size() / -2.0).extend(0.0); + let alignment_offset = (uinode.size() / -2.0).extend(0.0) * scale_factor; let mut color = Color::WHITE; let mut current_section = usize::MAX; + let transform = global_transform.compute_matrix() + * Mat4::from_scale(Vec3::splat(scale_factor.recip())); for text_glyph in text_glyphs { if text_glyph.section_index != current_section { color = text.sections[text_glyph.section_index] @@ -348,12 +350,8 @@ pub fn extract_text_uinodes( let rect = atlas.textures[index]; let atlas_size = Some(atlas.size); - // NOTE: Should match `bevy_text::text2d::extract_text2d_sprite` - let extracted_transform = global_transform.compute_matrix() - * Mat4::from_scale(Vec3::splat(scale_factor.recip())) - * Mat4::from_translation( - alignment_offset * scale_factor + text_glyph.position.extend(0.), - ); + let extracted_transform = transform + * Mat4::from_translation(alignment_offset + text_glyph.position.extend(0.)); extracted_uinodes.uinodes.push(ExtractedUiNode { stack_index, From 67519e5d7f30257842da7664fbdee318c00b8621 Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Sat, 25 Feb 2023 13:27:59 +0000 Subject: [PATCH 02/22] fix scaling in text2d --- crates/bevy_text/src/text2d.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_text/src/text2d.rs b/crates/bevy_text/src/text2d.rs index 35e09e84ba54c..3570fcfb25cb5 100644 --- a/crates/bevy_text/src/text2d.rs +++ b/crates/bevy_text/src/text2d.rs @@ -107,7 +107,7 @@ pub fn extract_text2d_sprite( let alignment_offset = text_layout_info.size * text_anchor; let mut color = Color::WHITE; let mut current_section = usize::MAX; - let transform = *global_transform * Transform::from_scale(Vec3::splat(scale_factor)); + let transform = *global_transform * Transform::from_scale(Vec3::splat(scale_factor.recip())); for text_glyph in text_glyphs { if text_glyph.section_index != current_section { color = text.sections[text_glyph.section_index] From 39f2f86fb204079c93728333ec08181a96fd26d0 Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Sat, 25 Feb 2023 13:49:06 +0000 Subject: [PATCH 03/22] add many_glyphs example --- Cargo.toml | 10 ++++ examples/README.md | 1 + examples/stress_tests/many_glyphs.rs | 68 ++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 examples/stress_tests/many_glyphs.rs diff --git a/Cargo.toml b/Cargo.toml index 0b1427689d214..eee7708c9d926 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1451,6 +1451,16 @@ description = "Loads an animated fox model and spawns lots of them. Good for tes category = "Stress Tests" wasm = true +[[example]] +name = "many_glyphs" +path = "examples/stress_tests/many_glyphs.rs" + +[package.metadata.example.many_glyphs] +name = "Many Glyphs" +description = "Simple benchmark to test text rendering." +category = "Stress Tests" +wasm = true + [[example]] name = "many_lights" path = "examples/stress_tests/many_lights.rs" diff --git a/examples/README.md b/examples/README.md index c54ca491ec420..8e7262e1fae1f 100644 --- a/examples/README.md +++ b/examples/README.md @@ -297,6 +297,7 @@ Example | Description [Many Buttons](../examples/stress_tests/many_buttons.rs) | Test rendering of many UI elements [Many Cubes](../examples/stress_tests/many_cubes.rs) | Simple benchmark to test per-entity draw overhead. Run with the `sphere` argument to test frustum culling [Many Foxes](../examples/stress_tests/many_foxes.rs) | Loads an animated fox model and spawns lots of them. Good for testing skinned mesh performance. Takes an unsigned integer argument for the number of foxes to spawn. Defaults to 1000 +[Many Glyphs](../examples/stress_tests/many_glyphs.rs) | Simple text rendering benchmark. [Many Lights](../examples/stress_tests/many_lights.rs) | Simple benchmark to test rendering many point lights. Run with `WGPU_SETTINGS_PRIO=webgl2` to restrict to uniform buffers and max 256 lights [Many Sprites](../examples/stress_tests/many_sprites.rs) | Displays many sprites in a grid arrangement! Used for performance testing. Use `--colored` to enable color tinted sprites. [Transform Hierarchy](../examples/stress_tests/transform_hierarchy.rs) | Various test cases for hierarchy and transform propagation performance diff --git a/examples/stress_tests/many_glyphs.rs b/examples/stress_tests/many_glyphs.rs new file mode 100644 index 0000000000000..2f9567b2836ce --- /dev/null +++ b/examples/stress_tests/many_glyphs.rs @@ -0,0 +1,68 @@ +use bevy::{ + diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}, + prelude::*, + window::{PresentMode, WindowPlugin}, text::BreakLineOn, +}; + +const GLYPH_COUNT: usize = 100_000; + +/// This example shows what happens when there is a lot of buttons on screen. +fn main() { + App::new() + .add_plugins(DefaultPlugins.set(WindowPlugin { + primary_window: Some(Window { + present_mode: PresentMode::Immediate, + ..default() + }), + ..default() + })) + .add_plugin(FrameTimeDiagnosticsPlugin::default()) + .add_plugin(LogDiagnosticsPlugin::default()) + .add_startup_system(setup) + .run(); +} + +fn setup(mut commands: Commands, asset_server: Res) { + let font = asset_server.load("fonts/FiraSans-Bold.ttf"); + let mut text_sections = vec![]; + for i in 0..GLYPH_COUNT { + let section = TextSection { + value: (i % 10).to_string(), + style: TextStyle { + font: font.clone(), + font_size: 8., + color: Color::WHITE, + ..Default::default() + } + }; + text_sections.push(section); + } + commands.spawn(Camera2dBundle::default()); + commands + .spawn(NodeBundle { + style: Style { + size: Size::all(Val::Px(1050.)), + align_items: AlignItems::Center, + justify_content: JustifyContent::Center, + ..default() + }, + ..default() + }) + .with_children(|commands| { + commands.spawn(TextBundle { + text: Text { + sections: text_sections, + alignment: TextAlignment::Left, + linebreak_behaviour: BreakLineOn::AnyCharacter, + ..Default::default() + }, + style: Style { + size: Size::all(Val::Px(1050.)), + ..Default::default() + }, + background_color: Color::MAROON.into(), + ..Default::default() + }); + }); +} + From a2ef631969fcf5a78f2a08b8a57ee7e1437df26d Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Sat, 25 Feb 2023 14:29:07 +0000 Subject: [PATCH 04/22] modify example --- examples/stress_tests/many_glyphs.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/stress_tests/many_glyphs.rs b/examples/stress_tests/many_glyphs.rs index 2f9567b2836ce..37e8e3f010e78 100644 --- a/examples/stress_tests/many_glyphs.rs +++ b/examples/stress_tests/many_glyphs.rs @@ -30,7 +30,7 @@ fn setup(mut commands: Commands, asset_server: Res) { value: (i % 10).to_string(), style: TextStyle { font: font.clone(), - font_size: 8., + font_size: 4., color: Color::WHITE, ..Default::default() } @@ -41,7 +41,7 @@ fn setup(mut commands: Commands, asset_server: Res) { commands .spawn(NodeBundle { style: Style { - size: Size::all(Val::Px(1050.)), + flex_basis: Val::Percent(100.), align_items: AlignItems::Center, justify_content: JustifyContent::Center, ..default() @@ -57,10 +57,9 @@ fn setup(mut commands: Commands, asset_server: Res) { ..Default::default() }, style: Style { - size: Size::all(Val::Px(1050.)), + size: Size::width(Val::Px(1000.)), ..Default::default() }, - background_color: Color::MAROON.into(), ..Default::default() }); }); From 65763ab37282c14499711b62243a91b9f8aebf7f Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Sat, 25 Feb 2023 14:45:59 +0000 Subject: [PATCH 05/22] switch to single text section --- examples/stress_tests/many_glyphs.rs | 31 ++++++++++------------------ 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/examples/stress_tests/many_glyphs.rs b/examples/stress_tests/many_glyphs.rs index 2f9567b2836ce..beda43a2638c0 100644 --- a/examples/stress_tests/many_glyphs.rs +++ b/examples/stress_tests/many_glyphs.rs @@ -1,11 +1,10 @@ +//! Simple text rendering benchmark. use bevy::{ diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}, prelude::*, window::{PresentMode, WindowPlugin}, text::BreakLineOn, }; -const GLYPH_COUNT: usize = 100_000; - /// This example shows what happens when there is a lot of buttons on screen. fn main() { App::new() @@ -23,25 +22,11 @@ fn main() { } fn setup(mut commands: Commands, asset_server: Res) { - let font = asset_server.load("fonts/FiraSans-Bold.ttf"); - let mut text_sections = vec![]; - for i in 0..GLYPH_COUNT { - let section = TextSection { - value: (i % 10).to_string(), - style: TextStyle { - font: font.clone(), - font_size: 8., - color: Color::WHITE, - ..Default::default() - } - }; - text_sections.push(section); - } commands.spawn(Camera2dBundle::default()); commands .spawn(NodeBundle { style: Style { - size: Size::all(Val::Px(1050.)), + flex_basis: Val::Percent(100.), align_items: AlignItems::Center, justify_content: JustifyContent::Center, ..default() @@ -51,16 +36,22 @@ fn setup(mut commands: Commands, asset_server: Res) { .with_children(|commands| { commands.spawn(TextBundle { text: Text { - sections: text_sections, + sections: vec![TextSection { + value: std::iter::repeat("0123456789").take(10_000).collect::(), + style: TextStyle { + font: asset_server.load("fonts/FiraSans-Bold.ttf"), + font_size: 20.0, + color: Color::WHITE, + }, + }], alignment: TextAlignment::Left, linebreak_behaviour: BreakLineOn::AnyCharacter, ..Default::default() }, style: Style { - size: Size::all(Val::Px(1050.)), + flex_basis: Val::Px(1000.), ..Default::default() }, - background_color: Color::MAROON.into(), ..Default::default() }); }); From b48bf4a8ed6117ea559f580975b8571252ea774a Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Sat, 25 Feb 2023 14:50:09 +0000 Subject: [PATCH 06/22] swapped flex_basis for style constraint on text node --- examples/stress_tests/many_glyphs.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/stress_tests/many_glyphs.rs b/examples/stress_tests/many_glyphs.rs index beda43a2638c0..158c0c4e960d6 100644 --- a/examples/stress_tests/many_glyphs.rs +++ b/examples/stress_tests/many_glyphs.rs @@ -40,16 +40,15 @@ fn setup(mut commands: Commands, asset_server: Res) { value: std::iter::repeat("0123456789").take(10_000).collect::(), style: TextStyle { font: asset_server.load("fonts/FiraSans-Bold.ttf"), - font_size: 20.0, + font_size: 4., color: Color::WHITE, }, }], alignment: TextAlignment::Left, linebreak_behaviour: BreakLineOn::AnyCharacter, - ..Default::default() }, style: Style { - flex_basis: Val::Px(1000.), + size: Size::width(Val::Px(1000.)), ..Default::default() }, ..Default::default() From ed801f5871b44eed6dfdc1a37a27ea31a0ad3bbd Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Sat, 25 Feb 2023 15:04:50 +0000 Subject: [PATCH 07/22] cargo fmt --- crates/bevy_text/src/text2d.rs | 3 ++- examples/stress_tests/many_glyphs.rs | 8 +++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/crates/bevy_text/src/text2d.rs b/crates/bevy_text/src/text2d.rs index 3570fcfb25cb5..a099479ffd70a 100644 --- a/crates/bevy_text/src/text2d.rs +++ b/crates/bevy_text/src/text2d.rs @@ -107,7 +107,8 @@ pub fn extract_text2d_sprite( let alignment_offset = text_layout_info.size * text_anchor; let mut color = Color::WHITE; let mut current_section = usize::MAX; - let transform = *global_transform * Transform::from_scale(Vec3::splat(scale_factor.recip())); + let transform = + *global_transform * Transform::from_scale(Vec3::splat(scale_factor.recip())); for text_glyph in text_glyphs { if text_glyph.section_index != current_section { color = text.sections[text_glyph.section_index] diff --git a/examples/stress_tests/many_glyphs.rs b/examples/stress_tests/many_glyphs.rs index 158c0c4e960d6..7b557bc960349 100644 --- a/examples/stress_tests/many_glyphs.rs +++ b/examples/stress_tests/many_glyphs.rs @@ -2,7 +2,8 @@ use bevy::{ diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}, prelude::*, - window::{PresentMode, WindowPlugin}, text::BreakLineOn, + text::BreakLineOn, + window::{PresentMode, WindowPlugin}, }; /// This example shows what happens when there is a lot of buttons on screen. @@ -37,7 +38,9 @@ fn setup(mut commands: Commands, asset_server: Res) { commands.spawn(TextBundle { text: Text { sections: vec![TextSection { - value: std::iter::repeat("0123456789").take(10_000).collect::(), + value: std::iter::repeat("0123456789") + .take(10_000) + .collect::(), style: TextStyle { font: asset_server.load("fonts/FiraSans-Bold.ttf"), font_size: 4., @@ -55,4 +58,3 @@ fn setup(mut commands: Commands, asset_server: Res) { }); }); } - From c64ee5c33f725b1dfb7bb76ac340fe1fd72c0393 Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Sat, 25 Feb 2023 15:52:30 +0000 Subject: [PATCH 08/22] fix manual-str-repeat --- examples/README.md | 2 +- examples/stress_tests/many_glyphs.rs | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/README.md b/examples/README.md index 8e7262e1fae1f..5ffb895036dfe 100644 --- a/examples/README.md +++ b/examples/README.md @@ -297,7 +297,7 @@ Example | Description [Many Buttons](../examples/stress_tests/many_buttons.rs) | Test rendering of many UI elements [Many Cubes](../examples/stress_tests/many_cubes.rs) | Simple benchmark to test per-entity draw overhead. Run with the `sphere` argument to test frustum culling [Many Foxes](../examples/stress_tests/many_foxes.rs) | Loads an animated fox model and spawns lots of them. Good for testing skinned mesh performance. Takes an unsigned integer argument for the number of foxes to spawn. Defaults to 1000 -[Many Glyphs](../examples/stress_tests/many_glyphs.rs) | Simple text rendering benchmark. +[Many Glyphs](../examples/stress_tests/many_glyphs.rs) | Simple benchmark to test text rendering. [Many Lights](../examples/stress_tests/many_lights.rs) | Simple benchmark to test rendering many point lights. Run with `WGPU_SETTINGS_PRIO=webgl2` to restrict to uniform buffers and max 256 lights [Many Sprites](../examples/stress_tests/many_sprites.rs) | Displays many sprites in a grid arrangement! Used for performance testing. Use `--colored` to enable color tinted sprites. [Transform Hierarchy](../examples/stress_tests/transform_hierarchy.rs) | Various test cases for hierarchy and transform propagation performance diff --git a/examples/stress_tests/many_glyphs.rs b/examples/stress_tests/many_glyphs.rs index 7b557bc960349..5a26145d36d8d 100644 --- a/examples/stress_tests/many_glyphs.rs +++ b/examples/stress_tests/many_glyphs.rs @@ -38,9 +38,7 @@ fn setup(mut commands: Commands, asset_server: Res) { commands.spawn(TextBundle { text: Text { sections: vec![TextSection { - value: std::iter::repeat("0123456789") - .take(10_000) - .collect::(), + value: "0123456789".repeat(10_000), style: TextStyle { font: asset_server.load("fonts/FiraSans-Bold.ttf"), font_size: 4., From 734ddb168be6fc95f18f2f9452885b1ae8b99f75 Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Sat, 25 Feb 2023 19:28:47 +0000 Subject: [PATCH 09/22] * cleaned up example * tidied up `extract_text_uinodes` and moved alignment translation out of loop --- crates/bevy_ui/src/render/mod.rs | 55 +++++++++++++--------------- examples/stress_tests/many_glyphs.rs | 1 - 2 files changed, 26 insertions(+), 30 deletions(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index dba573e743328..2a939b47a8818 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -311,6 +311,9 @@ pub fn extract_text_uinodes( >, ) { // TODO: Support window-independent UI scale: https://github.com/bevyengine/bevy/issues/5621 + + use bevy_math::Quat; + use bevy_text::PositionedGlyph; let scale_factor = windows .get_single() .map(|window| window.resolution.scale_factor() as f32) @@ -320,46 +323,40 @@ pub fn extract_text_uinodes( if let Ok((uinode, global_transform, text, text_layout_info, visibility, clip)) = uinode_query.get(*entity) { - if !visibility.is_visible() { - continue; - } - // Skip if size is set to zero (e.g. when a parent is set to `Display::None`) - if uinode.size() == Vec2::ZERO { + // Skip if not visible or if size is set to zero (e.g. when a parent is set to `Display::None`) + if !visibility.is_visible() || uinode.size().x == 0. || uinode.size().y == 0. { continue; } - let text_glyphs = &text_layout_info.glyphs; - let alignment_offset = (uinode.size() / -2.0).extend(0.0) * scale_factor; let mut color = Color::WHITE; let mut current_section = usize::MAX; let transform = global_transform.compute_matrix() - * Mat4::from_scale(Vec3::splat(scale_factor.recip())); - for text_glyph in text_glyphs { - if text_glyph.section_index != current_section { - color = text.sections[text_glyph.section_index] - .style - .color - .as_rgba_linear(); - current_section = text_glyph.section_index; + * Mat4::from_scale_rotation_translation( + Vec3::splat(scale_factor.recip()), + Quat::IDENTITY, + (uinode.size() / -2.0).extend(0.0), + ); + + for PositionedGlyph { + position, + atlas_info, + section_index, + .. + } in &text_layout_info.glyphs + { + if *section_index != current_section { + color = text.sections[*section_index].style.color.as_rgba_linear(); + current_section = *section_index; } - let atlas = texture_atlases - .get(&text_glyph.atlas_info.texture_atlas) - .unwrap(); - let texture = atlas.texture.clone_weak(); - let index = text_glyph.atlas_info.glyph_index; - let rect = atlas.textures[index]; - let atlas_size = Some(atlas.size); - - let extracted_transform = transform - * Mat4::from_translation(alignment_offset + text_glyph.position.extend(0.)); + let atlas = texture_atlases.get(&atlas_info.texture_atlas).unwrap(); extracted_uinodes.uinodes.push(ExtractedUiNode { stack_index, - transform: extracted_transform, + transform: transform * Mat4::from_translation(position.extend(0.)), color, - rect, - image: texture, - atlas_size, + rect: atlas.textures[atlas_info.glyph_index], + image: atlas.texture.clone_weak(), + atlas_size: Some(atlas.size), clip: clip.map(|clip| clip.clip), flip_x: false, flip_y: false, diff --git a/examples/stress_tests/many_glyphs.rs b/examples/stress_tests/many_glyphs.rs index 5a26145d36d8d..e8ad8fe3d1c69 100644 --- a/examples/stress_tests/many_glyphs.rs +++ b/examples/stress_tests/many_glyphs.rs @@ -6,7 +6,6 @@ use bevy::{ window::{PresentMode, WindowPlugin}, }; -/// This example shows what happens when there is a lot of buttons on screen. fn main() { App::new() .add_plugins(DefaultPlugins.set(WindowPlugin { From 983b44d176607f606c6689f1b3b1c4cd9ae43262 Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Sat, 25 Feb 2023 19:48:07 +0000 Subject: [PATCH 10/22] cleaned up imports and improve transform calculations --- crates/bevy_ui/src/render/mod.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 2a939b47a8818..602b3601170c2 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -12,7 +12,7 @@ use crate::{prelude::UiCameraConfig, BackgroundColor, CalculatedClip, Node, UiIm use bevy_app::prelude::*; use bevy_asset::{load_internal_asset, AssetEvent, Assets, Handle, HandleUntyped}; use bevy_ecs::prelude::*; -use bevy_math::{Mat4, Rect, UVec4, Vec2, Vec3, Vec4Swizzles}; +use bevy_math::{mat4, Mat4, Rect, UVec4, Vec2, Vec3, Vec4, Vec4Swizzles}; use bevy_reflect::TypeUuid; use bevy_render::texture::DEFAULT_IMAGE_HANDLE; use bevy_render::{ @@ -31,7 +31,7 @@ use bevy_sprite::SpriteAssetEvents; #[cfg(feature = "bevy_text")] use bevy_sprite::TextureAtlas; #[cfg(feature = "bevy_text")] -use bevy_text::{Text, TextLayoutInfo}; +use bevy_text::{PositionedGlyph, Text, TextLayoutInfo}; use bevy_transform::components::GlobalTransform; use bevy_utils::FloatOrd; use bevy_utils::HashMap; @@ -312,8 +312,6 @@ pub fn extract_text_uinodes( ) { // TODO: Support window-independent UI scale: https://github.com/bevyengine/bevy/issues/5621 - use bevy_math::Quat; - use bevy_text::PositionedGlyph; let scale_factor = windows .get_single() .map(|window| window.resolution.scale_factor() as f32) @@ -330,11 +328,13 @@ pub fn extract_text_uinodes( let mut color = Color::WHITE; let mut current_section = usize::MAX; + let scale = scale_factor.recip(); let transform = global_transform.compute_matrix() - * Mat4::from_scale_rotation_translation( - Vec3::splat(scale_factor.recip()), - Quat::IDENTITY, - (uinode.size() / -2.0).extend(0.0), + * mat4( + scale * Vec4::X, + scale * Vec4::Y, + scale * Vec4::Z, + (-0.5 * uinode.size()).extend(0.0).extend(1.0), ); for PositionedGlyph { From 15a41e4ecb395505c66aaa2b085f60f44ea31cd1 Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Sat, 25 Feb 2023 20:21:31 +0000 Subject: [PATCH 11/22] replaced `extend` chain with `Vec4::from` --- crates/bevy_ui/src/render/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 602b3601170c2..19f39f014696d 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -331,10 +331,10 @@ pub fn extract_text_uinodes( let scale = scale_factor.recip(); let transform = global_transform.compute_matrix() * mat4( - scale * Vec4::X, - scale * Vec4::Y, - scale * Vec4::Z, - (-0.5 * uinode.size()).extend(0.0).extend(1.0), + Vec4::X * scale, + Vec4::Y * scale, + Vec4::Z * scale, + Vec4::from((-0.5 * uinode.size(), 0., 1.)), ); for PositionedGlyph { From 838fba2207206d5c922dbba3f66fcf01789aa7ac Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Mon, 27 Feb 2023 11:04:56 +0000 Subject: [PATCH 12/22] Changed the precompution in `extract_text_uinodes` to use `from_scale_rotation_translation` instead of constructing the matrix from columns. --- crates/bevy_ui/src/render/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 19f39f014696d..f0c6f731e4ca2 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -12,7 +12,7 @@ use crate::{prelude::UiCameraConfig, BackgroundColor, CalculatedClip, Node, UiIm use bevy_app::prelude::*; use bevy_asset::{load_internal_asset, AssetEvent, Assets, Handle, HandleUntyped}; use bevy_ecs::prelude::*; -use bevy_math::{mat4, Mat4, Rect, UVec4, Vec2, Vec3, Vec4, Vec4Swizzles}; +use bevy_math::{Mat4, Rect, UVec4, Vec2, Vec3, Vec4, Vec4Swizzles}; use bevy_reflect::TypeUuid; use bevy_render::texture::DEFAULT_IMAGE_HANDLE; use bevy_render::{ @@ -329,12 +329,12 @@ pub fn extract_text_uinodes( let mut color = Color::WHITE; let mut current_section = usize::MAX; let scale = scale_factor.recip(); + let alignment_translation = -0.5 * uinode.size(); let transform = global_transform.compute_matrix() - * mat4( - Vec4::X * scale, - Vec4::Y * scale, - Vec4::Z * scale, - Vec4::from((-0.5 * uinode.size(), 0., 1.)), + * Mat4::from_scale_rotation_translation( + Vec3::splat(scale), + Quat::IDENTITY, + alignment_translation.extend(0.), ); for PositionedGlyph { From 6eabeef41e92bbabc7b75070bf9f89fc0a043cb3 Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Mon, 27 Feb 2023 11:31:35 +0000 Subject: [PATCH 13/22] cleaned up `extract_text2d_sprite` to be more similar to`extract_text_uinodes` --- crates/bevy_text/src/text2d.rs | 46 ++++++++++++++++---------------- crates/bevy_ui/src/render/mod.rs | 4 +-- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/crates/bevy_text/src/text2d.rs b/crates/bevy_text/src/text2d.rs index a099479ffd70a..360b7a3495976 100644 --- a/crates/bevy_text/src/text2d.rs +++ b/crates/bevy_text/src/text2d.rs @@ -23,8 +23,8 @@ use bevy_utils::HashSet; use bevy_window::{PrimaryWindow, Window, WindowScaleFactorChanged}; use crate::{ - Font, FontAtlasSet, FontAtlasWarning, Text, TextError, TextLayoutInfo, TextPipeline, - TextSettings, YAxisOrientation, + Font, FontAtlasSet, FontAtlasWarning, PositionedGlyph, Text, TextError, TextLayoutInfo, + TextPipeline, TextSettings, YAxisOrientation, }; /// The maximum width and height of text. The text will wrap according to the specified size. @@ -105,35 +105,35 @@ pub fn extract_text2d_sprite( let text_glyphs = &text_layout_info.glyphs; let text_anchor = anchor.as_vec() * Vec2::new(1., -1.) - 0.5; let alignment_offset = text_layout_info.size * text_anchor; + let transform = *global_transform + * Transform::from_scale_rotation_translation( + Vec3::splat(scale_factor.recip()), + Quat::IDENTITY, + alignment_offset.extend(0.), + ); + let mut color = Color::WHITE; let mut current_section = usize::MAX; - let transform = - *global_transform * Transform::from_scale(Vec3::splat(scale_factor.recip())); - for text_glyph in text_glyphs { - if text_glyph.section_index != current_section { - color = text.sections[text_glyph.section_index] - .style - .color - .as_rgba_linear(); - current_section = text_glyph.section_index; + for PositionedGlyph { + position, + atlas_info, + section_index, + .. + } in &text_layout_info.glyphs + { + if *section_index != current_section { + color = text.sections[*section_index].style.color.as_rgba_linear(); + current_section = *section_index; } - let atlas = texture_atlases - .get(&text_glyph.atlas_info.texture_atlas) - .unwrap(); - let handle = atlas.texture.clone_weak(); - let index = text_glyph.atlas_info.glyph_index; - let rect = Some(atlas.textures[index]); - - let transform = transform - * Transform::from_translation((alignment_offset + text_glyph.position).extend(0.)); + let atlas = texture_atlases.get(&atlas_info.texture_atlas).unwrap(); extracted_sprites.sprites.push(ExtractedSprite { entity, - transform, + transform: transform * Transform::from_translation(position.extend(0.)), color, - rect, + rect: Some(atlas.textures[atlas_info.glyph_index]), custom_size: None, - image_handle_id: handle.id(), + image_handle_id: atlas.texture.clone_weak().id(), flip_x: false, flip_y: false, anchor: Anchor::Center.as_vec(), diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index f0c6f731e4ca2..34e97095754c0 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -326,8 +326,6 @@ pub fn extract_text_uinodes( continue; } - let mut color = Color::WHITE; - let mut current_section = usize::MAX; let scale = scale_factor.recip(); let alignment_translation = -0.5 * uinode.size(); let transform = global_transform.compute_matrix() @@ -337,6 +335,8 @@ pub fn extract_text_uinodes( alignment_translation.extend(0.), ); + let mut color = Color::WHITE; + let mut current_section = usize::MAX; for PositionedGlyph { position, atlas_info, From 3b760e75896eb7d52a7919f16dd9072446696d09 Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Mon, 27 Feb 2023 11:33:03 +0000 Subject: [PATCH 14/22] Cleaned up `extract_text2d_sprite` to be more similar to`extract_text_uinodes` (part 2). --- crates/bevy_text/src/text2d.rs | 17 +++++++++-------- crates/bevy_ui/src/render/mod.rs | 2 ++ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/crates/bevy_text/src/text2d.rs b/crates/bevy_text/src/text2d.rs index 360b7a3495976..8fcbdc9a44fe0 100644 --- a/crates/bevy_text/src/text2d.rs +++ b/crates/bevy_text/src/text2d.rs @@ -102,16 +102,17 @@ pub fn extract_text2d_sprite( continue; } + let scale = Vec3::splat(scale_factor.recip()); let text_glyphs = &text_layout_info.glyphs; let text_anchor = anchor.as_vec() * Vec2::new(1., -1.) - 0.5; - let alignment_offset = text_layout_info.size * text_anchor; - let transform = *global_transform - * Transform::from_scale_rotation_translation( - Vec3::splat(scale_factor.recip()), - Quat::IDENTITY, - alignment_offset.extend(0.), - ); - + let translation = (text_layout_info.size * text_anchor).extend(0.) * scale; + let mut transform = *global_transform + * Transform { + scale, + translation, + ..Default::default() + }; + let mut color = Color::WHITE; let mut current_section = usize::MAX; for PositionedGlyph { diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 34e97095754c0..f8d3d8d26242e 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -312,6 +312,8 @@ pub fn extract_text_uinodes( ) { // TODO: Support window-independent UI scale: https://github.com/bevyengine/bevy/issues/5621 + use bevy_math::Quat; + let scale_factor = windows .get_single() .map(|window| window.resolution.scale_factor() as f32) From 26a04fed66e9118c6969f5a0b08b9c24838c2cfe Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Mon, 27 Feb 2023 12:16:35 +0000 Subject: [PATCH 15/22] Added text drawn with Text2d to the many_glyphs example. --- examples/stress_tests/many_glyphs.rs | 42 +++++++++++++++++++--------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/examples/stress_tests/many_glyphs.rs b/examples/stress_tests/many_glyphs.rs index e8ad8fe3d1c69..95647f2d328b5 100644 --- a/examples/stress_tests/many_glyphs.rs +++ b/examples/stress_tests/many_glyphs.rs @@ -1,8 +1,11 @@ //! Simple text rendering benchmark. +//! +//! Creates a `Text` with a single `TextSection` containing 100_000 glyphs, +//! and renders it with the UI in a white color and with Text2d in a red color. use bevy::{ diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}, prelude::*, - text::BreakLineOn, + text::{BreakLineOn, Text2dBounds}, window::{PresentMode, WindowPlugin}, }; @@ -23,6 +26,19 @@ fn main() { fn setup(mut commands: Commands, asset_server: Res) { commands.spawn(Camera2dBundle::default()); + let mut text = Text { + sections: vec![TextSection { + value: "0123456789".repeat(10_000), + style: TextStyle { + font: asset_server.load("fonts/FiraSans-Bold.ttf"), + font_size: 4., + color: Color::WHITE, + }, + }], + alignment: TextAlignment::Left, + linebreak_behaviour: BreakLineOn::AnyCharacter, + }; + commands .spawn(NodeBundle { style: Style { @@ -35,18 +51,7 @@ fn setup(mut commands: Commands, asset_server: Res) { }) .with_children(|commands| { commands.spawn(TextBundle { - text: Text { - sections: vec![TextSection { - value: "0123456789".repeat(10_000), - style: TextStyle { - font: asset_server.load("fonts/FiraSans-Bold.ttf"), - font_size: 4., - color: Color::WHITE, - }, - }], - alignment: TextAlignment::Left, - linebreak_behaviour: BreakLineOn::AnyCharacter, - }, + text: text.clone(), style: Style { size: Size::width(Val::Px(1000.)), ..Default::default() @@ -54,4 +59,15 @@ fn setup(mut commands: Commands, asset_server: Res) { ..Default::default() }); }); + + text.sections[0].style.color = Color::RED; + + commands.spawn(Text2dBundle { + text, + text_anchor: bevy::sprite::Anchor::Center, + text_2d_bounds: Text2dBounds { + size: Vec2::new(1000., f32::INFINITY), + }, + ..Default::default() + }); } From c8ca00896ac1e0df9c06ddead7bd38e4aed766bb Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Mon, 27 Feb 2023 12:17:41 +0000 Subject: [PATCH 16/22] cargo fmt --- crates/bevy_text/src/text2d.rs | 2 +- examples/stress_tests/many_glyphs.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/bevy_text/src/text2d.rs b/crates/bevy_text/src/text2d.rs index 8fcbdc9a44fe0..2ca3a92d85136 100644 --- a/crates/bevy_text/src/text2d.rs +++ b/crates/bevy_text/src/text2d.rs @@ -112,7 +112,7 @@ pub fn extract_text2d_sprite( translation, ..Default::default() }; - + let mut color = Color::WHITE; let mut current_section = usize::MAX; for PositionedGlyph { diff --git a/examples/stress_tests/many_glyphs.rs b/examples/stress_tests/many_glyphs.rs index 95647f2d328b5..020bb9f3ff70b 100644 --- a/examples/stress_tests/many_glyphs.rs +++ b/examples/stress_tests/many_glyphs.rs @@ -1,5 +1,5 @@ //! Simple text rendering benchmark. -//! +//! //! Creates a `Text` with a single `TextSection` containing 100_000 glyphs, //! and renders it with the UI in a white color and with Text2d in a red color. use bevy::{ @@ -38,7 +38,7 @@ fn setup(mut commands: Commands, asset_server: Res) { alignment: TextAlignment::Left, linebreak_behaviour: BreakLineOn::AnyCharacter, }; - + commands .spawn(NodeBundle { style: Style { From 63f60cc61114558d428417f8191c3a51cb4f4e96 Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Mon, 27 Feb 2023 12:34:52 +0000 Subject: [PATCH 17/22] removed an unnecessary `mut` and an unused variable --- crates/bevy_text/src/text2d.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/bevy_text/src/text2d.rs b/crates/bevy_text/src/text2d.rs index 2ca3a92d85136..4d90aef1415ca 100644 --- a/crates/bevy_text/src/text2d.rs +++ b/crates/bevy_text/src/text2d.rs @@ -103,10 +103,9 @@ pub fn extract_text2d_sprite( } let scale = Vec3::splat(scale_factor.recip()); - let text_glyphs = &text_layout_info.glyphs; let text_anchor = anchor.as_vec() * Vec2::new(1., -1.) - 0.5; let translation = (text_layout_info.size * text_anchor).extend(0.) * scale; - let mut transform = *global_transform + let transform = *global_transform * Transform { scale, translation, From 6944b78e46b274814ffa18978dc9643d79a81c3d Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Mon, 27 Feb 2023 14:06:54 +0000 Subject: [PATCH 18/22] simplify text transform calculations --- crates/bevy_ui/src/render/mod.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index f8d3d8d26242e..47a3dd2feb7d4 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -328,14 +328,9 @@ pub fn extract_text_uinodes( continue; } - let scale = scale_factor.recip(); - let alignment_translation = -0.5 * uinode.size(); let transform = global_transform.compute_matrix() - * Mat4::from_scale_rotation_translation( - Vec3::splat(scale), - Quat::IDENTITY, - alignment_translation.extend(0.), - ); + * Mat4::from_translation(-0.5 * uinode.size().extend(0.)) + * Mat4::from_scale(Vec3::splat(scale_factor.recip())); let mut color = Color::WHITE; let mut current_section = usize::MAX; From faedcab7599e006a5778e9498482d8406e2ebb43 Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Mon, 27 Feb 2023 14:06:56 +0000 Subject: [PATCH 19/22] simplified text calculations --- crates/bevy_text/src/text2d.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/crates/bevy_text/src/text2d.rs b/crates/bevy_text/src/text2d.rs index 4d90aef1415ca..cd2a54ef36544 100644 --- a/crates/bevy_text/src/text2d.rs +++ b/crates/bevy_text/src/text2d.rs @@ -102,15 +102,11 @@ pub fn extract_text2d_sprite( continue; } - let scale = Vec3::splat(scale_factor.recip()); let text_anchor = anchor.as_vec() * Vec2::new(1., -1.) - 0.5; - let translation = (text_layout_info.size * text_anchor).extend(0.) * scale; + let alignment_translation = (text_layout_info.size * text_anchor); let transform = *global_transform - * Transform { - scale, - translation, - ..Default::default() - }; + * Transform::from_scale(Vec3::splat(scale_factor.recip())) + * Transform::from_translation(alignment_translation.extend(0.)); let mut color = Color::WHITE; let mut current_section = usize::MAX; From 567749c25ac8ddfde15a0121d423a8e460e30e93 Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Mon, 27 Feb 2023 14:12:08 +0000 Subject: [PATCH 20/22] fixed imports and fmt --- crates/bevy_text/src/text2d.rs | 2 +- crates/bevy_ui/src/render/mod.rs | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/crates/bevy_text/src/text2d.rs b/crates/bevy_text/src/text2d.rs index cd2a54ef36544..1510b537ced97 100644 --- a/crates/bevy_text/src/text2d.rs +++ b/crates/bevy_text/src/text2d.rs @@ -103,7 +103,7 @@ pub fn extract_text2d_sprite( } let text_anchor = anchor.as_vec() * Vec2::new(1., -1.) - 0.5; - let alignment_translation = (text_layout_info.size * text_anchor); + let alignment_translation = text_layout_info.size * text_anchor; let transform = *global_transform * Transform::from_scale(Vec3::splat(scale_factor.recip())) * Transform::from_translation(alignment_translation.extend(0.)); diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 47a3dd2feb7d4..80e81416c67d3 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -12,7 +12,7 @@ use crate::{prelude::UiCameraConfig, BackgroundColor, CalculatedClip, Node, UiIm use bevy_app::prelude::*; use bevy_asset::{load_internal_asset, AssetEvent, Assets, Handle, HandleUntyped}; use bevy_ecs::prelude::*; -use bevy_math::{Mat4, Rect, UVec4, Vec2, Vec3, Vec4, Vec4Swizzles}; +use bevy_math::{Mat4, Rect, UVec4, Vec2, Vec3, Vec4Swizzles}; use bevy_reflect::TypeUuid; use bevy_render::texture::DEFAULT_IMAGE_HANDLE; use bevy_render::{ @@ -311,9 +311,6 @@ pub fn extract_text_uinodes( >, ) { // TODO: Support window-independent UI scale: https://github.com/bevyengine/bevy/issues/5621 - - use bevy_math::Quat; - let scale_factor = windows .get_single() .map(|window| window.resolution.scale_factor() as f32) From fdfe3217d8dfdbd7c0d0c8371b5c457c8762385f Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Mon, 27 Feb 2023 15:01:32 +0000 Subject: [PATCH 21/22] fix clippy::doc-markdown warning --- examples/stress_tests/many_glyphs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/stress_tests/many_glyphs.rs b/examples/stress_tests/many_glyphs.rs index 020bb9f3ff70b..b5c7fc0f377ff 100644 --- a/examples/stress_tests/many_glyphs.rs +++ b/examples/stress_tests/many_glyphs.rs @@ -1,6 +1,6 @@ //! Simple text rendering benchmark. //! -//! Creates a `Text` with a single `TextSection` containing 100_000 glyphs, +//! Creates a `Text` with a single `TextSection` containing `100_000` glyphs, //! and renders it with the UI in a white color and with Text2d in a red color. use bevy::{ diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}, From d01878e7a4748577696c9799d2c7a518db7d5ff7 Mon Sep 17 00:00:00 2001 From: ickshonpe Date: Mon, 13 Mar 2023 18:17:23 +0000 Subject: [PATCH 22/22] Moved scaling inversion calculation out of loop extraction loop. --- crates/bevy_ui/src/render/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 2d6a90cf43d9b..029fd5d8a1659 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -318,6 +318,8 @@ pub fn extract_text_uinodes( .map(|window| window.resolution.scale_factor() as f32) .unwrap_or(1.0); + let scaling = Mat4::from_scale(Vec3::splat(scale_factor.recip())); + for (stack_index, entity) in ui_stack.uinodes.iter().enumerate() { if let Ok((uinode, global_transform, text, text_layout_info, visibility, clip)) = uinode_query.get(*entity) @@ -329,7 +331,7 @@ pub fn extract_text_uinodes( let transform = global_transform.compute_matrix() * Mat4::from_translation(-0.5 * uinode.size().extend(0.)) - * Mat4::from_scale(Vec3::splat(scale_factor.recip())); + * scaling; let mut color = Color::WHITE; let mut current_section = usize::MAX;