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

split up TextStyle #15857

Merged
merged 61 commits into from
Oct 13, 2024
Merged

split up TextStyle #15857

merged 61 commits into from
Oct 13, 2024

Conversation

ickshonpe
Copy link
Contributor

@ickshonpe ickshonpe commented Oct 11, 2024

Objective

Currently text is recomputed unnecessarily on any changes to its color, which is extremely expensive.

Solution

Split up TextStyle into two separate components TextFont and TextColor.

Testing

I added this system to many_buttons:

fn set_text_colors_changed(mut colors: Query<&mut TextColor>) {
    for mut text_color in colors.iter_mut() {
        text_color.set_changed();
    }
}

reports ~4fps on main, ~50fps with this PR.

Migration Guide

TextStyle has been renamed to TextFont and its color field has been moved to a separate component named TextColor which newtypes Color.

@alice-i-cecile alice-i-cecile added C-Usability A targeted quality-of-life change that makes Bevy easier to use A-Text Rendering and layout for characters X-Contentious There are nontrivial implications that should be thought through S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Oct 11, 2024
@alice-i-cecile alice-i-cecile added this to the 0.15 milestone Oct 11, 2024
@alice-i-cecile alice-i-cecile added the C-Performance A change motivated by improving speed, memory usage or compile times label Oct 11, 2024
@alice-i-cecile
Copy link
Member

I really like this change. It's more granular, allowing us to be lazier about recomputations, but IMO it's also much clearer to users.

@rparrett
Copy link
Contributor

It looks like the current status of the examples is that they've been find/replaced, but many are likely broken in an obvious way. Feel free to ping me when this is ready for review.

@alice-i-cecile alice-i-cecile added S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Oct 11, 2024
@viridia
Copy link
Contributor

viridia commented Oct 11, 2024

This all sounds good to me. Adapting my framework to work with this will not be difficult.

@ickshonpe
Copy link
Contributor Author

Yeah I thought about this, but not sure either. I can't think of any use since there aren't any TextColor fields or parameters?

Easier to use TextColor::from(Srgba::new(...)) than TextColor(Srgba::new(...).into()).

I guess and might be useful if someone is constructing a bunch of spans using an iterator or something.

Copy link
Member

@alice-i-cecile alice-i-cecile left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I spotted a couple of missed internal renames, but those are just nits :) Nice stuff!

@alice-i-cecile alice-i-cecile added S-Needs-Review Needs reviewer attention (from anyone!) to move forward and removed S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged labels Oct 12, 2024
Copy link
Contributor

@pablo-lua pablo-lua left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Big changes. I have some questions

@@ -40,7 +40,7 @@ fn main() {
}

impl AnimatableProperty for FontSizeProperty {
type Component = TextStyle;
type Component = TextFont;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand the bevy error 0005 correctly, we shouldn't generally be changing the size of a font this way, and instead use transform or ui_scale. Should this example continue to teach this possible footgun to the users?

Copy link
Contributor Author

@ickshonpe ickshonpe Oct 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I agree it's not a good example, it should probably be removed. Scaling the foot using transform isn't normally a good solution either as the text will end up blurred (or blocky if you turn off anti-aliasing). It's outside the scope of this PR to fix it though I think.

examples/animation/easing_functions.rs Outdated Show resolved Hide resolved
@@ -433,11 +432,11 @@ mod menu {
// Display the game name
parent.spawn((
Text::new("Bevy Game Menu UI"),
TextStyle {
TextFont {
font_size: 67.0,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: generally we only set the size of the font when creating it. Is it possible that we maybe add a shorthand method for this? like TextFont::from_size(size: f32)

Copy link
Contributor Author

@ickshonpe ickshonpe Oct 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I agree it's annoying. FontSmoothing is quite niche as well, I'd rather it was a separate component.
I want to keep this PR to just dealing with color though as it's the biggest problem.

Copy link
Contributor

@rparrett rparrett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have some slight reservations about ux, particularly the amount of

let text_style = (
    TextFont {
        // ...
    },
    TextColor(/* ... */)
);

now happening, which I think will be very common in user code.

But if we're happy with the design then the code looks good to me. The benefits are certainly obvious.

Copy link
Contributor

@pablo-lua pablo-lua left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with the changes and has some good improvements. I have one small nit, but otherwise LGTM

examples/async_tasks/external_source_external_thread.rs Outdated Show resolved Hide resolved
@rparrett rparrett added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Oct 12, 2024
@ickshonpe
Copy link
Contributor Author

ickshonpe commented Oct 12, 2024

I have some slight reservations about ux, particularly the amount of

let text_style = (
    TextFont {
        // ...
    },
    TextColor(/* ... */)
);

now happening, which I think will be very common in user code.

But if we're happy with the design then the code looks good to me. The benefits are certainly obvious.

Yeah I think what this needs is just text font + color inheritance flowing down the tree, It's trivial to implement a basic version, but maybe depends what's being planned with bsn etc.

Copy link
Contributor

@UkoeHB UkoeHB left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good, just one API request.

Comment on lines -131 to +137
writer.for_each_style(entity, |mut style| {
*style = overlay_config.text_config.clone();
writer.for_each_font(entity, |mut font| {
*font = overlay_config.text_config.clone();
});
writer.for_each_color(entity, |mut color| color.0 = overlay_config.text_color);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we keep for_each_style and have it pass both the font and color as params?

Copy link
Contributor Author

@ickshonpe ickshonpe Oct 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could but I'm wondering if all these helper functions are even needed though. Users can just use for_each and ignore the fields that they don't need? We could return a struct with named fields instread of an optional tuple to make it more ergonomic.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I believe that we should leave this helpers to a follow-up PR so we can discuss better what to do with them

crates/bevy_text/src/text.rs Show resolved Hide resolved
@alice-i-cecile alice-i-cecile added this pull request to the merge queue Oct 13, 2024
Merged via the queue into bevyengine:main with commit 6f7d0e5 Oct 13, 2024
27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Text Rendering and layout for characters C-Performance A change motivated by improving speed, memory usage or compile times C-Usability A targeted quality-of-life change that makes Bevy easier to use S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it X-Contentious There are nontrivial implications that should be thought through
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants