use assets_manager::{loader::TomlLoader, AnyCache, Asset, BoxedError, Compound, SharedString};
use blit::{prelude::SubRect, Blit, BlitBuffer, BlitOptions};
use serde::Deserialize;
use vek::{Extent2, Vec2};
use crate::{sprite::Sprite, SIZE};
pub struct Font {
sprite: BlitBuffer,
pub char_size: Extent2<u8>,
}
impl Font {
pub fn render(&self, text: &str, pos: Vec2<f64>, canvas: &mut [u32]) {
let char_start = '!';
let char_end = '~';
let pos: Vec2<i32> = pos.as_() - (self.char_size.w as i32, 0);
let mut x = pos.x;
let mut y = pos.y;
text.chars().for_each(|ch| {
x += self.char_size.w as i32;
if ch < char_start || ch > char_end {
if ch == '\n' {
x = pos.x;
y += self.char_size.h as i32;
} else if ch == '\t' {
x += self.char_size.w as i32 * 3;
}
return;
}
let char_offset = (ch as u8 - char_start as u8) as u32 * self.char_size.w as u32;
self.sprite.blit(
canvas,
SIZE.into_tuple().into(),
&BlitOptions::new_position(x, y).with_sub_rect(SubRect::new(
char_offset,
0,
self.char_size.into_tuple(),
)),
);
});
}
pub fn render_centered(&self, text: &str, pos: Vec2<f64>, canvas: &mut [u32]) {
self.render(
text,
pos - Vec2::new(
(text.len() as f64 * self.char_size.w as f64) / 2.0,
self.char_size.h as f64 / 2.0,
),
canvas,
)
}
}
impl Compound for Font {
fn load(cache: AnyCache, id: &SharedString) -> Result<Self, BoxedError> {
let sprite = cache.load_owned::<Sprite>(id)?.into_blit_buffer();
let metadata = cache.load::<FontMetadata>(id)?.read();
let char_size = Extent2::new(metadata.char_width, metadata.char_height);
Ok(Self { sprite, char_size })
}
}
#[derive(Deserialize)]
struct FontMetadata {
char_width: u8,
char_height: u8,
}
impl Asset for FontMetadata {
const EXTENSION: &'static str = "toml";
type Loader = TomlLoader;
}