WIP
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
parent
247afa1666
commit
ad7974608b
14 changed files with 311 additions and 117 deletions
|
@ -2,7 +2,10 @@ use std::{collections::HashMap, sync::Arc};
|
|||
|
||||
use crate::{
|
||||
fonts::{FontId, GlyphId},
|
||||
geometry::{rect::RectI, vector::Vector2I},
|
||||
geometry::{
|
||||
rect::RectI,
|
||||
vector::{vec2i, Vector2I},
|
||||
},
|
||||
FontCache,
|
||||
};
|
||||
use etagere::BucketedAtlasAllocator;
|
||||
|
@ -17,19 +20,21 @@ struct GlyphDescriptor {
|
|||
}
|
||||
|
||||
pub struct SpriteCache {
|
||||
font_cache: Arc<FontCache>,
|
||||
device: metal::Device,
|
||||
size: Vector2I,
|
||||
atlas_size: Vector2I,
|
||||
font_cache: Arc<FontCache>,
|
||||
atlasses: Vec<Atlas>,
|
||||
glyphs: HashMap<GlyphDescriptor, (usize, RectI)>,
|
||||
glyphs: HashMap<GlyphDescriptor, Option<(usize, RectI)>>,
|
||||
}
|
||||
|
||||
impl SpriteCache {
|
||||
pub fn new(device: metal::Device, size: Vector2I) -> Self {
|
||||
pub fn new(device: metal::Device, size: Vector2I, font_cache: Arc<FontCache>) -> Self {
|
||||
let atlasses = vec![Atlas::new(&device, size)];
|
||||
Self {
|
||||
device,
|
||||
size,
|
||||
atlasses: vec![Atlas::new(&device, size)],
|
||||
atlas_size: size,
|
||||
font_cache,
|
||||
atlasses,
|
||||
glyphs: Default::default(),
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +44,12 @@ impl SpriteCache {
|
|||
font_id: FontId,
|
||||
font_size: f32,
|
||||
glyph_id: GlyphId,
|
||||
) -> (usize, RectI) {
|
||||
scale_factor: f32,
|
||||
) -> Option<(usize, RectI)> {
|
||||
let font_cache = &self.font_cache;
|
||||
let atlasses = &mut self.atlasses;
|
||||
let atlas_size = self.atlas_size;
|
||||
let device = &self.device;
|
||||
self.glyphs
|
||||
.entry(GlyphDescriptor {
|
||||
font_id,
|
||||
|
@ -47,12 +57,27 @@ impl SpriteCache {
|
|||
glyph_id,
|
||||
})
|
||||
.or_insert_with(|| {
|
||||
let rendered_glyph = self.font_cache.render_glyph(font_id, font_size, glyph_id);
|
||||
// let atlas = self.atlasses.last_mut().unwrap();
|
||||
todo!()
|
||||
let (size, mask) =
|
||||
font_cache.render_glyph(font_id, font_size, glyph_id, scale_factor)?;
|
||||
assert!(size.x() < atlas_size.x());
|
||||
assert!(size.y() < atlas_size.y());
|
||||
|
||||
let atlas = atlasses.last_mut().unwrap();
|
||||
if let Some(bounds) = atlas.try_insert(size, &mask) {
|
||||
Some((atlasses.len() - 1, bounds))
|
||||
} else {
|
||||
let mut atlas = Atlas::new(device, atlas_size);
|
||||
let bounds = atlas.try_insert(size, &mask).unwrap();
|
||||
atlasses.push(atlas);
|
||||
Some((atlasses.len() - 1, bounds))
|
||||
}
|
||||
})
|
||||
.clone()
|
||||
}
|
||||
|
||||
pub fn atlas_texture(&self, atlas_id: usize) -> Option<&metal::TextureRef> {
|
||||
self.atlasses.get(atlas_id).map(|a| a.texture.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
struct Atlas {
|
||||
|
@ -72,4 +97,24 @@ impl Atlas {
|
|||
texture: device.new_texture(&descriptor),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_insert(&mut self, size: Vector2I, mask: &[u8]) -> Option<RectI> {
|
||||
let allocation = self
|
||||
.allocator
|
||||
.allocate(etagere::size2(size.x(), size.y()))?;
|
||||
|
||||
let bounds = allocation.rectangle;
|
||||
let region = metal::MTLRegion::new_2d(
|
||||
bounds.min.x as u64,
|
||||
bounds.min.y as u64,
|
||||
bounds.width() as u64,
|
||||
bounds.height() as u64,
|
||||
);
|
||||
self.texture
|
||||
.replace_region(region, 0, mask.as_ptr() as *const _, size.x() as u64);
|
||||
Some(RectI::from_points(
|
||||
vec2i(bounds.min.x, bounds.min.y),
|
||||
vec2i(bounds.max.x, bounds.max.y),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue