Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/examples/ui/text/font_atlas_debug.rs
9341 views
1
//! This example illustrates how `FontAtlas`'s are populated.
2
//! Bevy uses `FontAtlas`'s under the hood to optimize text rendering.
3
4
use bevy::{color::palettes::basic::YELLOW, prelude::*, text::FontAtlasSet};
5
6
use rand::{Rng, SeedableRng};
7
use rand_chacha::ChaCha8Rng;
8
9
fn main() {
10
App::new()
11
.init_resource::<State>()
12
.insert_resource(ClearColor(Color::BLACK))
13
.add_plugins(DefaultPlugins)
14
.add_systems(Startup, setup)
15
.add_systems(Update, (text_update_system, atlas_render_system))
16
.run();
17
}
18
19
#[derive(Resource)]
20
struct State {
21
atlas_count: u32,
22
handle: Handle<Font>,
23
timer: Timer,
24
}
25
26
impl Default for State {
27
fn default() -> Self {
28
Self {
29
atlas_count: 0,
30
handle: Handle::default(),
31
timer: Timer::from_seconds(0.05, TimerMode::Repeating),
32
}
33
}
34
}
35
36
#[derive(Resource, Deref, DerefMut)]
37
struct SeededRng(ChaCha8Rng);
38
39
fn atlas_render_system(
40
mut commands: Commands,
41
mut state: ResMut<State>,
42
font_atlas_set: Res<FontAtlasSet>,
43
images: Res<Assets<Image>>,
44
) {
45
if let Some(font_atlases) = font_atlas_set.values().next() {
46
let x_offset = state.atlas_count as f32;
47
if state.atlas_count == font_atlases.len() as u32 {
48
return;
49
}
50
let font_atlas = &font_atlases[state.atlas_count as usize];
51
let image = images.get(&font_atlas.texture).unwrap();
52
state.atlas_count += 1;
53
commands.spawn((
54
ImageNode::new(font_atlas.texture.clone()),
55
Node {
56
position_type: PositionType::Absolute,
57
top: Val::ZERO,
58
left: px(image.width() as f32 * x_offset),
59
..default()
60
},
61
));
62
}
63
}
64
65
fn text_update_system(
66
mut state: ResMut<State>,
67
time: Res<Time>,
68
mut query: Query<&mut Text>,
69
mut seeded_rng: ResMut<SeededRng>,
70
) {
71
if !state.timer.tick(time.delta()).just_finished() {
72
return;
73
}
74
75
for mut text in &mut query {
76
let c = seeded_rng.random::<u8>() as char;
77
let string = &mut **text;
78
if !string.contains(c) {
79
string.push(c);
80
}
81
}
82
}
83
84
fn setup(mut commands: Commands, asset_server: Res<AssetServer>, mut state: ResMut<State>) {
85
state.handle = asset_server.load("fonts/FiraSans-Bold.ttf");
86
let font = FontSource::from(state.handle.clone());
87
commands.spawn(Camera2d);
88
commands
89
.spawn((
90
Node {
91
position_type: PositionType::Absolute,
92
bottom: Val::ZERO,
93
..default()
94
},
95
BackgroundColor(Color::NONE),
96
))
97
.with_children(|parent| {
98
parent.spawn((
99
Text::new("a"),
100
TextFont {
101
font,
102
font_size: FontSize::Px(50.0),
103
..default()
104
},
105
TextColor(YELLOW.into()),
106
));
107
});
108
// We're seeding the PRNG here to make this example deterministic for testing purposes.
109
// This isn't strictly required in practical use unless you need your app to be deterministic.
110
commands.insert_resource(SeededRng(ChaCha8Rng::seed_from_u64(19878367467713)));
111
}
112
113