text_typeset/atlas/
allocator.rs1use etagere::{AllocId, Allocation, BucketedAtlasAllocator, size2};
2
3const INITIAL_ATLAS_SIZE: i32 = 512;
4const MAX_ATLAS_SIZE: i32 = 4096;
5
6pub struct GlyphAtlas {
7 pub allocator: BucketedAtlasAllocator,
8 pub pixels: Vec<u8>,
9 pub width: u32,
10 pub height: u32,
11 pub dirty: bool,
12}
13
14impl Default for GlyphAtlas {
15 fn default() -> Self {
16 Self::new()
17 }
18}
19
20impl GlyphAtlas {
21 pub fn new() -> Self {
22 let size = INITIAL_ATLAS_SIZE;
23 let pixel_count = (size * size) as usize * 4;
24 Self {
25 allocator: BucketedAtlasAllocator::new(size2(size, size)),
26 pixels: vec![0u8; pixel_count],
27 width: size as u32,
28 height: size as u32,
29 dirty: false,
30 }
31 }
32
33 pub fn allocate(&mut self, width: u32, height: u32) -> Option<Allocation> {
40 let padded = size2(width as i32 + 1, height as i32 + 1);
41 if let Some(alloc) = self.allocator.allocate(padded) {
42 return Some(alloc);
43 }
44 let new_w = (self.width * 2).min(MAX_ATLAS_SIZE as u32) as i32;
46 let new_h = (self.height * 2).min(MAX_ATLAS_SIZE as u32) as i32;
47 if new_w as u32 == self.width && new_h as u32 == self.height {
48 return None; }
50 self.grow(new_w as u32, new_h as u32);
51 self.allocator.allocate(padded)
52 }
53
54 pub fn deallocate(&mut self, id: AllocId) {
55 self.allocator.deallocate(id);
56 }
57
58 fn grow(&mut self, new_width: u32, new_height: u32) {
59 let mut new_pixels = vec![0u8; (new_width * new_height) as usize * 4];
60 for y in 0..self.height {
62 let src_start = (y * self.width) as usize * 4;
63 let src_end = src_start + self.width as usize * 4;
64 let dst_start = (y * new_width) as usize * 4;
65 let dst_end = dst_start + self.width as usize * 4;
66 new_pixels[dst_start..dst_end].copy_from_slice(&self.pixels[src_start..src_end]);
67 }
68 self.allocator
69 .grow(size2(new_width as i32, new_height as i32));
70 self.pixels = new_pixels;
71 self.width = new_width;
72 self.height = new_height;
73 self.dirty = true;
74 }
75
76 pub fn blit_rgba(&mut self, x: u32, y: u32, w: u32, h: u32, data: &[u8]) {
78 for row in 0..h {
79 let src_start = (row * w) as usize * 4;
80 let src_end = src_start + w as usize * 4;
81 let dst_start = ((y + row) * self.width + x) as usize * 4;
82 let dst_end = dst_start + w as usize * 4;
83 self.pixels[dst_start..dst_end].copy_from_slice(&data[src_start..src_end]);
84 }
85 self.dirty = true;
86 }
87
88 pub fn blit_mask(&mut self, x: u32, y: u32, w: u32, h: u32, data: &[u8]) {
90 for row in 0..h {
91 for col in 0..w {
92 let alpha = data[(row * w + col) as usize];
93 let dst = ((y + row) * self.width + x + col) as usize * 4;
94 self.pixels[dst] = 255;
95 self.pixels[dst + 1] = 255;
96 self.pixels[dst + 2] = 255;
97 self.pixels[dst + 3] = alpha;
98 }
99 }
100 self.dirty = true;
101 }
102}