///|
/// Atlas that combines region tracking (GlyphCache) with pixel storage.
///|
pub struct GlyphAtlas {
cache : GlyphCache
width : Int
height : Int
pixels : Array[Int]
mut dirty : Bool
mut last_used_generation : Int
}
///|
pub fn GlyphAtlas::new(width : Int, height : Int, page_id : Int) -> GlyphAtlas {
let total = width * height * 4
let pixels : Array[Int] = Array::make(total, 0)
{
cache: GlyphCache::new(width.to_double(), height.to_double(), page_id),
width,
height,
pixels,
dirty: false,
last_used_generation: 0,
}
}
///|
pub fn GlyphAtlas::get_cache(self : GlyphAtlas) -> GlyphCache {
self.cache
}
///|
pub fn GlyphAtlas::get_pixels(self : GlyphAtlas) -> Array[Int] {
self.pixels
}
///|
/// Rasterize a single glyph and place it into the atlas.
pub fn GlyphAtlas::rasterize_glyph(
self : GlyphAtlas,
font : TTFont,
codepoint : Int,
size_px : Double,
) -> GlyphCacheEntry? {
let glyph_id = font.glyph_index(codepoint)
let cache_key = make_glyph_cache_key(glyph_id, size_px)
match self.cache.get(cache_key) {
Some(entry) => return Some(entry)
None => ()
}
match rasterize_glyph(font, codepoint, size_px) {
None => None
Some(bitmap) =>
match
self.cache.allocate(
cache_key,
bitmap.width.to_double(),
bitmap.height.to_double(),
) {
None => None
Some(entry) => {
blit_to_atlas(
self.pixels,
self.width,
bitmap,
entry.atlas_x.to_int(),
entry.atlas_y.to_int(),
)
self.dirty = true
Some(entry)
}
}
}
}