micro_games_kit/assets/
font.rs

1use crate::{context::GameContext, game::GameSubsystem};
2use anput::world::World;
3use fontdue::Font;
4use keket::{
5    database::{handle::AssetHandle, path::AssetPathStatic},
6    protocol::AssetProtocol,
7};
8use std::error::Error;
9
10use super::name_from_path;
11
12pub struct FontAsset {
13    pub font: Font,
14}
15
16pub struct FontAssetSubsystem;
17
18impl GameSubsystem for FontAssetSubsystem {
19    fn run(&mut self, context: GameContext, _: f32) {
20        for entity in context.assets.storage.added().iter_of::<FontAsset>() {
21            if let Some((path, asset)) = context
22                .assets
23                .storage
24                .lookup_one::<true, (&AssetPathStatic, &FontAsset)>(entity)
25            {
26                context
27                    .draw
28                    .fonts
29                    .insert(name_from_path(&path).to_owned(), asset.font.clone());
30            }
31        }
32        for entity in context.assets.storage.removed().iter_of::<FontAsset>() {
33            if let Some(path) = context
34                .assets
35                .storage
36                .lookup_one::<true, &AssetPathStatic>(entity)
37            {
38                context.draw.fonts.remove(name_from_path(&path));
39            }
40        }
41    }
42}
43
44pub struct FontAssetProtocol;
45
46impl AssetProtocol for FontAssetProtocol {
47    fn name(&self) -> &str {
48        "font"
49    }
50
51    fn process_bytes(
52        &mut self,
53        handle: AssetHandle,
54        storage: &mut World,
55        bytes: Vec<u8>,
56    ) -> Result<(), Box<dyn Error>> {
57        let path = storage.component::<true, AssetPathStatic>(handle.entity())?;
58        let font = Font::from_bytes(bytes, Default::default())
59            .map_err(|_| format!("Failed to load font: {:?}", path.path()))?;
60        drop(path);
61
62        storage.insert(handle.entity(), (FontAsset { font },))?;
63
64        Ok(())
65    }
66}