1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
//! ```rust
//! let ilmenite = Ilmenite::new();
//!
//! ilmenite.add_font(
//!     ImtFont::from_file(
//!         "MyFont",
//!         ImtWeight::Normal,
//!         ImtRasterOpts::default(),
//!         device,
//!         queue,
//!         "MyFont.ttf",
//!     )
//!     .unwrap(),
//! );
//!
//! let glyphs = ilmenite
//!     .glyphs_for_text("MyFont", ImtWeight::Normal, 12.0, None, "Hello World!")
//!     .unwrap();
//! ```

pub mod bitmap;
pub mod error;
pub mod font;
pub mod image_view;
pub mod parse;
pub mod primative;
pub mod raster;
pub mod script;
pub mod shaders;
pub mod shape;

use std::collections::HashMap;

pub use bitmap::{ImtBitmapData, ImtGlyphBitmap};
use crossbeam::sync::ShardedLock;
pub use error::{ImtError, ImtErrorSrc, ImtErrorTy};
pub(crate) use font::ImtFontKey;
pub use font::{ImtFont, ImtWeight};
pub use image_view::{ImtImageVarient, ImtImageView};
pub use parse::{ImtFontProps, ImtParsedGlyph, ImtParser};
pub use primative::{ImtGeometry, ImtPoint, ImtPosition};
pub use raster::{ImtFillQuality, ImtRaster, ImtRasterOpts, ImtRasteredGlyph, ImtSampleQuality};
pub use script::{ImtLang, ImtScript};
pub use shape::{
    ImtGlyphInfo, ImtHoriAlign, ImtShapeOpts, ImtShapedGlyph, ImtShaper, ImtTextWrap, ImtVertAlign,
};
use vulkano::device::Features as VkFeatures;

pub fn ilmenite_required_vk_features() -> VkFeatures {
    VkFeatures {
        shader_storage_image_write_without_format: true,
        ..VkFeatures::empty()
    }
}

pub struct ImtGlyph {
    pub x: f32,
    pub y: f32,
    pub w: u32,
    pub h: u32,
    pub crop_x: f32,
    pub crop_y: f32,
    pub family: String,
    pub weight: ImtWeight,
    pub index: u16,
    pub bitmap: Option<ImtBitmapData>,
}

pub struct Ilmenite {
    fonts: ShardedLock<HashMap<ImtFontKey, ImtFont>>,
}

impl Ilmenite {
    pub fn new() -> Self {
        Ilmenite {
            fonts: ShardedLock::new(HashMap::new()),
        }
    }

    pub fn add_font(&self, font: ImtFont) {
        let key = font.key();
        self.fonts.write().unwrap().insert(key, font);
    }

    pub fn glyphs_for_text<T: AsRef<str>>(
        &self,
        family: String,
        weight: ImtWeight,
        text_height: f32,
        shape_ops: Option<ImtShapeOpts>,
        text: T,
    ) -> Result<Vec<ImtGlyph>, ImtError> {
        self.fonts
            .read()
            .unwrap()
            .get(&ImtFontKey {
                family,
                weight,
            })
            .ok_or(ImtError::src_and_ty(
                ImtErrorSrc::Ilmenite,
                ImtErrorTy::MissingFont,
            ))?
            .glyphs_for_text(
                text_height,
                shape_ops.unwrap_or(ImtShapeOpts::default()),
                text,
            )
    }
}