Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Text rework #15591

Merged
merged 41 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
e782612
text rework WIP
UkoeHB Oct 1, 2024
88ac373
rework WIP
UkoeHB Oct 2, 2024
91be8cb
text rework WIP
UkoeHB Oct 2, 2024
94b1b13
cleanup WIP
UkoeHB Oct 2, 2024
a1cc06d
cleanup WIP
UkoeHB Oct 2, 2024
120c4a4
crates compile
UkoeHB Oct 3, 2024
3045288
bevy_text tests work
UkoeHB Oct 3, 2024
00ef953
ui::text example works
UkoeHB Oct 3, 2024
aa84ebb
TextReader/TextWriter WIP
UkoeHB Oct 3, 2024
f4d19ae
TextReader/TextWriter system params
UkoeHB Oct 3, 2024
b8df0a8
API adjustments, text_debug example
UkoeHB Oct 3, 2024
6090ba0
ui examples migrated
UkoeHB Oct 3, 2024
21ff426
2d examples migrated
UkoeHB Oct 3, 2024
256836e
add iteration tool to TextWriter; animation examples migrated
UkoeHB Oct 3, 2024
7f18c45
Update text stress tests (#4)
ickshonpe Oct 3, 2024
1293b35
move font_smoothing to TextStyle; add empty() method to Text/Text2d
UkoeHB Oct 3, 2024
35c2bc5
add Clone to TextBlock; remove BackgroundColor req from Text
UkoeHB Oct 3, 2024
18ed641
warn if a text span entity has TextBlock
UkoeHB Oct 3, 2024
6832cc9
add TextBuilderExt for EntityCommands
UkoeHB Oct 3, 2024
f4d3078
add spawn_text_block() extension method for Commands/EntityCommands
UkoeHB Oct 3, 2024
b90e158
use IntoIterator for text builders
UkoeHB Oct 3, 2024
2938060
add warnings to detect_text_needs_rerender
UkoeHB Oct 3, 2024
24994dd
update dev_tools; add EntityCommands::commands_mut
UkoeHB Oct 3, 2024
c237922
3d examples migrated
UkoeHB Oct 4, 2024
b4fb7ab
app/asset/async_tasks/audio/camera/ecs/games examples migrated
UkoeHB Oct 4, 2024
f6014f9
detect orphaned span subtrees
UkoeHB Oct 4, 2024
7dcbe6f
remaining examples migrated
UkoeHB Oct 4, 2024
cce1470
Remove spawn_text_block and with_spans
cart Oct 4, 2024
57056b0
migration fix
UkoeHB Oct 4, 2024
9c1adde
rebase fixes
UkoeHB Oct 4, 2024
b93434d
Remove Text2d::empty()
cart Oct 9, 2024
199422d
TextNEW -> Text
cart Oct 9, 2024
8f55fe0
fmt
cart Oct 9, 2024
8ca3ccb
More empty -> default
cart Oct 9, 2024
d9f12a2
Share TextSpan across contexts. Port remaining examples
cart Oct 9, 2024
61a864c
Remove span generics
cart Oct 9, 2024
bc1008a
clippy fixes
UkoeHB Oct 9, 2024
da42e96
rebase fixes
UkoeHB Oct 9, 2024
cf90e1c
lints and lingering example migrations
UkoeHB Oct 9, 2024
1092adc
doc fixes; system ambiguity fixes
UkoeHB Oct 9, 2024
d584d08
ambiguity fixes
UkoeHB Oct 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 24 additions & 17 deletions crates/bevy_dev_tools/src/fps_overlay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@ use bevy_diagnostic::{DiagnosticsStore, FrameTimeDiagnosticsPlugin};
use bevy_ecs::{
change_detection::DetectChangesMut,
component::Component,
entity::Entity,
query::With,
schedule::{common_conditions::resource_changed, IntoSystemConfigs},
system::{Commands, Query, Res, Resource},
};
use bevy_hierarchy::{BuildChildren, ChildBuild};
use bevy_render::view::Visibility;
use bevy_text::{Font, Text, TextSection, TextStyle};
use bevy_text::{Font, TextSpan, TextStyle};
use bevy_ui::{
node_bundles::{NodeBundle, TextBundle},
node_bundles::NodeBundle,
widget::{Text, UiTextWriter},
GlobalZIndex, PositionType, Style,
};
use bevy_utils::default;
Expand Down Expand Up @@ -72,6 +74,7 @@ impl Default for FpsOverlayConfig {
font: Handle::<Font>::default(),
font_size: 32.0,
color: Color::WHITE,
..default()
},
enabled: true,
}
Expand All @@ -95,35 +98,39 @@ fn setup(mut commands: Commands, overlay_config: Res<FpsOverlayConfig>) {
},
GlobalZIndex(FPS_OVERLAY_ZINDEX),
))
.with_children(|c| {
c.spawn((
TextBundle::from_sections([
TextSection::new("FPS: ", overlay_config.text_config.clone()),
TextSection::from_style(overlay_config.text_config.clone()),
]),
.with_children(|p| {
p.spawn((
Text::new("FPS: "),
overlay_config.text_config.clone(),
FpsText,
));
))
.with_child((TextSpan::default(), overlay_config.text_config.clone()));
});
}

fn update_text(diagnostic: Res<DiagnosticsStore>, mut query: Query<&mut Text, With<FpsText>>) {
for mut text in &mut query {
fn update_text(
diagnostic: Res<DiagnosticsStore>,
query: Query<Entity, With<FpsText>>,
mut writer: UiTextWriter,
) {
for entity in &query {
if let Some(fps) = diagnostic.get(&FrameTimeDiagnosticsPlugin::FPS) {
if let Some(value) = fps.smoothed() {
text.sections[1].value = format!("{value:.2}");
*writer.text(entity, 1) = format!("{value:.2}");
}
}
}
}

fn customize_text(
overlay_config: Res<FpsOverlayConfig>,
mut query: Query<&mut Text, With<FpsText>>,
query: Query<Entity, With<FpsText>>,
mut writer: UiTextWriter,
) {
for mut text in &mut query {
for section in text.sections.iter_mut() {
section.style = overlay_config.text_config.clone();
}
for entity in &query {
writer.for_each_style(entity, |mut style| {
*style = overlay_config.text_config.clone();
});
}
}

Expand Down
7 changes: 6 additions & 1 deletion crates/bevy_ecs/src/system/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -939,7 +939,7 @@ pub struct EntityCommands<'a> {
pub(crate) commands: Commands<'a, 'a>,
}

impl EntityCommands<'_> {
impl<'a> EntityCommands<'a> {
/// Returns the [`Entity`] id of the entity.
///
/// # Example
Expand Down Expand Up @@ -1533,6 +1533,11 @@ impl EntityCommands<'_> {
self.commands.reborrow()
}

/// Returns a mutable reference to the underlying [`Commands`].
pub fn commands_mut(&mut self) -> &mut Commands<'a, 'a> {
cart marked this conversation as resolved.
Show resolved Hide resolved
&mut self.commands
}

/// Sends a [`Trigger`] targeting this entity. This will run any [`Observer`] of the `event` that
/// watches this entity.
///
Expand Down
2 changes: 2 additions & 0 deletions crates/bevy_text/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ bevy_asset = { path = "../bevy_asset", version = "0.15.0-dev" }
bevy_color = { path = "../bevy_color", version = "0.15.0-dev" }
bevy_derive = { path = "../bevy_derive", version = "0.15.0-dev" }
bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev" }
bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.15.0-dev" }
bevy_math = { path = "../bevy_math", version = "0.15.0-dev" }
bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev", features = [
"bevy",
Expand All @@ -36,6 +37,7 @@ derive_more = { version = "1", default-features = false, features = [
"display",
] }
serde = { version = "1", features = ["derive"] }
smallvec = "1.13"
unicode-bidi = "0.3.13"
sys-locale = "0.3.0"

Expand Down
4 changes: 2 additions & 2 deletions crates/bevy_text/src/font_atlas_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ pub struct FontAtlasKey(pub u32, pub FontSmoothing);
/// A `FontAtlasSet` is an [`Asset`].
///
/// There is one `FontAtlasSet` for each font:
/// - When a [`Font`] is loaded as an asset and then used in [`Text`](crate::Text),
/// - When a [`Font`] is loaded as an asset and then used in [`TextStyle`](crate::TextStyle),
/// a `FontAtlasSet` asset is created from a weak handle to the `Font`.
/// - ~When a font is loaded as a system font, and then used in [`Text`](crate::Text),
/// - ~When a font is loaded as a system font, and then used in [`TextStyle`](crate::TextStyle),
/// a `FontAtlasSet` asset is created and stored with a strong handle to the `FontAtlasSet`.~
/// (*Note that system fonts are not currently supported by the `TextPipeline`.*)
///
Expand Down
15 changes: 5 additions & 10 deletions crates/bevy_text/src/glyph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ use bevy_sprite::TextureAtlasLayout;
/// Used in [`TextPipeline::queue_text`](crate::TextPipeline::queue_text) and [`crate::TextLayoutInfo`] for rendering glyphs.
#[derive(Debug, Clone, Reflect)]
pub struct PositionedGlyph {
/// The position of the glyph in the [`Text`](crate::Text)'s bounding box.
/// The position of the glyph in the text block's bounding box.
pub position: Vec2,
/// The width and height of the glyph in logical pixels.
pub size: Vec2,
/// Information about the glyph's atlas.
pub atlas_info: GlyphAtlasInfo,
/// The index of the glyph in the [`Text`](crate::Text)'s sections.
pub section_index: usize,
/// The index of the glyph in the [`ComputedTextBlock`](crate::ComputedTextBlock)'s tracked spans.
pub span_index: usize,
/// TODO: In order to do text editing, we need access to the size of glyphs and their index in the associated String.
/// For example, to figure out where to place the cursor in an input box from the mouse's position.
/// Without this, it's only possible in texts where each glyph is one byte. Cosmic text has methods for this
Expand All @@ -30,17 +30,12 @@ pub struct PositionedGlyph {

impl PositionedGlyph {
/// Creates a new [`PositionedGlyph`]
pub fn new(
position: Vec2,
size: Vec2,
atlas_info: GlyphAtlasInfo,
section_index: usize,
) -> Self {
pub fn new(position: Vec2, size: Vec2, atlas_info: GlyphAtlasInfo, span_index: usize) -> Self {
Self {
position,
size,
atlas_info,
section_index,
span_index,
byte_index: 0,
}
}
Expand Down
35 changes: 21 additions & 14 deletions crates/bevy_text/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
//!
//! The [`TextPipeline`] resource does all of the heavy lifting for rendering text.
//!
//! [`Text`] is first measured by creating a [`TextMeasureInfo`] in [`TextPipeline::create_text_measure`],
//! UI `Text` is first measured by creating a [`TextMeasureInfo`] in [`TextPipeline::create_text_measure`],
//! which is called by the `measure_text_system` system of `bevy_ui`.
//!
//! Note that text measurement is only relevant in a UI context.
Expand All @@ -23,7 +23,7 @@
//! or [`text2d::update_text2d_layout`] system (in a 2d world space context)
//! passes it into [`TextPipeline::queue_text`], which:
//!
//! 1. creates a [`Buffer`](cosmic_text::Buffer) from the [`TextSection`]s, generating new [`FontAtlasSet`]s if necessary.
//! 1. updates a [`Buffer`](cosmic_text::Buffer) from the [`TextSpan`]s, generating new [`FontAtlasSet`]s if necessary.
//! 2. iterates over each glyph in the [`Buffer`](cosmic_text::Buffer) to create a [`PositionedGlyph`],
//! retrieving glyphs from the cache, or rasterizing to a [`FontAtlas`] if necessary.
//! 3. [`PositionedGlyph`]s are stored in a [`TextLayoutInfo`],
Expand All @@ -43,6 +43,7 @@ mod glyph;
mod pipeline;
mod text;
mod text2d;
mod text_access;

pub use cosmic_text;

Expand All @@ -56,13 +57,17 @@ pub use glyph::*;
pub use pipeline::*;
pub use text::*;
pub use text2d::*;
pub use text_access::*;

/// The text prelude.
///
/// This includes the most common types in this crate, re-exported for your convenience.
pub mod prelude {
#[doc(hidden)]
pub use crate::{Font, JustifyText, Text, Text2dBundle, TextError, TextSection, TextStyle};
pub use crate::{
Font, JustifyText, LineBreak, Text2d, TextBlock, TextError, TextReader2d, TextSpan,
TextStyle, TextWriter2d,
};
}

use bevy_app::prelude::*;
Expand All @@ -87,7 +92,7 @@ pub const DEFAULT_FONT_DATA: &[u8] = include_bytes!("FiraMono-subset.ttf");
pub struct TextPlugin;

/// Text is rendered for two different view projections;
/// 2-dimensional text ([`Text2dBundle`]) is rendered in "world space" with a `BottomToTop` Y-axis,
/// 2-dimensional text ([`Text2d`]) is rendered in "world space" with a `BottomToTop` Y-axis,
/// while UI is rendered with a `TopToBottom` Y-axis.
/// This matters for text because the glyph positioning is different in either layout.
/// For `TopToBottom`, 0 is the top of the text, while for `BottomToTop` 0 is the bottom.
Expand All @@ -98,35 +103,37 @@ pub enum YAxisOrientation {
BottomToTop,
}

/// A convenient alias for `With<Text>`, for use with
/// [`bevy_render::view::VisibleEntities`].
pub type WithText = With<Text>;
/// System set in [`PostUpdate`] where all 2d text update systems are executed.
#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
pub struct Update2dText;

impl Plugin for TextPlugin {
fn build(&self, app: &mut App) {
app.init_asset::<Font>()
.register_type::<Text>()
.register_type::<Text2d>()
.register_type::<TextSpan>()
.register_type::<TextBounds>()
.init_asset_loader::<FontLoader>()
.init_resource::<FontAtlasSets>()
.init_resource::<TextPipeline>()
.init_resource::<CosmicFontSystem>()
.init_resource::<SwashCache>()
.init_resource::<TextIterScratch>()
.add_systems(
PostUpdate,
(
calculate_bounds_text2d
.in_set(VisibilitySystems::CalculateBounds)
.after(update_text2d_layout),
remove_dropped_font_atlas_sets,
detect_text_needs_rerender::<Text2d>,
update_text2d_layout
.after(remove_dropped_font_atlas_sets)
// Potential conflict: `Assets<Image>`
// In practice, they run independently since `bevy_render::camera_update_system`
// will only ever observe its own render target, and `update_text2d_layout`
// will never modify a pre-existing `Image` asset.
.ambiguous_with(CameraUpdateSystem),
remove_dropped_font_atlas_sets,
),
calculate_bounds_text2d.in_set(VisibilitySystems::CalculateBounds),
)
.chain()
.in_set(Update2dText),
)
.add_systems(Last, trim_cosmic_cache);

Expand Down
Loading