Skip to main content

spyne_text/fonts/atlas/
generator.rs

1pub struct Atlas {
2    lookup_table: Vec<Option<GlyphRegion>>,
3    algorithm: AtlasAlgorithm,
4    width: usize,
5    height: usize,
6    current_x: usize,
7    current_y: usize
8}
9
10impl Atlas {
11    pub fn lookup_table(&self) -> &[Option<GlyphRegion>] {
12        &self.lookup_table
13    }
14    
15    pub fn algorithm(&self) -> AtlasAlgorithm {
16        self.algorithm
17    }
18    
19    pub fn width(&self) -> usize {
20        self.width
21    }
22    
23    pub fn height(&self) -> usize {
24        self.height
25    }
26    
27    pub fn current_x(&self) -> usize {
28        self.current_x
29    }
30    
31    pub fn current_y(&self) -> usize {
32        self.current_y
33    }
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub struct GlyphRegion {
38    x: usize,
39    y: usize,
40    width: usize,
41    height: usize
42}
43
44impl GlyphRegion {
45    pub fn x(&self) -> usize {
46        self.x
47    }
48    
49    pub fn y(&self) -> usize {
50        self.y
51    }
52    
53    pub fn width(&self) -> usize {
54        self.width
55    }
56    
57    pub fn height(&self) -> usize {
58        self.height
59    }
60}
61
62impl Atlas {
63    pub fn new(algorithm: AtlasAlgorithm) -> Self {
64        Self {
65            lookup_table: vec![None; 1114112],
66            algorithm,
67            width: 0,
68            height: 0,
69            current_x: 0,
70            current_y: 0
71        }
72    }
73    
74    pub fn append(&mut self, bitmaps: Vec<(char, Vec<Vec<u8>>)>, buffer: &mut Vec<(GlyphRegion, Vec<u8>)>) {
75        match self.algorithm {
76            AtlasAlgorithm::ShelfPacker => self.shelf_packer(bitmaps, buffer)
77        }
78    }
79    
80    // UNOPTIMIZED, BENCHMARK LATER AND SEE IF IT NEEDS TO BE OPTIMIZED
81    
82    fn shelf_packer(&mut self, mut bitmaps: Vec<(char, Vec<Vec<u8>>)>, buffer: &mut Vec<(GlyphRegion, Vec<u8>)>) {
83        bitmaps.sort_by(|a, b| b.1.len().cmp(&a.1.len()));
84        let mut area = 0;
85        bitmaps.iter()
86            .for_each(|(_, bitmap)| {
87                area += bitmap.len() * bitmap[0].len();
88            });
89        area += self.width * self.width;
90        let n = area.isqrt();
91        let width = if (n & (n - 1)) != 0 { 1 << (usize::BITS - n.leading_zeros()) } else { n };
92        if self.height == 0 { self.height = bitmaps[0].1.len(); }
93        if self.width < width { self.width = width; }
94        buffer.extend(bitmaps.into_iter()
95            .map(|(char, bitmap)| {
96                if self.current_x + bitmap[0].len() > self.width || bitmap.len() > self.height - self.current_y {
97                    self.current_x = 0;
98                    self.current_y = self.height;
99                    self.height += bitmap.len();
100                }
101                
102                let region = GlyphRegion {
103                    x: self.current_x,
104                    y: self.current_y,
105                    width: bitmap[0].len(),
106                    height: bitmap.len()
107                };
108                
109                self.lookup_table[char as usize] = Some(region);
110                
111                self.current_x += bitmap[0].len();
112                
113                (region, bitmap.into_iter().flatten().collect::<Vec<u8>>())
114            }).collect::<Vec<(GlyphRegion, Vec<u8>)>>())
115    }
116}
117
118#[derive(Clone, Copy)]
119pub enum AtlasAlgorithm {
120    ShelfPacker
121    // MaxRects
122    // Skyline
123}
124
125#[cfg(test)]
126mod test {
127    use crate::fonts::atlas::generator::{Atlas, AtlasAlgorithm, GlyphRegion};
128
129    #[test]
130    fn test_shelf_packer() {
131        let mut atlas = Atlas::new(AtlasAlgorithm::ShelfPacker);
132        let a_bitmap = vec![
133            vec![0, 1, 0],
134            vec![1, 1, 1],
135            vec![1, 0, 1]
136        ];
137        let d_bitmap = vec![
138            vec![1, 1, 0],
139            vec![1, 0, 1],
140            vec![1, 1, 0]
141        ];
142        let b_bitmap = vec![
143            vec![1, 1, 0],
144            vec![1, 0, 1],
145            vec![1, 1, 0],
146            vec![1, 0, 1],
147            vec![1, 1, 0]
148        ];
149        let mut regions: Vec<(GlyphRegion, Vec<u8>)> = Vec::new();
150        atlas.append(
151            vec![
152                ('A', a_bitmap),
153                ('D', d_bitmap),
154                ('B', b_bitmap)
155            ],
156            &mut regions
157        );
158        let b_glyph_region = atlas.lookup_table['B' as usize];
159        match b_glyph_region {
160            Some(gr) => {
161                assert_eq!(gr.x, 0);
162                assert_eq!(gr.y, 0);
163                assert_eq!(gr.width, 3);
164                assert_eq!(gr.height, 5);
165            }
166            None => panic!("Glyph 'B' doesn't exist when it clearly should")
167        }
168        assert_eq!(regions[0].1.len(), 15);
169        assert_eq!(regions[0].1[0 * 3 + 0], 1);
170        assert_eq!(regions[0].1[0 * 3 + 1], 1);
171        assert_eq!(regions[0].1[0 * 3 + 2], 0);
172        assert_eq!(regions[0].1[1 * 3 + 0], 1);
173        assert_eq!(regions[0].1[1 * 3 + 1], 0);
174        assert_eq!(regions[0].1[1 * 3 + 2], 1);
175        assert_eq!(regions[0].1[2 * 3 + 0], 1);
176        assert_eq!(regions[0].1[2 * 3 + 1], 1);
177        assert_eq!(regions[0].1[2 * 3 + 2], 0);
178        assert_eq!(regions[0].1[3 * 3 + 1], 0);
179        assert_eq!(regions[0].1[3 * 3 + 2], 1);
180        assert_eq!(regions[0].1[4 * 3 + 0], 1);
181        assert_eq!(regions[0].1[4 * 3 + 1], 1);
182        assert_eq!(regions[0].1[4 * 3 + 2], 0);
183        let a_glyph_region = atlas.lookup_table['A' as usize];
184        match a_glyph_region {
185            Some(gr) => {
186                assert_eq!(gr.x, 3);
187                assert_eq!(gr.y, 0);
188                assert_eq!(gr.width, 3);
189                assert_eq!(gr.height, 3);
190            }
191            None => panic!("Glyph 'A' doesn't exist when it clearly should")
192        }
193        assert_eq!(regions[1].1[0 * 3 + 0], 0);
194        assert_eq!(regions[1].1[0 * 3 + 1], 1);
195        assert_eq!(regions[1].1[0 * 3 + 2], 0);
196        assert_eq!(regions[1].1[1 * 3 + 0], 1);
197        assert_eq!(regions[1].1[1 * 3 + 1], 1);
198        assert_eq!(regions[1].1[1 * 3 + 2], 1);
199        assert_eq!(regions[1].1[2 * 3 + 0], 1);
200        assert_eq!(regions[1].1[2 * 3 + 1], 0);
201        assert_eq!(regions[1].1[2 * 3 + 2], 1);
202        // Horizontal overflow
203        let d_glyph_region = atlas.lookup_table['D' as usize];
204        match d_glyph_region {
205            Some(gr) => {
206                assert_eq!(gr.x, 0);
207                assert_eq!(gr.y, 5);
208                assert_eq!(gr.width, 3);
209                assert_eq!(gr.height, 3);
210            },
211            None => panic!("Glyph 'D' doesn't exist when it clearly should")
212        }
213        assert_eq!(regions[2].1[0 * 3 + 0], 1);
214        assert_eq!(regions[2].1[0 * 3 + 1], 1);
215        assert_eq!(regions[2].1[0 * 3 + 2], 0);
216        assert_eq!(regions[2].1[1 * 3 + 0], 1);
217        assert_eq!(regions[2].1[1 * 3 + 1], 0);
218        assert_eq!(regions[2].1[1 * 3 + 2], 1);
219        assert_eq!(regions[2].1[2 * 3 + 0], 1);
220        assert_eq!(regions[2].1[2 * 3 + 1], 1);
221        assert_eq!(regions[2].1[2 * 3 + 2], 0);
222        
223        // Vertical Overflow
224        let mut atlas = Atlas::new(AtlasAlgorithm::ShelfPacker);
225        let a_bitmap = vec![
226            vec![0, 1, 0],
227            vec![1, 1, 1],
228            vec![1, 0, 1]
229        ];
230        let d_bitmap = vec![
231            vec![1, 1, 0],
232            vec![1, 0, 1],
233            vec![1, 1, 0]
234        ];
235        let b_bitmap = vec![
236            vec![1, 1, 0],
237            vec![1, 0, 1],
238            vec![1, 1, 0],
239            vec![1, 0, 1],
240            vec![1, 1, 0]
241        ];
242        let mut regions: Vec<(GlyphRegion, Vec<u8>)> = Vec::new();
243        atlas.append(vec![('A', a_bitmap)], &mut regions);
244        atlas.append(vec![('D', d_bitmap)], &mut regions);
245        atlas.append(vec![('B', b_bitmap)], &mut regions);
246        let a_glyph_region = atlas.lookup_table['A' as usize];
247        match a_glyph_region {
248            Some(gr) => {
249                assert_eq!(gr.x, 0);
250                assert_eq!(gr.y, 0);
251                assert_eq!(gr.width, 3);
252                assert_eq!(gr.height, 3);
253            }
254            None => panic!("Glyph 'A' doesn't exist when it clearly should")
255        }
256        assert_eq!(regions[0].1[0 * 3 + 0], 0);
257        assert_eq!(regions[0].1[0 * 3 + 1], 1);
258        assert_eq!(regions[0].1[0 * 3 + 2], 0);
259        assert_eq!(regions[0].1[1 * 3 + 0], 1);
260        assert_eq!(regions[0].1[1 * 3 + 1], 1);
261        assert_eq!(regions[0].1[1 * 3 + 2], 1);
262        assert_eq!(regions[0].1[2 * 3 + 0], 1);
263        assert_eq!(regions[0].1[2 * 3 + 1], 0);
264        assert_eq!(regions[0].1[2 * 3 + 2], 1);
265        let d_glyph_region = atlas.lookup_table['D' as usize];
266        match d_glyph_region {
267            Some(gr) => {
268                assert_eq!(gr.x, 3);
269                assert_eq!(gr.y, 0);
270                assert_eq!(gr.width, 3);
271                assert_eq!(gr.height, 3);
272            },
273            None => panic!("Glyph 'D' doesn't exist when it clearly should")
274        }
275        assert_eq!(regions[1].1[0 * 3 + 0], 1);
276        assert_eq!(regions[1].1[0 * 3 + 1], 1);
277        assert_eq!(regions[1].1[0 * 3 + 2], 0);
278        assert_eq!(regions[1].1[1 * 3 + 0], 1);
279        assert_eq!(regions[1].1[1 * 3 + 1], 0);
280        assert_eq!(regions[1].1[1 * 3 + 2], 1);
281        assert_eq!(regions[1].1[2 * 3 + 0], 1);
282        assert_eq!(regions[1].1[2 * 3 + 1], 1);
283        assert_eq!(regions[1].1[2 * 3 + 2], 0);
284        let b_glyph_region = atlas.lookup_table['B' as usize];
285        match b_glyph_region {
286            Some(gr) => {
287                assert_eq!(gr.x, 0);
288                assert_eq!(gr.y, 3);
289                assert_eq!(gr.width, 3);
290                assert_eq!(gr.height, 5);
291            }
292            None => panic!("Glyph 'B' doesn't exist when it clearly should")
293        }
294        assert_eq!(regions[2].1.len(), 15);
295        assert_eq!(regions[2].1[0 * 3 + 0], 1);
296        assert_eq!(regions[2].1[0 * 3 + 1], 1);
297        assert_eq!(regions[2].1[0 * 3 + 2], 0);
298        assert_eq!(regions[2].1[1 * 3 + 0], 1);
299        assert_eq!(regions[2].1[1 * 3 + 1], 0);
300        assert_eq!(regions[2].1[1 * 3 + 2], 1);
301        assert_eq!(regions[2].1[2 * 3 + 0], 1);
302        assert_eq!(regions[2].1[2 * 3 + 1], 1);
303        assert_eq!(regions[2].1[2 * 3 + 2], 0);
304        assert_eq!(regions[2].1[3 * 3 + 0], 1);
305        assert_eq!(regions[2].1[3 * 3 + 1], 0);
306        assert_eq!(regions[2].1[3 * 3 + 2], 1);
307        assert_eq!(regions[2].1[4 * 3 + 0], 1);
308        assert_eq!(regions[2].1[4 * 3 + 1], 1);
309        assert_eq!(regions[2].1[4 * 3 + 2], 0);
310    }
311}