Skip to content

Commit 7d0e98f

Browse files
nsideCleanCut
andcommitted
Implement rotation for Text2d (#2084)
Fixes #2080 ![CleanShot 2021-05-02 at 22 50 09](https://user-images.githubusercontent.com/11653/116844876-373ca780-ab99-11eb-8f61-8d93d929bff0.gif) Co-authored-by: Nathan Stocks <[email protected]> Co-authored-by: Denis Laprise <[email protected]>
1 parent 41d9122 commit 7d0e98f

File tree

4 files changed

+88
-53
lines changed

4 files changed

+88
-53
lines changed

crates/bevy_text/src/draw.rs

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
use crate::{PositionedGlyph, TextSection};
12
use bevy_math::{Mat4, Vec3};
3+
use bevy_render::pipeline::IndexFormat;
24
use bevy_render::{
35
draw::{Draw, DrawContext, DrawError, Drawable},
46
mesh,
@@ -8,19 +10,18 @@ use bevy_render::{
810
renderer::{BindGroup, RenderResourceBindings, RenderResourceId},
911
};
1012
use bevy_sprite::TextureAtlasSprite;
13+
use bevy_transform::prelude::GlobalTransform;
1114
use bevy_utils::tracing::error;
1215

13-
use crate::{PositionedGlyph, TextSection};
14-
use bevy_render::pipeline::IndexFormat;
15-
1616
pub struct DrawableText<'a> {
1717
pub render_resource_bindings: &'a mut RenderResourceBindings,
18-
pub position: Vec3,
18+
pub global_transform: GlobalTransform,
1919
pub scale_factor: f32,
2020
pub sections: &'a [TextSection],
2121
pub text_glyphs: &'a Vec<PositionedGlyph>,
2222
pub msaa: &'a Msaa,
2323
pub font_quad_vertex_layout: &'a VertexBufferLayout,
24+
pub alignment_offset: Vec3,
2425
}
2526

2627
impl<'a> Drawable for DrawableText<'a> {
@@ -76,19 +77,12 @@ impl<'a> Drawable for DrawableText<'a> {
7677
flip_y: false,
7778
};
7879

79-
// To get the rendering right for non-one scaling factors, we need
80-
// the sprite to be drawn in "physical" coordinates. This is because
81-
// the shader uses the size of the sprite to control the size on
82-
// screen. To accomplish this we make the sprite transform
83-
// convert from physical coordinates to logical coordinates in
84-
// addition to altering the origin. Since individual glyphs will
85-
// already be in physical coordinates, we just need to convert the
86-
// overall position to physical coordinates to get the sprites
87-
// physical position.
88-
89-
let transform = Mat4::from_scale(Vec3::splat(1. / self.scale_factor))
80+
let transform = Mat4::from_rotation_translation(
81+
self.global_transform.rotation,
82+
self.global_transform.translation,
83+
) * Mat4::from_scale(self.global_transform.scale / self.scale_factor)
9084
* Mat4::from_translation(
91-
self.position * self.scale_factor + tv.position.extend(0.),
85+
self.alignment_offset * self.scale_factor + tv.position.extend(0.),
9286
);
9387

9488
let transform_buffer = context.get_uniform_buffer(&transform).unwrap();

crates/bevy_text/src/text2d.rs

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -93,26 +93,25 @@ pub fn draw_text2d_system(
9393
let (width, height) = (calculated_size.size.width, calculated_size.size.height);
9494

9595
if let Some(text_glyphs) = text_pipeline.get_glyphs(&entity) {
96-
let position = global_transform.translation
97-
+ match text.alignment.vertical {
98-
VerticalAlign::Top => Vec3::ZERO,
99-
VerticalAlign::Center => Vec3::new(0.0, -height * 0.5, 0.0),
100-
VerticalAlign::Bottom => Vec3::new(0.0, -height, 0.0),
101-
}
102-
+ match text.alignment.horizontal {
103-
HorizontalAlign::Left => Vec3::new(-width, 0.0, 0.0),
104-
HorizontalAlign::Center => Vec3::new(-width * 0.5, 0.0, 0.0),
105-
HorizontalAlign::Right => Vec3::ZERO,
106-
};
96+
let alignment_offset = match text.alignment.vertical {
97+
VerticalAlign::Top => Vec3::new(0.0, -height, 0.0),
98+
VerticalAlign::Center => Vec3::new(0.0, -height * 0.5, 0.0),
99+
VerticalAlign::Bottom => Vec3::ZERO,
100+
} + match text.alignment.horizontal {
101+
HorizontalAlign::Left => Vec3::ZERO,
102+
HorizontalAlign::Center => Vec3::new(-width * 0.5, 0.0, 0.0),
103+
HorizontalAlign::Right => Vec3::new(-width, 0.0, 0.0),
104+
};
107105

108106
let mut drawable_text = DrawableText {
109107
render_resource_bindings: &mut render_resource_bindings,
110-
position,
108+
global_transform: *global_transform,
109+
scale_factor,
111110
msaa: &msaa,
112111
text_glyphs: &text_glyphs.glyphs,
113112
font_quad_vertex_layout: &font_quad_vertex_layout,
114-
scale_factor,
115113
sections: &text.sections,
114+
alignment_offset,
116115
};
117116

118117
drawable_text.draw(&mut draw, &mut context).unwrap();

crates/bevy_ui/src/widget/text.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,16 +167,15 @@ pub fn draw_text_system(
167167
}
168168

169169
if let Some(text_glyphs) = text_pipeline.get_glyphs(&entity) {
170-
let position = global_transform.translation - (node.size / 2.0).extend(0.0);
171-
172170
let mut drawable_text = DrawableText {
173171
render_resource_bindings: &mut render_resource_bindings,
174-
position,
172+
global_transform: *global_transform,
175173
scale_factor: scale_factor as f32,
176174
msaa: &msaa,
177175
text_glyphs: &text_glyphs.glyphs,
178176
font_quad_vertex_layout: &vertex_buffer_layout,
179177
sections: &text.sections,
178+
alignment_offset: (node.size / -2.0).extend(0.0),
180179
};
181180

182181
drawable_text.draw(&mut draw, &mut context).unwrap();

examples/2d/text2d.rs

Lines changed: 64 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,36 +4,79 @@ fn main() {
44
App::build()
55
.add_plugins(DefaultPlugins)
66
.add_startup_system(setup.system())
7-
.add_system(animate.system())
7+
.add_system(animate_translation.system())
8+
.add_system(animate_rotation.system())
9+
.add_system(animate_scale.system())
810
.run();
911
}
1012

13+
struct AnimateTranslation;
14+
struct AnimateRotation;
15+
struct AnimateScale;
16+
1117
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
18+
let font = asset_server.load("fonts/FiraSans-Bold.ttf");
19+
let text_style = TextStyle {
20+
font,
21+
font_size: 60.0,
22+
color: Color::WHITE,
23+
};
24+
let text_alignment = TextAlignment {
25+
vertical: VerticalAlign::Center,
26+
horizontal: HorizontalAlign::Center,
27+
};
1228
// 2d camera
1329
commands.spawn_bundle(OrthographicCameraBundle::new_2d());
14-
commands.spawn_bundle(Text2dBundle {
15-
text: Text::with_section(
16-
"This text is in the 2D scene.",
17-
TextStyle {
18-
font: asset_server.load("fonts/FiraSans-Bold.ttf"),
19-
font_size: 60.0,
20-
color: Color::WHITE,
21-
},
22-
TextAlignment {
23-
vertical: VerticalAlign::Center,
24-
horizontal: HorizontalAlign::Center,
25-
},
26-
),
27-
..Default::default()
28-
});
30+
// Demonstrate changing translation
31+
commands
32+
.spawn_bundle(Text2dBundle {
33+
text: Text::with_section("translation", text_style.clone(), text_alignment),
34+
..Default::default()
35+
})
36+
.insert(AnimateTranslation);
37+
// Demonstrate changing rotation
38+
commands
39+
.spawn_bundle(Text2dBundle {
40+
text: Text::with_section("rotation", text_style.clone(), text_alignment),
41+
..Default::default()
42+
})
43+
.insert(AnimateRotation);
44+
// Demonstrate changing scale
45+
commands
46+
.spawn_bundle(Text2dBundle {
47+
text: Text::with_section("scale", text_style, text_alignment),
48+
..Default::default()
49+
})
50+
.insert(AnimateScale);
2951
}
3052

31-
fn animate(time: Res<Time>, mut query: Query<&mut Transform, With<Text>>) {
32-
// `Transform.translation` will determine the location of the text.
33-
// `Transform.scale` and `Transform.rotation` do not yet affect text (though you can set the
34-
// size of the text via `Text.style.font_size`)
53+
fn animate_translation(
54+
time: Res<Time>,
55+
mut query: Query<&mut Transform, (With<Text>, With<AnimateTranslation>)>,
56+
) {
3557
for mut transform in query.iter_mut() {
36-
transform.translation.x = 100.0 * time.seconds_since_startup().sin() as f32;
58+
transform.translation.x = 100.0 * time.seconds_since_startup().sin() as f32 - 400.0;
3759
transform.translation.y = 100.0 * time.seconds_since_startup().cos() as f32;
3860
}
3961
}
62+
63+
fn animate_rotation(
64+
time: Res<Time>,
65+
mut query: Query<&mut Transform, (With<Text>, With<AnimateRotation>)>,
66+
) {
67+
for mut transform in query.iter_mut() {
68+
transform.rotation = Quat::from_rotation_z(time.seconds_since_startup().cos() as f32);
69+
}
70+
}
71+
72+
fn animate_scale(
73+
time: Res<Time>,
74+
mut query: Query<&mut Transform, (With<Text>, With<AnimateScale>)>,
75+
) {
76+
// Consider changing font-size instead of scaling the transform. Scaling a Text2D will scale the
77+
// rendered quad, resulting in a pixellated look.
78+
for mut transform in query.iter_mut() {
79+
transform.translation = Vec3::new(400.0, 0.0, 0.0);
80+
transform.scale = Vec3::splat((time.seconds_since_startup().sin() as f32 + 1.1) * 2.0);
81+
}
82+
}

0 commit comments

Comments
 (0)