Skip to content

Commit 9fb125e

Browse files
authored
Improved font handling (#6)
* Add system for conveniently loading fonts * Use the font plugin to only specify a font family, not each font individually * Simplify querying for a font handle * Improve structure of font module and exports * Improve syntax for configuring font folder and make it optional * Example setup doesn't need the AssetServer anymore
1 parent f05e5a0 commit 9fb125e

File tree

14 files changed

+274
-60
lines changed

14 files changed

+274
-60
lines changed

Cargo.lock

Lines changed: 60 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ categories = ["game-development"]
1111
exclude = ["assets/**/*", ".github/**/*"]
1212

1313
[dependencies]
14+
ab_glyph = "0.2.28"
15+
fontdb = "0.20.0"
1416
nom = "7.1.3"
17+
tinyvec = "1.8.0"
1518

1619
[dependencies.bevy]
1720
version = "0.14"

assets/CREDITS.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Credits
2+
3+
| Path | License |
4+
| ------- | --------- |
5+
| `fonts` | `OFL.txt` |
File renamed without changes.

examples/dynamic.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,18 @@ struct TimeMarker;
1010

1111
fn main() {
1212
App::new()
13-
.add_plugins((DefaultPlugins, BbcodePlugin))
13+
.add_plugins((DefaultPlugins, BbcodePlugin::new().with_fonts("fonts")))
1414
.add_systems(Startup, setup)
1515
.add_systems(Update, update)
1616
.run();
1717
}
1818

19-
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
19+
fn setup(mut commands: Commands) {
2020
commands.spawn(Camera2dBundle::default());
2121

2222
commands.spawn(BbcodeBundle::from_content(
2323
"Time passed: [m=time]0.0[/m] s",
24-
BbcodeSettings::new(40., Color::WHITE)
25-
.with_regular_font(asset_server.load("fonts/FiraSans-Regular.ttf"))
26-
.with_bold_font(asset_server.load("fonts/FiraSans-Bold.ttf"))
27-
.with_italic_font(asset_server.load("fonts/FiraSans-Italic.ttf"))
24+
BbcodeSettings::new("Fira Sans", 40., Color::WHITE)
2825
// Register the marker component for the `m=time` tag
2926
.with_marker("time", TimeMarker),
3027
));

examples/static.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,16 @@ use bevy_mod_bbcode::{BbcodeBundle, BbcodePlugin, BbcodeSettings};
33

44
fn main() {
55
App::new()
6-
.add_plugins((DefaultPlugins, BbcodePlugin))
6+
.add_plugins((DefaultPlugins, BbcodePlugin::new().with_fonts("fonts")))
77
.add_systems(Startup, setup)
88
.run();
99
}
1010

11-
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
11+
fn setup(mut commands: Commands) {
1212
commands.spawn(Camera2dBundle::default());
1313

1414
commands.spawn(BbcodeBundle::from_content(
15-
"test [b]bold[/b] with [i]italic[/i] and [c=#ff00ff]color[/c]",
16-
BbcodeSettings::new(40., Color::WHITE)
17-
.with_regular_font(asset_server.load("fonts/FiraSans-Regular.ttf"))
18-
.with_bold_font(asset_server.load("fonts/FiraSans-Bold.ttf"))
19-
.with_italic_font(asset_server.load("fonts/FiraSans-Italic.ttf")),
15+
"test [b]bold with [i]italic[/i][/b] and [c=#ff00ff]color[/c]",
16+
BbcodeSettings::new("Fira Sans", 40., Color::WHITE),
2017
));
2118
}

src/bevy/bbcode.rs

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,46 +18,23 @@ pub(crate) struct Modifiers {
1818

1919
#[derive(Clone, Component)]
2020
pub struct BbcodeSettings {
21+
pub font_family: String,
2122
pub font_size: f32,
2223
pub color: Color,
2324

24-
pub(crate) regular_font: Option<Handle<Font>>,
25-
pub(crate) bold_font: Option<Handle<Font>>,
26-
pub(crate) italic_font: Option<Handle<Font>>,
27-
2825
pub(crate) modifiers: Modifiers,
2926
}
3027

3128
impl BbcodeSettings {
32-
pub fn new(font_size: f32, color: Color) -> Self {
29+
pub fn new<F: Into<String>>(font_family: F, font_size: f32, color: Color) -> Self {
3330
Self {
31+
font_family: font_family.into(),
3432
font_size,
3533
color,
36-
regular_font: None,
37-
bold_font: None,
38-
italic_font: None,
3934
modifiers: Default::default(),
4035
}
4136
}
4237

43-
/// Add a font to use for regular text.
44-
pub fn with_regular_font(mut self, handle: Handle<Font>) -> Self {
45-
self.regular_font = Some(handle);
46-
self
47-
}
48-
49-
/// Add a font to use for bold text.
50-
pub fn with_bold_font(mut self, handle: Handle<Font>) -> Self {
51-
self.bold_font = Some(handle);
52-
self
53-
}
54-
55-
/// Add a font to use for italic text.
56-
pub fn with_italic_font(mut self, handle: Handle<Font>) -> Self {
57-
self.italic_font = Some(handle);
58-
self
59-
}
60-
6138
/// Register a marker component for the `[m]` tag.
6239
pub fn with_marker<N: Into<String>, M: Component + Clone>(
6340
mut self,

src/bevy/conversion.rs

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ use bevy::{ecs::system::EntityCommands, prelude::*};
44

55
use crate::bbcode::{parser::parse_bbcode, BbcodeNode, BbcodeTag};
66

7-
use super::bbcode::{Bbcode, BbcodeSettings};
7+
use super::{
8+
bbcode::{Bbcode, BbcodeSettings},
9+
font::FontRegistry,
10+
};
811

912
#[derive(Debug, Clone)]
1013
struct BbcodeContext {
@@ -69,9 +72,10 @@ impl BbcodeContext {
6972
pub fn convert_bbcode(
7073
mut commands: Commands,
7174
bbcode_query: Query<(Entity, Ref<Bbcode>, Ref<BbcodeSettings>)>,
75+
font_registry: Res<FontRegistry>,
7276
) {
7377
for (entity, bbcode, settings) in bbcode_query.iter() {
74-
if !bbcode.is_changed() && !settings.is_changed() {
78+
if !bbcode.is_changed() && !settings.is_changed() && !font_registry.is_changed() {
7579
continue;
7680
}
7781

@@ -100,6 +104,7 @@ pub fn convert_bbcode(
100104
},
101105
&settings,
102106
&nodes,
107+
font_registry.as_ref(),
103108
)
104109
}
105110
}
@@ -109,23 +114,26 @@ fn construct_recursively(
109114
context: BbcodeContext,
110115
settings: &BbcodeSettings,
111116
nodes: &Vec<Arc<BbcodeNode>>,
117+
font_registry: &FontRegistry,
112118
) {
113-
let default_font = settings.regular_font.clone().unwrap_or_default();
114-
115119
for node in nodes {
116120
match **node {
117121
BbcodeNode::Text(ref text) => {
118-
let font = match (context.is_bold, context.is_italic) {
119-
(true, _) => default_font.clone(),
120-
(_, true) => settings
121-
.italic_font
122-
.clone()
123-
.unwrap_or_else(|| default_font.clone()),
124-
(false, false) => settings
125-
.regular_font
126-
.clone()
127-
.unwrap_or_else(|| default_font.clone()),
122+
let font_query = fontdb::Query {
123+
families: &[fontdb::Family::Name(&settings.font_family)],
124+
weight: if context.is_bold {
125+
fontdb::Weight::BOLD
126+
} else {
127+
fontdb::Weight::NORMAL
128+
},
129+
stretch: fontdb::Stretch::Normal,
130+
style: if context.is_italic {
131+
fontdb::Style::Italic
132+
} else {
133+
fontdb::Style::Normal
134+
},
128135
};
136+
let font = font_registry.query_handle(&font_query).unwrap_or_default();
129137

130138
entity_commands.with_children(|builder| {
131139
let mut text_commands = builder.spawn(TextBundle::from_section(
@@ -151,6 +159,7 @@ fn construct_recursively(
151159
context.apply_tag(tag),
152160
settings,
153161
tag.children(),
162+
font_registry,
154163
),
155164
}
156165
}

src/bevy/font/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
mod plugin;
2+
mod registry;
3+
4+
pub use plugin::FontPlugin;
5+
pub use registry::FontRegistry;

src/bevy/font/plugin.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
use bevy::prelude::*;
2+
3+
use super::registry::FontRegistry;
4+
5+
#[derive(Debug)]
6+
pub struct FontPlugin;
7+
8+
impl Plugin for FontPlugin {
9+
fn build(&self, app: &mut App) {
10+
app.init_resource::<FontRegistry>()
11+
.add_systems(Update, update_font_registry);
12+
}
13+
}
14+
15+
/// Track when fonts are loaded, modified or removed and update the font registry accordingly.
16+
fn update_font_registry(
17+
mut font_registry: ResMut<FontRegistry>,
18+
mut font_changes: EventReader<AssetEvent<Font>>,
19+
font_assets: Res<Assets<Font>>,
20+
) {
21+
for change in font_changes.read() {
22+
match *change {
23+
AssetEvent::Added { id } => font_registry.add(id, font_assets.as_ref()),
24+
AssetEvent::Modified { id } => font_registry.update(id, font_assets.as_ref()),
25+
AssetEvent::Removed { id } => font_registry.remove(id),
26+
AssetEvent::Unused { id: _ } => {}
27+
AssetEvent::LoadedWithDependencies { id: _ } => {}
28+
}
29+
}
30+
}

0 commit comments

Comments
 (0)