mireforge_font/
lib.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/mireforge/mireforge
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5use bmf_parser::BMFont;
6use int_math::{URect, UVec2, Vec2};
7use limnus_app::prelude::{App, Plugin};
8use limnus_asset_registry::AssetRegistry;
9use limnus_assets::Assets;
10use limnus_assets::prelude::{Asset, AssetName, Id, RawWeakId, WeakId};
11use limnus_assets_loader::{
12    AssetLoader, ConversionError, ResourceStorage, WrappedAssetLoaderRegistry,
13};
14use limnus_local_resource::LocalResourceStorage;
15use std::str::FromStr;
16use tracing::debug;
17
18pub type FontRef = Id<Font>;
19pub type WeakFontRef = WeakId<Font>;
20
21#[derive(Debug, Asset)]
22pub struct Font {
23    font: BMFont,
24}
25
26pub struct FontPlugin;
27
28impl Plugin for FontPlugin {
29    fn build(&self, app: &mut App) {
30        {
31            let registry = app.resource_mut::<WrappedAssetLoaderRegistry>();
32            let loader = FontConverter::new();
33
34            registry.value.lock().unwrap().register_loader(loader);
35        }
36
37        app.insert_resource(Assets::<Font>::default());
38    }
39}
40
41#[derive(Default)]
42pub struct FontConverter;
43
44impl FontConverter {
45    #[must_use]
46    pub const fn new() -> Self {
47        Self {}
48    }
49}
50
51impl AssetLoader for FontConverter {
52    type AssetType = Font;
53
54    fn convert_and_insert(
55        &self,
56        id: RawWeakId,
57        octets: &[u8],
58        resources: &mut ResourceStorage,
59        _local_resources: &mut LocalResourceStorage,
60    ) -> Result<(), ConversionError> {
61        let name: AssetName;
62        {
63            let asset_container = resources.fetch::<AssetRegistry>();
64            name = asset_container
65                .name_raw(id)
66                .expect("should know about this Id");
67        }
68
69        debug!("convert from fnt {name}");
70
71        let font = if name.value().ends_with(".txt.fnt") {
72            let str = String::from_utf8(octets.to_vec()).unwrap();
73            BMFont::from_str(&str)?
74        } else {
75            BMFont::from_octets(octets)?
76        };
77
78        debug!("font complete {name}");
79        let font_assets = resources.fetch_mut::<Assets<Font>>();
80
81        font_assets.set_raw(id, Font { font });
82
83        Ok(())
84    }
85}
86
87#[derive(Debug)]
88pub struct Glyph {
89    pub relative_position: Vec2,
90    pub texture_rectangle: URect,
91}
92
93impl Font {
94    /// # Panics
95    ///
96    #[must_use]
97    pub fn from_octets(bm_contents: &[u8]) -> Self {
98        let font = BMFont::from_octets(bm_contents).unwrap();
99        Self { font }
100    }
101
102		pub fn info(&self) -> &BMFont {
103			&self.font
104		}
105
106    /// # Panics
107    ///
108    #[must_use]
109    pub fn draw(&self, text: &str) -> Vec<Glyph> {
110        let mut x = 0;
111        let y = 0;
112        let common = self.font.common.as_ref().unwrap();
113        let height = self.font.info.as_ref().unwrap().font_size;
114        let mut glyphs = Vec::new();
115        let factor = 1u16;
116        let y_offset = -(common.line_height as i16 - common.base as i16);
117        for ch in text.chars() {
118            if let Some(bm_char) = self.font.chars.get(&(ch as u32)) {
119                let cx = x + bm_char.x_offset * factor as i16;
120                let cy = y + y_offset + height - (bm_char.height as i16) - bm_char.y_offset;
121
122                let glyph = Glyph {
123                    relative_position: Vec2 { x: cx, y: cy },
124                    texture_rectangle: URect {
125                        position: UVec2 {
126                            x: bm_char.x,
127                            y: bm_char.y,
128                        },
129                        size: UVec2 {
130                            x: bm_char.width,
131                            y: bm_char.height,
132                        },
133                    },
134                };
135                x += bm_char.x_advance * factor as i16;
136
137                glyphs.push(glyph);
138            }
139        }
140
141        glyphs
142    }
143}