update dependencies, initial UTF-8 support
Some checks failed
Rust / build (push) Has been cancelled
Some checks failed
Rust / build (push) Has been cancelled
This commit is contained in:
parent
398cb8c165
commit
ad5f1e8abe
9 changed files with 805 additions and 648 deletions
94
src/font_renderer.rs
Normal file
94
src/font_renderer.rs
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
use crate::font_renderer::RenderError::{GlyphNotFound, OutOfBounds};
|
||||
use font_kit::canvas::{Canvas, Format, RasterizationOptions};
|
||||
use font_kit::error::GlyphLoadingError;
|
||||
use font_kit::family_name::FamilyName;
|
||||
use font_kit::font::Font;
|
||||
use font_kit::hinting::HintingOptions;
|
||||
use font_kit::properties::Properties;
|
||||
use font_kit::source::SystemSource;
|
||||
use pathfinder_geometry::transform2d::Transform2F;
|
||||
use pathfinder_geometry::vector::{vec2f, vec2i};
|
||||
use servicepoint::{Bitmap, Grid, Origin, Pixels, TILE_SIZE};
|
||||
use std::sync::Mutex;
|
||||
|
||||
pub struct FontRenderer8x8 {
|
||||
font: Font,
|
||||
canvas: Mutex<Canvas>,
|
||||
fallback_char: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum RenderError {
|
||||
#[error("Glyph not found for '{0}'")]
|
||||
GlyphNotFound(char),
|
||||
#[error(transparent)]
|
||||
GlyphLoadingError(#[from] GlyphLoadingError),
|
||||
#[error("out of bounds at {0} {1}")]
|
||||
OutOfBounds(usize, usize),
|
||||
}
|
||||
|
||||
impl FontRenderer8x8 {
|
||||
pub fn new(font: Font, fallback_char: Option<char>) -> Self {
|
||||
let canvas =
|
||||
Canvas::new(vec2i(TILE_SIZE as i32, TILE_SIZE as i32), Format::A8);
|
||||
assert_eq!(canvas.pixels.len(), TILE_SIZE * TILE_SIZE);
|
||||
assert_eq!(canvas.stride, TILE_SIZE);
|
||||
let fallback_char = fallback_char.and_then(|c| font.glyph_for_char(c));
|
||||
let result = Self {
|
||||
font,
|
||||
fallback_char,
|
||||
canvas: Mutex::new(canvas),
|
||||
};
|
||||
result
|
||||
}
|
||||
|
||||
pub fn render(
|
||||
&self,
|
||||
char: char,
|
||||
bitmap: &mut Bitmap,
|
||||
offset: Origin<Pixels>,
|
||||
) -> Result<(), RenderError> {
|
||||
let mut canvas = self.canvas.lock().unwrap();
|
||||
let glyph_id = self.font.glyph_for_char(char).or(self.fallback_char);
|
||||
let glyph_id = match glyph_id {
|
||||
None => return Err(GlyphNotFound(char)),
|
||||
Some(val) => val,
|
||||
};
|
||||
|
||||
canvas.pixels.fill(0);
|
||||
self.font.rasterize_glyph(
|
||||
&mut canvas,
|
||||
glyph_id,
|
||||
TILE_SIZE as f32,
|
||||
Transform2F::from_translation(vec2f(0f32, TILE_SIZE as f32))
|
||||
* Transform2F::default(),
|
||||
HintingOptions::None,
|
||||
RasterizationOptions::Bilevel,
|
||||
)?;
|
||||
|
||||
for y in 0..TILE_SIZE {
|
||||
for x in 0..TILE_SIZE {
|
||||
let index = x + y * TILE_SIZE;
|
||||
let canvas_val = canvas.pixels[index] != 0;
|
||||
let bitmap_x = (offset.x + x) as isize;
|
||||
let bitmap_y = (offset.y + y) as isize;
|
||||
if !bitmap.set_optional(bitmap_x, bitmap_y, canvas_val) {
|
||||
return Err(OutOfBounds(x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FontRenderer8x8 {
|
||||
fn default() -> Self {
|
||||
let utf8_font = SystemSource::new()
|
||||
.select_best_match(&[FamilyName::Monospace], &Properties::new())
|
||||
.unwrap()
|
||||
.load()
|
||||
.unwrap();
|
||||
FontRenderer8x8::new(utf8_font, Some('?'))
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue