Skip to main content

cotis_raylib/
fonts.rs

1//! Font loading and lazy size management for raylib text drawing.
2
3use raylib::consts::TextureFilter;
4use raylib::error::RaylibError;
5use raylib::prelude::*;
6use raylib::{RaylibHandle, RaylibThread};
7use std::collections::HashMap;
8
9/// A font file loaded at an initial size, with lazy loading of additional pixel sizes.
10///
11/// Created by [`RaylibRender::load_font_ex_and_keep`](crate::renderer::RaylibRender::load_font_ex_and_keep)
12/// and stored in the renderer's font table. Queued sizes are flushed at the start of each frame.
13///
14/// This type has no public methods; interact through font IDs on [`TextConfig`](cotis_defaults::element_configs::text_config::TextConfig).
15pub struct ScalableFont {
16    file_name: String,
17    chars: Option<String>,
18    filter: Option<TextureFilter>,
19    default_font: Font,
20    default_size: usize,
21    map: HashMap<usize, Font>,
22    to_load: Vec<usize>,
23}
24
25impl ScalableFont {
26    pub(crate) fn new(
27        file_name: String,
28        chars: Option<String>,
29        filter: Option<TextureFilter>,
30        rl: &mut RaylibHandle,
31        raylib_thread: &RaylibThread,
32        font_size: usize,
33    ) -> Result<Self, RaylibError> {
34        let font = rl.load_font_ex(
35            raylib_thread,
36            &file_name,
37            font_size as i32,
38            chars.as_deref(),
39        )?;
40        if let Some(tex_filter) = filter {
41            font.texture().set_texture_filter(raylib_thread, tex_filter);
42        }
43        let res = Self {
44            file_name,
45            chars,
46            filter,
47            default_font: font,
48            default_size: font_size,
49            map: Default::default(),
50            to_load: vec![],
51        };
52        Ok(res)
53    }
54
55    fn load(
56        &mut self,
57        font_size: usize,
58        rl: &mut RaylibHandle,
59        raylib_thread: &RaylibThread,
60    ) -> Result<(), RaylibError> {
61        if self.default_size == font_size {
62            return Ok(());
63        }
64        if self.map.contains_key(&font_size) {
65            return Ok(());
66        }
67        let font = rl.load_font_ex(
68            raylib_thread,
69            &self.file_name,
70            font_size as i32,
71            self.chars.as_deref(),
72        )?;
73        if let Some(filter) = self.filter {
74            font.texture().set_texture_filter(raylib_thread, filter);
75        }
76        self.map.insert(font_size, font);
77        Ok(())
78    }
79
80    pub(crate) fn get_font_for_size(&mut self, font_size: usize) -> &Font {
81        if !self.map.contains_key(&font_size) {
82            if font_size > 0 {
83                self.to_load.push(font_size);
84            }
85            &self.default_font
86        } else {
87            self.map.get(&font_size).unwrap()
88        }
89    }
90
91    pub(crate) fn get_font_for_size_borrow(&self, font_size: usize) -> &Font {
92        if !self.map.contains_key(&font_size) {
93            &self.default_font
94        } else {
95            self.map.get(&font_size).unwrap()
96        }
97    }
98
99    pub(crate) fn load_queued_fonts(
100        &mut self,
101        rl: &mut RaylibHandle,
102        raylib_thread: &RaylibThread,
103    ) -> Result<(), RaylibError> {
104        for size in self.to_load.clone().into_iter() {
105            self.load(size, rl, raylib_thread)?;
106        }
107        self.to_load.clear();
108        Ok(())
109    }
110}